mattercontrol/PartPreviewWindow/View3D/View3DWidget.cs

2624 lines
80 KiB
C#
Raw Normal View History

2014-01-29 19:09:30 -08:00
/*
Copyright (c) 2014, Lars Brubaker
2014-01-29 19:09:30 -08:00
All rights reserved.
Redistribution and use in source and binary forms, with or without
2015-04-08 15:20:10 -07:00
modification, are permitted provided that the following conditions are met:
2014-01-29 19:09:30 -08:00
1. Redistributions of source code must retain the above copyright notice, this
2015-04-08 15:20:10 -07:00
list of conditions and the following disclaimer.
2014-01-29 19:09:30 -08:00
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
2015-04-08 15:20:10 -07:00
and/or other materials provided with the distribution.
2014-01-29 19:09:30 -08:00
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
2015-04-08 15:20:10 -07:00
of the authors and should not be interpreted as representing official policies,
2014-01-29 19:09:30 -08:00
either expressed or implied, of the FreeBSD Project.
*/
using System;
2017-05-27 16:29:35 -07:00
using System.Collections;
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;
2014-01-29 19:09:30 -08:00
using MatterHackers.Agg;
using MatterHackers.Agg.Image;
using MatterHackers.Agg.ImageProcessing;
using MatterHackers.Agg.PlatformAbstract;
2015-04-08 15:20:10 -07:00
using MatterHackers.Agg.Transform;
2014-01-29 19:09:30 -08:00
using MatterHackers.Agg.UI;
using MatterHackers.Agg.VertexSource;
2017-03-15 16:17:06 -07:00
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.PrintQueue;
using MatterHackers.MatterControl.SlicerConfiguration;
2014-01-29 19:09:30 -08:00
using MatterHackers.MeshVisualizer;
using MatterHackers.PolygonMesh;
2014-01-29 19:09:30 -08:00
using MatterHackers.RayTracer;
using MatterHackers.RenderOpenGl;
using MatterHackers.VectorMath;
2017-05-27 16:29:35 -07:00
using MatterHackers.RayTracer.Traceable;
2014-01-29 19:09:30 -08:00
namespace MatterHackers.MatterControl.PartPreviewWindow
{
2017-03-15 16:17:06 -07:00
public class BaseObject3DEditor : IObject3DEditor
{
private IObject3D item;
private View3DWidget view3DWidget;
public string Name => "General";
2017-03-15 16:17:06 -07:00
public bool Unlocked => true;
2017-03-15 16:17:06 -07:00
public IEnumerable<Type> SupportedTypes()
{
return new Type[] { typeof(Object3D) };
}
public GuiWidget Create(IObject3D item, View3DWidget view3DWidget)
{
this.view3DWidget = view3DWidget;
this.item = item;
FlowLayoutWidget mainContainer = new FlowLayoutWidget(FlowDirection.TopToBottom);
FlowLayoutWidget tabContainer = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
HAnchor = HAnchor.AbsolutePosition,
Visible = true,
Width = view3DWidget.WhiteButtonFactory.FixedWidth
};
mainContainer.AddChild(tabContainer);
Button updateButton = view3DWidget.textImageButtonFactory.Generate("Color".Localize());
updateButton.Margin = new BorderDouble(5);
updateButton.HAnchor = HAnchor.ParentRight;
updateButton.Click += ChangeColor;
tabContainer.AddChild(updateButton);
return mainContainer;
}
Random rand = new Random();
private void ChangeColor(object sender, EventArgs e)
{
item.Color = new RGBA_Bytes(rand.Next(255), rand.Next(255), rand.Next(255));
view3DWidget.Invalidate();
}
}
public interface IInteractionVolumeCreator
{
2016-03-04 10:11:05 -08:00
InteractionVolume CreateInteractionVolume(View3DWidget widget);
}
2017-03-15 16:17:06 -07:00
public class DragDropLoadProgress
{
IObject3D trackingObject;
View3DWidget view3DWidget;
private ProgressBar progressBar;
public DragDropLoadProgress(View3DWidget view3DWidget, IObject3D trackingObject)
{
this.trackingObject = trackingObject;
this.view3DWidget = view3DWidget;
view3DWidget.AfterDraw += View3DWidget_AfterDraw;
progressBar = new ProgressBar(80, 15)
{
FillColor = ActiveTheme.Instance.PrimaryAccentColor,
};
}
private void View3DWidget_AfterDraw(object sender, DrawEventArgs e)
{
if (view3DWidget?.meshViewerWidget?.TrackballTumbleWidget != null)
{
AxisAlignedBoundingBox bounds = trackingObject.GetAxisAlignedBoundingBox(Matrix4X4.Identity);
Vector3 renderPosition = bounds.Center;
Vector2 cornerScreenSpace = view3DWidget.meshViewerWidget.TrackballTumbleWidget.GetScreenPosition(renderPosition) - new Vector2(40, 20);
e.graphics2D.PushTransform();
Affine currentGraphics2DTransform = e.graphics2D.GetTransform();
Affine accumulatedTransform = currentGraphics2DTransform * Affine.NewTranslation(cornerScreenSpace.x, cornerScreenSpace.y);
e.graphics2D.SetTransform(accumulatedTransform);
progressBar.OnDraw(e.graphics2D);
e.graphics2D.PopTransform();
}
}
public void ProgressReporter(double progress0To1, string processingState, out bool continueProcessing)
2017-03-15 16:17:06 -07:00
{
continueProcessing = true;
progressBar.RatioComplete = progress0To1;
if (progress0To1 == 1)
{
if (view3DWidget != null)
{
view3DWidget.AfterDraw -= View3DWidget_AfterDraw;
}
view3DWidget = null;
}
}
}
public class InteractionVolumePlugin : IInteractionVolumeCreator
{
2016-03-04 10:11:05 -08:00
public virtual InteractionVolume CreateInteractionVolume(View3DWidget widget)
{
return null;
}
}
2015-04-08 15:20:10 -07:00
public partial class View3DWidget : PartPreview3DWidget
{
2017-03-15 16:17:06 -07:00
private bool DoBooleanTest = false;
2017-04-05 19:03:04 -07:00
private bool deferEditorTillMouseUp = false;
2017-03-15 16:17:06 -07:00
public FlowLayoutWidget doEdittingButtonsContainer;
public UndoBuffer UndoBuffer { get; private set; } = new UndoBuffer();
public readonly int EditButtonHeight = 44;
2017-03-15 16:17:06 -07:00
private static string PartsNotPrintableMessage = "Parts are not on the bed or outside the print area.\n\nWould you like to center them on the bed?".Localize();
private static string PartsNotPrintableTitle = "Parts not in print area".Localize();
private Action afterSaveCallback = null;
2015-05-30 12:48:16 -07:00
private bool editorThatRequestedSave = false;
private ExportPrintItemWindow exportingWindow = null;
private ObservableCollection<GuiWidget> extruderButtons = new ObservableCollection<GuiWidget>();
private bool hasDrawn = false;
2017-03-15 16:17:06 -07:00
2015-05-30 12:48:16 -07:00
private OpenMode openMode;
private bool partHasBeenEdited = false;
2017-03-15 16:17:06 -07:00
private PrintItemWrapper printItemWrapper { get; set; }
2015-04-08 15:20:10 -07:00
private ProgressControl processingProgressControl;
2015-05-30 12:48:16 -07:00
private SaveAsWindow saveAsWindow = null;
private SplitButton saveButtons;
private bool saveSucceded = true;
private RGBA_Bytes[] SelectionColors = new RGBA_Bytes[] { new RGBA_Bytes(131, 4, 66), new RGBA_Bytes(227, 31, 61), new RGBA_Bytes(255, 148, 1), new RGBA_Bytes(247, 224, 23), new RGBA_Bytes(143, 212, 1) };
private Stopwatch timeSinceLastSpin = new Stopwatch();
private Stopwatch timeSinceReported = new Stopwatch();
private Matrix4X4 transformOnMouseDown = Matrix4X4.Identity;
private EventHandler unregisterEvents;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
private bool viewIsInEditModePreLock = false;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
private bool wasInSelectMode = false;
2015-04-08 15:20:10 -07:00
public event EventHandler SelectedTransformChanged;
public static ImageBuffer ArrowRight
{
get
{
2016-10-10 15:16:26 -07:00
if (ActiveTheme.Instance.IsDarkTheme)
{
return StaticData.Instance.LoadIcon("icon_arrow_right_no_border_32x32.png", 32, 32).InvertLightness();
}
else
{
return StaticData.Instance.LoadIcon("icon_arrow_right_no_border_32x32.png", 32, 32);
}
}
}
public static ImageBuffer ArrowDown
{
get
{
2016-10-10 15:16:26 -07:00
if (ActiveTheme.Instance.IsDarkTheme)
{
return StaticData.Instance.LoadIcon("icon_arrow_down_no_border_32x32.png", 32, 32).InvertLightness();
}
else
{
return StaticData.Instance.LoadIcon("icon_arrow_down_no_border_32x32.png", 32, 32);
}
}
}
2017-03-15 16:17:06 -07:00
protected FlowLayoutWidget editPlateButtonsContainer;
public View3DWidget(PrintItemWrapper printItemWrapper, Vector3 viewerVolume, Vector2 bedCenter, BedShape bedShape, WindowMode windowType, AutoRotate autoRotate, ViewControls3D viewControls3D, OpenMode openMode = OpenMode.Viewing)
: base(viewControls3D)
2015-05-30 12:48:16 -07:00
{
this.openMode = openMode;
this.windowType = windowType;
allowAutoRotate = (autoRotate == AutoRotate.Enabled);
autoRotating = allowAutoRotate;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
this.printItemWrapper = printItemWrapper;
this.Name = "View3DWidget";
2015-04-08 15:20:10 -07:00
this.BackgroundColor = ApplicationController.Instance.Theme.TabBodyBackground;
viewControls3D.TransformStateChanged += ViewControls3D_TransformStateChanged;
2015-05-30 12:48:16 -07:00
FlowLayoutWidget mainContainerTopToBottom = new FlowLayoutWidget(FlowDirection.TopToBottom);
mainContainerTopToBottom.HAnchor = Agg.UI.HAnchor.Max_FitToChildren_ParentWidth;
mainContainerTopToBottom.VAnchor = Agg.UI.VAnchor.Max_FitToChildren_ParentHeight;
2015-04-08 15:20:10 -07:00
var centerPartPreviewAndControls = new FlowLayoutWidget(FlowDirection.LeftToRight);
2015-05-30 12:48:16 -07:00
centerPartPreviewAndControls.Name = "centerPartPreviewAndControls";
centerPartPreviewAndControls.AnchorAll();
2015-04-08 15:20:10 -07:00
var textImageButtonFactory = ApplicationController.Instance.Theme.BreadCrumbButtonFactorySmallMargins;
2015-05-30 12:48:16 -07:00
GuiWidget viewArea = new GuiWidget();
viewArea.AnchorAll();
{
2017-03-15 16:17:06 -07:00
meshViewerWidget = new MeshViewerWidget(viewerVolume, bedCenter, bedShape);
2015-04-08 15:20:10 -07:00
//viewControls3D.RegisterViewer(meshViewerWidget);
2015-05-30 12:48:16 -07:00
PutOemImageOnBed();
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
meshViewerWidget.AnchorAll();
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
viewArea.AddChild(meshViewerWidget);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
centerPartPreviewAndControls.AddChild(viewArea);
mainContainerTopToBottom.AddChild(centerPartPreviewAndControls);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
FlowLayoutWidget buttonBottomPanel = new FlowLayoutWidget(FlowDirection.LeftToRight);
buttonBottomPanel.HAnchor = HAnchor.ParentLeftRight;
buttonBottomPanel.Padding = new BorderDouble(3, 3);
buttonBottomPanel.BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor;
2015-04-08 15:20:10 -07:00
HashSet<IObject3DEditor> mappedEditors;
objectEditorsByType = new Dictionary<Type, HashSet<IObject3DEditor>>();
// TODO: Consider only loading once into a static
var objectEditors = new PluginFinder<IObject3DEditor>().Plugins;
foreach (IObject3DEditor editor in objectEditors)
{
foreach (Type type in editor.SupportedTypes())
{
if (!objectEditorsByType.TryGetValue(type, out mappedEditors))
{
mappedEditors = new HashSet<IObject3DEditor>();
objectEditorsByType.Add(type, mappedEditors);
}
mappedEditors.Add(editor);
}
}
2017-03-15 16:17:06 -07:00
Scene.SelectionChanged += Scene_SelectionChanged;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
// add in the plater tools
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
FlowLayoutWidget editToolBar = new FlowLayoutWidget();
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
string progressFindPartsLabel = "Entering Editor".Localize();
string progressFindPartsLabelFull = "{0}:".FormatWith(progressFindPartsLabel);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
processingProgressControl = new ProgressControl(progressFindPartsLabelFull, ActiveTheme.Instance.PrimaryTextColor, ActiveTheme.Instance.PrimaryAccentColor);
processingProgressControl.VAnchor = Agg.UI.VAnchor.ParentCenter;
editToolBar.AddChild(processingProgressControl);
editToolBar.VAnchor |= Agg.UI.VAnchor.ParentCenter;
processingProgressControl.Visible = false;
2015-04-08 15:20:10 -07:00
doEdittingButtonsContainer = new FlowLayoutWidget();
doEdittingButtonsContainer.Visible = false;
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
{
2014-12-20 09:07:13 -08:00
Button addButton = textImageButtonFactory.Generate("Insert".Localize(), "icon_insert_32x32.png");
2015-04-08 15:20:10 -07:00
addButton.Margin = new BorderDouble(right: 10);
doEdittingButtonsContainer.AddChild(addButton);
addButton.Click += (sender, e) =>
{
UiThread.RunOnIdle(() =>
2015-04-08 15:20:10 -07:00
{
FileDialog.OpenFileDialog(
new OpenFileDialogParams(ApplicationSettings.OpenDesignFileParams, multiSelect: true),
(openParams) =>
{
LoadAndAddPartsToPlate(openParams.FileNames);
});
});
};
2014-01-29 19:09:30 -08:00
2014-12-20 09:07:13 -08:00
GuiWidget separator = new GuiWidget(1, 2);
separator.BackgroundColor = ActiveTheme.Instance.PrimaryTextColor;
separator.Margin = new BorderDouble(4, 2);
separator.VAnchor = VAnchor.ParentBottomTop;
doEdittingButtonsContainer.AddChild(separator);
2015-04-08 15:20:10 -07:00
Button ungroupButton = textImageButtonFactory.Generate("Ungroup".Localize());
ungroupButton.Name = "3D View Ungroup";
2015-04-08 15:20:10 -07:00
doEdittingButtonsContainer.AddChild(ungroupButton);
ungroupButton.Click += (sender, e) =>
{
UngroupSelectedMeshGroup();
};
2015-04-08 15:20:10 -07:00
Button groupButton = textImageButtonFactory.Generate("Group".Localize());
groupButton.Name = "3D View Group";
2015-04-08 15:20:10 -07:00
doEdittingButtonsContainer.AddChild(groupButton);
groupButton.Click += (sender, e) =>
{
GroupSelectedMeshs();
};
2015-04-08 15:20:10 -07:00
Button alignButton = textImageButtonFactory.Generate("Align".Localize());
doEdittingButtonsContainer.AddChild(alignButton);
alignButton.Click += (sender, e) =>
{
AlignToSelectedMeshGroup();
};
Button arrangeButton = textImageButtonFactory.Generate("Arrange".Localize());
doEdittingButtonsContainer.AddChild(arrangeButton);
arrangeButton.Click += (sender, e) =>
{
AutoArrangePartsInBackground();
};
2014-12-20 09:07:13 -08:00
GuiWidget separatorTwo = new GuiWidget(1, 2);
separatorTwo.BackgroundColor = ActiveTheme.Instance.PrimaryTextColor;
separatorTwo.Margin = new BorderDouble(4, 2);
separatorTwo.VAnchor = VAnchor.ParentBottomTop;
doEdittingButtonsContainer.AddChild(separatorTwo);
2015-04-08 15:20:10 -07:00
Button copyButton = textImageButtonFactory.Generate("Copy".Localize());
2015-09-01 16:03:29 -07:00
copyButton.Name = "3D View Copy";
2015-04-08 15:20:10 -07:00
doEdittingButtonsContainer.AddChild(copyButton);
copyButton.Click += (sender, e) =>
{
MakeCopyOfGroup();
};
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
Button deleteButton = textImageButtonFactory.Generate("Remove".Localize());
deleteButton.Name = "3D View Remove";
2015-04-08 15:20:10 -07:00
doEdittingButtonsContainer.AddChild(deleteButton);
deleteButton.Click += (sender, e) =>
{
DeleteSelectedMesh();
};
2014-12-20 09:07:13 -08:00
GuiWidget separatorThree = new GuiWidget(1, 2);
separatorThree.BackgroundColor = ActiveTheme.Instance.PrimaryTextColor;
separatorThree.Margin = new BorderDouble(4, 1);
separatorThree.VAnchor = VAnchor.ParentBottomTop;
doEdittingButtonsContainer.AddChild(separatorThree);
Button exportButton = textImageButtonFactory.Generate("Export".Localize() + "...");
exportButton.Margin = new BorderDouble(right: 10);
exportButton.Click += (sender, e) =>
{
UiThread.RunOnIdle(() =>
2014-12-20 09:07:13 -08:00
{
OpenExportWindow();
});
};
2016-02-14 17:53:44 -08:00
2014-12-20 09:07:13 -08:00
// put in the save button
AddSaveAndSaveAs(doEdittingButtonsContainer);
var rotateButton = textImageButtonFactory.Generate("Rotate".Localize());
rotateButton.Click += (s, e) =>
{
var popup = new PopupWidget(this.CreateRotateControls(), rotateButton, Vector2.Zero, Direction.Up, 0, true);
popup.Focus();
};
doEdittingButtonsContainer.AddChild(rotateButton);
var scaleButton = textImageButtonFactory.Generate("Scale".Localize());
scaleButton.Click += (s, e) =>
{
var popup = new PopupWidget(new ScaleControls(this)
{
BackgroundColor = ActiveTheme.Instance.SecondaryBackgroundColor,
Padding = 15
}, scaleButton, Vector2.Zero, Direction.Up, 0, true);
popup.Focus();
};
doEdittingButtonsContainer.AddChild(scaleButton);
var mirrorButton = textImageButtonFactory.Generate("Mirror".Localize());
mirrorButton.Click += (s, e) =>
{
var popup = new PopupWidget(new MirrorControls(this)
{
BackgroundColor = ActiveTheme.Instance.SecondaryBackgroundColor,
Padding = 15
}, mirrorButton, Vector2.Zero, Direction.Up, 0, true);
popup.Focus();
};
doEdittingButtonsContainer.AddChild(mirrorButton);
// put in the material options
int numberOfExtruders = ActiveSliceSettings.Instance.GetValue<int>(SettingsKey.extruder_count);
if (numberOfExtruders > 1)
{
var materialsButton = textImageButtonFactory.Generate("Materials".Localize());
materialsButton.Click += (s, e) =>
{
var popup = new PopupWidget(this.AddMaterialControls(), materialsButton, Vector2.Zero, Direction.Up, 0, true);
popup.Focus();
};
doEdittingButtonsContainer.AddChild(materialsButton);
}
2015-04-08 15:20:10 -07:00
}
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
editToolBar.AddChild(doEdittingButtonsContainer);
buttonBottomPanel.AddChild(editToolBar);
}
2014-01-29 19:09:30 -08:00
GuiWidget buttonRightPanelHolder = new GuiWidget()
{
HAnchor = HAnchor.FitToChildren,
VAnchor = VAnchor.ParentBottomTop
};
buttonRightPanelHolder.Name = "buttonRightPanelHolder";
2015-04-08 15:20:10 -07:00
centerPartPreviewAndControls.AddChild(buttonRightPanelHolder);
buttonRightPanelDisabledCover = new GuiWidget()
{
HAnchor = HAnchor.ParentLeftRight,
VAnchor = VAnchor.ParentBottomTop
};
2015-04-08 15:20:10 -07:00
buttonRightPanelDisabledCover.BackgroundColor = new RGBA_Bytes(ActiveTheme.Instance.PrimaryBackgroundColor, 150);
buttonRightPanelHolder.AddChild(buttonRightPanelDisabledCover);
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
LockEditControls();
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
GuiWidget leftRightSpacer = new GuiWidget();
leftRightSpacer.HAnchor = HAnchor.ParentLeftRight;
buttonBottomPanel.AddChild(leftRightSpacer);
2015-04-08 15:20:10 -07:00
if (windowType == WindowMode.StandAlone)
{
Button closeButton = textImageButtonFactory.Generate("Close".Localize());
buttonBottomPanel.AddChild(closeButton);
closeButton.Click += (sender, e) =>
{
CloseOnIdle();
};
}
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
mainContainerTopToBottom.AddChild(buttonBottomPanel);
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
this.AddChild(mainContainerTopToBottom);
this.AnchorAll();
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
meshViewerWidget.TrackballTumbleWidget.TransformState = TrackBallController.MouseDownType.Rotation;
2017-03-15 16:17:06 -07:00
/* TODO: Why doesn't this pattern work but using new SelectedObjectPanel object does?
selectedObjectPanel = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
Width = 215,
Margin = new BorderDouble(0, 0, buttonRightPanel.Width + 5, 5),
BackgroundColor = RGBA_Bytes.Red,
HAnchor = HAnchor.ParentRight,
VAnchor = VAnchor.ParentTop
}; */
selectedObjectPanel = new SelectedObjectPanel()
{
Margin = 5,
BackgroundColor = new RGBA_Bytes(0, 0, 0, ViewControlsBase.overlayAlpha)
2017-03-15 16:17:06 -07:00
};
AddChild(selectedObjectPanel);
2015-04-08 15:20:10 -07:00
UiThread.RunOnIdle(AutoSpin);
2014-05-27 09:16:35 -07:00
2015-04-08 15:20:10 -07:00
if (windowType == WindowMode.Embeded)
{
PrinterConnectionAndCommunication.Instance.CommunicationStateChanged.RegisterEvent(SetEditControlsBasedOnPrinterState, ref unregisterEvents);
if (windowType == WindowMode.Embeded)
{
// make sure we lock the controls if we are printing or paused
switch (PrinterConnectionAndCommunication.Instance.CommunicationState)
{
case PrinterConnectionAndCommunication.CommunicationStates.Printing:
case PrinterConnectionAndCommunication.CommunicationStates.Paused:
LockEditControls();
break;
}
}
}
2016-04-29 07:45:15 -07:00
ActiveTheme.ThemeChanged.RegisterEvent(ThemeChanged, ref unregisterEvents);
2015-04-08 15:20:10 -07:00
meshViewerWidget.interactionVolumes.Add(new UpArrow3D(this));
meshViewerWidget.interactionVolumes.Add(new SelectionShadow(this));
meshViewerWidget.interactionVolumes.Add(new SnappingIndicators(this));
2015-04-08 15:20:10 -07:00
PluginFinder<InteractionVolumePlugin> InteractionVolumePlugins = new PluginFinder<InteractionVolumePlugin>();
foreach (InteractionVolumePlugin plugin in InteractionVolumePlugins.Plugins)
{
meshViewerWidget.interactionVolumes.Add(plugin.CreateInteractionVolume(this));
}
2016-02-17 18:06:32 -08:00
// make sure the colors are set correct
2015-04-08 15:20:10 -07:00
ThemeChanged(this, null);
saveButtons.VisibleChanged += (sender, e) =>
{
partHasBeenEdited = true;
};
2016-02-29 14:04:52 -08:00
meshViewerWidget.ResetView();
2017-03-15 16:17:06 -07:00
if (DoBooleanTest)
{
BeforeDraw += CreateBooleanTestGeometry;
AfterDraw += RemoveBooleanTestGeometry;
}
2017-05-30 10:10:30 -07:00
meshViewerWidget.AfterDraw += AfterDebugTest;
2017-03-15 16:17:06 -07:00
meshViewerWidget.TrackballTumbleWidget.DrawGlContent += TrackballTumbleWidget_DrawGlContent;
}
private void ViewControls3D_TransformStateChanged(object sender, TransformStateChangedEventArgs e)
{
switch (e.TransformMode)
{
case ViewControls3DButtons.Rotate:
meshViewerWidget.TrackballTumbleWidget.TransformState = TrackBallController.MouseDownType.Rotation;
break;
case ViewControls3DButtons.Translate:
meshViewerWidget.TrackballTumbleWidget.TransformState = TrackBallController.MouseDownType.Translation;
break;
case ViewControls3DButtons.Scale:
meshViewerWidget.TrackballTumbleWidget.TransformState = TrackBallController.MouseDownType.Scale;
break;
case ViewControls3DButtons.PartSelect:
meshViewerWidget.TrackballTumbleWidget.TransformState = TrackBallController.MouseDownType.None;
break;
}
}
2017-03-15 16:17:06 -07:00
public void SelectAll()
{
Scene.ClearSelection();
foreach(var child in Scene.Children)
{
Scene.AddToSelection(child);
}
}
public ILibraryContentStream DragSourceModel { get; set; }
// TODO: Rename to DragDropItem
2017-03-15 16:17:06 -07:00
private IObject3D dragDropSource;
public IObject3D DragDropSource
{
get
{
return dragDropSource;
}
set
{
if (InEditMode)
{
// <IObject3D>
2017-03-15 16:17:06 -07:00
dragDropSource = value;
// Clear the DragSourceModel - <ILibraryItem>
DragSourceModel = null;
2017-03-15 16:17:06 -07:00
// Suppress ui volumes when dragDropSource is not null
meshViewerWidget.SuppressUiVolumes = (dragDropSource != null);
}
}
}
2017-05-27 16:29:35 -07:00
2017-03-15 16:17:06 -07:00
private void TrackballTumbleWidget_DrawGlContent(object sender, EventArgs e)
{
// This shows the BVH as rects around the scene items
//Scene?.TraceData().RenderBvhRecursive(0, 3);
}
public override void OnKeyDown(KeyEventArgs keyEvent)
{
if (activeButtonBeforeKeyOverride == null)
{
activeButtonBeforeKeyOverride = viewControls3D.ActiveButton;
if (keyEvent.Alt)
{
viewControls3D.ActiveButton = ViewControls3DButtons.Rotate;
}
else if (keyEvent.Shift)
{
viewControls3D.ActiveButton = ViewControls3DButtons.Translate;
}
else if (keyEvent.Control)
{
viewControls3D.ActiveButton = ViewControls3DButtons.Scale;
}
}
switch (keyEvent.KeyCode)
{
2017-03-15 16:17:06 -07:00
case Keys.A:
if (keyEvent.Control)
{
SelectAll();
keyEvent.Handled = true;
keyEvent.SuppressKeyPress = true;
}
break;
case Keys.Z:
if (keyEvent.Control)
{
UndoBuffer.Undo();
keyEvent.Handled = true;
keyEvent.SuppressKeyPress = true;
}
break;
case Keys.Y:
if (keyEvent.Control)
{
UndoBuffer.Redo();
keyEvent.Handled = true;
keyEvent.SuppressKeyPress = true;
}
break;
case Keys.Delete:
case Keys.Back:
DeleteSelectedMesh();
break;
case Keys.Escape:
if (CurrentSelectInfo.DownOnPart)
{
CurrentSelectInfo.DownOnPart = false;
2017-03-15 16:17:06 -07:00
Scene.SelectedItem.Matrix = transformOnMouseDown;
Invalidate();
}
break;
}
base.OnKeyDown(keyEvent);
}
2017-03-15 16:17:06 -07:00
public bool IsEditing { get; private set; }
2016-02-17 18:06:32 -08:00
public bool DragingPart
{
2016-02-19 08:29:49 -08:00
get { return CurrentSelectInfo.DownOnPart; }
2016-02-17 18:06:32 -08:00
}
2017-03-15 16:17:06 -07:00
public void AddUndoOperation(IUndoRedoCommand operation)
2016-02-14 17:53:44 -08:00
{
2017-03-15 16:17:06 -07:00
UndoBuffer.Add(operation);
2016-02-14 17:53:44 -08:00
}
2017-03-15 16:17:06 -07:00
#region DoBooleanTest
Object3D booleanGroup;
2016-03-12 14:16:34 -08:00
Vector3 offset = new Vector3();
Vector3 direction = new Vector3(.11, .12, .13);
Vector3 rotCurrent = new Vector3();
Vector3 rotChange = new Vector3(.011, .012, .013);
Vector3 scaleChange = new Vector3(.0011, .0012, .0013);
Vector3 scaleCurrent = new Vector3(1, 1, 1);
2017-03-15 16:17:06 -07:00
private void CreateBooleanTestGeometry(object sender, DrawEventArgs e)
2016-03-07 14:23:22 -08:00
{
try
{
2017-03-15 16:17:06 -07:00
booleanGroup = new Object3D { ItemType = Object3DTypes.Group };
booleanGroup.Children.Add(new Object3D()
{
Mesh = ApplyBoolean(PolygonMesh.Csg.CsgOperations.Union, AxisAlignedBoundingBox.Union, new Vector3(100, 0, 20), "U")
});
2016-03-07 14:23:22 -08:00
2017-03-15 16:17:06 -07:00
booleanGroup.Children.Add(new Object3D()
{
Mesh = ApplyBoolean(PolygonMesh.Csg.CsgOperations.Subtract, null, new Vector3(100, 100, 20), "S")
});
booleanGroup.Children.Add(new Object3D()
{
Mesh = ApplyBoolean(PolygonMesh.Csg.CsgOperations.Intersect, AxisAlignedBoundingBox.Intersection, new Vector3(100, 200, 20), "I")
});
2016-03-07 14:23:22 -08:00
offset += direction;
2016-03-12 14:16:34 -08:00
rotCurrent += rotChange;
scaleCurrent += scaleChange;
2016-03-07 14:23:22 -08:00
2017-03-15 16:17:06 -07:00
Scene.ModifyChildren(children =>
{
children.Add(booleanGroup);
});
2016-03-07 14:23:22 -08:00
}
catch(Exception e2)
{
string text = e2.Message;
2017-03-15 16:17:06 -07:00
int a = 0;
2016-03-07 14:23:22 -08:00
}
}
private Mesh ApplyBoolean(Func<Mesh, Mesh, Mesh> meshOpperation, Func<AxisAlignedBoundingBox, AxisAlignedBoundingBox, AxisAlignedBoundingBox> aabbOpperation, Vector3 centering, string opp)
2016-03-07 14:23:22 -08:00
{
Mesh boxA = PlatonicSolids.CreateCube(40, 40, 40);
2017-03-15 16:17:06 -07:00
//boxA = PlatonicSolids.CreateIcosahedron(35);
2016-03-07 14:23:22 -08:00
boxA.Translate(centering);
Mesh boxB = PlatonicSolids.CreateCube(40, 40, 40);
2017-03-15 16:17:06 -07:00
//boxB = PlatonicSolids.CreateIcosahedron(35);
2016-03-07 14:23:22 -08:00
for (int i = 0; i < 3; i++)
{
if (Math.Abs(direction[i] + offset[i]) > 10)
{
2016-03-12 14:16:34 -08:00
direction[i] = direction[i] * -1.00073112;
2016-03-07 14:23:22 -08:00
}
}
2016-03-12 14:16:34 -08:00
for (int i = 0; i < 3; i++)
{
if (Math.Abs(rotChange[i] + rotCurrent[i]) > 6)
{
rotChange[i] = rotChange[i] * -1.000073112;
}
}
for (int i = 0; i < 3; i++)
{
if (scaleChange[i] + scaleCurrent[i] > 1.1 || scaleChange[i] + scaleCurrent[i] < .9)
{
scaleChange[i] = scaleChange[i] * -1.000073112;
}
}
Vector3 offsetB = offset + centering;
// switch to the failing offset
//offsetB = new Vector3(105.240172225344, 92.9716306394062, 18.4619570261172);
//rotCurrent = new Vector3(4.56890223673623, -2.67874102322035, 1.02768848238523);
//scaleCurrent = new Vector3(1.07853517569753, 0.964980885267323, 1.09290934544604);
2016-03-12 14:16:34 -08:00
Debug.WriteLine("t"+offsetB.ToString() + " r" + rotCurrent.ToString() + " s" + scaleCurrent.ToString() + " " + opp);
Matrix4X4 transformB = Matrix4X4.CreateScale(scaleCurrent) * Matrix4X4.CreateRotation(rotCurrent) * Matrix4X4.CreateTranslation(offsetB);
boxB.Transform(transformB);
Mesh meshToAdd = meshOpperation(boxA, boxB);
2016-03-07 14:23:22 -08:00
meshToAdd.CleanAndMergMesh();
if(aabbOpperation != null)
{
AxisAlignedBoundingBox boundsA = boxA.GetAxisAlignedBoundingBox();
AxisAlignedBoundingBox boundsB = boxB.GetAxisAlignedBoundingBox();
AxisAlignedBoundingBox boundsAdd = meshToAdd.GetAxisAlignedBoundingBox();
AxisAlignedBoundingBox boundsResult = aabbOpperation(boundsA, boundsB);
if(!boundsAdd.Equals(boundsResult, .0001))
{
int a = 0;
}
}
int nonManifoldEdges = meshToAdd.GetNonManifoldEdges().Count;
if (nonManifoldEdges > 0)
{
// shoud be manifold
int a = 0;
}
2016-03-07 14:23:22 -08:00
return meshToAdd;
}
2017-03-15 16:17:06 -07:00
private void RemoveBooleanTestGeometry(object sender, DrawEventArgs e)
{
2017-03-15 16:17:06 -07:00
if (meshViewerWidget.Scene.Children.Contains(booleanGroup))
2016-03-07 14:23:22 -08:00
{
2017-03-15 16:17:06 -07:00
meshViewerWidget.Scene.Children.Remove(booleanGroup);
2016-03-07 14:23:22 -08:00
UiThread.RunOnIdle(() => Invalidate(), 1.0 / 30.0);
}
}
2017-03-15 16:17:06 -07:00
#endregion DoBooleanTest
2015-04-08 15:20:10 -07:00
public enum AutoRotate { Enabled, Disabled };
2015-05-30 12:48:16 -07:00
public enum OpenMode { Viewing, Editing }
2015-05-30 12:48:16 -07:00
public enum WindowMode { Embeded, StandAlone };
2015-05-30 12:48:16 -07:00
public bool DisplayAllValueData { get; set; }
2017-03-15 16:17:06 -07:00
public WindowMode windowType { get; set; }
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
public override void OnClosed(ClosedEventArgs e)
2015-05-30 12:48:16 -07:00
{
// Not needed but safer than without
viewControls3D.TransformStateChanged -= ViewControls3D_TransformStateChanged;
2017-03-15 16:17:06 -07:00
unregisterEvents?.Invoke(this, null);
base.OnClosed(e);
2015-05-30 12:48:16 -07:00
}
public override void OnMouseEnterBounds(MouseEventArgs mouseEvent)
2015-05-30 12:48:16 -07:00
{
if (mouseEvent.DragFiles?.Count > 0)
{
if (AllowDragDrop())
{
mouseEvent.AcceptDrop = mouseEvent.DragFiles.TrueForAll(filePath => ApplicationController.Instance.IsLoadableFile(filePath));
if (mouseEvent.AcceptDrop)
2015-05-30 12:48:16 -07:00
{
2017-04-05 19:03:04 -07:00
string filePath = mouseEvent.DragFiles.FirstOrDefault();
string extensionWithoutPeriod = Path.GetExtension(filePath).Trim('.');
IContentProvider contentProvider;
if (!string.IsNullOrEmpty(filePath)
&& ApplicationController.Instance.Library.ContentProviders.TryGetValue(extensionWithoutPeriod, out contentProvider)
&& contentProvider is ISceneContentProvider)
2017-04-05 19:03:04 -07:00
{
var sceneProvider = contentProvider as ISceneContentProvider;
this.DragDropSource = sceneProvider.CreateItem(new FileSystemFileItem(filePath), null).Object3D;
2017-04-05 19:03:04 -07:00
}
else
{
this.DragDropSource = new Object3D
2017-04-05 19:03:04 -07:00
{
ItemType = Object3DTypes.Model,
Mesh = PlatonicSolids.CreateCube(10, 10, 10)
};
}
2015-05-30 12:48:16 -07:00
}
}
2015-04-08 15:20:10 -07:00
}
2017-03-15 16:17:06 -07:00
base.OnMouseEnterBounds(mouseEvent);
2015-04-08 15:20:10 -07:00
}
2017-03-15 16:17:06 -07:00
private GuiWidget topMostParent;
private PlaneShape bedPlane = new PlaneShape(Vector3.UnitZ, 0, null);
/// <summary>
/// Provides a View3DWidget specific drag implementation
/// </summary>
/// <param name="screenSpaceMousePosition">The screen space mouse position.</param>
2017-04-05 19:03:04 -07:00
/// <returns>A value indicating if a new item was generated for the DragDropSource and added to the scene</returns>
2017-03-15 16:17:06 -07:00
public bool AltDragOver(Vector2 screenSpaceMousePosition)
2015-04-08 15:20:10 -07:00
{
if (this.HasBeenClosed || this.DragDropSource == null)
2017-03-15 16:17:06 -07:00
{
return false;
}
bool itemAddedToScene = false;
var meshViewerPosition = this.meshViewerWidget.TransformToScreenSpace(meshViewerWidget.LocalBounds);
// If the mouse is within this control
if (meshViewerPosition.Contains(screenSpaceMousePosition)
&& this.DragDropSource != null)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
var localPosition = this.TransformFromParentSpace(topMostParent, screenSpaceMousePosition);
// Inject the DragDropSource if it's missing from the scene, using the default "loading" mesh
if (!Scene.Children.Contains(DragDropSource))
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
// Set the hitplane to the bed plane
CurrentSelectInfo.HitPlane = bedPlane;
// Find intersection position of the mouse with the bed plane
var intersectInfo = GetIntersectPosition(screenSpaceMousePosition);
if (intersectInfo == null)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
return false;
2015-05-30 12:48:16 -07:00
}
2017-03-15 16:17:06 -07:00
// Set the initial transform on the inject part to the current transform mouse position
var sourceItemBounds = DragDropSource.GetAxisAlignedBoundingBox(Matrix4X4.Identity);
var center = sourceItemBounds.Center;
DragDropSource.Matrix *= Matrix4X4.CreateTranslation(-center.x, -center.y, -sourceItemBounds.minXYZ.z);
DragDropSource.Matrix *= Matrix4X4.CreateTranslation(new Vector3(intersectInfo.hitPosition));
CurrentSelectInfo.PlaneDownHitPos = intersectInfo.hitPosition;
CurrentSelectInfo.LastMoveDelta = Vector3.Zero;
2017-04-05 19:03:04 -07:00
this.deferEditorTillMouseUp = true;
2017-03-15 16:17:06 -07:00
// Add item to scene and select it
Scene.ModifyChildren(children =>
{
children.Add(DragDropSource);
});
Scene.Select(DragDropSource);
itemAddedToScene = true;
}
// Move the object being dragged
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection)
{
// Pass the mouse position, transformed to local cords, through to the view3D widget to move the target item
localPosition = meshViewerWidget.TransformFromScreenSpace(screenSpaceMousePosition);
DragSelectedObject(localPosition);
2015-05-30 12:48:16 -07:00
}
2017-03-15 16:17:06 -07:00
return itemAddedToScene;
2015-05-30 12:48:16 -07:00
}
2017-03-15 16:17:06 -07:00
return false;
2015-04-08 15:20:10 -07:00
}
internal void FinishDrop()
{
this.DragDropSource = null;
this.DragSourceModel = null;
this.deferEditorTillMouseUp = false;
Scene_SelectionChanged(null, null);
}
public override void OnLoad(EventArgs args)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
topMostParent = this.TopmostParent();
base.OnLoad(args);
}
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
/// <summary>
/// Loads the referenced DragDropSource object.
/// </summary>
/// <param name="dragSource">The drag source at the original time of invocation.</param>
/// <returns></returns>
public async Task LoadDragSource(ListViewItem sourceListItem)
2017-03-15 16:17:06 -07:00
{
// Hold initial reference
IObject3D dragDropItem = DragDropSource;
if (dragDropItem == null)
2017-03-15 16:17:06 -07:00
{
return;
}
this.DragSourceModel = sourceListItem?.Model as ILibraryContentStream;
IObject3D loadedItem = await Task.Run(async () =>
2017-03-15 16:17:06 -07:00
{
if (File.Exists(dragDropItem.MeshPath))
2017-04-05 19:03:04 -07:00
{
string extensionWithoutPeriod = Path.GetExtension(dragDropItem.MeshPath).Trim('.');
if (ApplicationController.Instance.Library.ContentProviders.ContainsKey(extensionWithoutPeriod))
{
return null;
}
else
{
return Object3D.Load(dragDropItem.MeshPath, progress: new DragDropLoadProgress(this, dragDropItem).ProgressReporter);
}
2017-04-05 19:03:04 -07:00
}
else if (DragSourceModel != null)
2017-04-05 19:03:04 -07:00
{
var loadProgress = new DragDropLoadProgress(this, dragDropItem);
ContentResult contentResult;
if (sourceListItem == null)
{
contentResult = DragSourceModel.CreateContent(loadProgress.ProgressReporter);
await contentResult.MeshLoaded;
}
else
{
sourceListItem.StartProgress();
contentResult = DragSourceModel.CreateContent((double progress0To1, string processingState, out bool continueProcessing) =>
{
sourceListItem.ProgressReporter(progress0To1, processingState, out continueProcessing);
loadProgress.ProgressReporter(progress0To1, processingState, out continueProcessing);
});
await contentResult.MeshLoaded;
sourceListItem.EndProgress();
loadProgress.ProgressReporter(1, "", out bool continuex);
}
return contentResult?.Object3D;
2017-04-05 19:03:04 -07:00
}
return null;
2017-03-15 16:17:06 -07:00
});
if (loadedItem != null)
{
Vector3 meshGroupCenter = loadedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity).Center;
dragDropItem.Mesh = loadedItem.Mesh;
dragDropItem.Children = loadedItem.Children;
// TODO: jlewin - also need to apply the translation to the scale/rotation from the source (loadedItem.Matrix)
dragDropItem.Matrix = loadedItem.Matrix * dragDropItem.Matrix;
dragDropItem.Matrix *= Matrix4X4.CreateTranslation(-meshGroupCenter.x, -meshGroupCenter.y, -dragDropItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity).minXYZ.z);
2017-03-15 16:17:06 -07:00
}
}
public override void OnDraw(Graphics2D graphics2D)
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
var selectedItem = Scene.SelectedItem;
foreach (InteractionVolume volume in meshViewerWidget.interactionVolumes)
{
2017-03-15 16:17:06 -07:00
volume.SetPosition(selectedItem);
}
2015-04-08 15:20:10 -07:00
}
2014-03-20 18:20:52 -07:00
2015-05-30 12:48:16 -07:00
hasDrawn = true;
2015-05-30 12:48:16 -07:00
base.OnDraw(graphics2D);
}
2015-04-08 15:20:10 -07:00
private void AfterDebugTest(object sender, DrawEventArgs e)
{
foreach (var bvhAndTransform in Scene?.TraceData().MakeEnumerable())
{
TriangleShape tri = bvhAndTransform.Bvh as TriangleShape;
if (tri != null)
{
for (int i = 0; i < 3; i++)
{
var vertexPos = tri.GetVertex(i);
var screenCenter = Vector3.Transform(vertexPos, bvhAndTransform.TransformToWorld);
var screenPos = meshViewerWidget.TrackballTumbleWidget.GetScreenPosition(screenCenter);
e.graphics2D.Circle(screenPos, 3, RGBA_Bytes.Red);
}
}
}
}
private ViewControls3DButtons? activeButtonBeforeMouseOverride = null;
private ViewControls3DButtons? activeButtonBeforeKeyOverride = null;
public override void OnKeyUp(KeyEventArgs keyEvent)
{
if (activeButtonBeforeKeyOverride != null)
{
viewControls3D.ActiveButton = (ViewControls3DButtons)activeButtonBeforeKeyOverride;
activeButtonBeforeKeyOverride = null;
}
base.OnKeyUp(keyEvent);
}
2015-05-30 12:48:16 -07:00
public override void OnMouseDown(MouseEventArgs mouseEvent)
2015-04-08 15:20:10 -07:00
{
// Show transform override
if (activeButtonBeforeMouseOverride == null && mouseEvent.Button == MouseButtons.Right)
{
activeButtonBeforeMouseOverride = viewControls3D.ActiveButton;
viewControls3D.ActiveButton = ViewControls3DButtons.Rotate;
}
else if (activeButtonBeforeMouseOverride == null && mouseEvent.Button == MouseButtons.Middle)
{
activeButtonBeforeMouseOverride = viewControls3D.ActiveButton;
viewControls3D.ActiveButton = ViewControls3DButtons.Translate;
}
2017-03-15 16:17:06 -07:00
if(mouseEvent.Button == MouseButtons.Right ||
mouseEvent.Button == MouseButtons.Middle)
{
meshViewerWidget.SuppressUiVolumes = true;
}
2015-05-30 12:48:16 -07:00
autoRotating = false;
base.OnMouseDown(mouseEvent);
2017-03-15 16:17:06 -07:00
2015-05-30 12:48:16 -07:00
if (meshViewerWidget.TrackballTumbleWidget.UnderMouseState == Agg.UI.UnderMouseState.FirstUnderMouse)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if (mouseEvent.Button == MouseButtons.Left
&&
ModifierKeys == Keys.Shift ||
(
meshViewerWidget.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None
2015-05-30 12:48:16 -07:00
&& ModifierKeys != Keys.Control
2017-03-15 16:17:06 -07:00
&& ModifierKeys != Keys.Alt))
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
if (!meshViewerWidget.MouseDownOnInteractionVolume)
{
2017-03-15 16:17:06 -07:00
meshViewerWidget.SuppressUiVolumes = true;
2016-02-19 08:29:49 -08:00
IntersectInfo info = new IntersectInfo();
2017-03-15 16:17:06 -07:00
IObject3D hitObject = FindHitObject3D(mouseEvent.Position, ref info);
if (hitObject != null)
2015-05-30 12:48:16 -07:00
{
2016-02-19 08:29:49 -08:00
CurrentSelectInfo.HitPlane = new PlaneShape(Vector3.UnitZ, CurrentSelectInfo.PlaneDownHitPos.z, null);
2014-03-20 18:20:52 -07:00
2017-03-15 16:17:06 -07:00
if (hitObject != Scene.SelectedItem)
{
if (Scene.SelectedItem == null)
{
// No selection exists
Scene.Select(hitObject);
}
else if (ModifierKeys == Keys.Shift && !Scene.SelectedItem.Children.Contains(hitObject))
{
Scene.AddToSelection(hitObject);
}
else if (Scene.SelectedItem == hitObject || Scene.SelectedItem.Children.Contains(hitObject))
{
// Selection should not be cleared and drag should occur
}
else if (ModifierKeys != Keys.Shift)
{
Scene.ModifyChildren(children =>
{
ClearSelectionApplyChanges(children);
});
Scene.Select(hitObject);
}
PartHasBeenChanged();
}
transformOnMouseDown = Scene.SelectedItem.Matrix;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
Invalidate();
2016-02-19 08:29:49 -08:00
CurrentSelectInfo.DownOnPart = true;
2017-03-15 16:17:06 -07:00
AxisAlignedBoundingBox selectedBounds = meshViewerWidget.Scene.SelectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity);
2016-02-19 08:29:49 -08:00
if (info.hitPosition.x < selectedBounds.Center.x)
{
if (info.hitPosition.y < selectedBounds.Center.y)
{
CurrentSelectInfo.HitQuadrant = HitQuadrant.LB;
}
else
{
CurrentSelectInfo.HitQuadrant = HitQuadrant.LT;
}
}
else
{
if (info.hitPosition.y < selectedBounds.Center.y)
{
CurrentSelectInfo.HitQuadrant = HitQuadrant.RB;
}
else
{
CurrentSelectInfo.HitQuadrant = HitQuadrant.RT;
}
}
2015-05-30 12:48:16 -07:00
}
else
{
2017-03-15 16:17:06 -07:00
if(!Scene.HasSelection)
{
return;
}
if(Scene.SelectedItem.ItemType == Object3DTypes.SelectionGroup)
{
Scene.ModifyChildren(ClearSelectionApplyChanges);
}
else
{
Scene.ClearSelection();
}
2015-05-30 12:48:16 -07:00
}
SelectedTransformChanged?.Invoke(this, null);
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
}
}
2015-02-27 11:09:37 -08:00
2017-03-15 16:17:06 -07:00
public void ClearSelectionApplyChanges(List<IObject3D> target)
{
Scene.SelectedItem.CollapseInto(target);
Scene.ClearSelection();
}
public IntersectInfo GetIntersectPosition(Vector2 screenSpacePosition)
{
//Vector2 meshViewerWidgetScreenPosition = meshViewerWidget.TransformFromParentSpace(this, new Vector2(mouseEvent.X, mouseEvent.Y));
2017-03-15 16:17:06 -07:00
// Translate to local
Vector2 localPosition = this.TransformFromScreenSpace(screenSpacePosition);
Ray ray = meshViewerWidget.TrackballTumbleWidget.GetRayForLocalBounds(localPosition);
return CurrentSelectInfo.HitPlane.GetClosestIntersection(ray);
}
public void DragSelectedObject(Vector2 localMousePostion)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
Vector2 meshViewerWidgetScreenPosition = meshViewerWidget.TransformFromParentSpace(this, localMousePostion);
Ray ray = meshViewerWidget.TrackballTumbleWidget.GetRayForLocalBounds(meshViewerWidgetScreenPosition);
IntersectInfo info = CurrentSelectInfo.HitPlane.GetClosestIntersection(ray);
if (info != null)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
// move the mesh back to the start position
{
Matrix4X4 totalTransform = Matrix4X4.CreateTranslation(new Vector3(-CurrentSelectInfo.LastMoveDelta));
Scene.SelectedItem.Matrix *= totalTransform;
}
Vector3 delta = info.hitPosition - CurrentSelectInfo.PlaneDownHitPos;
double snapGridDistance = meshViewerWidget.SnapGridDistance;
if (snapGridDistance > 0)
2015-02-27 11:09:37 -08:00
{
2017-03-15 16:17:06 -07:00
// snap this position to the grid
AxisAlignedBoundingBox selectedBounds = meshViewerWidget.Scene.SelectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity);
double xSnapOffset = selectedBounds.minXYZ.x;
// snap the x position
if (CurrentSelectInfo.HitQuadrant == HitQuadrant.RB
|| CurrentSelectInfo.HitQuadrant == HitQuadrant.RT)
2016-02-18 09:36:01 -08:00
{
2017-03-15 16:17:06 -07:00
// switch to the other side
xSnapOffset = selectedBounds.maxXYZ.x;
2016-02-18 09:36:01 -08:00
}
2017-03-15 16:17:06 -07:00
double xToSnap = xSnapOffset + delta.x;
2016-02-18 09:36:01 -08:00
2017-03-15 16:17:06 -07:00
double snappedX = ((int)((xToSnap / snapGridDistance) + .5)) * snapGridDistance;
delta.x = snappedX - xSnapOffset;
2015-02-27 11:09:37 -08:00
2017-03-15 16:17:06 -07:00
double ySnapOffset = selectedBounds.minXYZ.y;
// snap the y position
if (CurrentSelectInfo.HitQuadrant == HitQuadrant.LT
|| CurrentSelectInfo.HitQuadrant == HitQuadrant.RT)
{
2017-03-15 16:17:06 -07:00
// switch to the other side
ySnapOffset = selectedBounds.maxXYZ.y;
}
double yToSnap = ySnapOffset + delta.y;
2017-03-15 16:17:06 -07:00
double snappedY = ((int)((yToSnap / snapGridDistance) + .5)) * snapGridDistance;
delta.y = snappedY - ySnapOffset;
}
2017-03-15 16:17:06 -07:00
// move the mesh back to the new position
{
Matrix4X4 totalTransform = Matrix4X4.CreateTranslation(new Vector3(delta));
2015-02-27 11:09:37 -08:00
2017-03-15 16:17:06 -07:00
Scene.SelectedItem.Matrix *= totalTransform;
2016-02-18 09:36:01 -08:00
2017-03-15 16:17:06 -07:00
CurrentSelectInfo.LastMoveDelta = delta;
}
2016-02-18 09:36:01 -08:00
2017-03-15 16:17:06 -07:00
Invalidate();
}
}
2015-02-27 11:09:37 -08:00
2017-03-15 16:17:06 -07:00
public override void OnMouseMove(MouseEventArgs mouseEvent)
{
if (AllowDragDrop() && mouseEvent.DragFiles?.Count == 1)
{
var screenSpaceMousePosition = this.TransformToScreenSpace(new Vector2(mouseEvent.X, mouseEvent.Y));
// If the DragDropSource was added to the scene on this DragOver call, we start a task to replace
// the "loading" mesh with the actual file contents
if (AltDragOver(screenSpaceMousePosition))
{
this.DragDropSource.MeshPath = mouseEvent.DragFiles.FirstOrDefault();
// Run the rest of the OnDragOver pipeline since we're starting a new thread and won't finish for an unknown time
base.OnMouseMove(mouseEvent);
LoadDragSource(null);
// Don't fall through to the base.OnDragOver because we preemptively invoked it above
return;
}
}
// AcceptDrop anytime a DropSource has been queued
mouseEvent.AcceptDrop = this.DragDropSource != null;
2017-03-15 16:17:06 -07:00
if (CurrentSelectInfo.DownOnPart && meshViewerWidget.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None)
{
DragSelectedObject(new Vector2(mouseEvent.X, mouseEvent.Y));
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
base.OnMouseMove(mouseEvent);
2015-04-08 15:20:10 -07:00
}
public void AddUndoForSelectedMeshGroupTransform(Matrix4X4 undoTransform)
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection && undoTransform != Scene.SelectedItem?.Matrix)
{
2017-03-15 16:17:06 -07:00
UndoBuffer.Add(new TransformUndoCommand(this, Scene.SelectedItem, undoTransform, Scene.SelectedItem.Matrix));
}
}
2015-05-30 12:48:16 -07:00
public override void OnMouseUp(MouseEventArgs mouseEvent)
2015-04-08 15:20:10 -07:00
{
if (mouseEvent.DragFiles?.Count > 0)
{
if (AllowDragDrop() && mouseEvent.DragFiles.Count == 1)
{
// Item is already in the scene
this.DragDropSource = null;
}
else if (AllowDragDrop())
{
// Items need to be added to the scene
var partsToAdd = mouseEvent.DragFiles.Where(filePath => ApplicationController.Instance.IsLoadableFile(filePath)).ToArray();
if (partsToAdd.Length > 0)
{
loadAndAddPartsToPlate(partsToAdd);
}
}
}
2015-05-30 12:48:16 -07:00
if (meshViewerWidget.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None
2016-02-19 08:29:49 -08:00
&& CurrentSelectInfo.DownOnPart
&& CurrentSelectInfo.LastMoveDelta != Vector3.Zero)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if (Scene.SelectedItem.Matrix != transformOnMouseDown)
{
AddUndoForSelectedMeshGroupTransform(transformOnMouseDown);
PartHasBeenChanged();
}
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
meshViewerWidget.SuppressUiVolumes = false;
2016-02-19 08:29:49 -08:00
CurrentSelectInfo.DownOnPart = false;
2015-04-08 15:20:10 -07:00
if (activeButtonBeforeMouseOverride != null)
{
viewControls3D.ActiveButton = (ViewControls3DButtons)activeButtonBeforeMouseOverride;
activeButtonBeforeMouseOverride = null;
}
2015-05-30 12:48:16 -07:00
base.OnMouseUp(mouseEvent);
if (deferEditorTillMouseUp)
{
this.deferEditorTillMouseUp = false;
Scene_SelectionChanged(null, null);
}
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
public void PartHasBeenChanged()
{
saveButtons.Visible = true;
SelectedTransformChanged?.Invoke(this, null);
2016-02-27 15:01:28 -08:00
Invalidate();
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
public void ThemeChanged(object sender, EventArgs e)
{
2015-07-14 13:38:22 -07:00
processingProgressControl.FillColor = ActiveTheme.Instance.PrimaryAccentColor;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
MeshViewerWidget.SetMaterialColor(1, ActiveTheme.Instance.PrimaryAccentColor);
}
internal GuiWidget AddMaterialControls()
2015-04-08 15:20:10 -07:00
{
FlowLayoutWidget buttonPanel = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
VAnchor = VAnchor.FitToChildren,
HAnchor = HAnchor.FitToChildren,
BackgroundColor = ActiveTheme.Instance.SecondaryBackgroundColor,
Padding = 15
};
2015-05-30 12:48:16 -07:00
extruderButtons.Clear();
for (int extruderIndex = 0; extruderIndex < ActiveSliceSettings.Instance.GetValue<int>(SettingsKey.extruder_count); extruderIndex++)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
FlowLayoutWidget colorSelectionContainer = new FlowLayoutWidget(FlowDirection.LeftToRight);
colorSelectionContainer.HAnchor = HAnchor.FitToChildren;
2015-05-30 12:48:16 -07:00
colorSelectionContainer.Padding = new BorderDouble(5);
2016-04-18 11:31:31 -07:00
string colorLabelText = string.Format("{0} {1}", "Material".Localize(), extruderIndex + 1);
2015-05-30 12:48:16 -07:00
RadioButton extruderSelection = new RadioButton(colorLabelText, textColor: ActiveTheme.Instance.PrimaryTextColor);
extruderButtons.Add(extruderSelection);
extruderSelection.SiblingRadioButtonList = extruderButtons;
colorSelectionContainer.AddChild(extruderSelection);
colorSelectionContainer.AddChild(new HorizontalSpacer());
int extruderIndexLocal = extruderIndex;
extruderSelection.Click += (sender, e) =>
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection)
{
2017-03-15 16:17:06 -07:00
// TODO: In the new model, we probably need to iterate this object and all its children, setting
// some state along the way or modify the tree processing to pass the parent value down the chain
MeshMaterialData material = MeshMaterialData.Get(Scene.SelectedItem.Mesh);
if (material.MaterialIndex != extruderIndexLocal + 1)
{
2017-03-15 16:17:06 -07:00
material.MaterialIndex = extruderIndexLocal + 1;
PartHasBeenChanged();
2015-04-08 15:20:10 -07:00
}
}
2015-05-30 12:48:16 -07:00
};
2014-10-13 19:29:25 -07:00
2015-05-30 12:48:16 -07:00
buttonPanel.AddChild(colorSelectionContainer);
2015-04-08 15:20:10 -07:00
}
return buttonPanel;
2015-04-08 15:20:10 -07:00
}
internal GuiWidget CreateRotateControls()
2015-04-08 15:20:10 -07:00
{
var buttonPanel = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
BackgroundColor = ActiveTheme.Instance.SecondaryBackgroundColor,
Padding = 15
};
2015-05-30 12:48:16 -07:00
List<GuiWidget> rotateControls = new List<GuiWidget>();
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
textImageButtonFactory.FixedWidth = EditButtonHeight;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
FlowLayoutWidget degreesContainer = new FlowLayoutWidget(FlowDirection.LeftToRight);
degreesContainer.HAnchor = HAnchor.ParentLeftRight;
degreesContainer.Padding = new BorderDouble(5);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
string degreesLabelText = "Degrees".Localize();
string degreesLabelTextFull = "{0}:".FormatWith(degreesLabelText);
TextWidget degreesLabel = new TextWidget(degreesLabelText, textColor: ActiveTheme.Instance.PrimaryTextColor);
degreesContainer.AddChild(degreesLabel);
degreesContainer.AddChild(new HorizontalSpacer());
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
MHNumberEdit degreesControl = new MHNumberEdit(45, pixelWidth: 40, allowNegatives: true, allowDecimals: true, increment: 5, minValue: -360, maxValue: 360);
degreesControl.VAnchor = Agg.UI.VAnchor.ParentTop;
degreesContainer.AddChild(degreesControl);
rotateControls.Add(degreesControl);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
buttonPanel.AddChild(degreesContainer);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
FlowLayoutWidget rotateButtonContainer = new FlowLayoutWidget(FlowDirection.LeftToRight);
rotateButtonContainer.HAnchor = HAnchor.ParentLeftRight;
2015-04-08 15:20:10 -07:00
ImageBuffer rotateImage = StaticData.Instance.LoadIcon("icon_rotate_32x32.png", 32, 32);
Button rotateXButton = textImageButtonFactory.Generate("", rotateImage);
2015-05-30 12:48:16 -07:00
TextWidget centeredX = new TextWidget("X", pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor); centeredX.Margin = new BorderDouble(3, 0, 0, 0); centeredX.AnchorCenter(); rotateXButton.AddChild(centeredX);
rotateButtonContainer.AddChild(rotateXButton);
rotateControls.Add(rotateXButton);
rotateXButton.Click += (s, e) =>
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
double radians = MathHelper.DegreesToRadians(degreesControl.ActuallNumberEdit.Value);
Matrix4X4 rotation = Matrix4X4.CreateRotationX(radians);
2017-03-15 16:17:06 -07:00
Matrix4X4 undoTransform = Scene.SelectedItem.Matrix;
Scene.SelectedItem.Matrix = PlatingHelper.ApplyAtCenter(Scene.SelectedItem, rotation);
2017-03-15 16:17:06 -07:00
UndoBuffer.Add(new TransformUndoCommand(this, Scene.SelectedItem, undoTransform, Scene.SelectedItem.Matrix));
2015-05-30 12:48:16 -07:00
PartHasBeenChanged();
Invalidate();
}
};
2015-04-08 15:20:10 -07:00
Button rotateYButton = textImageButtonFactory.Generate("", rotateImage);
2015-05-30 12:48:16 -07:00
TextWidget centeredY = new TextWidget("Y", pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor); centeredY.Margin = new BorderDouble(3, 0, 0, 0); centeredY.AnchorCenter(); rotateYButton.AddChild(centeredY);
rotateButtonContainer.AddChild(rotateYButton);
rotateControls.Add(rotateYButton);
rotateYButton.Click += (s, e) =>
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
double radians = MathHelper.DegreesToRadians(degreesControl.ActuallNumberEdit.Value);
Matrix4X4 rotation = Matrix4X4.CreateRotationY(radians);
2017-03-15 16:17:06 -07:00
Matrix4X4 undoTransform = Scene.SelectedItem.Matrix;
Scene.SelectedItem.Matrix = PlatingHelper.ApplyAtCenter(Scene.SelectedItem, rotation);
UndoBuffer.Add(new TransformUndoCommand(this, Scene.SelectedItem, undoTransform, Scene.SelectedItem.Matrix));
PartHasBeenChanged();
2015-05-30 12:48:16 -07:00
Invalidate();
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
};
2015-04-08 15:20:10 -07:00
Button rotateZButton = textImageButtonFactory.Generate("", rotateImage);
2015-05-30 12:48:16 -07:00
TextWidget centeredZ = new TextWidget("Z", pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor); centeredZ.Margin = new BorderDouble(3, 0, 0, 0); centeredZ.AnchorCenter(); rotateZButton.AddChild(centeredZ);
rotateButtonContainer.AddChild(rotateZButton);
rotateControls.Add(rotateZButton);
rotateZButton.Click += (s, e) =>
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
double radians = MathHelper.DegreesToRadians(degreesControl.ActuallNumberEdit.Value);
Matrix4X4 rotation = Matrix4X4.CreateRotationZ(radians);
2017-03-15 16:17:06 -07:00
Matrix4X4 undoTransform = Scene.SelectedItem.Matrix;
Scene.SelectedItem.Matrix = PlatingHelper.ApplyAtCenter(Scene.SelectedItem, rotation);
UndoBuffer.Add(new TransformUndoCommand(this, Scene.SelectedItem, undoTransform, Scene.SelectedItem.Matrix));
2015-05-30 12:48:16 -07:00
PartHasBeenChanged();
Invalidate();
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
};
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
buttonPanel.AddChild(rotateButtonContainer);
2015-04-08 15:20:10 -07:00
Button layFlatButton = WhiteButtonFactory.Generate("Align to Bed".Localize(), centerText: true);
2015-05-30 12:48:16 -07:00
layFlatButton.Cursor = Cursors.Hand;
buttonPanel.AddChild(layFlatButton);
2015-04-08 15:20:10 -07:00
layFlatButton.Click += (s, e) =>
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
Matrix4X4 undoTransform = Scene.SelectedItem.Matrix;
MakeLowestFaceFlat(Scene.SelectedItem);
UndoBuffer.Add(new TransformUndoCommand(this, Scene.SelectedItem, undoTransform, Scene.SelectedItem.Matrix));
2015-05-30 12:48:16 -07:00
PartHasBeenChanged();
Invalidate();
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
};
2015-04-08 15:20:10 -07:00
buttonPanel.AddChild(GenerateHorizontalRule());
2015-05-30 12:48:16 -07:00
textImageButtonFactory.FixedWidth = 0;
return buttonPanel;
2015-04-08 15:20:10 -07:00
}
private void AddSaveAndSaveAs(FlowLayoutWidget flowToAddTo)
{
TupleList<string, Func<bool>> buttonList = new TupleList<string, Func<bool>>();
2016-01-20 10:12:01 -08:00
buttonList.Add("Save".Localize(), () =>
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if(printItemWrapper == null)
{
UiThread.RunOnIdle(OpenSaveAsWindow);
}
else
{
SaveChanges(null);
}
2015-04-08 15:20:10 -07:00
return true;
});
2016-01-20 10:12:01 -08:00
buttonList.Add("Save As".Localize(), () =>
2015-04-08 15:20:10 -07:00
{
UiThread.RunOnIdle(OpenSaveAsWindow);
2015-04-08 15:20:10 -07:00
return true;
});
2015-08-10 13:36:31 -07:00
/*
DynamicDropDownMenu menu = CreateMenu(direction);
for (int index = 1; index < buttonList.Count; index++)
{
menu.addItem(buttonList[index].Item1, buttonList[index].Item2);
}
SplitButton splitButton = new SplitButton(button, menu);
*/
var textImageButtonFactory = ApplicationController.Instance.Theme.BreadCrumbButtonFactorySmallMargins;
2015-04-08 15:20:10 -07:00
SplitButtonFactory splitButtonFactory = new SplitButtonFactory();
splitButtonFactory.FixedHeight = textImageButtonFactory.FixedHeight;
2017-03-15 16:17:06 -07:00
2015-04-08 15:20:10 -07:00
saveButtons = splitButtonFactory.Generate(buttonList, Direction.Up, imageName: "icon_save_32x32.png");
saveButtons.Visible = false;
saveButtons.Margin = new BorderDouble();
saveButtons.VAnchor |= VAnchor.ParentCenter;
2015-04-08 15:20:10 -07:00
flowToAddTo.AddChild(saveButtons);
}
2017-04-05 19:03:04 -07:00
// Indicates if MatterControl is in a mode that allows DragDrop
2015-05-30 12:48:16 -07:00
private bool AllowDragDrop()
{
return printItemWrapper?.PrintItem.ReadOnly != false;
2015-05-30 12:48:16 -07:00
}
private void AutoSpin()
2015-05-30 12:48:16 -07:00
{
if (!HasBeenClosed && autoRotating)
2015-05-30 12:48:16 -07:00
{
// add it back in to keep it running.
UiThread.RunOnIdle(AutoSpin, .04);
if ((!timeSinceLastSpin.IsRunning || timeSinceLastSpin.ElapsedMilliseconds > 50)
&& hasDrawn)
{
hasDrawn = false;
timeSinceLastSpin.Restart();
Quaternion currentRotation = meshViewerWidget.TrackballTumbleWidget.TrackBallController.CurrentRotation.GetRotation();
Quaternion invertedRotation = Quaternion.Invert(currentRotation);
Quaternion rotateAboutZ = Quaternion.FromEulerAngles(new Vector3(0, 0, .01));
rotateAboutZ = invertedRotation * rotateAboutZ * currentRotation;
meshViewerWidget.TrackballTumbleWidget.TrackBallController.Rotate(rotateAboutZ);
Invalidate();
}
}
}
private void ReportProgressChanged(double progress0To1, string processingState)
{
bool continueProcessing;
ReportProgressChanged(progress0To1, processingState, out continueProcessing);
}
private void ReportProgressChanged(double progress0To1, string processingState, out bool continueProcessing)
2015-05-30 12:48:16 -07:00
{
if (!timeSinceReported.IsRunning || timeSinceReported.ElapsedMilliseconds > 100
|| processingState != processingProgressControl.ProgressMessage)
{
UiThread.RunOnIdle(() =>
2015-05-30 12:48:16 -07:00
{
2015-07-14 13:38:22 -07:00
processingProgressControl.RatioComplete = progress0To1;
2015-05-30 12:48:16 -07:00
processingProgressControl.ProgressMessage = processingState;
});
timeSinceReported.Restart();
}
continueProcessing = true;
}
2017-03-15 16:17:06 -07:00
public async Task ClearBedAndLoadPrintItemWrapper(PrintItemWrapper newPrintItem, bool switchToEditingMode = false)
2015-05-30 12:48:16 -07:00
{
SwitchStateToEditing();
2017-03-15 16:17:06 -07:00
Scene.ModifyChildren(children => children.Clear());
PrintItemWrapper.FileHasChanged.UnregisterEvent(ReloadMeshIfChangeExternaly, ref unregisterEvents);
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
if (newPrintItem != null)
2015-05-30 12:48:16 -07:00
{
// remove it first to make sure we don't double add it
2015-09-23 13:33:14 -07:00
PrintItemWrapper.FileHasChanged.UnregisterEvent(ReloadMeshIfChangeExternaly, ref unregisterEvents);
2016-12-01 15:14:53 -08:00
PrintItemWrapper.FileHasChanged.RegisterEvent(ReloadMeshIfChangeExternaly, ref unregisterEvents);
2015-05-30 12:48:16 -07:00
// don't load the mesh until we get all the rest of the interface built
meshViewerWidget.LoadDone += new EventHandler(meshViewerWidget_LoadDone);
Vector2 bedCenter = new Vector2();
MeshViewerWidget.CenterPartAfterLoad doCentering = MeshViewerWidget.CenterPartAfterLoad.DONT;
if (ActiveSliceSettings.Instance?.GetValue<bool>(SettingsKey.center_part_on_bed) == true)
{
doCentering = MeshViewerWidget.CenterPartAfterLoad.DO;
bedCenter = ActiveSliceSettings.Instance.GetValue<Vector2>(SettingsKey.print_center);
}
2017-03-15 16:17:06 -07:00
await meshViewerWidget.LoadItemIntoScene(newPrintItem.FileLocation, doCentering, bedCenter, newPrintItem.Name);
Invalidate();
2015-05-30 12:48:16 -07:00
}
2017-03-15 16:17:06 -07:00
this.printItemWrapper = newPrintItem;
PartHasBeenChanged();
2015-05-30 12:48:16 -07:00
partHasBeenEdited = false;
}
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
public List<IObject3DEditor> objectEditors = new List<IObject3DEditor>();
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
public Dictionary<Type, HashSet<IObject3DEditor>> objectEditorsByType = new Dictionary<Type, HashSet<IObject3DEditor>>();
2015-05-30 12:48:16 -07:00
public IObject3DEditor ActiveSelectionEditor { get; set; }
2017-03-15 16:17:06 -07:00
private void Scene_SelectionChanged(object sender, EventArgs e)
{
if (!Scene.HasSelection)
{
selectedObjectPanel.RemoveAllChildren();
return;
}
2015-05-30 12:48:16 -07:00
2017-04-05 19:03:04 -07:00
if (deferEditorTillMouseUp)
{
return;
}
2017-03-15 16:17:06 -07:00
var selectedItem = Scene.SelectedItem;
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
HashSet<IObject3DEditor> mappedEditors;
objectEditorsByType.TryGetValue(selectedItem.GetType(), out mappedEditors);
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
if(mappedEditors == null)
{
foreach(var editor in objectEditorsByType)
2016-03-04 10:11:05 -08:00
{
2017-03-15 16:17:06 -07:00
if (selectedItem.GetType().IsSubclassOf(editor.Key))
{
mappedEditors = editor.Value;
break;
}
2016-03-04 10:11:05 -08:00
}
2017-03-15 16:17:06 -07:00
}
2016-03-04 10:11:05 -08:00
2017-03-15 16:17:06 -07:00
editorPanel = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
VAnchor = VAnchor.FitToChildren,
2017-03-15 16:17:06 -07:00
};
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
if (mappedEditors != null)
{
var dropDownList = new DropDownList("", maxHeight: 300)
{
Margin = 3
2017-03-15 16:17:06 -07:00
};
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
foreach (IObject3DEditor editor in mappedEditors)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
MenuItem menuItem = dropDownList.AddItem(editor.Name);
menuItem.Selected += (s, e2) =>
{
ShowObjectEditor(editor);
};
}
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
selectedObjectPanel.RemoveAllChildren();
selectedObjectPanel.AddChild(dropDownList);
selectedObjectPanel.AddChild(editorPanel);
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
// Select the active editor or fall back to the first if not found
this.ActiveSelectionEditor = (from editor in mappedEditors
2017-03-15 16:17:06 -07:00
let type = editor.GetType()
where type.Name == selectedItem.ActiveEditor
select editor).FirstOrDefault();
2015-05-30 12:48:16 -07:00
// Fall back to default editor?
if(this.ActiveSelectionEditor == null)
2015-05-30 12:48:16 -07:00
{
this.ActiveSelectionEditor = mappedEditors.First();
2017-03-15 16:17:06 -07:00
}
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
int selectedIndex = 0;
for(int i = 0; i < dropDownList.MenuItems.Count; i++)
{
if(dropDownList.MenuItems[i].Text == this.ActiveSelectionEditor.Name)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
selectedIndex = i;
break;
2015-05-30 12:48:16 -07:00
}
}
2017-03-15 16:17:06 -07:00
dropDownList.SelectedIndex = selectedIndex;
2016-02-14 17:53:44 -08:00
ShowObjectEditor(this.ActiveSelectionEditor);
2015-05-30 12:48:16 -07:00
}
2017-03-15 16:17:06 -07:00
}
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
private void ShowObjectEditor(IObject3DEditor editor)
{
editorPanel.CloseAllChildren();
2017-03-15 16:17:06 -07:00
var newEditor = editor.Create(Scene.SelectedItem, this);
editorPanel.AddChild(newEditor);
2015-05-30 12:48:16 -07:00
}
private void DeleteSelectedMesh()
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection && Scene.Children.Count > 1)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
// Create and perform the delete operation
var deleteOperation = new DeleteCommand(this, Scene.SelectedItem);
deleteOperation.Do();
2016-02-27 15:01:28 -08:00
2017-03-15 16:17:06 -07:00
// Store the operation for undo/redo
UndoBuffer.Add(deleteOperation);
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
}
2014-01-29 19:09:30 -08:00
2017-03-15 16:17:06 -07:00
private void DrawStuffForSelectedPart(Graphics2D graphics2D)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
if (Scene.HasSelection)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
AxisAlignedBoundingBox selectedBounds = Scene.SelectedItem.GetAxisAlignedBoundingBox(Scene.SelectedItem.Matrix);
Vector3 boundsCenter = selectedBounds.Center;
Vector3 centerTop = new Vector3(boundsCenter.x, boundsCenter.y, selectedBounds.maxXYZ.z);
2014-01-29 19:09:30 -08:00
2017-03-15 16:17:06 -07:00
Vector2 centerTopScreenPosition = meshViewerWidget.TrackballTumbleWidget.GetScreenPosition(centerTop);
centerTopScreenPosition = meshViewerWidget.TransformToParentSpace(this, centerTopScreenPosition);
//graphics2D.Circle(screenPosition.x, screenPosition.y, 5, RGBA_Bytes.Cyan);
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
PathStorage zArrow = new PathStorage();
zArrow.MoveTo(-6, -2);
zArrow.curve3(0, -4);
zArrow.LineTo(6, -2);
zArrow.LineTo(0, 12);
zArrow.LineTo(-6, -2);
2017-03-15 16:17:06 -07:00
VertexSourceApplyTransform translate = new VertexSourceApplyTransform(zArrow, Affine.NewTranslation(centerTopScreenPosition));
//graphics2D.Render(translate, RGBA_Bytes.Black);
}
2015-04-08 15:20:10 -07:00
}
2017-03-15 16:17:06 -07:00
private void ExitEditingAndSaveIfRequested(bool userResponseYesSave)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
if (userResponseYesSave)
{
SaveChanges(null);
2015-05-30 12:48:16 -07:00
}
2017-03-15 16:17:06 -07:00
else
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
// and reload the part
ClearBedAndLoadPrintItemWrapper(printItemWrapper);
}
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
private async void LoadAndAddPartsToPlate(string[] filesToLoad)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
if (Scene.HasChildren && filesToLoad != null && filesToLoad.Length > 0)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
processingProgressControl.ProcessType = "Loading Parts".Localize() + ":";
2015-05-30 12:48:16 -07:00
processingProgressControl.Visible = true;
processingProgressControl.PercentComplete = 0;
LockEditControls();
2015-04-08 15:20:10 -07:00
await Task.Run(() => loadAndAddPartsToPlate(filesToLoad));
2015-04-08 15:20:10 -07:00
if (HasBeenClosed)
{
return;
}
UnlockEditControls();
PartHasBeenChanged();
2017-03-15 16:17:06 -07:00
bool addingOnlyOneItem = Scene.Children.Count == Scene.Children.Count + 1;
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
if (Scene.HasChildren)
{
if (addingOnlyOneItem)
{
// if we are only adding one part to the plate set the selection to it
2017-03-15 16:17:06 -07:00
Scene.SelectLastChild();
}
}
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
}
2014-01-29 19:09:30 -08:00
private void loadAndAddPartsToPlate(string[] filesToLoadIncludingZips)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
2017-03-15 16:17:06 -07:00
if (filesToLoadIncludingZips?.Any() == true)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
List<string> filesToLoad = new List<string>();
foreach (string loadedFileName in filesToLoadIncludingZips)
2015-05-30 12:48:16 -07:00
{
string extension = Path.GetExtension(loadedFileName).ToUpper();
2015-08-03 16:46:57 -07:00
if ((extension != "" && MeshFileIo.ValidFileExtensions().Contains(extension)))
2015-05-30 12:48:16 -07:00
{
filesToLoad.Add(loadedFileName);
}
else if (extension == ".ZIP")
{
2017-03-15 16:17:06 -07:00
List<PrintItem> partFiles = ProjectFileHandler.ImportFromProjectArchive(loadedFileName);
2015-05-30 12:48:16 -07:00
if (partFiles != null)
{
foreach (PrintItem part in partFiles)
{
filesToLoad.Add(part.FileLocation);
}
}
}
}
2015-05-30 12:48:16 -07:00
string progressMessage = "Loading Parts...".Localize();
2017-03-15 16:17:06 -07:00
2015-05-30 12:48:16 -07:00
double ratioPerFile = 1.0 / filesToLoad.Count;
double currentRatioDone = 0;
2017-03-15 16:17:06 -07:00
var itemCache = new Dictionary<string, IObject3D>();
foreach (string filePath in filesToLoad)
2015-05-30 12:48:16 -07:00
{
var libraryItem = new FileSystemFileItem(filePath);
2017-04-05 19:03:04 -07:00
var contentResult = libraryItem.CreateContent((double progress0To1, string processingState, out bool continueProcessing) =>
2015-05-30 12:48:16 -07:00
{
double ratioAvailable = (ratioPerFile * .5);
double currentRatio = currentRatioDone + progress0To1 * ratioAvailable;
ReportProgressChanged(currentRatio, progressMessage, out continueProcessing);
});
contentResult?.MeshLoaded.ContinueWith((task) =>
2017-04-05 19:03:04 -07:00
{
if (contentResult != null && contentResult.Object3D != null)
2017-04-05 19:03:04 -07:00
{
Scene.ModifyChildren(children => children.Add(contentResult.Object3D));
PlatingHelper.MoveToOpenPosition(contentResult.Object3D, this.Scene);
// TODO: There should be a batch insert so you can undo large 'add to scene' operations in one go
//this.InsertNewItem(tempScene);
}
});
2014-01-29 19:09:30 -08:00
if (HasBeenClosed)
2015-05-30 12:48:16 -07:00
{
return;
}
2014-01-29 19:09:30 -08:00
2015-05-30 12:48:16 -07:00
currentRatioDone += ratioPerFile;
}
}
}
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
public void LockEditControls()
2015-05-30 12:48:16 -07:00
{
viewIsInEditModePreLock = doEdittingButtonsContainer.Visible;
doEdittingButtonsContainer.Visible = false;
buttonRightPanelDisabledCover.Visible = true;
if (viewControls3D.PartSelectVisible == true)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
viewControls3D.PartSelectVisible = false;
if (viewControls3D.ActiveButton == ViewControls3DButtons.PartSelect)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
wasInSelectMode = true;
viewControls3D.ActiveButton = ViewControls3DButtons.Rotate;
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
}
2014-01-29 19:09:30 -08:00
2017-03-15 16:17:06 -07:00
private void MakeLowestFaceFlat(IObject3D objectToLayFlatGroup)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
Matrix4X4 objectToWold = objectToLayFlatGroup.Matrix;
IObject3D objectToLayFlat = objectToLayFlatGroup.Children[0];
Vertex lowestVertex = objectToLayFlat.Mesh.Vertices[0];
Vector3 lowestVertexPosition = Vector3.Transform(lowestVertex.Position, objectToWold);
2017-03-15 16:17:06 -07:00
IObject3D itemToLayFlat = null;
// Process each child, checking for the lowest vertex
foreach (IObject3D itemToCheck in objectToLayFlat.Children.Where(child => child.Mesh != null))
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
// find the lowest point on the model
2017-03-15 16:17:06 -07:00
for (int testIndex = 1; testIndex < itemToCheck.Mesh.Vertices.Count; testIndex++)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
Vertex vertex = itemToCheck.Mesh.Vertices[testIndex];
Vector3 vertexPosition = Vector3.Transform(vertex.Position, objectToWold);
2015-05-30 12:48:16 -07:00
if (vertexPosition.z < lowestVertexPosition.z)
{
2017-03-15 16:17:06 -07:00
lowestVertex = itemToCheck.Mesh.Vertices[testIndex];
2015-05-30 12:48:16 -07:00
lowestVertexPosition = vertexPosition;
2017-03-15 16:17:06 -07:00
itemToLayFlat = itemToCheck;
2015-05-30 12:48:16 -07:00
}
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
}
2014-01-29 19:09:30 -08:00
2015-05-30 12:48:16 -07:00
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())
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
double biggestAngleToFaceVertex = double.MinValue;
foreach (Vertex faceVertex in face.Vertices())
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
if (faceVertex != lowestVertex)
{
2017-03-15 16:17:06 -07:00
Vector3 faceVertexPosition = Vector3.Transform(faceVertex.Position, objectToWold);
2015-05-30 12:48:16 -07:00
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;
}
}
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
if (biggestAngleToFaceVertex < lowestAngleOfAnyFace)
{
lowestAngleOfAnyFace = biggestAngleToFaceVertex;
faceToLayFlat = face;
}
}
2014-01-29 19:09:30 -08:00
2015-05-30 12:48:16 -07:00
double maxDistFromLowestZ = 0;
List<Vector3> faceVertexes = new List<Vector3>();
foreach (Vertex vertex in faceToLayFlat.Vertices())
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
Vector3 vertexPosition = Vector3.Transform(vertex.Position, objectToWold);
2015-05-30 12:48:16 -07:00
faceVertexes.Add(vertexPosition);
maxDistFromLowestZ = Math.Max(maxDistFromLowestZ, vertexPosition.z - lowestVertexPosition.z);
}
2015-05-30 12:48:16 -07:00
if (maxDistFromLowestZ > .001)
{
Vector3 xPositive = (faceVertexes[1] - faceVertexes[0]).GetNormal();
Vector3 yPositive = (faceVertexes[2] - faceVertexes[0]).GetNormal();
Vector3 planeNormal = Vector3.Cross(xPositive, yPositive).GetNormal();
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
// 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);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
// rotate it
2017-03-15 16:17:06 -07:00
objectToLayFlatGroup.Matrix = PlatingHelper.ApplyAtCenter(objectToLayFlatGroup, partLevelMatrix);
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
PartHasBeenChanged();
Invalidate();
}
}
public static Regex fileNameNumberMatch = new Regex("\\(\\d+\\)", RegexOptions.Compiled);
2017-03-15 16:17:06 -07:00
private GuiWidget selectedObjectPanel;
private FlowLayoutWidget editorPanel;
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
private async void SaveChanges(SaveAsWindow.SaveAsReturnInfo returnInfo = null, Action eventToCallAfterSave = null)
{
editorThatRequestedSave = true;
afterSaveCallback = eventToCallAfterSave;
2015-05-30 12:48:16 -07:00
2017-03-15 16:17:06 -07:00
if (Scene.HasChildren)
2015-05-30 12:48:16 -07:00
{
2017-03-15 16:17:06 -07:00
processingProgressControl.ProcessType = "Saving".Localize() + ":";
processingProgressControl.Visible = true;
processingProgressControl.PercentComplete = 0;
2017-03-15 16:17:06 -07:00
LockEditControls();
2017-03-15 16:17:06 -07:00
// Perform the actual save operation
await Task.Run(() =>
{
2017-03-15 16:17:06 -07:00
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
2017-03-15 16:17:06 -07:00
try
{
2017-03-15 16:17:06 -07:00
// If null we are replacing a file from the current print item wrapper
if (returnInfo == null)
{
2017-03-15 16:17:06 -07:00
// Only save as .mcx
if (Path.GetExtension(printItemWrapper.FileLocation) != ".mcx")
{
printItemWrapper.FileLocation = Path.ChangeExtension(printItemWrapper.FileLocation, ".mcx");
}
}
2017-03-15 16:17:06 -07:00
else // Otherwise we are saving a new file
{
2017-03-15 16:17:06 -07:00
printItemWrapper = new PrintItemWrapper(
new PrintItem()
{
Name = returnInfo.newName,
FileLocation = Path.ChangeExtension(returnInfo.fileNameAndPath, ".mcx")
},
returnInfo.destinationLibraryProvider);
2017-03-15 16:17:06 -07:00
}
2017-03-15 16:17:06 -07:00
// TODO: Hook up progress reporting
Scene.Save(printItemWrapper.FileLocation, ApplicationDataStorage.Instance.ApplicationLibraryDataPath);
2017-03-15 16:17:06 -07:00
printItemWrapper.PrintItem.Commit();
2017-03-15 16:17:06 -07:00
// Wait for a second to report the file changed to give the OS a chance to finish closing it.
UiThread.RunOnIdle(printItemWrapper.ReportFileChange, 3);
2017-03-15 16:17:06 -07:00
// Save to the destination provider, otherwise it already exists and has a file monitor
if (returnInfo?.destinationLibraryProvider != null)
{
2017-03-15 16:17:06 -07:00
// save this part to correct library provider
var libraryToSaveTo = returnInfo.destinationLibraryProvider;
2017-03-15 16:17:06 -07:00
if (libraryToSaveTo != null)
{
var writableContainer = libraryToSaveTo as ILibraryWritableContainer;
if (writableContainer != null)
{
writableContainer.Add(new[] { new FileSystemFileItem(printItemWrapper.FileLocation) });
// HACK: This is a short term hack to get back into the game
// Set active item
//PrinterConnectionAndCommunication.Instance.ActivePrintItem = printItemWrapper;
}
libraryToSaveTo.Dispose();
}
}
2017-03-15 16:17:06 -07:00
saveSucceded = true;
}
2017-03-15 16:17:06 -07:00
catch (Exception ex)
{
Trace.WriteLine("Error saving file: ", ex.Message);
}
2017-03-15 16:17:06 -07:00
});
2015-09-23 13:33:14 -07:00
2017-03-15 16:17:06 -07:00
// Post Save cleanup
if (this.HasBeenClosed)
{
2017-03-15 16:17:06 -07:00
return;
}
2015-11-04 17:42:07 -08:00
2017-03-15 16:17:06 -07:00
UnlockEditControls();
saveButtons.Visible = !saveSucceded;
afterSaveCallback?.Invoke();
2015-04-08 15:20:10 -07:00
}
}
2015-05-30 12:48:16 -07:00
private void meshViewerWidget_LoadDone(object sender, EventArgs e)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
if (windowType == WindowMode.Embeded)
{
switch (PrinterConnectionAndCommunication.Instance.CommunicationState)
{
case PrinterConnectionAndCommunication.CommunicationStates.Printing:
case PrinterConnectionAndCommunication.CommunicationStates.Paused:
break;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
default:
UnlockEditControls();
break;
}
}
else
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
UnlockEditControls();
2015-04-08 15:20:10 -07:00
}
2017-03-15 16:17:06 -07:00
// Used to be bound to SelectionChanged event that no one was using and that overlapped with Queue SelectionChanged events that already signify this state change.
// Eliminate unnecessary event and restore later if some external caller needs this hook
if (Scene.HasSelection && Scene.SelectedItem.Mesh != null)
{
// TODO: Likely needs to be reviewed as described above and in the context of the scene graph
MeshMaterialData material = MeshMaterialData.Get(Scene.SelectedItem.Mesh);
for (int i = 0; i < extruderButtons.Count; i++)
{
if (material.MaterialIndex - 1 == i)
{
((RadioButton)extruderButtons[i]).Checked = true;
}
}
}
2015-04-08 15:20:10 -07:00
if (openMode == OpenMode.Editing)
2015-04-08 15:20:10 -07:00
{
2017-03-15 16:17:06 -07:00
UiThread.RunOnIdle(SwitchStateToEditing);
2015-05-30 12:48:16 -07:00
}
}
2015-04-08 15:20:10 -07:00
private bool PartsAreInPrintVolume()
{
if (ActiveSliceSettings.Instance?.GetValue<bool>(SettingsKey.center_part_on_bed) == false)
{
2017-03-15 16:17:06 -07:00
AxisAlignedBoundingBox allBounds = AxisAlignedBoundingBox.Empty;
foreach(var aabb in Scene.Children.Select(item => item.GetAxisAlignedBoundingBox(Matrix4X4.Identity)))
{
allBounds += aabb;
}
bool onBed = allBounds.minXYZ.z > -.001 && allBounds.minXYZ.z < .001; // really close to the bed
RectangleDouble bedRect = new RectangleDouble(0, 0, ActiveSliceSettings.Instance.GetValue<Vector2>(SettingsKey.bed_size).x, ActiveSliceSettings.Instance.GetValue<Vector2>(SettingsKey.bed_size).y);
bedRect.Offset(ActiveSliceSettings.Instance.GetValue<Vector2>(SettingsKey.print_center) - ActiveSliceSettings.Instance.GetValue<Vector2>(SettingsKey.bed_size) / 2);
bool inBounds = bedRect.Contains(new Vector2(allBounds.minXYZ)) && bedRect.Contains(new Vector2(allBounds.maxXYZ));
return onBed && inBounds;
}
return true;
}
2015-05-30 12:48:16 -07:00
private void OpenExportWindow()
{
if (exportingWindow == null)
{
exportingWindow = new ExportPrintItemWindow(this.printItemWrapper);
exportingWindow.Closed += (sender, e) =>
{
exportingWindow = null;
};
exportingWindow.ShowAsSystemWindow();
}
else
{
exportingWindow.BringToFront();
}
}
2014-01-29 19:09:30 -08:00
private void OpenSaveAsWindow()
2015-05-30 12:48:16 -07:00
{
if (saveAsWindow == null)
{
2017-03-15 16:17:06 -07:00
saveAsWindow = new SaveAsWindow(SaveChanges, printItemWrapper?.SourceLibraryProviderLocator, true, true);
saveAsWindow.Closed += SaveAsWindow_Closed;
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
else
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
saveAsWindow.BringToFront();
}
}
private void ReloadMeshIfChangeExternaly(Object sender, EventArgs e)
{
2015-09-23 13:33:14 -07:00
PrintItemWrapper senderItem = sender as PrintItemWrapper;
if (senderItem != null
&& senderItem.FileLocation == printItemWrapper.FileLocation)
2015-05-30 12:48:16 -07:00
{
2015-09-23 13:33:14 -07:00
if (!editorThatRequestedSave)
{
ClearBedAndLoadPrintItemWrapper(printItemWrapper);
}
2015-09-23 13:33:14 -07:00
editorThatRequestedSave = false;
}
2015-05-30 12:48:16 -07:00
}
private bool rotateQueueMenu_Click()
{
return true;
}
private void SaveAsWindow_Closed(object sender, ClosedEventArgs e)
2015-05-30 12:48:16 -07:00
{
this.saveAsWindow = null;
}
private bool scaleQueueMenu_Click()
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
return true;
}
2015-05-30 12:48:16 -07:00
private void SetEditControlsBasedOnPrinterState(object sender, EventArgs e)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
if (windowType == WindowMode.Embeded)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
switch (PrinterConnectionAndCommunication.Instance.CommunicationState)
2015-04-08 15:20:10 -07:00
{
2015-05-30 12:48:16 -07:00
case PrinterConnectionAndCommunication.CommunicationStates.Printing:
case PrinterConnectionAndCommunication.CommunicationStates.Paused:
LockEditControls();
break;
2015-04-08 15:20:10 -07:00
2015-05-30 12:48:16 -07:00
default:
UnlockEditControls();
break;
2015-04-08 15:20:10 -07:00
}
}
}
public override bool InEditMode => true;
2015-04-08 15:20:10 -07:00
2017-03-15 16:17:06 -07:00
internal async void SwitchStateToEditing()
{
this.IsEditing = true;
viewControls3D.ActiveButton = ViewControls3DButtons.PartSelect;
processingProgressControl.Visible = true;
LockEditControls();
viewIsInEditModePreLock = true;
if (Scene.HasChildren)
{
// CreateSelectionData()
await Task.Run(() =>
{
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
processingProgressControl.ProcessType = "Preparing Meshes".Localize() + ":";
// Force trace data generation
foreach (var object3D in Scene.Children)
{
object3D.TraceData();
}
// TODO: Why were we recreating GLData on edit?
//bool continueProcessing2;
//ReportProgressChanged(1, "Creating GL Data", out continueProcessing2);
//meshViewerWidget.CreateGlDataForMeshes(Scene.Children);
});
if (this.HasBeenClosed)
{
return;
}
Scene.SelectFirstChild();
}
UnlockEditControls();
viewControls3D.ActiveButton = ViewControls3DButtons.PartSelect;
Invalidate();
}
public void UnlockEditControls()
2015-05-30 12:48:16 -07:00
{
buttonRightPanelDisabledCover.Visible = false;
processingProgressControl.Visible = false;
if (viewIsInEditModePreLock)
2015-04-08 15:20:10 -07:00
{
viewControls3D.PartSelectVisible = true;
doEdittingButtonsContainer.Visible = true;
2015-04-08 15:20:10 -07:00
}
2015-05-30 12:48:16 -07:00
if (wasInSelectMode)
2015-04-08 15:20:10 -07:00
{
viewControls3D.ActiveButton = ViewControls3DButtons.PartSelect;
2015-05-30 12:48:16 -07:00
wasInSelectMode = false;
}
2015-04-08 15:20:10 -07:00
SelectedTransformChanged?.Invoke(this, null);
2015-04-08 15:20:10 -07:00
}
// ViewControls3D {{
internal GuiWidget ShowOverflowMenu()
{
var popupContainer = new FlowLayoutWidget(FlowDirection.TopToBottom);
var meshViewer = meshViewerWidget;
popupContainer.AddChild(
AddCheckbox(
"Show Print Bed".Localize(),
"Show Help Checkbox",
meshViewer.RenderBed,
5,
(s, e) =>
{
var checkbox = s as CheckBox;
if (checkbox != null)
{
meshViewer.RenderBed = checkbox.Checked;
}
}));
double buildHeight = ActiveSliceSettings.Instance.GetValue<double>(SettingsKey.build_height);
if (buildHeight > 0)
{
popupContainer.AddChild(
AddCheckbox(
"Show Print Area".Localize(),
"Show Help Checkbox",
meshViewer.RenderBed,
5,
(s, e) =>
{
var checkbox = s as CheckBox;
if (checkbox != null)
{
meshViewer.RenderBuildVolume = checkbox.Checked;
}
}));
}
var widget = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
HAnchor = HAnchor.ParentLeftRight,
Margin = new BorderDouble(5, 5, 5, 0)
};
popupContainer.AddChild(new HorizontalLine());
CreateRenderTypeRadioButtons(widget);
popupContainer.AddChild(widget);
return popupContainer;
}
private void CreateRenderTypeRadioButtons(GuiWidget parentContainer)
{
string renderTypeString = UserSettings.Instance.get(UserSettingsKey.defaultRenderSetting);
if (renderTypeString == null)
{
if (UserSettings.Instance.IsTouchScreen)
{
renderTypeString = "Shaded";
}
else
{
renderTypeString = "Outlines";
}
UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, renderTypeString);
}
//var itemTextColor = ActiveTheme.Instance.PrimaryTextColor;
var itemTextColor = RGBA_Bytes.Black;
RenderTypes renderType;
bool canParse = Enum.TryParse(renderTypeString, out renderType);
if (canParse)
{
meshViewerWidget.RenderType = renderType;
}
{
RadioButton renderTypeCheckBox = new RadioButton("Shaded".Localize(), textColor: itemTextColor);
renderTypeCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Shaded);
renderTypeCheckBox.CheckedStateChanged += (sender, e) =>
{
if (renderTypeCheckBox.Checked)
{
meshViewerWidget.RenderType = RenderTypes.Shaded;
UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, meshViewerWidget.RenderType.ToString());
}
};
parentContainer.AddChild(renderTypeCheckBox);
}
{
RadioButton renderTypeCheckBox = new RadioButton("Outlines".Localize(), textColor: itemTextColor);
renderTypeCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Outlines);
renderTypeCheckBox.CheckedStateChanged += (sender, e) =>
{
if (renderTypeCheckBox.Checked)
{
meshViewerWidget.RenderType = RenderTypes.Outlines;
UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, meshViewerWidget.RenderType.ToString());
}
};
parentContainer.AddChild(renderTypeCheckBox);
}
{
RadioButton renderTypeCheckBox = new RadioButton("Polygons".Localize(), textColor: itemTextColor);
renderTypeCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Polygons);
renderTypeCheckBox.CheckedStateChanged += (sender, e) =>
{
if (renderTypeCheckBox.Checked)
{
meshViewerWidget.RenderType = RenderTypes.Polygons;
UserSettings.Instance.set(UserSettingsKey.defaultRenderSetting, meshViewerWidget.RenderType.ToString());
}
};
parentContainer.AddChild(renderTypeCheckBox);
}
{
RadioButton renderTypeCheckBox = new RadioButton("Overhang".Localize(), textColor: itemTextColor);
renderTypeCheckBox.Checked = (meshViewerWidget.RenderType == RenderTypes.Overhang);
renderTypeCheckBox.CheckedStateChanged += (sender, e) =>
{
if (renderTypeCheckBox.Checked)
{
// TODO: Determine if Scene is available in scope
var scene = MatterControlApplication.Instance.ActiveView3DWidget.Scene;
meshViewerWidget.RenderType = RenderTypes.Overhang;
UserSettings.Instance.set("defaultRenderSetting", meshViewerWidget.RenderType.ToString());
foreach (var meshAndTransform in scene.VisibleMeshes(Matrix4X4.Identity))
{
meshAndTransform.MeshData.MarkAsChanged();
// change the color to be the right thing
GLMeshTrianglePlugin glMeshPlugin = GLMeshTrianglePlugin.Get(meshAndTransform.MeshData, (faceEdge) =>
{
Vector3 normal = faceEdge.containingFace.normal;
normal = Vector3.TransformVector(normal, meshAndTransform.Matrix).GetNormal();
VertexColorData colorData = new VertexColorData();
double startColor = 223.0 / 360.0;
double endColor = 5.0 / 360.0;
double delta = endColor - startColor;
RGBA_Bytes color = RGBA_Floats.FromHSL(startColor, .99, .49).GetAsRGBA_Bytes();
if (normal.z < 0)
{
color = RGBA_Floats.FromHSL(startColor - delta * normal.z, .99, .49).GetAsRGBA_Bytes();
}
colorData.red = color.red;
colorData.green = color.green;
colorData.blue = color.blue;
return colorData;
});
}
}
else
{
// TODO: Implement
/*
foreach (var meshTransform in Scene.VisibleMeshes(Matrix4X4.Identity))
{
// turn off the overhang colors
} */
}
};
parentContainer.AddChild(renderTypeCheckBox);
AddGridSnapSettings(parentContainer);
}
}
private void AddGridSnapSettings(GuiWidget widgetToAddTo)
{
TextWidget snapGridLabel = new TextWidget("Snap Grid".Localize())
{
TextColor = ActiveTheme.Instance.PrimaryBackgroundColor,
Margin = new BorderDouble(0, 0, 0, 10)
};
widgetToAddTo.AddChild(snapGridLabel);
var selectableOptions = new DropDownList("Custom", Direction.Down);
Dictionary<double, string> snapSettings = new Dictionary<double, string>()
{
{ 0, "Off" },
{ .1, "0.1" },
{ .25, "0.25" },
{ .5, "0.5" },
{ 1, "1" },
{ 2, "2" },
{ 5, "5" },
};
foreach (KeyValuePair<double, string> snapSetting in snapSettings)
{
double valueLocal = snapSetting.Key;
MenuItem newItem = selectableOptions.AddItem(snapSetting.Value);
if (meshViewerWidget.SnapGridDistance == valueLocal)
{
selectableOptions.SelectedLabel = snapSetting.Value;
}
newItem.Selected += (sender, e) =>
{
meshViewerWidget.SnapGridDistance = snapSetting.Key;
};
}
widgetToAddTo.AddChild(selectableOptions);
}
private static MenuItem AddCheckbox(string text, string itemValue, bool itemChecked, BorderDouble padding, EventHandler eventHandler)
{
var checkbox = new CheckBox(text)
{
Checked = itemChecked
};
checkbox.CheckedStateChanged += eventHandler;
return new MenuItem(checkbox, itemValue)
{
Padding = padding,
};
}
// ViewControls3D }}
2016-02-19 08:29:49 -08:00
}
2015-05-30 12:48:16 -07:00
2016-02-19 08:29:49 -08:00
public enum HitQuadrant { LB, LT, RB, RT }
public class MeshSelectInfo
{
public HitQuadrant HitQuadrant;
public bool DownOnPart;
public PlaneShape HitPlane;
public Vector3 LastMoveDelta;
public Vector3 PlaneDownHitPos;
2015-04-08 15:20:10 -07:00
}
}