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; + } + } +}