diff --git a/MatterControl.csproj b/MatterControl.csproj
index d16cacfd4..0593ad00a 100644
--- a/MatterControl.csproj
+++ b/MatterControl.csproj
@@ -292,7 +292,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SlicerConfiguration/SliceSettingsWidget.cs b/SlicerConfiguration/SliceSettingsWidget.cs
index feb7575b8..513ef6cf2 100644
--- a/SlicerConfiguration/SliceSettingsWidget.cs
+++ b/SlicerConfiguration/SliceSettingsWidget.cs
@@ -79,9 +79,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
private bool isPrimarySettingsView { get; set; }
PrinterConnection printerConnection;
- static SliceSettingsWidget()
- {
- }
+ private EventHandler unregisterEvents;
public SliceSettingsWidget(PrinterConnection printerConnection, List layerCascade = null, NamedSettingsLayers viewFilter = NamedSettingsLayers.All)
{
@@ -127,6 +125,27 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
RebuildSliceSettingsTabs();
+ ActiveSliceSettings.SettingChanged.RegisterEvent(
+ (s, e) =>
+ {
+ if (e is StringEventArgs stringEvent)
+ {
+ string settingsKey = stringEvent.Data;
+ if (allFields.TryGetValue(settingsKey, out ISettingsField field))
+ {
+ string currentValue = settingsContext.GetValue(settingsKey);
+ if (field.Value != currentValue
+ || settingsKey == "com_port")
+ {
+ field.Value = currentValue;
+ field.OnValueChanged(currentValue);
+ field.UpdateStyle();
+ }
+ }
+ }
+ },
+ ref unregisterEvents);
+
this.AnchorAll();
}
@@ -291,8 +310,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
}
}
- private EventHandler unregisterEvents;
-
public override void OnClosed(ClosedEventArgs e)
{
unregisterEvents?.Invoke(this, null);
@@ -411,12 +428,12 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
topToBottomSettings.AddChild(
CreateSettingInfoUIControls(
printerConnection,
- settingData,
- settingsContext,
- viewFilter,
- copyIndex,
- isPrimarySettingsView,
- ref tabIndexForItem));
+ settingData,
+ settingsContext,
+ viewFilter,
+ copyIndex,
+ isPrimarySettingsView,
+ ref tabIndexForItem));
if (showHelpControls)
{
@@ -608,6 +625,12 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
private static GuiWidget GetExtraSettingsWidget(SliceSettingData settingData)
{
+ // List elements contain list values in the field which normally contains label details, skip generation of invalid labels
+ if (settingData.DataEditType == SliceSettingData.DataEditTypes.LIST)
+ {
+ return null;
+ }
+
var nameHolder = new GuiWidget()
{
HAnchor = HAnchor.Stretch,
@@ -622,52 +645,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
private class SettingsRow : FlowLayoutWidget
{
- public string SettingsKey { get; set; }
- public string SettingsValue { get; set; }
- private EventHandler unregisterEvents;
-
- ///
- /// Gets or sets the delegate to be invoked when the settings values need to be refreshed. The implementation should
- /// take the passed in text value and update its editor to reflect the latest value
- ///
- public Action ValueChanged { get; set; }
public Action UpdateStyle { get; set; }
-
- public SettingsRow(SettingsContext settingsContext)
- {
- Margin = new BorderDouble(0, 2);
- Padding = new BorderDouble(3);
- HAnchor = HAnchor.Stretch;
-
- ActiveSliceSettings.SettingChanged.RegisterEvent((s, e) =>
- {
- if (((StringEventArgs)e).Data == SettingsKey)
- {
- string setting = settingsContext.GetValue(SettingsKey);
- if (SettingsValue != setting
- || SettingsKey == "com_port")
- {
- SettingsValue = setting;
- ValueChanged?.Invoke(setting);
- }
- UpdateStyle?.Invoke();
- }
- }, ref unregisterEvents);
- }
-
- public override void OnClosed(ClosedEventArgs e)
- {
- unregisterEvents?.Invoke(this, null);
- base.OnClosed(e);
- }
-
- public void RefreshValue(SettingsContext settingsContext)
- {
- string latestValue = settingsContext.GetValue(this.SettingsKey);
- SettingsValue = latestValue;
- UpdateStyle?.Invoke();
- ValueChanged?.Invoke(latestValue);
- }
}
private static readonly RGBA_Bytes materialSettingBackgroundColor = new RGBA_Bytes(255, 127, 0, 108);
@@ -739,7 +717,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
return dataArea;
}
- public static GuiWidget CreateSettingControl(PrinterConnection printerConnection, string sliceSettingsKey, bool isPrimarySettingsView, ref int tabIndex)
+ public GuiWidget CreateSettingControl(PrinterConnection printerConnection, string sliceSettingsKey, bool isPrimarySettingsView, ref int tabIndex)
{
return CreateSettingInfoUIControls(
printerConnection,
@@ -751,7 +729,9 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
ref tabIndex);
}
- private static GuiWidget CreateSettingInfoUIControls(
+ Dictionary allFields = new Dictionary();
+
+ private GuiWidget CreateSettingInfoUIControls(
PrinterConnection printerConnection,
SliceSettingData settingData,
SettingsContext settingsContext,
@@ -782,17 +762,21 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
Width = settingData.ShowAsOverride ? 30 * GuiWidget.DeviceScale : 0,
};
- var settingsRow = new SettingsRow(settingsContext)
+ var settingsRow = new SettingsRow()
{
- SettingsKey = settingData.SlicerConfigName,
- SettingsValue = sliceSettingValue,
+ Margin = new BorderDouble(0, 2),
+ Padding = new BorderDouble(3),
+ HAnchor = HAnchor.Stretch
};
+
settingsRow.AddChild(nameArea);
settingsRow.AddChild(dataArea);
settingsRow.AddChild(unitsArea);
settingsRow.AddChild(restoreArea);
settingsRow.Name = settingData.SlicerConfigName + " Edit Field";
+ ISettingsField field = null;
+
if (!PrinterSettings.KnownSettings.Contains(settingData.SlicerConfigName))
{
// the setting we think we are adding is not in the known settings it may have been deprecated
@@ -805,675 +789,70 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
{
int intEditWidth = (int)(60 * GuiWidget.DeviceScale + .5);
int doubleEditWidth = (int)(60 * GuiWidget.DeviceScale + .5);
- int vectorXYEditWidth = (int)(60 * GuiWidget.DeviceScale + .5);
- int multiLineEditHeight = (int)(120 * GuiWidget.DeviceScale + .5);
if (settingData.DataEditType != SliceSettingData.DataEditTypes.MULTI_LINE_TEXT)
{
nameArea.AddChild(new WrappedTextWidget(settingData.PresentationName.Localize(), pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor));
- //nameArea.AddChild(new TextWidget(settingData.PresentationName.Localize(), pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor));
}
switch (settingData.DataEditType)
{
case SliceSettingData.DataEditTypes.INT:
- {
- FlowLayoutWidget content = new FlowLayoutWidget();
- int currentValue;
- int.TryParse(sliceSettingValue, out currentValue);
-
- var intEditWidget = new MHNumberEdit(currentValue, pixelWidth: intEditWidth, tabIndex: tabIndexForItem++)
- {
- ToolTipText = settingData.HelpText,
- SelectAllOnFocus = true,
- Name = settingData.PresentationName + " Edit",
- };
- intEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
- {
- settingsContext.SetValue(settingData.SlicerConfigName, ((NumberEdit)sender).Value.ToString());
- settingsRow.UpdateStyle();
- };
-
- content.AddChild(intEditWidget);
- unitsArea.AddChild(GetExtraSettingsWidget(settingData));
-
- if (settingData.QuickMenuSettings.Count > 0)
- {
- dataArea.AddChild(CreateQuickMenu(settingData, settingsContext, content, intEditWidget.ActuallNumberEdit.InternalTextEditWidget));
- }
- else
- {
- dataArea.AddChild(content);
- }
-
- settingsRow.ValueChanged = (text) =>
- {
- intEditWidget.Text = text;
- };
- }
+ field = new IntField();
break;
case SliceSettingData.DataEditTypes.DOUBLE:
- {
- double currentValue;
- double.TryParse(sliceSettingValue, out currentValue);
-
- var doubleEditWidget = new MHNumberEdit(currentValue, allowNegatives: true, allowDecimals: true, pixelWidth: doubleEditWidth, tabIndex: tabIndexForItem++)
- {
- ToolTipText = settingData.HelpText,
- SelectAllOnFocus = true
- };
- doubleEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
- {
- settingsContext.SetValue(settingData.SlicerConfigName, ((NumberEdit)sender).Value.ToString());
- settingsRow.UpdateStyle();
- };
- dataArea.AddChild(doubleEditWidget);
- unitsArea.AddChild(GetExtraSettingsWidget(settingData));
-
- settingsRow.ValueChanged = (text) =>
- {
- double currentValue2 = 0;
- double.TryParse(text, out currentValue2);
- doubleEditWidget.ActuallNumberEdit.Value = currentValue2;
- };
- }
+ field = new DoubleField();
break;
case SliceSettingData.DataEditTypes.POSITIVE_DOUBLE:
- {
- const string multiValuesAreDiffernt = "-";
- FlowLayoutWidget content = new FlowLayoutWidget();
-
- var doubleEditWidget = new MHNumberEdit(0, allowDecimals: true, pixelWidth: doubleEditWidth, tabIndex: tabIndexForItem++)
- {
- ToolTipText = settingData.HelpText,
- Name = settingData.PresentationName + " Textbox",
- SelectAllOnFocus = true
- };
-
- double currentValue;
- bool ChangesMultipleOtherSettings = settingData.SetSettingsOnChange.Count > 0;
- if (ChangesMultipleOtherSettings)
- {
- bool allTheSame = true;
- string setting = settingsContext.GetValue(settingData.SetSettingsOnChange[0]["TargetSetting"]);
- for (int i = 1; i < settingData.SetSettingsOnChange.Count; i++)
- {
- string nextSetting = settingsContext.GetValue(settingData.SetSettingsOnChange[i]["TargetSetting"]);
- if (setting != nextSetting)
- {
- allTheSame = false;
- break;
- }
- }
-
- if (allTheSame && setting.EndsWith("mm"))
- {
- double.TryParse(setting.Substring(0, setting.Length - 2), out currentValue);
- doubleEditWidget.ActuallNumberEdit.Value = currentValue;
- }
- else
- {
- doubleEditWidget.ActuallNumberEdit.InternalNumberEdit.Text = multiValuesAreDiffernt;
- }
- }
- else // just set the setting normally
- {
- double.TryParse(sliceSettingValue, out currentValue);
- doubleEditWidget.ActuallNumberEdit.Value = currentValue;
- }
- doubleEditWidget.ActuallNumberEdit.InternalTextEditWidget.MarkAsStartingState();
-
- doubleEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
- {
- NumberEdit numberEdit = (NumberEdit)sender;
- // If this setting sets other settings, then do that.
- if (ChangesMultipleOtherSettings
- && numberEdit.Text != multiValuesAreDiffernt)
- {
- {
- settingsContext.SetValue(settingData.SetSettingsOnChange[0]["TargetSetting"], numberEdit.Value.ToString() + "mm");
- }
- }
-
- // also always save to the local setting
- settingsContext.SetValue(settingData.SlicerConfigName, numberEdit.Value.ToString());
- settingsRow.UpdateStyle();
- };
- content.AddChild(doubleEditWidget);
- unitsArea.AddChild(GetExtraSettingsWidget(settingData));
-
- if (settingData.QuickMenuSettings.Count > 0)
- {
- dataArea.AddChild(CreateQuickMenu(settingData, settingsContext, content, doubleEditWidget.ActuallNumberEdit.InternalTextEditWidget));
- }
- else
- {
- dataArea.AddChild(content);
- }
-
- settingsRow.ValueChanged = (text) =>
- {
- double currentValue2 = 0;
- double.TryParse(text, out currentValue2);
- doubleEditWidget.ActuallNumberEdit.Value = currentValue2;
- };
- }
+ field = new PositiveDoubleField();
break;
case SliceSettingData.DataEditTypes.OFFSET:
- {
- double currentValue;
- double.TryParse(sliceSettingValue, out currentValue);
- var doubleEditWidget = new MHNumberEdit(currentValue, allowDecimals: true, allowNegatives: true, pixelWidth: doubleEditWidth, tabIndex: tabIndexForItem++)
- {
- ToolTipText = settingData.HelpText,
- SelectAllOnFocus = true
-
- };
- doubleEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
- {
- settingsContext.SetValue(settingData.SlicerConfigName, ((NumberEdit)sender).Value.ToString());
- settingsRow.UpdateStyle();
- };
- dataArea.AddChild(doubleEditWidget);
- unitsArea.AddChild(GetExtraSettingsWidget(settingData));
-
- settingsRow.ValueChanged = (text) =>
- {
- double currentValue2;
- double.TryParse(text, out currentValue2);
- doubleEditWidget.ActuallNumberEdit.Value = currentValue2;
- };
- }
+ field = new OffsetField();
break;
case SliceSettingData.DataEditTypes.DOUBLE_OR_PERCENT:
- {
- FlowLayoutWidget content = new FlowLayoutWidget();
-
- var stringEdit = new MHTextEditWidget(sliceSettingValue, pixelWidth: doubleEditWidth - 2, tabIndex: tabIndexForItem++)
- {
- ToolTipText = settingData.HelpText,
- SelectAllOnFocus = true
- };
- stringEdit.ActualTextEditWidget.EditComplete += (sender, e) =>
- {
- var textEditWidget = (TextEditWidget)sender;
- string text = textEditWidget.Text.Trim();
-
- bool isPercent = text.Contains("%");
- if (isPercent)
- {
- text = text.Substring(0, text.IndexOf("%"));
- }
- double result;
- double.TryParse(text, out result);
- text = result.ToString();
- if (isPercent)
- {
- text += "%";
- }
- textEditWidget.Text = text;
- settingsContext.SetValue(settingData.SlicerConfigName, textEditWidget.Text);
- settingsRow.UpdateStyle();
- };
-
- stringEdit.ActualTextEditWidget.InternalTextEditWidget.AllSelected += (sender, e) =>
- {
- // select everything up to the % (if present)
- InternalTextEditWidget textEditWidget = (InternalTextEditWidget)sender;
- int percentIndex = textEditWidget.Text.IndexOf("%");
- if (percentIndex != -1)
- {
- textEditWidget.SetSelection(0, percentIndex - 1);
- }
- };
-
- content.AddChild(stringEdit);
- unitsArea.AddChild(GetExtraSettingsWidget(settingData));
-
- if (settingData.QuickMenuSettings.Count > 0)
- {
- dataArea.AddChild(CreateQuickMenu(settingData, settingsContext, content, stringEdit.ActualTextEditWidget.InternalTextEditWidget));
- }
- else
- {
- dataArea.AddChild(content);
- }
-
- settingsRow.ValueChanged = (text) =>
- {
- stringEdit.Text = text;
- };
- }
+ field = new DoubleOrPercentField();
break;
case SliceSettingData.DataEditTypes.INT_OR_MM:
- {
- FlowLayoutWidget content = new FlowLayoutWidget();
-
- var stringEdit = new MHTextEditWidget(sliceSettingValue, pixelWidth: doubleEditWidth - 2, tabIndex: tabIndexForItem++)
- {
- ToolTipText = settingData.HelpText,
- SelectAllOnFocus = true
- };
-
- string startingText = stringEdit.Text;
- stringEdit.ActualTextEditWidget.EditComplete += (sender, e) =>
- {
- TextEditWidget textEditWidget = (TextEditWidget)sender;
- // only validate when we lose focus
- if (!textEditWidget.ContainsFocus)
- {
- string text = textEditWidget.Text;
- text = text.Trim();
- bool isMm = text.Contains("mm");
- if (isMm)
- {
- text = text.Substring(0, text.IndexOf("mm"));
- }
- double result;
- double.TryParse(text, out result);
- text = result.ToString();
- if (isMm)
- {
- text += "mm";
- }
- else
- {
- result = (int)result;
- text = result.ToString();
- }
- textEditWidget.Text = text;
- startingText = stringEdit.Text;
- }
-
- settingsContext.SetValue(settingData.SlicerConfigName, textEditWidget.Text);
- settingsRow.UpdateStyle();
-
- // make sure we are still looking for the final validation before saving.
- if (textEditWidget.ContainsFocus)
- {
- UiThread.RunOnIdle(() =>
- {
- string currentText = textEditWidget.Text;
- int cursorIndex = textEditWidget.InternalTextEditWidget.CharIndexToInsertBefore;
- textEditWidget.Text = startingText;
- textEditWidget.InternalTextEditWidget.MarkAsStartingState();
- textEditWidget.Text = currentText;
- textEditWidget.InternalTextEditWidget.CharIndexToInsertBefore = cursorIndex;
- });
- }
- };
-
- stringEdit.ActualTextEditWidget.InternalTextEditWidget.AllSelected += (sender, e) =>
- {
- // select everything up to the mm (if present)
- InternalTextEditWidget textEditWidget = (InternalTextEditWidget)sender;
- int mMIndex = textEditWidget.Text.IndexOf("mm");
- if (mMIndex != -1)
- {
- textEditWidget.SetSelection(0, mMIndex - 1);
- }
- };
-
- content.AddChild(stringEdit);
- unitsArea.AddChild(GetExtraSettingsWidget(settingData));
-
- if (settingData.QuickMenuSettings.Count > 0)
- {
- dataArea.AddChild(CreateQuickMenu(settingData, settingsContext, content, stringEdit.ActualTextEditWidget.InternalTextEditWidget));
- }
- else
- {
- dataArea.AddChild(content);
- }
-
- settingsRow.ValueChanged = (text) =>
- {
- stringEdit.Text = text;
- };
- }
+ field = new IntOrMmField();
break;
case SliceSettingData.DataEditTypes.CHECK_BOX:
- {
- var checkBoxWidget = new CheckBox("")
- {
- Name = settingData.PresentationName + " Checkbox",
- ToolTipText = settingData.HelpText,
- VAnchor = VAnchor.Bottom,
- TextColor = ActiveTheme.Instance.PrimaryTextColor,
- Checked = sliceSettingValue == "1"
- };
- checkBoxWidget.Click += (sender, e) =>
- {
- // SetValue should only be called when the checkbox is clicked. If this code makes its way into checkstatechanged
- // we end up adding a key back into the dictionary after we call .ClearValue, resulting in the blue override bar reappearing after
- // clearing a useroverride with the red x
- settingsContext.SetValue(settingData.SlicerConfigName, checkBoxWidget.Checked ? "1" : "0");
- };
- checkBoxWidget.CheckedStateChanged += (s, e) =>
- {
- // Linked settings should be updated in all cases (user clicked checkbox, user clicked clear)
- foreach (var setSettingsData in settingData.SetSettingsOnChange)
- {
- string targetValue;
- if (setSettingsData.TryGetValue(checkBoxWidget.Checked ? "OnValue" : "OffValue", out targetValue))
- {
- settingsContext.SetValue(setSettingsData["TargetSetting"], targetValue);
- }
- }
-
- settingsRow.UpdateStyle();
- };
- dataArea.AddChild(checkBoxWidget);
-
- settingsRow.ValueChanged = (text) =>
- {
- checkBoxWidget.Checked = text == "1";
- };
- }
+ field = new CheckboxField();
break;
case SliceSettingData.DataEditTypes.STRING:
- {
- var stringEdit = new MHTextEditWidget(sliceSettingValue, pixelWidth: settingData.ShowAsOverride ? 120 : 200, tabIndex: tabIndexForItem++)
- {
- Name = settingData.PresentationName + " Edit",
- };
- stringEdit.ToolTipText = settingData.HelpText;
-
- stringEdit.ActualTextEditWidget.EditComplete += (sender, e) =>
- {
- settingsContext.SetValue(settingData.SlicerConfigName, ((TextEditWidget)sender).Text);
- settingsRow.UpdateStyle();
- };
-
- dataArea.AddChild(stringEdit);
-
- settingsRow.ValueChanged = (text) =>
- {
- stringEdit.Text = text;
- };
- }
+ field = new StringField();
break;
case SliceSettingData.DataEditTypes.MULTI_LINE_TEXT:
- {
- string convertedNewLines = sliceSettingValue.Replace("\\n", "\n");
- var stringEdit = new MHTextEditWidget(convertedNewLines, pixelWidth: 320, pixelHeight: multiLineEditHeight, multiLine: true, tabIndex: tabIndexForItem++, typeFace: ApplicationController.MonoSpacedTypeFace)
- {
- HAnchor = HAnchor.Stretch,
- };
-
- stringEdit.DrawFromHintedCache();
-
- stringEdit.ActualTextEditWidget.EditComplete += (sender, e) =>
- {
- settingsContext.SetValue(settingData.SlicerConfigName, ((TextEditWidget)sender).Text.Replace("\n", "\\n"));
- settingsRow.UpdateStyle();
- };
-
- nameArea.HAnchor = HAnchor.Absolute;
- nameArea.Width = 0;
- dataArea.AddChild(stringEdit);
- dataArea.HAnchor = HAnchor.Stretch;
-
- settingsRow.ValueChanged = (text) =>
- {
- stringEdit.Text = text.Replace("\\n", "\n");
- };
- }
+ field = new MultilineStringField();
break;
-
case SliceSettingData.DataEditTypes.COM_PORT:
- {
- // TODO: Conditionally opt out on Android
-
- EventHandler localUnregisterEvents = null;
-
- bool canChangeComPort = !printerConnection.PrinterIsConnected && printerConnection.CommunicationState != CommunicationStates.AttemptingToConnect;
- // The COM_PORT control is unique in its approach to the SlicerConfigName. It uses "com_port" settings name to
- // bind to a context that will place it in the SliceSetting view but it binds its values to a machine
- // specific dictionary key that is not exposed in the UI. At runtime we lookup and store to '_com_port'
- // ensuring that a single printer can be shared across different devices and we'll select the correct com port in each case
- var selectableOptions = new DropDownList("None".Localize(), maxHeight: 200)
- {
- ToolTipText = settingData.HelpText,
- Margin = new BorderDouble(),
- Name = "Serial Port Dropdown",
- // Prevent droplist interaction when connected
- Enabled = canChangeComPort,
- TextColor = canChangeComPort ? ActiveTheme.Instance.PrimaryTextColor : new RGBA_Bytes(ActiveTheme.Instance.PrimaryTextColor, 150),
- BorderColor = canChangeComPort ? ActiveTheme.Instance.SecondaryTextColor : new RGBA_Bytes(ActiveTheme.Instance.SecondaryTextColor, 150),
- };
-
- selectableOptions.Click += (s, e) =>
- {
- AddComMenuItems(settingData, settingsContext, settingsRow, selectableOptions);
- };
-
- AddComMenuItems(settingData, settingsContext, settingsRow, selectableOptions);
-
- dataArea.AddChild(selectableOptions);
-
- settingsRow.ValueChanged = (text) =>
- {
- // Lookup the machine specific comport value rather than the passed in text value
- selectableOptions.SelectedLabel = ActiveSliceSettings.Instance.Helpers.ComPort();
- };
-
- // Prevent droplist interaction when connected
- printerConnection.CommunicationStateChanged.RegisterEvent((s, e) =>
- {
- canChangeComPort = !printerConnection.PrinterIsConnected && printerConnection.CommunicationState != CommunicationStates.AttemptingToConnect;
- selectableOptions.Enabled = canChangeComPort;
- selectableOptions.TextColor = canChangeComPort ? ActiveTheme.Instance.PrimaryTextColor : new RGBA_Bytes(ActiveTheme.Instance.PrimaryTextColor, 150);
- selectableOptions.BorderColor = canChangeComPort ? ActiveTheme.Instance.SecondaryTextColor : new RGBA_Bytes(ActiveTheme.Instance.SecondaryTextColor, 150);
- }, ref localUnregisterEvents);
-
- // Release event listener on close
- selectableOptions.Closed += (s, e) =>
- {
- localUnregisterEvents?.Invoke(null, null);
- };
- }
+ field = new ComPortField();
break;
case SliceSettingData.DataEditTypes.LIST:
- {
- var selectableOptions = new DropDownList("None".Localize(), maxHeight: 200)
- {
- ToolTipText = settingData.HelpText,
- Margin = new BorderDouble()
- };
-
- foreach (string listItem in settingData.ExtraSettings.Split(','))
- {
- MenuItem newItem = selectableOptions.AddItem(listItem);
- if (newItem.Text == sliceSettingValue)
- {
- selectableOptions.SelectedLabel = sliceSettingValue;
- }
-
- newItem.Selected += (sender, e) =>
- {
- MenuItem menuItem = ((MenuItem)sender);
- settingsContext.SetValue(settingData.SlicerConfigName, menuItem.Text);
-
- settingsRow.UpdateStyle();
- };
- }
-
- dataArea.AddChild(selectableOptions);
-
- settingsRow.ValueChanged = (text) =>
- {
- selectableOptions.SelectedLabel = text;
- };
- }
+ field = new ListField();
break;
case SliceSettingData.DataEditTypes.HARDWARE_PRESENT:
- {
- var checkBoxWidget = new CheckBox("")
- {
- Name = settingData.PresentationName + " Checkbox",
- ToolTipText = settingData.HelpText,
- VAnchor = VAnchor.Bottom,
- TextColor = ActiveTheme.Instance.PrimaryTextColor,
- Checked = sliceSettingValue == "1"
- };
-
- checkBoxWidget.Click += (sender, e) =>
- {
- bool isChecked = ((CheckBox)sender).Checked;
- settingsContext.SetValue(settingData.SlicerConfigName, isChecked ? "1" : "0");
-
- settingsRow.UpdateStyle();
- };
-
- dataArea.AddChild(checkBoxWidget);
-
- settingsRow.ValueChanged = (text) =>
- {
- checkBoxWidget.Checked = text == "1";
- };
- }
+ field = new HardwarePresetField();
break;
case SliceSettingData.DataEditTypes.VECTOR2:
- {
- string[] xyValueStrings = sliceSettingValue.Split(',');
- if (xyValueStrings.Length != 2)
- {
- xyValueStrings = new string[] { "0", "0" };
- }
-
- double currentXValue;
- double.TryParse(xyValueStrings[0], out currentXValue);
-
- var xEditWidget = new MHNumberEdit(currentXValue, allowDecimals: true, pixelWidth: vectorXYEditWidth, tabIndex: tabIndexForItem++)
- {
- ToolTipText = settingData.HelpText,
- SelectAllOnFocus = true
- };
-
- double currentYValue;
- double.TryParse(xyValueStrings[1], out currentYValue);
-
- var yEditWidget = new MHNumberEdit(currentYValue, allowDecimals: true, pixelWidth: vectorXYEditWidth, tabIndex: tabIndexForItem++)
- {
- ToolTipText = settingData.HelpText,
- SelectAllOnFocus = true,
- Margin = new BorderDouble(20, 0, 0, 0),
- };
-
- xEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
- {
- settingsContext.SetValue(settingData.SlicerConfigName, xEditWidget.ActuallNumberEdit.Value.ToString() + "," + yEditWidget.ActuallNumberEdit.Value.ToString());
-
- settingsRow.UpdateStyle();
- };
- dataArea.AddChild(xEditWidget);
- dataArea.AddChild(new TextWidget("X", pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor)
- {
- VAnchor = VAnchor.Center,
- Margin = new BorderDouble(5, 0),
- });
-
- yEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
- {
- settingsContext.SetValue(settingData.SlicerConfigName, xEditWidget.ActuallNumberEdit.Value.ToString() + "," + yEditWidget.ActuallNumberEdit.Value.ToString());
-
- settingsRow.UpdateStyle();
- };
- dataArea.AddChild(yEditWidget);
- var yLabel = new GuiWidget()
- {
- VAnchor = VAnchor.Fit | VAnchor.Center,
- Padding = new BorderDouble(5, 0),
- HAnchor = HAnchor.Stretch,
- };
- yLabel.AddChild(new WrappedTextWidget("Y", pointSize: 9, textColor: ActiveTheme.Instance.PrimaryTextColor));
- unitsArea.AddChild(yLabel);
-
- settingsRow.ValueChanged = (text) =>
- {
- double currentValue2;
- string[] xyValueStrings2 = text.Split(',');
- if (xyValueStrings2.Length != 2)
- {
- xyValueStrings2 = new string[] { "0", "0" };
- }
-
- double.TryParse(xyValueStrings2[0], out currentValue2);
- xEditWidget.ActuallNumberEdit.Value = currentValue2;
-
- double.TryParse(xyValueStrings2[1], out currentValue2);
- yEditWidget.ActuallNumberEdit.Value = currentValue2;
- };
-
- }
+ field = new Vector2Field();
break;
case SliceSettingData.DataEditTypes.OFFSET2:
+ field = new Offset2Field();
+ if (field is Offset2Field offset2)
{
- Vector2 offset = ActiveSliceSettings.Instance.Helpers.ExtruderOffset(extruderIndex);
-
- var xEditWidget = new MHNumberEdit(offset.x, allowDecimals: true, allowNegatives: true, pixelWidth: vectorXYEditWidth, tabIndex: tabIndexForItem++)
- {
- ToolTipText = settingData.HelpText,
- SelectAllOnFocus = true,
- };
-
- var yEditWidget = new MHNumberEdit(offset.y, allowDecimals: true, allowNegatives: true, pixelWidth: vectorXYEditWidth, tabIndex: tabIndexForItem++)
- {
- ToolTipText = settingData.HelpText,
- SelectAllOnFocus = true,
- Margin = new BorderDouble(20, 0, 0, 0),
- };
-
- xEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
- {
- int extruderIndexLocal = extruderIndex;
- SaveCommaSeparatedIndexSetting(extruderIndexLocal, settingsContext, settingData.SlicerConfigName, xEditWidget.ActuallNumberEdit.Value.ToString() + "x" + yEditWidget.ActuallNumberEdit.Value.ToString());
-
- settingsRow.UpdateStyle();
- };
- dataArea.AddChild(xEditWidget);
- dataArea.AddChild(new TextWidget("X", pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor)
- {
- VAnchor = VAnchor.Center,
- Margin = new BorderDouble(5, 0),
- });
-
- yEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
- {
- int extruderIndexLocal = extruderIndex;
- SaveCommaSeparatedIndexSetting(extruderIndexLocal, settingsContext, settingData.SlicerConfigName, xEditWidget.ActuallNumberEdit.Value.ToString() + "x" + yEditWidget.ActuallNumberEdit.Value.ToString());
-
- settingsRow.UpdateStyle();
- };
- dataArea.AddChild(yEditWidget);
- var yLabel = new GuiWidget()
- {
- Padding = new BorderDouble(5, 0),
- HAnchor = HAnchor.Stretch,
- VAnchor = VAnchor.Fit | VAnchor.Center,
- };
- yLabel.AddChild(new WrappedTextWidget("Y", pointSize: 9, textColor: ActiveTheme.Instance.PrimaryTextColor));
- unitsArea.AddChild(yLabel);
-
- settingsRow.ValueChanged = (text) =>
- {
- Vector2 offset2 = ActiveSliceSettings.Instance.Helpers.ExtruderOffset(extruderIndex);
- xEditWidget.ActuallNumberEdit.Value = offset2.x;
- yEditWidget.ActuallNumberEdit.Value = offset2.y;
- };
+ offset2.ExtruderIndex = extruderIndex;
}
break;
@@ -1499,7 +878,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
{
// Revert the user override
settingsContext.ClearValue(settingData.SlicerConfigName);
- settingsRow.RefreshValue(settingsContext);
};
restoreArea.AddChild(restoreButton);
@@ -1583,6 +961,22 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
}
};
+ if (field != null)
+ {
+ allFields.Add(settingData.SlicerConfigName, field);
+
+ field.Value = sliceSettingValue;
+
+ this.PrepareRow(
+ field,
+ field.Create(settingsContext, settingData, tabIndexForItem++),
+ dataArea,
+ unitsArea,
+ settingData);
+
+ field.UpdateStyle = settingsRow.UpdateStyle;
+ }
+
// Invoke the UpdateStyle implementation
settingsRow.UpdateStyle();
@@ -1612,24 +1006,14 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
return settingsRow;
}
- private static void AddComMenuItems(SliceSettingData settingData, SettingsContext settingsContext, SettingsRow settingsRow, DropDownList selectableOptions)
+ private void PrepareRow(ISettingsField field, GuiWidget content, GuiWidget dataArea, GuiWidget unitsArea, SliceSettingData settingData)
{
- selectableOptions.MenuItems.Clear();
- string machineSpecificComPortValue = ActiveSliceSettings.Instance.Helpers.ComPort();
- foreach (string listItem in FrostedSerialPort.GetPortNames())
- {
- MenuItem newItem = selectableOptions.AddItem(listItem);
- if (newItem.Text == machineSpecificComPortValue)
- {
- selectableOptions.SelectedLabel = machineSpecificComPortValue;
- }
+ dataArea.AddChild(content);
- newItem.Selected += (sender, e) =>
- {
- MenuItem menuItem = ((MenuItem)sender);
- settingsContext.SetComPort(menuItem.Text);
- settingsRow.UpdateStyle();
- };
+ var extraInfo = GetExtraSettingsWidget(settingData);
+ if (extraInfo != null)
+ {
+ unitsArea.AddChild(extraInfo);
}
}
@@ -1697,7 +1081,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
return totalContent;
}
- private static void SaveCommaSeparatedIndexSetting(int extruderIndexLocal, SettingsContext settingsContext, string slicerConfigName, string newSingleValue)
+ public static void SaveCommaSeparatedIndexSetting(int extruderIndexLocal, SettingsContext settingsContext, string slicerConfigName, string newSingleValue)
{
string[] settings = settingsContext.GetValue(slicerConfigName).Split(',');
if (settings.Length > extruderIndexLocal)
@@ -1726,11 +1110,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
string newValue = string.Join(",", settings);
settingsContext.SetValue(slicerConfigName, newValue);
}
-
- public override void OnDraw(Graphics2D graphics2D)
- {
- base.OnDraw(graphics2D);
- }
}
internal class SliceSettingListControl : ScrollableWidget
diff --git a/SlicerConfiguration/UIFields/CheckboxField.cs b/SlicerConfiguration/UIFields/CheckboxField.cs
new file mode 100644
index 000000000..c5311b656
--- /dev/null
+++ b/SlicerConfiguration/UIFields/CheckboxField.cs
@@ -0,0 +1,83 @@
+/*
+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 System;
+using MatterHackers.Agg.UI;
+
+namespace MatterHackers.MatterControl.SlicerConfiguration
+{
+ public class CheckboxField : ISettingsField
+ {
+ private CheckBox checkBoxWidget;
+
+ public Action UpdateStyle { get; set; }
+
+ public string Value { get; set; }
+
+ public GuiWidget Create(SettingsContext settingsContext, SliceSettingData settingData, int tabIndex)
+ {
+ checkBoxWidget = new CheckBox("")
+ {
+ Name = settingData.PresentationName + " Checkbox",
+ ToolTipText = settingData.HelpText,
+ VAnchor = VAnchor.Bottom,
+ TextColor = ActiveTheme.Instance.PrimaryTextColor,
+ Checked = this.Value == "1"
+ };
+ checkBoxWidget.Click += (sender, e) =>
+ {
+ // SetValue should only be called when the checkbox is clicked. If this code makes its way into checkstatechanged
+ // we end up adding a key back into the dictionary after we call .ClearValue, resulting in the blue override bar reappearing after
+ // clearing a user override with the red x
+ settingsContext.SetValue(settingData.SlicerConfigName, checkBoxWidget.Checked ? "1" : "0");
+ };
+ checkBoxWidget.CheckedStateChanged += (s, e) =>
+ {
+ // Linked settings should be updated in all cases (user clicked checkbox, user clicked clear)
+ foreach (var setSettingsData in settingData.SetSettingsOnChange)
+ {
+ string targetValue;
+ if (setSettingsData.TryGetValue(checkBoxWidget.Checked ? "OnValue" : "OffValue", out targetValue))
+ {
+ settingsContext.SetValue(setSettingsData["TargetSetting"], targetValue);
+ }
+ }
+
+ this.UpdateStyle();
+ };
+
+ return checkBoxWidget;
+ }
+
+ public void OnValueChanged(string text)
+ {
+ checkBoxWidget.Checked = text == "1";
+ }
+ }
+}
diff --git a/SlicerConfiguration/UIFields/ComPortField.cs b/SlicerConfiguration/UIFields/ComPortField.cs
new file mode 100644
index 000000000..0533c0c4d
--- /dev/null
+++ b/SlicerConfiguration/UIFields/ComPortField.cs
@@ -0,0 +1,120 @@
+/*
+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 System;
+using MatterHackers.Agg;
+using MatterHackers.Agg.UI;
+using MatterHackers.Localizations;
+using MatterHackers.MatterControl.PrinterCommunication;
+using MatterHackers.SerialPortCommunication.FrostedSerial;
+
+namespace MatterHackers.MatterControl.SlicerConfiguration
+{
+ public class ComPortField : ISettingsField
+ {
+ private DropDownList selectableOptions;
+
+ public Action UpdateStyle { get; set; }
+
+ public string Value { get; set; }
+
+ public GuiWidget Create(SettingsContext settingsContext, SliceSettingData settingData, int tabIndex)
+ {
+ EventHandler unregisterEvents = null;
+
+ bool canChangeComPort = !PrinterConnection.Instance.PrinterIsConnected && PrinterConnection.Instance.CommunicationState != CommunicationStates.AttemptingToConnect;
+ // The COM_PORT control is unique in its approach to the SlicerConfigName. It uses "com_port" settings name to
+ // bind to a context that will place it in the SliceSetting view but it binds its values to a machine
+ // specific dictionary key that is not exposed in the UI. At runtime we lookup and store to '_com_port'
+ // ensuring that a single printer can be shared across different devices and we'll select the correct com port in each case
+ selectableOptions = new DropDownList("None".Localize(), maxHeight: 200)
+ {
+ ToolTipText = settingData.HelpText,
+ Margin = new BorderDouble(),
+ Name = "Serial Port Dropdown",
+ // Prevent droplist interaction when connected
+ Enabled = canChangeComPort,
+ TextColor = canChangeComPort ? ActiveTheme.Instance.PrimaryTextColor : new RGBA_Bytes(ActiveTheme.Instance.PrimaryTextColor, 150),
+ BorderColor = canChangeComPort ? ActiveTheme.Instance.SecondaryTextColor : new RGBA_Bytes(ActiveTheme.Instance.SecondaryTextColor, 150),
+ };
+
+ selectableOptions.Click += (s, e) =>
+ {
+ AddComMenuItems(settingData, settingsContext, selectableOptions);
+ };
+
+ AddComMenuItems(settingData, settingsContext, selectableOptions);
+
+ // Prevent droplist interaction when connected
+ PrinterConnection.Instance.CommunicationStateChanged.RegisterEvent((s, e) =>
+ {
+ canChangeComPort = !PrinterConnection.Instance.PrinterIsConnected && PrinterConnection.Instance.CommunicationState != CommunicationStates.AttemptingToConnect;
+ selectableOptions.Enabled = canChangeComPort;
+ selectableOptions.TextColor = canChangeComPort ? ActiveTheme.Instance.PrimaryTextColor : new RGBA_Bytes(ActiveTheme.Instance.PrimaryTextColor, 150);
+ selectableOptions.BorderColor = canChangeComPort ? ActiveTheme.Instance.SecondaryTextColor : new RGBA_Bytes(ActiveTheme.Instance.SecondaryTextColor, 150);
+ }, ref unregisterEvents);
+
+ // Release event listener on close
+ selectableOptions.Closed += (s, e) =>
+ {
+ unregisterEvents?.Invoke(null, null);
+ };
+
+ return selectableOptions;
+ }
+
+ public void OnValueChanged(string text)
+ {
+ // Lookup the machine specific comport value rather than the passed in text value
+ selectableOptions.SelectedLabel = ActiveSliceSettings.Instance.Helpers.ComPort();
+ }
+
+ private void AddComMenuItems(SliceSettingData settingData, SettingsContext settingsContext, DropDownList selectableOptions)
+ {
+ selectableOptions.MenuItems.Clear();
+ string machineSpecificComPortValue = ActiveSliceSettings.Instance.Helpers.ComPort();
+ foreach (string listItem in FrostedSerialPort.GetPortNames())
+ {
+ MenuItem newItem = selectableOptions.AddItem(listItem);
+ if (newItem.Text == machineSpecificComPortValue)
+ {
+ selectableOptions.SelectedLabel = machineSpecificComPortValue;
+ }
+
+ newItem.Selected += (sender, e) =>
+ {
+ MenuItem menuItem = ((MenuItem)sender);
+ settingsContext.SetComPort(menuItem.Text);
+ this.UpdateStyle();
+ };
+ }
+ }
+
+ }
+}
diff --git a/SlicerConfiguration/UIFields/DoubleField.cs b/SlicerConfiguration/UIFields/DoubleField.cs
new file mode 100644
index 000000000..fc649c64e
--- /dev/null
+++ b/SlicerConfiguration/UIFields/DoubleField.cs
@@ -0,0 +1,69 @@
+/*
+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 System;
+using MatterHackers.Agg.UI;
+
+namespace MatterHackers.MatterControl.SlicerConfiguration
+{
+ public class DoubleField : ISettingsField
+ {
+ public static int DoubleEditWidth = (int)(60 * GuiWidget.DeviceScale + .5);
+
+ public Action UpdateStyle { get; set; }
+
+ public string Value { get; set; }
+
+ private MHNumberEdit doubleEditWidget;
+
+ public GuiWidget Create(SettingsContext settingsContext, SliceSettingData settingData, int tabIndex)
+ {
+ double.TryParse(this.Value, out double currentValue);
+
+ doubleEditWidget = new MHNumberEdit(currentValue, allowNegatives: true, allowDecimals: true, pixelWidth: DoubleEditWidth, tabIndex: tabIndex)
+ {
+ ToolTipText = settingData.HelpText,
+ SelectAllOnFocus = true
+ };
+ doubleEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
+ {
+ settingsContext.SetValue(settingData.SlicerConfigName, ((NumberEdit)sender).Value.ToString());
+ this.UpdateStyle();
+ };
+
+ return doubleEditWidget;
+ }
+
+ public void OnValueChanged(string text)
+ {
+ double.TryParse(text, out double currentValue);
+ doubleEditWidget.ActuallNumberEdit.Value = currentValue;
+ }
+ }
+}
diff --git a/SlicerConfiguration/UIFields/DoubleOrPercentField.cs b/SlicerConfiguration/UIFields/DoubleOrPercentField.cs
new file mode 100644
index 000000000..615692c9c
--- /dev/null
+++ b/SlicerConfiguration/UIFields/DoubleOrPercentField.cs
@@ -0,0 +1,99 @@
+/*
+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 System;
+using MatterHackers.Agg.UI;
+
+namespace MatterHackers.MatterControl.SlicerConfiguration
+{
+ public class DoubleOrPercentField : ISettingsField
+ {
+ public Action UpdateStyle { get; set; }
+
+ private MHTextEditWidget editWidget;
+
+ public string Value { get; set; }
+
+ public GuiWidget Create(SettingsContext settingsContext, SliceSettingData settingData, int tabIndex)
+ {
+ editWidget = new MHTextEditWidget(this.Value, pixelWidth: DoubleField.DoubleEditWidth - 2, tabIndex: tabIndex)
+ {
+ ToolTipText = settingData.HelpText,
+ SelectAllOnFocus = true
+ };
+ editWidget.ActualTextEditWidget.EditComplete += (sender, e) =>
+ {
+ var textEditWidget = (TextEditWidget)sender;
+ string text = textEditWidget.Text.Trim();
+
+ bool isPercent = text.Contains("%");
+ if (isPercent)
+ {
+ text = text.Substring(0, text.IndexOf("%"));
+ }
+ double result;
+ double.TryParse(text, out result);
+ text = result.ToString();
+ if (isPercent)
+ {
+ text += "%";
+ }
+ textEditWidget.Text = text;
+ settingsContext.SetValue(settingData.SlicerConfigName, textEditWidget.Text);
+
+ this.UpdateStyle();
+ };
+
+ editWidget.ActualTextEditWidget.InternalTextEditWidget.AllSelected += (sender, e) =>
+ {
+ // select everything up to the % (if present)
+ InternalTextEditWidget textEditWidget = (InternalTextEditWidget)sender;
+ int percentIndex = textEditWidget.Text.IndexOf("%");
+ if (percentIndex != -1)
+ {
+ textEditWidget.SetSelection(0, percentIndex - 1);
+ }
+ };
+
+ if (settingData.QuickMenuSettings.Count > 0)
+ {
+ return SliceSettingsWidget.CreateQuickMenu(settingData, settingsContext, editWidget, editWidget.ActualTextEditWidget.InternalTextEditWidget);
+ }
+ else
+ {
+ return editWidget;
+ }
+ }
+
+ public void OnValueChanged(string text)
+ {
+ editWidget.Text = text;
+ }
+ }
+}
diff --git a/SlicerConfiguration/UIFields/HardwarePresetField.cs b/SlicerConfiguration/UIFields/HardwarePresetField.cs
new file mode 100644
index 000000000..29350333a
--- /dev/null
+++ b/SlicerConfiguration/UIFields/HardwarePresetField.cs
@@ -0,0 +1,70 @@
+/*
+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 System;
+using MatterHackers.Agg.UI;
+
+namespace MatterHackers.MatterControl.SlicerConfiguration
+{
+ public class HardwarePresetField : ISettingsField
+ {
+ private CheckBox checkBoxWidget;
+
+ public Action UpdateStyle { get; set; }
+
+ public string Value { get; set; }
+
+ public GuiWidget Create(SettingsContext settingsContext, SliceSettingData settingData, int tabIndex)
+ {
+ checkBoxWidget = new CheckBox("")
+ {
+ Name = settingData.PresentationName + " Checkbox",
+ ToolTipText = settingData.HelpText,
+ VAnchor = VAnchor.Bottom,
+ TextColor = ActiveTheme.Instance.PrimaryTextColor,
+ Checked = this.Value == "1"
+ };
+
+ checkBoxWidget.Click += (sender, e) =>
+ {
+ bool isChecked = ((CheckBox)sender).Checked;
+ settingsContext.SetValue(settingData.SlicerConfigName, isChecked ? "1" : "0");
+
+ this.UpdateStyle();
+ };
+
+ return checkBoxWidget;
+ }
+
+ public void OnValueChanged(string text)
+ {
+ checkBoxWidget.Checked = text == "1";
+ }
+ }
+}
diff --git a/SlicerConfiguration/UIFields/ISettingsField.cs b/SlicerConfiguration/UIFields/ISettingsField.cs
new file mode 100644
index 000000000..cb041177e
--- /dev/null
+++ b/SlicerConfiguration/UIFields/ISettingsField.cs
@@ -0,0 +1,45 @@
+/*
+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 System;
+using MatterHackers.Agg.UI;
+
+namespace MatterHackers.MatterControl.SlicerConfiguration
+{
+ public interface ISettingsField
+ {
+ void OnValueChanged(string text);
+
+ Action UpdateStyle { get; set; }
+
+ string Value { get; set; }
+
+ GuiWidget Create(SettingsContext settingsContext, SliceSettingData settingData, int tabIndex);
+ }
+}
diff --git a/SlicerConfiguration/UIFields/IntField.cs b/SlicerConfiguration/UIFields/IntField.cs
new file mode 100644
index 000000000..c90c5a73d
--- /dev/null
+++ b/SlicerConfiguration/UIFields/IntField.cs
@@ -0,0 +1,76 @@
+/*
+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 System;
+using MatterHackers.Agg.UI;
+
+namespace MatterHackers.MatterControl.SlicerConfiguration
+{
+ public class IntField : ISettingsField
+ {
+ private readonly int intEditWidth = (int)(60 * GuiWidget.DeviceScale + .5);
+
+ public Action UpdateStyle { get; set; }
+
+ public string Value { get; set; }
+
+ private MHNumberEdit intEditWidget;
+
+ public GuiWidget Create(SettingsContext settingsContext, SliceSettingData settingData, int tabIndex)
+ {
+ int.TryParse(this.Value, out int currentValue);
+
+ intEditWidget = new MHNumberEdit(currentValue, pixelWidth: intEditWidth, tabIndex: tabIndex)
+ {
+ ToolTipText = settingData.HelpText,
+ SelectAllOnFocus = true,
+ Name = settingData.PresentationName + " Edit",
+ };
+ intEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
+ {
+ settingsContext.SetValue(settingData.SlicerConfigName, ((NumberEdit)sender).Value.ToString());
+ this.UpdateStyle();
+ };
+
+ if (settingData.QuickMenuSettings.Count > 0)
+ {
+ return SliceSettingsWidget.CreateQuickMenu(settingData, settingsContext, intEditWidget, intEditWidget.ActuallNumberEdit.InternalTextEditWidget);
+ }
+ else
+ {
+ return intEditWidget;
+ }
+ }
+
+ public void OnValueChanged(string text)
+ {
+ intEditWidget.Text = text;
+ }
+ }
+}
diff --git a/SlicerConfiguration/UIFields/IntOrMmField.cs b/SlicerConfiguration/UIFields/IntOrMmField.cs
new file mode 100644
index 000000000..ea10e4739
--- /dev/null
+++ b/SlicerConfiguration/UIFields/IntOrMmField.cs
@@ -0,0 +1,125 @@
+/*
+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 System;
+using MatterHackers.Agg.UI;
+
+namespace MatterHackers.MatterControl.SlicerConfiguration
+{
+ public class IntOrMmField : ISettingsField
+ {
+ private MHTextEditWidget editWidget;
+
+ public Action UpdateStyle { get; set; }
+
+ public string Value { get; set; }
+
+ public GuiWidget Create(SettingsContext settingsContext, SliceSettingData settingData, int tabIndex)
+ {
+ editWidget = new MHTextEditWidget(this.Value, pixelWidth: DoubleField.DoubleEditWidth - 2, tabIndex: tabIndex)
+ {
+ ToolTipText = settingData.HelpText,
+ SelectAllOnFocus = true
+ };
+
+ string startingText = editWidget.Text;
+ editWidget.ActualTextEditWidget.EditComplete += (sender, e) =>
+ {
+ TextEditWidget textEditWidget = (TextEditWidget)sender;
+ // only validate when we lose focus
+ if (!textEditWidget.ContainsFocus)
+ {
+ string text = textEditWidget.Text;
+ text = text.Trim();
+ bool isMm = text.Contains("mm");
+ if (isMm)
+ {
+ text = text.Substring(0, text.IndexOf("mm"));
+ }
+ double result;
+ double.TryParse(text, out result);
+ text = result.ToString();
+ if (isMm)
+ {
+ text += "mm";
+ }
+ else
+ {
+ result = (int)result;
+ text = result.ToString();
+ }
+ textEditWidget.Text = text;
+ startingText = editWidget.Text;
+ }
+
+ settingsContext.SetValue(settingData.SlicerConfigName, textEditWidget.Text);
+ this.UpdateStyle();
+
+ // make sure we are still looking for the final validation before saving.
+ if (textEditWidget.ContainsFocus)
+ {
+ UiThread.RunOnIdle(() =>
+ {
+ string currentText = textEditWidget.Text;
+ int cursorIndex = textEditWidget.InternalTextEditWidget.CharIndexToInsertBefore;
+ textEditWidget.Text = startingText;
+ textEditWidget.InternalTextEditWidget.MarkAsStartingState();
+ textEditWidget.Text = currentText;
+ textEditWidget.InternalTextEditWidget.CharIndexToInsertBefore = cursorIndex;
+ });
+ }
+ };
+
+ editWidget.ActualTextEditWidget.InternalTextEditWidget.AllSelected += (sender, e) =>
+ {
+ // select everything up to the mm (if present)
+ InternalTextEditWidget textEditWidget = (InternalTextEditWidget)sender;
+ int mMIndex = textEditWidget.Text.IndexOf("mm");
+ if (mMIndex != -1)
+ {
+ textEditWidget.SetSelection(0, mMIndex - 1);
+ }
+ };
+
+ if (settingData.QuickMenuSettings.Count > 0)
+ {
+ return SliceSettingsWidget.CreateQuickMenu(settingData, settingsContext, editWidget, editWidget.ActualTextEditWidget.InternalTextEditWidget);
+ }
+ else
+ {
+ return editWidget;
+ }
+ }
+
+ public void OnValueChanged(string text)
+ {
+ editWidget.Text = text;
+ }
+ }
+}
diff --git a/SlicerConfiguration/UIFields/ListField.cs b/SlicerConfiguration/UIFields/ListField.cs
new file mode 100644
index 000000000..906eb2df1
--- /dev/null
+++ b/SlicerConfiguration/UIFields/ListField.cs
@@ -0,0 +1,78 @@
+/*
+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 System;
+using MatterHackers.Agg;
+using MatterHackers.Agg.UI;
+using MatterHackers.Localizations;
+
+namespace MatterHackers.MatterControl.SlicerConfiguration
+{
+ public class ListField : ISettingsField
+ {
+ private DropDownList selectableOptions;
+
+ public Action UpdateStyle { get; set; }
+
+ public string Value { get; set; }
+
+ public GuiWidget Create(SettingsContext settingsContext, SliceSettingData settingData, int tabIndex)
+ {
+ selectableOptions = new DropDownList("None".Localize(), maxHeight: 200)
+ {
+ ToolTipText = settingData.HelpText,
+ Margin = new BorderDouble()
+ };
+
+ foreach (string listItem in settingData.ExtraSettings.Split(','))
+ {
+ MenuItem newItem = selectableOptions.AddItem(listItem);
+ if (newItem.Text == this.Value)
+ {
+ selectableOptions.SelectedLabel = this.Value;
+ }
+
+ newItem.Selected += (sender, e) =>
+ {
+ MenuItem menuItem = ((MenuItem)sender);
+ settingsContext.SetValue(settingData.SlicerConfigName, menuItem.Text);
+
+ this.UpdateStyle();
+ };
+ }
+
+ return selectableOptions;
+ }
+
+ public void OnValueChanged(string text)
+ {
+ selectableOptions.SelectedLabel = text;
+ }
+ }
+}
diff --git a/SlicerConfiguration/UIFields/MultilineStringField.cs b/SlicerConfiguration/UIFields/MultilineStringField.cs
new file mode 100644
index 000000000..b8bde064a
--- /dev/null
+++ b/SlicerConfiguration/UIFields/MultilineStringField.cs
@@ -0,0 +1,68 @@
+/*
+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 System;
+using MatterHackers.Agg.UI;
+
+namespace MatterHackers.MatterControl.SlicerConfiguration
+{
+ public class MultilineStringField : ISettingsField
+ {
+ private readonly int multiLineEditHeight = (int)(120 * GuiWidget.DeviceScale + .5);
+
+ private MHTextEditWidget editWidget;
+
+ public Action UpdateStyle { get; set; }
+
+ public string Value { get; set; }
+
+ public GuiWidget Create(SettingsContext settingsContext, SliceSettingData settingData, int tabIndex)
+ {
+ string convertedNewLines = this.Value.Replace("\\n", "\n");
+
+ editWidget = new MHTextEditWidget(convertedNewLines, pixelWidth: 320, pixelHeight: multiLineEditHeight, multiLine: true, tabIndex: tabIndex, typeFace: ApplicationController.MonoSpacedTypeFace)
+ {
+ HAnchor = HAnchor.Stretch,
+ };
+ editWidget.DrawFromHintedCache();
+ editWidget.ActualTextEditWidget.EditComplete += (sender, e) =>
+ {
+ settingsContext.SetValue(settingData.SlicerConfigName, ((TextEditWidget)sender).Text.Replace("\n", "\\n"));
+ this.UpdateStyle();
+ };
+
+ return editWidget;
+ }
+
+ public void OnValueChanged(string text)
+ {
+ editWidget.Text = text.Replace("\\n", "\n");
+ }
+ }
+}
diff --git a/SlicerConfiguration/UIFields/Offset2Field.cs b/SlicerConfiguration/UIFields/Offset2Field.cs
new file mode 100644
index 000000000..435be068e
--- /dev/null
+++ b/SlicerConfiguration/UIFields/Offset2Field.cs
@@ -0,0 +1,100 @@
+/*
+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 System;
+using MatterHackers.Agg;
+using MatterHackers.Agg.UI;
+using MatterHackers.VectorMath;
+
+namespace MatterHackers.MatterControl.SlicerConfiguration
+{
+ public class Offset2Field : ISettingsField
+ {
+ private MHNumberEdit xEditWidget;
+ private MHNumberEdit yEditWidget;
+
+ public Action UpdateStyle { get; set; }
+
+ public string Value { get; set; }
+
+ public int ExtruderIndex { get; set; } = 0;
+
+ public GuiWidget Create(SettingsContext settingsContext, SliceSettingData settingData, int tabIndex)
+ {
+ var container = new FlowLayoutWidget();
+
+ Vector2 offset = ActiveSliceSettings.Instance.Helpers.ExtruderOffset(0);
+
+ xEditWidget = new MHNumberEdit(offset.x, allowDecimals: true, allowNegatives: true, pixelWidth: Vector2Field.VectorXYEditWidth, tabIndex: tabIndex)
+ {
+ ToolTipText = settingData.HelpText,
+ SelectAllOnFocus = true,
+ };
+ xEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
+ {
+ SliceSettingsWidget.SaveCommaSeparatedIndexSetting(this.ExtruderIndex, settingsContext, settingData.SlicerConfigName, xEditWidget.ActuallNumberEdit.Value.ToString() + "x" + yEditWidget.ActuallNumberEdit.Value.ToString());
+ this.UpdateStyle();
+ };
+
+ container.AddChild(new TextWidget("X:", pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor)
+ {
+ VAnchor = VAnchor.Center,
+ Margin = new BorderDouble(5, 0),
+ });
+ container.AddChild(xEditWidget);
+
+ yEditWidget = new MHNumberEdit(offset.y, allowDecimals: true, allowNegatives: true, pixelWidth: Vector2Field.VectorXYEditWidth, tabIndex: tabIndex)
+ {
+ ToolTipText = settingData.HelpText,
+ SelectAllOnFocus = true
+ };
+ yEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
+ {
+ SliceSettingsWidget.SaveCommaSeparatedIndexSetting(this.ExtruderIndex, settingsContext, settingData.SlicerConfigName, xEditWidget.ActuallNumberEdit.Value.ToString() + "x" + yEditWidget.ActuallNumberEdit.Value.ToString());
+ this.UpdateStyle();
+ };
+
+ container.AddChild(new TextWidget("Y:", pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor)
+ {
+ VAnchor = VAnchor.Center,
+ Margin = new BorderDouble(15, 0, 5, 0),
+ });
+ container.AddChild(yEditWidget);
+
+ return container;
+ }
+
+ public void OnValueChanged(string text)
+ {
+ Vector2 offset2 = ActiveSliceSettings.Instance.Helpers.ExtruderOffset(this.ExtruderIndex);
+ xEditWidget.ActuallNumberEdit.Value = offset2.x;
+ yEditWidget.ActuallNumberEdit.Value = offset2.y;
+ }
+ }
+}
diff --git a/SlicerConfiguration/UIFields/OffsetField.cs b/SlicerConfiguration/UIFields/OffsetField.cs
new file mode 100644
index 000000000..95ed204a1
--- /dev/null
+++ b/SlicerConfiguration/UIFields/OffsetField.cs
@@ -0,0 +1,68 @@
+/*
+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 System;
+using MatterHackers.Agg.UI;
+
+namespace MatterHackers.MatterControl.SlicerConfiguration
+{
+ public class OffsetField : ISettingsField
+ {
+ private MHNumberEdit editWidget;
+
+ public Action UpdateStyle { get; set; }
+
+ public string Value { get; set; }
+
+ public GuiWidget Create(SettingsContext settingsContext, SliceSettingData settingData, int tabIndex)
+ {
+ double.TryParse(this.Value, out double currentValue);
+
+ editWidget = new MHNumberEdit(currentValue, allowDecimals: true, allowNegatives: true, pixelWidth: DoubleField.DoubleEditWidth, tabIndex: tabIndex)
+ {
+ ToolTipText = settingData.HelpText,
+ SelectAllOnFocus = true
+
+ };
+ editWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
+ {
+ settingsContext.SetValue(settingData.SlicerConfigName, ((NumberEdit)sender).Value.ToString());
+ this.UpdateStyle();
+ };
+
+ return editWidget;
+ }
+
+ public void OnValueChanged(string text)
+ {
+ double.TryParse(text, out double currentValue);
+ editWidget.ActuallNumberEdit.Value = currentValue;
+ }
+ }
+}
diff --git a/SlicerConfiguration/UIFields/PositiveDoubleField.cs b/SlicerConfiguration/UIFields/PositiveDoubleField.cs
new file mode 100644
index 000000000..7394eb192
--- /dev/null
+++ b/SlicerConfiguration/UIFields/PositiveDoubleField.cs
@@ -0,0 +1,120 @@
+/*
+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 System;
+using MatterHackers.Agg.UI;
+
+namespace MatterHackers.MatterControl.SlicerConfiguration
+{
+ public class PositiveDoubleField : ISettingsField
+ {
+ private MHNumberEdit doubleEditWidget;
+
+ public Action UpdateStyle { get; set; }
+
+ public string Value { get; set; }
+
+ public GuiWidget Create(SettingsContext settingsContext, SliceSettingData settingData, int tabIndex)
+ {
+ const string multiValuesAreDiffernt = "-";
+
+ doubleEditWidget = new MHNumberEdit(0, allowDecimals: true, pixelWidth: DoubleField.DoubleEditWidth, tabIndex: tabIndex)
+ {
+ ToolTipText = settingData.HelpText,
+ Name = settingData.PresentationName + " Textbox",
+ SelectAllOnFocus = true
+ };
+
+ double currentValue;
+ bool ChangesMultipleOtherSettings = settingData.SetSettingsOnChange.Count > 0;
+ if (ChangesMultipleOtherSettings)
+ {
+ bool allTheSame = true;
+ string setting = settingsContext.GetValue(settingData.SetSettingsOnChange[0]["TargetSetting"]);
+ for (int i = 1; i < settingData.SetSettingsOnChange.Count; i++)
+ {
+ string nextSetting = settingsContext.GetValue(settingData.SetSettingsOnChange[i]["TargetSetting"]);
+ if (setting != nextSetting)
+ {
+ allTheSame = false;
+ break;
+ }
+ }
+
+ if (allTheSame && setting.EndsWith("mm"))
+ {
+ double.TryParse(setting.Substring(0, setting.Length - 2), out currentValue);
+ doubleEditWidget.ActuallNumberEdit.Value = currentValue;
+ }
+ else
+ {
+ doubleEditWidget.ActuallNumberEdit.InternalNumberEdit.Text = multiValuesAreDiffernt;
+ }
+ }
+ else // just set the setting normally
+ {
+ double.TryParse(this.Value, out currentValue);
+ doubleEditWidget.ActuallNumberEdit.Value = currentValue;
+ }
+ doubleEditWidget.ActuallNumberEdit.InternalTextEditWidget.MarkAsStartingState();
+
+ doubleEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
+ {
+ NumberEdit numberEdit = (NumberEdit)sender;
+ // If this setting sets other settings, then do that.
+ if (ChangesMultipleOtherSettings
+ && numberEdit.Text != multiValuesAreDiffernt)
+ {
+ {
+ settingsContext.SetValue(settingData.SetSettingsOnChange[0]["TargetSetting"], numberEdit.Value.ToString() + "mm");
+ }
+ }
+
+ // also always save to the local setting
+ settingsContext.SetValue(settingData.SlicerConfigName, numberEdit.Value.ToString());
+ this.UpdateStyle();
+ };
+
+ if (settingData.QuickMenuSettings.Count > 0)
+ {
+ return SliceSettingsWidget.CreateQuickMenu(settingData, settingsContext, doubleEditWidget, doubleEditWidget.ActuallNumberEdit.InternalTextEditWidget);
+ }
+ else
+ {
+ return doubleEditWidget;
+ }
+ }
+
+ public void OnValueChanged(string text)
+ {
+ double.TryParse(text, out double currentValue);
+ doubleEditWidget.ActuallNumberEdit.Value = currentValue;
+ }
+ }
+}
diff --git a/SlicerConfiguration/UIFields/StringField.cs b/SlicerConfiguration/UIFields/StringField.cs
new file mode 100644
index 000000000..95fba53a6
--- /dev/null
+++ b/SlicerConfiguration/UIFields/StringField.cs
@@ -0,0 +1,65 @@
+/*
+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 System;
+using MatterHackers.Agg.UI;
+
+namespace MatterHackers.MatterControl.SlicerConfiguration
+{
+ public class StringField : ISettingsField
+ {
+ private MHTextEditWidget editWidget;
+
+ public Action UpdateStyle { get; set; }
+
+ public string Value { get; set; }
+
+ public GuiWidget Create(SettingsContext settingsContext, SliceSettingData settingData, int tabIndex)
+ {
+ editWidget = new MHTextEditWidget(this.Value, pixelWidth: settingData.ShowAsOverride ? 120 : 200, tabIndex: tabIndex)
+ {
+ Name = settingData.PresentationName + " Edit",
+ };
+ editWidget.ToolTipText = settingData.HelpText;
+
+ editWidget.ActualTextEditWidget.EditComplete += (sender, e) =>
+ {
+ settingsContext.SetValue(settingData.SlicerConfigName, ((TextEditWidget)sender).Text);
+ this.UpdateStyle();
+ };
+
+ return editWidget;
+ }
+
+ public void OnValueChanged(string text)
+ {
+ editWidget.Text = text;
+ }
+ }
+}
diff --git a/SlicerConfiguration/UIFields/Vector2Field.cs b/SlicerConfiguration/UIFields/Vector2Field.cs
new file mode 100644
index 000000000..6a7db317a
--- /dev/null
+++ b/SlicerConfiguration/UIFields/Vector2Field.cs
@@ -0,0 +1,117 @@
+/*
+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 System;
+using MatterHackers.Agg;
+using MatterHackers.Agg.UI;
+
+namespace MatterHackers.MatterControl.SlicerConfiguration
+{
+ public class Vector2Field : ISettingsField
+ {
+ public static readonly int VectorXYEditWidth = (int)(60 * GuiWidget.DeviceScale + .5);
+
+ private MHNumberEdit yEditWidget;
+
+ private MHNumberEdit xEditWidget;
+
+ public Action UpdateStyle { get; set; }
+
+ public string Value { get; set; }
+
+ public GuiWidget Create(SettingsContext settingsContext, SliceSettingData settingData, int tabIndex)
+ {
+ var container = new FlowLayoutWidget();
+
+ string[] xyValueStrings = this.Value.Split(',');
+ if (xyValueStrings.Length != 2)
+ {
+ xyValueStrings = new string[] { "0", "0" };
+ }
+
+ double.TryParse(xyValueStrings[0], out double currentXValue);
+
+ xEditWidget = new MHNumberEdit(currentXValue, allowDecimals: true, pixelWidth: VectorXYEditWidth, tabIndex: tabIndex)
+ {
+ ToolTipText = settingData.HelpText,
+ SelectAllOnFocus = true
+ };
+ xEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
+ {
+ settingsContext.SetValue(settingData.SlicerConfigName, xEditWidget.ActuallNumberEdit.Value.ToString() + "," + yEditWidget.ActuallNumberEdit.Value.ToString());
+ this.UpdateStyle();
+ };
+
+ container.AddChild(new TextWidget("X:", pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor)
+ {
+ VAnchor = VAnchor.Center,
+ Margin = new BorderDouble(5, 0),
+ });
+ container.AddChild(xEditWidget);
+
+ double.TryParse(xyValueStrings[1], out double currentYValue);
+
+ yEditWidget = new MHNumberEdit(currentYValue, allowDecimals: true, pixelWidth: VectorXYEditWidth, tabIndex: tabIndex)
+ {
+ ToolTipText = settingData.HelpText,
+ SelectAllOnFocus = true,
+ };
+ yEditWidget.ActuallNumberEdit.EditComplete += (sender, e) =>
+ {
+ settingsContext.SetValue(settingData.SlicerConfigName, xEditWidget.ActuallNumberEdit.Value.ToString() + "," + yEditWidget.ActuallNumberEdit.Value.ToString());
+
+ this.UpdateStyle();
+ };
+
+ container.AddChild(new TextWidget("Y:", pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor)
+ {
+ VAnchor = VAnchor.Center,
+ Margin = new BorderDouble(15, 0, 5, 0),
+ });
+ container.AddChild(yEditWidget);
+
+ return container;
+ }
+
+ public void OnValueChanged(string text)
+ {
+ string[] xyValueStrings2 = text.Split(',');
+ if (xyValueStrings2.Length != 2)
+ {
+ xyValueStrings2 = new string[] { "0", "0" };
+ }
+
+ double.TryParse(xyValueStrings2[0], out double currentValue);
+ xEditWidget.ActuallNumberEdit.Value = currentValue;
+
+ double.TryParse(xyValueStrings2[1], out currentValue);
+ yEditWidget.ActuallNumberEdit.Value = currentValue;
+ }
+ }
+}