diff --git a/ApplicationView/ApplicationController.cs b/ApplicationView/ApplicationController.cs index 9d08475d4..6f261493d 100644 --- a/ApplicationView/ApplicationController.cs +++ b/ApplicationView/ApplicationController.cs @@ -389,11 +389,11 @@ namespace MatterHackers.MatterControl new SceneSelectionSeparator(), new SceneSelectionOperation() { - TitleResolver = () => "Array".Localize(), + TitleResolver = () => "Linear Array".Localize(), Action = (scene) => { - scene.AddSelectionAsChildren(new ArrayObject3D()); - if(scene.SelectedItem is ArrayObject3D array) + scene.AddSelectionAsChildren(new ArrayLinearObject3D()); + if(scene.SelectedItem is ArrayLinearObject3D array) { array.Rebuild(); } @@ -402,6 +402,36 @@ namespace MatterHackers.MatterControl IsEnabled = (scene) => scene.HasSelection && !(scene.SelectedItem is SelectionGroup), }, new SceneSelectionOperation() + { + TitleResolver = () => "Radial Array".Localize(), + Action = (scene) => + { + scene.AddSelectionAsChildren(new ArrayRadialObject3D()); + if(scene.SelectedItem is ArrayRadialObject3D array) + { + array.Rebuild(); + } + }, + Icon = AggContext.StaticData.LoadIcon("array.png").SetPreMultiply(), + IsEnabled = (scene) => scene.HasSelection && !(scene.SelectedItem is SelectionGroup), + }, + new SceneSelectionSeparator(), + new SceneSelectionOperation() + { + TitleResolver = () => "Advanced Array".Localize(), + Action = (scene) => + { + scene.AddSelectionAsChildren(new ArrayAdvancedObject3D()); + if(scene.SelectedItem is ArrayAdvancedObject3D array) + { + array.Rebuild(); + } + }, + Icon = AggContext.StaticData.LoadIcon("array.png").SetPreMultiply(), + IsEnabled = (scene) => scene.HasSelection && !(scene.SelectedItem is SelectionGroup), + }, + new SceneSelectionSeparator(), + new SceneSelectionOperation() { TitleResolver = () => "Package".Localize(), Action = (scene) => diff --git a/DesignTools/Operations/ArrayObject3D.cs b/DesignTools/Operations/ArrayObject3D.cs index 90aa9894e..339d55795 100644 --- a/DesignTools/Operations/ArrayObject3D.cs +++ b/DesignTools/Operations/ArrayObject3D.cs @@ -28,25 +28,35 @@ either expressed or implied, of the FreeBSD Project. */ using System; +using System.ComponentModel; using System.Linq; using MatterHackers.DataConverters3D; using MatterHackers.VectorMath; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; namespace MatterHackers.MatterControl.DesignTools.Operations { - public class ArrayObject3D : Object3D, IRebuildable + public class DirectionAxis + { + public Vector3 Origin { get; set; } + public Vector3 Normal { get; set; } + } + + public class DirectionVector + { + public Vector3 Normal { get; set; } + } + + public class ArrayLinearObject3D : Object3D, IRebuildable { public int Count { get; set; } = 3; - public double XOffset { get; set; } = 30; - public double YOffset { get; set; } = 0; - public double Rotate { get; set; } = 0; - public double Scale { get; set; } = 1; - public bool RotatePart { get; set; } = false; - public bool ScaleOffset { get; set; } = false; + public DirectionVector Direction { get; set; } = new DirectionVector { Normal = new Vector3(1, 0, 0) }; + public double Distance { get; set; } = 30; public override string ActiveEditor => "PublicPropertyEditor"; - public ArrayObject3D() + public ArrayLinearObject3D() { } @@ -59,6 +69,92 @@ namespace MatterHackers.MatterControl.DesignTools.Operations list.Add(lastChild); var offset = Vector3.Zero; for (int i=1; i "PublicPropertyEditor"; + + public ArrayRadialObject3D() + { + } + + public void Rebuild() + { + this.Children.Modify(list => + { + IObject3D lastChild = list.First(); + var partCenter = lastChild.GetAxisAlignedBoundingBox().Center; + + list.Clear(); + list.Add(lastChild); + var offset = Vector3.Zero; + for (int i = 1; i < Count; i++) + { + var angleRadians = MathHelper.DegreesToRadians(Angle); + var nextOffset = Axis.Origin; + + //nextOffset Rotate(angleRadians * i); + var next = lastChild.Clone(); + next.Matrix *= Matrix4X4.CreateTranslation(nextOffset.X, nextOffset.Y, 0); + + if (RotatePart) + { + next.ApplyAtBoundsCenter(Matrix4X4.CreateRotationZ(angleRadians)); + } + + lastChild = next; + } + }); + } + } + + public class ArrayAdvancedObject3D : Object3D, IRebuildable + { + public int Count { get; set; } = 3; + public double XOffset { get; set; } = 30; + public double YOffset { get; set; } = 0; + public double Rotate { get; set; } = 0; + public double Scale { get; set; } = 1; + public bool RotatePart { get; set; } = false; + public bool ScaleOffset { get; set; } = false; + + public override string ActiveEditor => "PublicPropertyEditor"; + + public ArrayAdvancedObject3D() + { + } + + public void Rebuild() + { + this.Children.Modify(list => + { + IObject3D lastChild = list.First(); + list.Clear(); + list.Add(lastChild); + var offset = Vector3.Zero; + for (int i = 1; i < Count; i++) { var rotateRadians = MathHelper.DegreesToRadians(Rotate); var nextOffset = new Vector2(XOffset, YOffset); @@ -80,7 +176,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations } next.ApplyAtBoundsCenter(Matrix4X4.CreateScale(Scale)); - list.Add(next.Clone()); + list.Add(next); lastChild = next; } }); diff --git a/DesignTools/Primitives/TextObject3D.cs b/DesignTools/Primitives/TextObject3D.cs index 644e5bbad..1a2a32f27 100644 --- a/DesignTools/Primitives/TextObject3D.cs +++ b/DesignTools/Primitives/TextObject3D.cs @@ -88,6 +88,7 @@ namespace MatterHackers.MatterControl.DesignTools public double Height { get; set; } = 5; + [Sortable] [JsonConverter(typeof(StringEnumConverter))] public NamedTypeFace Font { get; set; } = new NamedTypeFace(); diff --git a/DesignTools/PublicPropertyEditor.cs b/DesignTools/PublicPropertyEditor.cs index 7d2b8a0ff..53f9edc76 100644 --- a/DesignTools/PublicPropertyEditor.cs +++ b/DesignTools/PublicPropertyEditor.cs @@ -37,7 +37,10 @@ using MatterHackers.Agg.UI; using MatterHackers.DataConverters3D; using MatterHackers.Localizations; using MatterHackers.MatterControl.CustomWidgets; +using MatterHackers.MatterControl.DesignTools.Operations; using MatterHackers.MatterControl.PartPreviewWindow; +using MatterHackers.MatterControl.SlicerConfiguration; +using MatterHackers.VectorMath; namespace MatterHackers.MatterControl.DesignTools { @@ -46,6 +49,11 @@ namespace MatterHackers.MatterControl.DesignTools void Rebuild(); } + [AttributeUsage(AttributeTargets.Property)] + public class SortableAttribute : Attribute + { + } + public class PublicPropertyEditor : IObject3DEditor { private IObject3D item; @@ -56,7 +64,7 @@ namespace MatterHackers.MatterControl.DesignTools private static Type[] allowedTypes = { - typeof(double), typeof(int), typeof(string), typeof(bool) + typeof(double), typeof(int), typeof(string), typeof(bool), typeof(DirectionVector), typeof(DirectionAxis) }; public const BindingFlags OwnedPropertiesOnly = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; @@ -129,42 +137,116 @@ namespace MatterHackers.MatterControl.DesignTools if (property.Value is double doubleValue) { FlowLayoutWidget rowContainer = CreateSettingsRow(property.DisplayName.Localize()); - var doubleEditWidget = new MHNumberEdit(doubleValue, pixelWidth: 50 * GuiWidget.DeviceScale, allowNegatives: true, allowDecimals: true, increment: .05) + + var field = new DoubleField(); + field.Initialize(0); + field.DoubleValue = doubleValue; + field.ValueChanged += (s, e) => { - SelectAllOnFocus = true, - VAnchor = VAnchor.Center - }; - doubleEditWidget.ActuallNumberEdit.EditComplete += (s, e) => - { - double editValue; - if (double.TryParse(doubleEditWidget.Text, out editValue)) - { - property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { editValue }); - } + property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { field.DoubleValue }); rebuildable?.Rebuild(); }; - rowContainer.AddChild(doubleEditWidget); + + rowContainer.AddChild(field.Content); tabContainer.AddChild(rowContainer); } + else if (property.Value is Vector2 vector2) + { + FlowLayoutWidget rowContainer = CreateSettingsRow(property.DisplayName.Localize()); + + var field = new Vector2Field(); + field.Initialize(0); + field.Vector2 = vector2; + field.ValueChanged += (s, e) => + { + property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { field.Vector2 }); + rebuildable?.Rebuild(); + }; + + rowContainer.AddChild(field.Content); + tabContainer.AddChild(rowContainer); + } + else if (property.Value is Vector3 vector3) + { + FlowLayoutWidget rowContainer = CreateSettingsRow(property.DisplayName.Localize()); + + var field = new Vector3Field(); + field.Initialize(0); + field.Vector3 = vector3; + field.ValueChanged += (s, e) => + { + property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { field.Vector3 }); + rebuildable?.Rebuild(); + }; + + rowContainer.AddChild(field.Content); + tabContainer.AddChild(rowContainer); + } + else if (property.Value is DirectionVector directionVector) + { + FlowLayoutWidget rowContainer = CreateSettingsRow(property.DisplayName.Localize()); + + var field = new Vector3Field(); + field.Initialize(0); + field.Vector3 = directionVector.Normal; + field.ValueChanged += (s, e) => + { + property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { new DirectionVector() { Normal = field.Vector3 } }); + rebuildable?.Rebuild(); + }; + + rowContainer.AddChild(field.Content); + tabContainer.AddChild(rowContainer); + } + else if (property.Value is DirectionAxis directionAxis) + { + // add in the position + FlowLayoutWidget originRowContainer = CreateSettingsRow(property.DisplayName.Localize()); + + var originField = new Vector3Field(); + originField.Initialize(0); + originField.Vector3 = directionAxis.Origin; + + var normalField = new Vector3Field(); + normalField.Initialize(0); + normalField.Vector3 = directionAxis.Normal; + + originField.ValueChanged += (s, e) => + { + property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { new DirectionAxis() { Origin = originField.Vector3, Normal = normalField.Vector3 } }); + rebuildable?.Rebuild(); + }; + + originRowContainer.AddChild(originField.Content); + tabContainer.AddChild(originRowContainer); + + // add in the direction + FlowLayoutWidget directionRowContainer = CreateSettingsRow(property.DisplayName.Localize()); + + normalField.ValueChanged += (s, e) => + { + property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { new DirectionAxis() { Origin = originField.Vector3, Normal = normalField.Vector3 } }); + rebuildable?.Rebuild(); + }; + + directionRowContainer.AddChild(normalField.Content); + tabContainer.AddChild(directionRowContainer); + } // create a int editor else if (property.Value is int intValue) { FlowLayoutWidget rowContainer = CreateSettingsRow(property.DisplayName.Localize()); - var intEditWidget = new MHNumberEdit(intValue, pixelWidth: 50 * GuiWidget.DeviceScale, allowNegatives: true, allowDecimals: false, increment: 1) + + var field = new IntField(); + field.Initialize(0); + field.IntValue = intValue; + field.ValueChanged += (s, e) => { - SelectAllOnFocus = true, - VAnchor = VAnchor.Center - }; - intEditWidget.ActuallNumberEdit.EditComplete += (s, e) => - { - int editValue; - if (int.TryParse(intEditWidget.Text, out editValue)) - { - property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { editValue }); - } + property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { field.IntValue }); rebuildable?.Rebuild(); }; - rowContainer.AddChild(intEditWidget); + + rowContainer.AddChild(field.Content); tabContainer.AddChild(rowContainer); } // create a bool editor @@ -172,14 +254,16 @@ namespace MatterHackers.MatterControl.DesignTools { FlowLayoutWidget rowContainer = CreateSettingsRow(property.DisplayName.Localize()); - var doubleEditWidget = new CheckBox(""); - doubleEditWidget.Checked = boolValue; - doubleEditWidget.CheckedStateChanged += (s, e) => + var field = new ToggleboxField(ApplicationController.Instance.Theme.Colors.PrimaryTextColor); + field.Initialize(0); + field.Checked = boolValue; + field.ValueChanged += (s, e) => { - property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { doubleEditWidget.Checked }); + property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { field.Checked }); rebuildable?.Rebuild(); }; - rowContainer.AddChild(doubleEditWidget); + + rowContainer.AddChild(field.Content); tabContainer.AddChild(rowContainer); } // create a string editor @@ -199,7 +283,7 @@ namespace MatterHackers.MatterControl.DesignTools rowContainer.AddChild(textEditWidget); tabContainer.AddChild(rowContainer); } - // create a NamedTypeFace editor + // create a enum editor else if (property.PropertyType.IsEnum) { // Enum keyed on name to friendly name @@ -216,16 +300,19 @@ namespace MatterHackers.MatterControl.DesignTools var dropDownList = new DropDownList("Name".Localize(), theme.Colors.PrimaryTextColor, Direction.Down, pointSize: theme.DefaultFontSize); - foreach (var fontName in enumItems.OrderBy(n => n.Value)) - { - MenuItem newItem = dropDownList.AddItem(fontName.Value); + var sortableAttribute = property.PropertyInfo.GetCustomAttributes(true).OfType().FirstOrDefault(); + var orderedItems = sortableAttribute != null ? enumItems.OrderBy(n => n.Value) : enumItems; - var localFontName = fontName; + foreach (var orderItem in orderedItems) + { + MenuItem newItem = dropDownList.AddItem(orderItem.Value); + + var localOredrItem = orderItem; newItem.Selected += (sender, e) => { property.PropertyInfo.GetSetMethod().Invoke( - this.item, - new Object[] { Enum.Parse(property.PropertyType, localFontName.Key) }); + this.item, + new Object[] { Enum.Parse(property.PropertyType, localOredrItem.Key) }); rebuildable?.Rebuild(); }; } diff --git a/MatterControl.csproj b/MatterControl.csproj index 810fcb464..e32dee5ef 100644 --- a/MatterControl.csproj +++ b/MatterControl.csproj @@ -200,6 +200,7 @@ + Form diff --git a/SlicerConfiguration/UIFields/CheckboxField.cs b/SlicerConfiguration/UIFields/CheckboxField.cs index c2066e0cb..dc089b724 100644 --- a/SlicerConfiguration/UIFields/CheckboxField.cs +++ b/SlicerConfiguration/UIFields/CheckboxField.cs @@ -37,6 +37,8 @@ namespace MatterHackers.MatterControl.SlicerConfiguration { private CheckBox checkBoxWidget; + public bool Checked => checkBoxWidget.Checked; + public override void Initialize(int tabIndex) { checkBoxWidget = new CheckBox("") @@ -69,6 +71,18 @@ namespace MatterHackers.MatterControl.SlicerConfiguration private CheckBox checkBoxWidget; private Color textColor; + public bool Checked + { + get + { + return checkBoxWidget.Checked; + } + set + { + checkBoxWidget.Checked = value; + } + } + public ToggleboxField(Color textColor) { this.textColor = textColor; diff --git a/SlicerConfiguration/UIFields/DoubleField.cs b/SlicerConfiguration/UIFields/DoubleField.cs index 2eb6b62a8..180a5f74a 100644 --- a/SlicerConfiguration/UIFields/DoubleField.cs +++ b/SlicerConfiguration/UIFields/DoubleField.cs @@ -35,19 +35,31 @@ namespace MatterHackers.MatterControl.SlicerConfiguration { public class DoubleField : NumberField { - protected double doubleValue; + double _doubleValue; + public double DoubleValue + { + get { return _doubleValue; } + set + { + if (_doubleValue != value) + { + _doubleValue = value; + numberEdit.Value = _doubleValue; + } + } + } protected override string ConvertValue(string newValue) { double.TryParse(newValue, out double currentValue); - doubleValue = currentValue; + DoubleValue = currentValue; - return doubleValue.ToString(); + return DoubleValue.ToString(); } protected override void OnValueChanged(FieldChangedEventArgs fieldChangedEventArgs) { - numberEdit.ActuallNumberEdit.Value = doubleValue; + numberEdit.ActuallNumberEdit.Value = DoubleValue; base.OnValueChanged(fieldChangedEventArgs); } } diff --git a/SlicerConfiguration/UIFields/IntField.cs b/SlicerConfiguration/UIFields/IntField.cs index c5ade67d5..025f899a8 100644 --- a/SlicerConfiguration/UIFields/IntField.cs +++ b/SlicerConfiguration/UIFields/IntField.cs @@ -33,7 +33,19 @@ namespace MatterHackers.MatterControl.SlicerConfiguration { public class IntField : NumberField { - private int intValue; + int _intValue; + public int IntValue + { + get { return _intValue; } + set + { + if (_intValue != value) + { + _intValue = value; + numberEdit.Value = _intValue; + } + } + } public int MinValue { get; set; } = int.MinValue; @@ -44,15 +56,15 @@ namespace MatterHackers.MatterControl.SlicerConfiguration decimal.TryParse(newValue, out decimal currentValue); // Clamp to range - intValue = Math.Min((int)currentValue, this.MaxValue); - intValue = Math.Max(intValue, this.MinValue); + IntValue = Math.Min((int)currentValue, this.MaxValue); + IntValue = Math.Max(IntValue, this.MinValue); - return intValue.ToString(); + return IntValue.ToString(); } protected override void OnValueChanged(FieldChangedEventArgs fieldChangedEventArgs) { - numberEdit.ActuallNumberEdit.Value = intValue; + numberEdit.ActuallNumberEdit.Value = IntValue; base.OnValueChanged(fieldChangedEventArgs); } } diff --git a/SlicerConfiguration/UIFields/PositiveDoubleField.cs b/SlicerConfiguration/UIFields/PositiveDoubleField.cs index 694e43227..e5df50c0a 100644 --- a/SlicerConfiguration/UIFields/PositiveDoubleField.cs +++ b/SlicerConfiguration/UIFields/PositiveDoubleField.cs @@ -42,9 +42,9 @@ namespace MatterHackers.MatterControl.SlicerConfiguration protected override string ConvertValue(string newValue) { base.ConvertValue(newValue); - doubleValue = doubleValue < 0 ? 0 : Math.Abs(doubleValue); + DoubleValue = DoubleValue < 0 ? 0 : Math.Abs(DoubleValue); - return doubleValue.ToString(); + return DoubleValue.ToString(); } } } diff --git a/SlicerConfiguration/UIFields/Vector2Field.cs b/SlicerConfiguration/UIFields/Vector2Field.cs index 948cefd03..13cd85926 100644 --- a/SlicerConfiguration/UIFields/Vector2Field.cs +++ b/SlicerConfiguration/UIFields/Vector2Field.cs @@ -29,6 +29,7 @@ either expressed or implied, of the FreeBSD Project. using MatterHackers.Agg; using MatterHackers.Agg.UI; +using MatterHackers.VectorMath; namespace MatterHackers.MatterControl.SlicerConfiguration { @@ -40,6 +41,20 @@ namespace MatterHackers.MatterControl.SlicerConfiguration private MHNumberEdit xEditWidget; + public Vector2 Vector2 + { + get + { + return new Vector2(xEditWidget.Value, yEditWidget.Value); + } + + set + { + xEditWidget.Value = value.X; + yEditWidget.Value = value.Y; + } + } + public override void Initialize(int tabIndex) { var container = new FlowLayoutWidget(); diff --git a/SlicerConfiguration/UIFields/Vector3Field.cs b/SlicerConfiguration/UIFields/Vector3Field.cs new file mode 100644 index 000000000..1914133c6 --- /dev/null +++ b/SlicerConfiguration/UIFields/Vector3Field.cs @@ -0,0 +1,174 @@ +/* +Copyright (c) 2017, Lars Brubaker, John Lewin +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +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 +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +using MatterHackers.Agg; +using MatterHackers.Agg.UI; +using MatterHackers.VectorMath; + +namespace MatterHackers.MatterControl.SlicerConfiguration +{ + public class Vector3Field : UIField + { + public static readonly int VectorXYZEditWidth = (int)(60 * GuiWidget.DeviceScale + .5); + + private MHNumberEdit xEditWidget; + private MHNumberEdit yEditWidget; + private MHNumberEdit zEditWidget; + + public Vector3 Vector3 + { + get + { + return new Vector3(xEditWidget.Value, yEditWidget.Value, zEditWidget.Value); + } + + set + { + xEditWidget.Value = value.X; + yEditWidget.Value = value.Y; + zEditWidget.Value = value.Z; + } + } + + public override void Initialize(int tabIndex) + { + var container = new FlowLayoutWidget(); + + string[] xyzValueStrings = this.Value?.Split(','); + if (xyzValueStrings == null + || xyzValueStrings.Length != 3) + { + xyzValueStrings = new string[] { "0", "0", "0" }; + } + + double.TryParse(xyzValueStrings[0], out double currentXValue); + + xEditWidget = new MHNumberEdit(currentXValue, allowNegatives: true, allowDecimals: true, pixelWidth: VectorXYZEditWidth, tabIndex: tabIndex) + { + ToolTipText = this.HelpText, + TabIndex = tabIndex, + SelectAllOnFocus = true + }; + xEditWidget.ActuallNumberEdit.EditComplete += (sender, e) => + { + this.SetValue( + string.Format("{0},{1},{2}", + xEditWidget.ActuallNumberEdit.Value.ToString(), + yEditWidget.ActuallNumberEdit.Value.ToString(), + zEditWidget.ActuallNumberEdit.Value.ToString()), + userInitiated: true); + }; + + container.AddChild(new TextWidget("X:", pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor) + { + VAnchor = VAnchor.Center, + Margin = new BorderDouble(5, 0), + }); + container.AddChild(xEditWidget); + + double.TryParse(xyzValueStrings[1], out double currentYValue); + + yEditWidget = new MHNumberEdit(currentYValue, allowNegatives: true, allowDecimals: true, pixelWidth: VectorXYZEditWidth, tabIndex: tabIndex) + { + ToolTipText = this.HelpText, + TabIndex = tabIndex + 1, + SelectAllOnFocus = true, + }; + yEditWidget.ActuallNumberEdit.EditComplete += (sender, e) => + { + this.SetValue( + string.Format("{0},{1},{2}", + xEditWidget.ActuallNumberEdit.Value.ToString(), + yEditWidget.ActuallNumberEdit.Value.ToString(), + zEditWidget.ActuallNumberEdit.Value.ToString()), + userInitiated: true); + }; + + container.AddChild(new TextWidget("Y:", pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor) + { + VAnchor = VAnchor.Center, + Margin = new BorderDouble(15, 0, 5, 0), + }); + container.AddChild(yEditWidget); + + double.TryParse(xyzValueStrings[2], out double currentZValue); + + zEditWidget = new MHNumberEdit(currentZValue, allowNegatives: true, allowDecimals: true, pixelWidth: VectorXYZEditWidth, tabIndex: tabIndex) + { + ToolTipText = this.HelpText, + TabIndex = tabIndex + 1, + SelectAllOnFocus = true, + }; + zEditWidget.ActuallNumberEdit.EditComplete += (sender, e) => + { + this.SetValue( + string.Format("{0},{1},{2}", + xEditWidget.ActuallNumberEdit.Value.ToString(), + yEditWidget.ActuallNumberEdit.Value.ToString(), + zEditWidget.ActuallNumberEdit.Value.ToString()), + userInitiated: true); + }; + + container.AddChild(new TextWidget("Z:", pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor) + { + VAnchor = VAnchor.Center, + Margin = new BorderDouble(15, 0, 5, 0), + }); + container.AddChild(zEditWidget); + + this.Content = container; + } + + protected override string ConvertValue(string newValue) + { + // Ensure we have a two value CSV or force to '0,0' + return (newValue?.Split(',').Length == 3) ? newValue.Trim() : "0,0"; + } + + protected override void OnValueChanged(FieldChangedEventArgs fieldChangedEventArgs) + { + string[] xyzValueStrings3 = this.Value.Split(','); + if (xyzValueStrings3.Length != 3) + { + xyzValueStrings3 = new string[] { "0", "0", "0" }; + } + + double.TryParse(xyzValueStrings3[0], out double currentValue); + xEditWidget.ActuallNumberEdit.Value = currentValue; + + double.TryParse(xyzValueStrings3[1], out currentValue); + yEditWidget.ActuallNumberEdit.Value = currentValue; + + double.TryParse(xyzValueStrings3[2], out currentValue); + zEditWidget.ActuallNumberEdit.Value = currentValue; + + base.OnValueChanged(fieldChangedEventArgs); + } + } +} diff --git a/Submodules/MatterSlice b/Submodules/MatterSlice index ab9ae8594..a2b16945b 160000 --- a/Submodules/MatterSlice +++ b/Submodules/MatterSlice @@ -1 +1 @@ -Subproject commit ab9ae85941ee030e16762d0a6ec1cf5ee771fe30 +Subproject commit a2b16945b16273fa243153926b9121ec20f06911