Lots of work on Array tool and support property editors

This commit is contained in:
Lars Brubaker 2018-02-09 18:10:41 -08:00 committed by LarsBrubaker
parent 5675973207
commit 2cd09dd365
12 changed files with 503 additions and 61 deletions

View file

@ -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) =>

View file

@ -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<Count; i++)
{
var next = lastChild.Clone();
next.Matrix *= Matrix4X4.CreateTranslation(Direction.Normal.GetNormal() * Distance);
list.Add(next);
lastChild = next;
}
});
}
}
public class ArrayRadialObject3D : Object3D, IRebuildable
{
public int Count { get; set; } = 3;
public DirectionAxis Axis { get; set; } = new DirectionAxis() { Origin = new Vector3(-30, 0, 0), Normal = Vector3.UnitZ };
public double Angle { get; set; } = 360;
[DisplayName("Keep Within Angle")]
[Description("Keep the entire extents of the part within the angle described.")]
public bool KeepInAngle { get; set; } = false;
[DisplayName("Rotate Part")]
[Description("Rotate the part to the same angle as the array.")]
public bool RotatePart { get; set; } = true;
public override string ActiveEditor => "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;
}
});

View file

@ -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();

View file

@ -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<SortableAttribute>().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();
};
}

View file

@ -200,6 +200,7 @@
<Compile Include="SlicerConfiguration\SettingsOrganizer.cs" />
<Compile Include="SlicerConfiguration\SlicerMapping\SliceEngineMapping.cs" />
<Compile Include="SlicerConfiguration\UIFields\IpAddessField.cs" />
<Compile Include="SlicerConfiguration\UIFields\Vector3Field.cs" />
<Compile Include="Utilities\InspectForm.cs" Condition="'$(Configuration)' == 'Debug'">
<SubType>Form</SubType>
</Compile>

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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();
}
}
}

View file

@ -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();

View file

@ -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);
}
}
}

@ -1 +1 @@
Subproject commit ab9ae85941ee030e16762d0a6ec1cf5ee771fe30
Subproject commit a2b16945b16273fa243153926b9121ec20f06911