Extract PrinterSettings from MatterControl
This commit is contained in:
parent
e53d1f614f
commit
ed16199978
9 changed files with 9 additions and 9 deletions
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2018, 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 System.Text.RegularExpressions;
|
||||
|
||||
namespace MatterHackers.MatterControl.SlicerConfiguration
|
||||
{
|
||||
public class GCodeMacro
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string GCode { get; set; }
|
||||
public DateTime LastModified { get; set; }
|
||||
|
||||
public static string FixMacroName(string input)
|
||||
{
|
||||
int lengthLimit = 24;
|
||||
|
||||
string result = Regex.Replace(input, @"\r\n?|\n", " ");
|
||||
|
||||
if (result.Length > lengthLimit)
|
||||
{
|
||||
result = result.Substring(0, lengthLimit) + "...";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,967 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2018, 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 System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Platform;
|
||||
using MatterHackers.VectorMath;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace MatterHackers.MatterControl.SlicerConfiguration
|
||||
{
|
||||
public enum NamedSettingsLayers { MHBaseSettings, OEMSettings, Quality, Material, User, All }
|
||||
|
||||
public enum BedShape { Rectangular, Circular };
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum LevelingSystem { Probe3Points, Probe7PointRadial, Probe13PointRadial, Probe100PointRadial, Probe3x3Mesh, Probe5x5Mesh, Probe10x10Mesh, ProbeCustom }
|
||||
|
||||
public class PrinterSettings
|
||||
{
|
||||
// Latest version should be in the form of:
|
||||
// Year|month|day|versionForDay (to support multiple revisions on a given day)
|
||||
public static int LatestVersion { get; } = 201606271;
|
||||
|
||||
public static EventHandler AnyPrinterSettingChanged;
|
||||
|
||||
public event EventHandler SettingChanged;
|
||||
|
||||
public event EventHandler MaterialPresetChanged;
|
||||
|
||||
public void OnMaterialPresetChanged()
|
||||
{
|
||||
MaterialPresetChanged?.Invoke(null, null);
|
||||
}
|
||||
|
||||
public void OnSettingChanged(string slicerConfigName)
|
||||
{
|
||||
SettingChanged?.Invoke(this, new StringEventArgs(slicerConfigName));
|
||||
AnyPrinterSettingChanged?.Invoke(this, new StringEventArgs(slicerConfigName));
|
||||
}
|
||||
|
||||
public event EventHandler PrintLevelingEnabledChanged;
|
||||
|
||||
public event EventHandler MacrosChanged;
|
||||
|
||||
public static PrinterSettings Empty { get; }
|
||||
|
||||
public int DocumentVersion { get; set; } = LatestVersion;
|
||||
|
||||
public string ID { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
internal PrinterSettingsLayer QualityLayer { get; private set; }
|
||||
|
||||
[JsonIgnore]
|
||||
internal PrinterSettingsLayer MaterialLayer { get; private set; }
|
||||
|
||||
public PrinterSettingsLayer StagedUserSettings { get; set; } = new PrinterSettingsLayer();
|
||||
|
||||
|
||||
static PrinterSettings()
|
||||
{
|
||||
Empty = new PrinterSettings() { ID = "EmptyProfile" };
|
||||
Empty.UserLayer[SettingsKey.printer_name] = "Empty Printer";
|
||||
}
|
||||
|
||||
public PrinterSettings()
|
||||
{
|
||||
this.Helpers = new SettingsHelpers(this);
|
||||
}
|
||||
|
||||
public List<GCodeMacro> Macros { get; set; } = new List<GCodeMacro>();
|
||||
|
||||
/// <summary>
|
||||
/// Restore deactivated user overrides by iterating the active preset and removing/restoring matching items
|
||||
/// </summary>
|
||||
public void RestoreConflictingUserOverrides(PrinterSettingsLayer settingsLayer)
|
||||
{
|
||||
if (settingsLayer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var settingsKey in settingsLayer.Keys)
|
||||
{
|
||||
RestoreUserOverride(settingsLayer, settingsKey);
|
||||
}
|
||||
}
|
||||
|
||||
private void RestoreUserOverride(PrinterSettingsLayer settingsLayer, string settingsKey)
|
||||
{
|
||||
string stagedUserOverride;
|
||||
if (StagedUserSettings.TryGetValue(settingsKey, out stagedUserOverride))
|
||||
{
|
||||
StagedUserSettings.Remove(settingsKey);
|
||||
UserLayer[settingsKey] = stagedUserOverride;
|
||||
}
|
||||
}
|
||||
|
||||
internal void NotifyMacrosChanged()
|
||||
{
|
||||
this.MacrosChanged?.Invoke(this, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move conflicting user overrides to the temporary staging area, allowing presets values to take effect
|
||||
/// </summary>
|
||||
public void DeactivateConflictingUserOverrides(PrinterSettingsLayer settingsLayer)
|
||||
{
|
||||
if (settingsLayer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var settingsKey in settingsLayer.Keys)
|
||||
{
|
||||
StashUserOverride(settingsLayer, settingsKey);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a given field should be shown given its filter
|
||||
/// </summary>
|
||||
/// <param name="filter">The view filter - order of precedence &, |, !, =</param>
|
||||
/// <returns>An indicator if the field should be shown given the current filter</returns>
|
||||
public bool ParseShowString(string filter)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(filter))
|
||||
{
|
||||
string[] splitOnAnd = filter.Split('&');
|
||||
foreach (var andGroup in splitOnAnd)
|
||||
{
|
||||
bool orResult = false;
|
||||
string[] splitOnOr = andGroup.Split('|');
|
||||
foreach (var orGroup in splitOnOr)
|
||||
{
|
||||
var matchString = "1";
|
||||
var orItem = orGroup;
|
||||
bool negate = orItem.StartsWith("!");
|
||||
if (negate)
|
||||
{
|
||||
orItem = orItem.Substring(1);
|
||||
}
|
||||
|
||||
string sliceSettingValue = "";
|
||||
if (orItem.Contains("="))
|
||||
{
|
||||
string[] splitOnEquals = orItem.Split('=');
|
||||
|
||||
sliceSettingValue = this.GetValue(splitOnEquals[0]);
|
||||
matchString = splitOnEquals[1];
|
||||
}
|
||||
else if (orItem.Contains(">"))
|
||||
{
|
||||
matchString = "no_match";
|
||||
string[] splitOnGreater = orItem.Split('>');
|
||||
|
||||
sliceSettingValue = this.GetValue(splitOnGreater[0]);
|
||||
if (double.TryParse(sliceSettingValue, out double doubleValue))
|
||||
{
|
||||
if (double.TryParse(splitOnGreater[1], out double greater))
|
||||
{
|
||||
if (doubleValue > greater)
|
||||
{
|
||||
matchString = sliceSettingValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sliceSettingValue = this.GetValue(orItem);
|
||||
}
|
||||
|
||||
if ((!negate && sliceSettingValue == matchString)
|
||||
|| (negate && sliceSettingValue != matchString))
|
||||
{
|
||||
orResult = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (orResult == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move conflicting user overrides to the temporary staging area, allowing presets values to take effect
|
||||
/// </summary>
|
||||
private void StashUserOverride(PrinterSettingsLayer settingsLayer, string settingsKey)
|
||||
{
|
||||
string userOverride;
|
||||
if (this.UserLayer.TryGetValue(settingsKey, out userOverride))
|
||||
{
|
||||
this.UserLayer.Remove(settingsKey);
|
||||
this.StagedUserSettings.Add(settingsKey, userOverride);
|
||||
}
|
||||
}
|
||||
|
||||
[OnDeserialized]
|
||||
internal void OnDeserializedMethod(StreamingContext context)
|
||||
{
|
||||
QualityLayer = GetQualityLayer(ActiveQualityKey);
|
||||
|
||||
if (!string.IsNullOrEmpty(ActiveMaterialKey))
|
||||
{
|
||||
MaterialLayer = GetMaterialLayer(ActiveMaterialKey);
|
||||
}
|
||||
}
|
||||
|
||||
public PrinterSettingsLayer OemLayer { get; set; }
|
||||
|
||||
public void Merge(PrinterSettingsLayer destinationLayer, PrinterSettings settingsToImport, List<PrinterSettingsLayer> rawSourceFilter, bool setLayerName)
|
||||
{
|
||||
HashSet<string> skipKeys = new HashSet<string>
|
||||
{
|
||||
"layer_id",
|
||||
};
|
||||
|
||||
if (!setLayerName)
|
||||
{
|
||||
skipKeys.Add(SettingsKey.layer_name);
|
||||
}
|
||||
|
||||
var destinationFilter = new List<PrinterSettingsLayer>
|
||||
{
|
||||
OemLayer,
|
||||
BaseLayer,
|
||||
destinationLayer,
|
||||
}.Where(layer => layer != null);
|
||||
|
||||
var sourceFilter = rawSourceFilter.Where(layer => layer != null);
|
||||
|
||||
foreach (var keyName in PrinterSettings.KnownSettings)
|
||||
{
|
||||
if (settingsToImport.Contains(keyName))
|
||||
{
|
||||
// Compare the value to import to the layer cascade value and only set if different
|
||||
string currentValue = this.GetValue(keyName, destinationFilter).Trim();
|
||||
string importValue = settingsToImport.GetValue(keyName, sourceFilter).Trim();
|
||||
|
||||
if (!string.IsNullOrEmpty(importValue)
|
||||
&& currentValue != importValue
|
||||
&& !skipKeys.Contains(keyName))
|
||||
{
|
||||
destinationLayer[keyName] = importValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (setLayerName)
|
||||
{
|
||||
destinationLayer[SettingsKey.layer_name] = settingsToImport.GetValue(SettingsKey.layer_name, sourceFilter);
|
||||
}
|
||||
|
||||
this.Save();
|
||||
}
|
||||
|
||||
internal PrinterSettingsLayer GetMaterialLayer(string layerID)
|
||||
{
|
||||
if (string.IsNullOrEmpty(layerID))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return MaterialLayers.Where(layer => layer.LayerID == layerID).FirstOrDefault();
|
||||
}
|
||||
|
||||
private PrinterSettingsLayer GetQualityLayer(string layerID)
|
||||
{
|
||||
return QualityLayers.Where(layer => layer.LayerID == layerID).FirstOrDefault();
|
||||
}
|
||||
|
||||
public string ActiveQualityKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetValue(SettingsKey.active_quality_key);
|
||||
}
|
||||
internal set
|
||||
{
|
||||
SetValue(SettingsKey.active_quality_key, value);
|
||||
QualityLayer = GetQualityLayer(value);
|
||||
|
||||
this.OnSettingChanged(SettingsKey.active_quality_key);
|
||||
}
|
||||
}
|
||||
|
||||
public string ActiveMaterialKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if (MaterialSettingsKeys.Count > 0)
|
||||
{
|
||||
return MaterialSettingsKeys[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
internal set
|
||||
{
|
||||
if (MaterialSettingsKeys.Count == 0 || value != MaterialSettingsKeys[0])
|
||||
{
|
||||
MaterialSettingsKeys.Clear();
|
||||
MaterialSettingsKeys.Add(value);
|
||||
MaterialLayer = GetMaterialLayer(value);
|
||||
this.OnMaterialPresetChanged();
|
||||
|
||||
this.OnSettingChanged(SettingsKey.active_material_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> MaterialSettingsKeys { get; set; } = new List<string>();
|
||||
|
||||
|
||||
[JsonIgnore]
|
||||
public bool AutoSave { get; set; } = true;
|
||||
|
||||
internal string ComputeSHA1()
|
||||
{
|
||||
return ComputeSHA1(this.ToJson());
|
||||
}
|
||||
|
||||
public string ComputeSHA1(string json)
|
||||
{
|
||||
// SHA1 value is based on UTF8 encoded file contents
|
||||
using (var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
|
||||
{
|
||||
return HashGenerator.ComputeSHA1(memoryStream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// User settings overrides
|
||||
/// </summary>
|
||||
public PrinterSettingsLayer UserLayer { get; } = new PrinterSettingsLayer();
|
||||
|
||||
public static PrinterSettings LoadFile(string printerProfilePath, bool performMigrations = false)
|
||||
{
|
||||
if (performMigrations)
|
||||
{
|
||||
JObject jObject = null;
|
||||
|
||||
try
|
||||
{
|
||||
jObject = JObject.Parse(File.ReadAllText(printerProfilePath));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int documentVersion = jObject?.GetValue("DocumentVersion")?.Value<int>() ?? PrinterSettings.LatestVersion;
|
||||
if (documentVersion < PrinterSettings.LatestVersion)
|
||||
{
|
||||
printerProfilePath = ProfileMigrations.MigrateDocument(printerProfilePath, documentVersion);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return JsonConvert.DeserializeObject<PrinterSettings>(File.ReadAllText(printerProfilePath));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnPrintLevelingEnabledChanged(object s, EventArgs e)
|
||||
{
|
||||
PrintLevelingEnabledChanged?.Invoke(s, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should contain both user created and oem specified material layers
|
||||
/// </summary>
|
||||
public ObservableCollection<PrinterSettingsLayer> MaterialLayers { get; } = new ObservableCollection<PrinterSettingsLayer>();
|
||||
|
||||
/// <summary>
|
||||
/// Should contain both user created and oem specified quality layers
|
||||
/// </summary>
|
||||
public ObservableCollection<PrinterSettingsLayer> QualityLayers { get; } = new ObservableCollection<PrinterSettingsLayer>();
|
||||
|
||||
///<summary>
|
||||
///Returns the settings value at the 'top' of the stack
|
||||
///Returns the first matching value discovered while enumerating the settings layers
|
||||
///</summary>
|
||||
public string GetValue(string sliceSetting, IEnumerable<PrinterSettingsLayer> layerCascade = null)
|
||||
{
|
||||
if (layerCascade == null)
|
||||
{
|
||||
layerCascade = defaultLayerCascade;
|
||||
}
|
||||
|
||||
foreach (PrinterSettingsLayer layer in layerCascade)
|
||||
{
|
||||
string value;
|
||||
if (layer.TryGetValue(sliceSetting, out value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public bool IsOverride(string sliceSetting)
|
||||
{
|
||||
var values = new List<string>();
|
||||
|
||||
string firstBaseValue = null;
|
||||
|
||||
foreach (PrinterSettingsLayer layer in defaultLayerCascade)
|
||||
{
|
||||
if (layer.TryGetValue(sliceSetting, out string value))
|
||||
{
|
||||
if (layer == this.BaseLayer
|
||||
|| layer == this.OemLayer)
|
||||
{
|
||||
firstBaseValue = value;
|
||||
break;
|
||||
}
|
||||
|
||||
values.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
string currentValue = values.FirstOrDefault();
|
||||
|
||||
string firstPresetValue = values.Skip(1).FirstOrDefault();
|
||||
|
||||
bool differsFromPreset = values.Count > 0
|
||||
&& firstPresetValue != null
|
||||
&& firstPresetValue != currentValue;
|
||||
|
||||
bool differsFromBase = currentValue != firstBaseValue;
|
||||
|
||||
return currentValue != null
|
||||
&& (differsFromPreset || differsFromBase);
|
||||
}
|
||||
|
||||
// Helper method to debug settings layers per setting
|
||||
public List<(string layerName, string currentValue)> GetLayerValues(string sliceSetting, IEnumerable<PrinterSettingsLayer> layerCascade = null)
|
||||
{
|
||||
if (layerCascade == null)
|
||||
{
|
||||
layerCascade = defaultLayerCascade;
|
||||
}
|
||||
|
||||
var results = new List<(string layerName, string currentValue)>();
|
||||
|
||||
foreach (PrinterSettingsLayer layer in layerCascade)
|
||||
{
|
||||
if (layer.TryGetValue(sliceSetting, out string value))
|
||||
{
|
||||
string layerName = "User";
|
||||
|
||||
if (layer == this.BaseLayer)
|
||||
{
|
||||
layerName = "Base";
|
||||
}
|
||||
else if (layer == this.OemLayer)
|
||||
{
|
||||
layerName = "Oem";
|
||||
}
|
||||
else if (layer == this.MaterialLayer)
|
||||
{
|
||||
layerName = "Material";
|
||||
}
|
||||
else if (layer == this.QualityLayer)
|
||||
{
|
||||
layerName = "Quality";
|
||||
}
|
||||
|
||||
results.Add((layerName, value));
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public (string currentValue, string layerName) GetValueAndLayerName(string sliceSetting, IEnumerable<PrinterSettingsLayer> layerCascade = null)
|
||||
{
|
||||
if (layerCascade == null)
|
||||
{
|
||||
layerCascade = defaultLayerCascade;
|
||||
}
|
||||
|
||||
foreach (PrinterSettingsLayer layer in layerCascade)
|
||||
{
|
||||
string value;
|
||||
if (layer.TryGetValue(sliceSetting, out value))
|
||||
{
|
||||
string layerName = "User";
|
||||
|
||||
if (layer == this.BaseLayer)
|
||||
{
|
||||
layerName = "Base";
|
||||
}
|
||||
else if (layer == this.OemLayer)
|
||||
{
|
||||
layerName = "Oem";
|
||||
}
|
||||
else if (layer == this.MaterialLayer)
|
||||
{
|
||||
layerName = "Material";
|
||||
}
|
||||
else if (layer == this.QualityLayer)
|
||||
{
|
||||
layerName = "Quality";
|
||||
}
|
||||
|
||||
return (value, layerName);
|
||||
}
|
||||
}
|
||||
|
||||
return ("", "");
|
||||
}
|
||||
|
||||
public bool Contains(string sliceSetting, IEnumerable<PrinterSettingsLayer> layerCascade = null)
|
||||
{
|
||||
if (layerCascade == null)
|
||||
{
|
||||
layerCascade = defaultLayerCascade;
|
||||
}
|
||||
foreach (PrinterSettingsLayer layer in layerCascade)
|
||||
{
|
||||
if (layer.ContainsKey(sliceSetting))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PrinterSettingsLayer _baseLayer;
|
||||
[JsonIgnore]
|
||||
public PrinterSettingsLayer BaseLayer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_baseLayer == null)
|
||||
{
|
||||
string propertiesFileContents = AggContext.StaticData.ReadAllText(Path.Combine("SliceSettings", "Properties.json"));
|
||||
|
||||
var settingsLayer = new PrinterSettingsLayer();
|
||||
foreach (var settingsData in JsonConvert.DeserializeObject<List<SliceSettingData>>(propertiesFileContents))
|
||||
{
|
||||
settingsLayer[settingsData.SlicerConfigName] = settingsData.DefaultValue;
|
||||
}
|
||||
|
||||
_baseLayer = settingsLayer;
|
||||
}
|
||||
|
||||
return _baseLayer;
|
||||
}
|
||||
}
|
||||
|
||||
internal IEnumerable<PrinterSettingsLayer> defaultLayerCascade
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.UserLayer != null)
|
||||
{
|
||||
yield return this.UserLayer;
|
||||
}
|
||||
|
||||
if (this.MaterialLayer != null)
|
||||
{
|
||||
yield return this.MaterialLayer;
|
||||
}
|
||||
|
||||
if (this.QualityLayer != null)
|
||||
{
|
||||
yield return this.QualityLayer;
|
||||
}
|
||||
|
||||
if (this.OemLayer != null)
|
||||
{
|
||||
yield return this.OemLayer;
|
||||
}
|
||||
|
||||
yield return this.BaseLayer;
|
||||
}
|
||||
}
|
||||
[JsonIgnore]
|
||||
public SettingsHelpers Helpers { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public bool PrinterSelected => OemLayer?.Keys.Count > 0;
|
||||
|
||||
internal void RunInTransaction(Action<PrinterSettings> action)
|
||||
{
|
||||
// TODO: Implement RunInTransaction
|
||||
// Suspend writes
|
||||
action(this);
|
||||
// Commit
|
||||
}
|
||||
|
||||
public void ClearUserOverrides()
|
||||
{
|
||||
var userOverrides = this.UserLayer.Keys.ToArray();
|
||||
|
||||
// Leave user layer items that have no Organizer definition and thus cannot be changed by the user
|
||||
var keysToRetain = new HashSet<string>(userOverrides.Except(KnownSettings));
|
||||
|
||||
// Print leveling data has no SliceSettingsWidget editor but should be removed on 'Reset to Defaults'
|
||||
keysToRetain.Remove(SettingsKey.print_leveling_data);
|
||||
keysToRetain.Remove(SettingsKey.print_leveling_enabled);
|
||||
|
||||
// Iterate all items that have .ShowAsOverride = false and conditionally add to the retention list
|
||||
foreach (var item in SettingsOrganizer.SettingsData.Values.Where(settingsItem => settingsItem.ShowAsOverride == false))
|
||||
{
|
||||
switch (item.SlicerConfigName)
|
||||
{
|
||||
case SettingsKey.baud_rate:
|
||||
case SettingsKey.auto_connect:
|
||||
// Items *should* reset to defaults
|
||||
break;
|
||||
default:
|
||||
//Items should *not* reset to defaults
|
||||
keysToRetain.Add(item.SlicerConfigName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var keysToRemove = (from keyValue in this.UserLayer
|
||||
where !keysToRetain.Contains(keyValue.Key)
|
||||
select keyValue.Key).ToList();
|
||||
|
||||
foreach (string key in keysToRemove)
|
||||
{
|
||||
this.UserLayer.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
#region Migrate to LayeredProfile
|
||||
|
||||
static Dictionary<string, Type> expectedMappingTypes = new Dictionary<string, Type>()
|
||||
{
|
||||
[SettingsKey.extruders_share_temperature] = typeof(int),
|
||||
[SettingsKey.extruders_share_temperature] = typeof(bool),
|
||||
[SettingsKey.has_heated_bed] = typeof(bool),
|
||||
[SettingsKey.nozzle_diameter] = typeof(double),
|
||||
[SettingsKey.bed_temperature] = typeof(double),
|
||||
};
|
||||
|
||||
void ValidateType<T>(string settingsKey)
|
||||
{
|
||||
if (expectedMappingTypes.ContainsKey(settingsKey))
|
||||
{
|
||||
if (expectedMappingTypes[settingsKey] != typeof(T))
|
||||
{
|
||||
throw new Exception("You must request the correct type of this settingsKey.");
|
||||
}
|
||||
}
|
||||
|
||||
if (settingsKey.Contains("%"))
|
||||
{
|
||||
if (typeof(T) != typeof(double))
|
||||
{
|
||||
throw new Exception("To get processing of a % you must request the type as double.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///Returns the first matching value discovered while enumerating the settings layers
|
||||
///</summary>
|
||||
public T GetValue<T>(string settingsKey) where T : IConvertible
|
||||
{
|
||||
#if DEBUG
|
||||
ValidateType<T>(settingsKey);
|
||||
#endif
|
||||
if (typeof(T) == typeof(string))
|
||||
{
|
||||
// this way we can use the common pattern without error
|
||||
return (T)(object)this.GetValue(settingsKey);
|
||||
}
|
||||
else if(typeof(T) == typeof(LevelingSystem))
|
||||
{
|
||||
switch(this.GetValue(settingsKey))
|
||||
{
|
||||
case "3 Point Plane":
|
||||
return (T)(object)(LevelingSystem.Probe3Points);
|
||||
case "7 Point Disk":
|
||||
return (T)(object)(LevelingSystem.Probe7PointRadial);
|
||||
case "13 Point Disk":
|
||||
return (T)(object)(LevelingSystem.Probe13PointRadial);
|
||||
case "100 Point Disk":
|
||||
return (T)(object)(LevelingSystem.Probe100PointRadial);
|
||||
case "3x3 Mesh":
|
||||
return (T)(object)(LevelingSystem.Probe3x3Mesh);
|
||||
case "5x5 Mesh":
|
||||
return (T)(object)(LevelingSystem.Probe5x5Mesh);
|
||||
case "10x10 Mesh":
|
||||
return (T)(object)(LevelingSystem.Probe10x10Mesh);
|
||||
case "Custom Points":
|
||||
return (T)(object)(LevelingSystem.ProbeCustom);
|
||||
default:
|
||||
#if DEBUG
|
||||
throw new NotImplementedException();
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return (T)(object)(LevelingSystem.Probe3Points);
|
||||
}
|
||||
else if (typeof(T) == typeof(bool))
|
||||
{
|
||||
return (T)(object)(this.GetValue(settingsKey) == "1");
|
||||
}
|
||||
else if (typeof(T) == typeof(int))
|
||||
{
|
||||
int result;
|
||||
int.TryParse(this.GetValue(settingsKey), out result);
|
||||
return (T)(object)(result);
|
||||
}
|
||||
else if (typeof(T) == typeof(Vector2))
|
||||
{
|
||||
string[] twoValues = GetValue(settingsKey).Split(',');
|
||||
if (twoValues.Length != 2)
|
||||
{
|
||||
throw new Exception("Not parsing {0} as a Vector2".FormatWith(settingsKey));
|
||||
}
|
||||
Vector2 valueAsVector2 = new Vector2();
|
||||
valueAsVector2.X = Helpers.ParseDouble(twoValues[0]);
|
||||
valueAsVector2.Y = Helpers.ParseDouble(twoValues[1]);
|
||||
return (T)(object)(valueAsVector2);
|
||||
}
|
||||
else if (typeof(T) == typeof(double))
|
||||
{
|
||||
string settingsStringh = GetValue(settingsKey);
|
||||
if (settingsStringh.Contains("%"))
|
||||
{
|
||||
string onlyNumber = settingsStringh.Replace("%", "");
|
||||
double ratio = Helpers.ParseDouble(onlyNumber) / 100;
|
||||
|
||||
if (settingsKey == SettingsKey.first_layer_height)
|
||||
{
|
||||
return (T)(object)(GetValue<double>(SettingsKey.layer_height) * ratio);
|
||||
}
|
||||
else if (settingsKey == SettingsKey.first_layer_extrusion_width
|
||||
|| settingsKey == SettingsKey.external_perimeter_extrusion_width)
|
||||
{
|
||||
return (T)(object)(GetValue<double>(SettingsKey.nozzle_diameter) * ratio);
|
||||
}
|
||||
|
||||
return (T)(object)(ratio);
|
||||
}
|
||||
else if (settingsKey == SettingsKey.first_layer_extrusion_width
|
||||
|| settingsKey == SettingsKey.external_perimeter_extrusion_width)
|
||||
{
|
||||
double extrusionResult;
|
||||
double.TryParse(this.GetValue(settingsKey), out extrusionResult);
|
||||
return (T)(object)(extrusionResult == 0 ? GetValue<double>(SettingsKey.nozzle_diameter) : extrusionResult);
|
||||
}
|
||||
|
||||
if (settingsKey == SettingsKey.bed_temperature
|
||||
&& !this.GetValue<bool>(SettingsKey.has_heated_bed))
|
||||
{
|
||||
return (T)Convert.ChangeType(0, typeof(double));
|
||||
}
|
||||
|
||||
double result;
|
||||
double.TryParse(this.GetValue(settingsKey), out result);
|
||||
return (T)(object)(result);
|
||||
}
|
||||
else if (typeof(T) == typeof(BedShape))
|
||||
{
|
||||
switch (GetValue(settingsKey))
|
||||
{
|
||||
case "rectangular":
|
||||
return (T)(object)BedShape.Rectangular;
|
||||
|
||||
case "circular":
|
||||
return (T)(object)BedShape.Circular;
|
||||
|
||||
default:
|
||||
#if DEBUG
|
||||
throw new NotImplementedException("{0} is not a known bed_shape.".FormatWith(GetValue(SettingsKey.bed_shape)));
|
||||
#else
|
||||
return (T)(object)BedShape.Rectangular;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return (T)default(T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether or not the setting is overridden by the active layer
|
||||
/// </summary>
|
||||
public bool SettingExistsInLayer(string sliceSetting, NamedSettingsLayers layer)
|
||||
{
|
||||
switch (layer)
|
||||
{
|
||||
case NamedSettingsLayers.Quality:
|
||||
return QualityLayer?.ContainsKey(sliceSetting) == true;
|
||||
case NamedSettingsLayers.Material:
|
||||
return MaterialLayer?.ContainsKey(sliceSetting) == true;
|
||||
case NamedSettingsLayers.User:
|
||||
return UserLayer?.ContainsKey(sliceSetting) == true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public long GetLongHashCode()
|
||||
{
|
||||
var bigStringForHashCode = new StringBuilder();
|
||||
|
||||
foreach (var keyValue in this.BaseLayer)
|
||||
{
|
||||
// Add key/value to accumulating string for hash
|
||||
SliceSettingData data = SettingsOrganizer.Instance.GetSettingsData(keyValue.Key);
|
||||
if (data?.RebuildGCodeOnChange == true)
|
||||
{
|
||||
bigStringForHashCode.Append(keyValue.Key);
|
||||
bigStringForHashCode.Append(this.GetValue(keyValue.Key));
|
||||
}
|
||||
}
|
||||
|
||||
return agg_basics.ComputeHash(bigStringForHashCode.ToString());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private static HashSet<string> knownSettings;
|
||||
[JsonIgnore]
|
||||
public static HashSet<string> KnownSettings
|
||||
{
|
||||
get
|
||||
{
|
||||
if (knownSettings == null)
|
||||
{
|
||||
knownSettings = LoadSettingsNamesFromPropertiesJson();
|
||||
}
|
||||
|
||||
return knownSettings;
|
||||
}
|
||||
}
|
||||
|
||||
private static HashSet<string> LoadSettingsNamesFromPropertiesJson()
|
||||
{
|
||||
string propertiesJson = AggContext.StaticData.ReadAllText(Path.Combine("SliceSettings", "Properties.json"));
|
||||
var settingsData = JArray.Parse(propertiesJson);
|
||||
|
||||
return new HashSet<string>(settingsData.Select(s => s["SlicerConfigName"].Value<string>()));
|
||||
}
|
||||
|
||||
public void SetValue(string settingsKey, string settingsValue, PrinterSettingsLayer layer = null)
|
||||
{
|
||||
// Stash user overrides if a non-user override is being set
|
||||
if (layer != null && layer != UserLayer)
|
||||
{
|
||||
StashUserOverride(layer, settingsKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove any staged/conflicting user override, making this the new and active user override
|
||||
if (StagedUserSettings.ContainsKey(settingsKey))
|
||||
{
|
||||
StagedUserSettings.Remove(settingsKey);
|
||||
}
|
||||
}
|
||||
|
||||
var persistenceLayer = layer ?? UserLayer;
|
||||
|
||||
// If the setting exists and is set to the requested value, exit without setting or saving
|
||||
string existingValue;
|
||||
if (persistenceLayer.TryGetValue(settingsKey, out existingValue) && existingValue == settingsValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, set and save
|
||||
persistenceLayer[settingsKey] = settingsValue;
|
||||
|
||||
this.OnSettingChanged(settingsKey);
|
||||
}
|
||||
|
||||
public string ToJson()
|
||||
{
|
||||
return JsonConvert.SerializeObject(this, Formatting.Indented);
|
||||
}
|
||||
|
||||
internal void ClearValue(string settingsKey, PrinterSettingsLayer layer = null)
|
||||
{
|
||||
var persistenceLayer = layer ?? UserLayer;
|
||||
if (persistenceLayer.ContainsKey(settingsKey))
|
||||
{
|
||||
persistenceLayer.Remove(settingsKey);
|
||||
|
||||
// Restore user overrides if a non-user override is being cleared
|
||||
if (layer != null && layer != UserLayer)
|
||||
{
|
||||
RestoreUserOverride(layer, settingsKey);
|
||||
}
|
||||
|
||||
if (SettingsOrganizer.SettingsData.TryGetValue(settingsKey, out SliceSettingData settingData))
|
||||
{
|
||||
if (settingData.DataEditType == SliceSettingData.DataEditTypes.CHECK_BOX)
|
||||
{
|
||||
string checkedKey = this.GetValue<bool>(settingsKey) ? "OnValue" : "OffValue";
|
||||
|
||||
// Linked settings should be updated in all cases (user clicked checkbox, user clicked clear)
|
||||
foreach (var setSettingsData in settingData.SetSettingsOnChange)
|
||||
{
|
||||
if (setSettingsData.TryGetValue(checkedKey, out string targetValue))
|
||||
{
|
||||
if (this.GetValue(setSettingsData["TargetSetting"]) != targetValue)
|
||||
{
|
||||
this.SetValue(setSettingsData["TargetSetting"], targetValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.OnSettingChanged(settingsKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2018, 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 System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MatterHackers.MatterControl.SlicerConfiguration
|
||||
{
|
||||
using SettingsDictionary = Dictionary<string, string>;
|
||||
|
||||
public class PrinterSettingsLayer : SettingsDictionary
|
||||
{
|
||||
public PrinterSettingsLayer() { }
|
||||
|
||||
public PrinterSettingsLayer(Dictionary<string, string> settingsDictionary)
|
||||
{
|
||||
foreach(var keyValue in settingsDictionary)
|
||||
{
|
||||
this[keyValue.Key] = keyValue.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public string LayerID
|
||||
{
|
||||
get
|
||||
{
|
||||
string layerKey = ValueOrDefault("layer_id");
|
||||
if (string.IsNullOrEmpty(layerKey))
|
||||
{
|
||||
// Generate a new GUID when missing or empty. We can't do this in the constructor as the dictionary deserialization will fail if
|
||||
// an existing key exists for layer_id and on new empty layers, we still need to construct an initial identifier.
|
||||
layerKey = Guid.NewGuid().ToString();
|
||||
LayerID = layerKey;
|
||||
}
|
||||
|
||||
return layerKey;
|
||||
}
|
||||
set
|
||||
{
|
||||
this["layer_id"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return ValueOrDefault(SettingsKey.layer_name);
|
||||
}
|
||||
set
|
||||
{
|
||||
this[SettingsKey.layer_name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string Source
|
||||
{
|
||||
get
|
||||
{
|
||||
return ValueOrDefault("layer_source");
|
||||
}
|
||||
set
|
||||
{
|
||||
this["layer_source"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string ETag
|
||||
{
|
||||
get
|
||||
{
|
||||
return ValueOrDefault("layer_etag");
|
||||
}
|
||||
set
|
||||
{
|
||||
this["layer_etag"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string ValueOrDefault(string key, string defaultValue = "")
|
||||
{
|
||||
string foundValue;
|
||||
this.TryGetValue(key, out foundValue);
|
||||
|
||||
return foundValue ?? defaultValue;
|
||||
}
|
||||
|
||||
public static PrinterSettingsLayer LoadFromIni(TextReader reader)
|
||||
{
|
||||
var layer = new PrinterSettingsLayer();
|
||||
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
var segments = line.Split('=');
|
||||
if (!line.StartsWith("#") && !string.IsNullOrEmpty(line))
|
||||
{
|
||||
string key = segments[0].Trim();
|
||||
layer[key] = segments[1].Trim();
|
||||
}
|
||||
}
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
public static PrinterSettingsLayer LoadFromIni(string filePath)
|
||||
{
|
||||
var settings = from line in File.ReadAllLines(filePath)
|
||||
let segments = line.Split('=')
|
||||
where !line.StartsWith("#") && !string.IsNullOrEmpty(line) && segments.Length == 2
|
||||
select new
|
||||
{
|
||||
Key = segments[0].Trim(),
|
||||
Value = segments[1].Trim()
|
||||
};
|
||||
|
||||
var layer = new PrinterSettingsLayer();
|
||||
foreach (var setting in settings)
|
||||
{
|
||||
layer[setting.Key] = setting.Value;
|
||||
}
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
public PrinterSettingsLayer Clone()
|
||||
{
|
||||
string id = Guid.NewGuid().ToString();
|
||||
return new PrinterSettingsLayer(this as Dictionary<string, string>)
|
||||
{
|
||||
LayerID = id,
|
||||
Name = this.Name,
|
||||
ETag = this.ETag,
|
||||
Source = this.Source
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2016, 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 Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MatterHackers.MatterControl.SlicerConfiguration
|
||||
{
|
||||
public static class ProfileMigrations
|
||||
{
|
||||
public static string MigrateDocument(string filePath, int fromVersion = -1)
|
||||
{
|
||||
var jObject = JObject.Parse(File.ReadAllText(filePath));
|
||||
|
||||
/*
|
||||
if (fromVersion < 201605131)
|
||||
{
|
||||
var materialLayers = jObject["MaterialLayers"] as JObject;
|
||||
if (materialLayers != null)
|
||||
{
|
||||
foreach (JProperty layer in materialLayers.Properties().ToList())
|
||||
{
|
||||
layer.Remove();
|
||||
|
||||
string layerID = Guid.NewGuid().ToString();
|
||||
|
||||
var body = layer.Value as JObject;
|
||||
body["MatterControl.LayerID"] = layerID;
|
||||
body["MatterControl.LayerName"] = layer.Name;
|
||||
|
||||
materialLayers[layerID] = layer.Value;
|
||||
}
|
||||
}
|
||||
|
||||
var qualityLayers = jObject["QualityLayers"] as JObject;
|
||||
if (qualityLayers != null)
|
||||
{
|
||||
foreach (JProperty layer in qualityLayers.Properties().ToList())
|
||||
{
|
||||
layer.Remove();
|
||||
|
||||
string layerID = Guid.NewGuid().ToString();
|
||||
|
||||
var body = layer.Value as JObject;
|
||||
body["MatterControl.LayerID"] = layerID;
|
||||
body["MatterControl.LayerName"] = layer.Name;
|
||||
|
||||
qualityLayers[layerID] = layer.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
jObject["DocumentVersion"] = 201605131;
|
||||
}
|
||||
|
||||
if (fromVersion < 201605132)
|
||||
{
|
||||
string printerID = Guid.NewGuid().ToString();
|
||||
jObject.Remove("DocumentPath");
|
||||
jObject["ID"] = printerID;
|
||||
jObject["DocumentVersion"] = 201605132;
|
||||
|
||||
File.Delete(filePath);
|
||||
filePath = Path.Combine(Path.GetDirectoryName(filePath), printerID + ProfileManager.ProfileExtension);
|
||||
}
|
||||
*/
|
||||
|
||||
if (fromVersion < 201606271)
|
||||
{
|
||||
JObject oemProfile = jObject["OemProfile"] as JObject;
|
||||
if (oemProfile != null)
|
||||
{
|
||||
jObject.Property("OemProfile").Remove();
|
||||
jObject["OemLayer"] = oemProfile["OemLayer"];
|
||||
|
||||
}
|
||||
jObject["DocumentVersion"] = 201606271;
|
||||
}
|
||||
|
||||
File.WriteAllText(
|
||||
filePath,
|
||||
JsonConvert.SerializeObject(jObject, Formatting.Indented));
|
||||
|
||||
return filePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,251 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2018, 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 System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MatterHackers.VectorMath;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MatterHackers.MatterControl.SlicerConfiguration
|
||||
{
|
||||
public class SettingsHelpers
|
||||
{
|
||||
private PrinterSettings printerSettings;
|
||||
|
||||
public SettingsHelpers(PrinterSettings printerSettings)
|
||||
{
|
||||
this.printerSettings = printerSettings;
|
||||
}
|
||||
|
||||
public double ExtruderTemperature(int extruderIndex)
|
||||
{
|
||||
if (extruderIndex == 0)
|
||||
{
|
||||
return printerSettings.GetValue<double>(SettingsKey.temperature);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if there is a material override for this extruder
|
||||
// Otherwise, use the SettingsLayers that is bound to this extruder
|
||||
if (extruderIndex < printerSettings.GetValue<int>(SettingsKey.extruder_count))
|
||||
{
|
||||
return printerSettings.GetValue<double>($"{SettingsKey.temperature}{extruderIndex}");
|
||||
}
|
||||
|
||||
// else return the normal settings cascade
|
||||
return printerSettings.GetValue<double>(SettingsKey.temperature);
|
||||
}
|
||||
}
|
||||
|
||||
public int[] LayerToPauseOn()
|
||||
{
|
||||
string[] userValues = printerSettings.GetValue("layer_to_pause").Split(';');
|
||||
|
||||
int temp;
|
||||
return userValues.Where(v => int.TryParse(v, out temp)).Select(v =>
|
||||
{
|
||||
//Convert from 0 based index to 1 based index
|
||||
int val = int.Parse(v);
|
||||
|
||||
// Special case for user entered zero that pushes 0 to 1, otherwise val = val - 1 for 1 based index
|
||||
return val == 0 ? 1 : val - 1;
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
internal double ParseDouble(string firstLayerValueString)
|
||||
{
|
||||
double firstLayerValue;
|
||||
if (!double.TryParse(firstLayerValueString, out firstLayerValue))
|
||||
{
|
||||
throw new Exception(string.Format("Format cannot be parsed. FirstLayerHeight '{0}'", firstLayerValueString));
|
||||
}
|
||||
return firstLayerValue;
|
||||
}
|
||||
|
||||
public void SetBaudRate(string baudRate)
|
||||
{
|
||||
printerSettings.SetValue(SettingsKey.baud_rate, baudRate);
|
||||
}
|
||||
|
||||
public string ComPort()
|
||||
{
|
||||
return printerSettings.GetValue($"{Environment.MachineName}_com_port");
|
||||
}
|
||||
|
||||
public void SetComPort(string port)
|
||||
{
|
||||
printerSettings.SetValue($"{Environment.MachineName}_com_port", port);
|
||||
}
|
||||
|
||||
public void SetComPort(string port, PrinterSettingsLayer layer)
|
||||
{
|
||||
printerSettings.SetValue($"{Environment.MachineName}_com_port", port, layer);
|
||||
}
|
||||
|
||||
public void SetDriverType(string driver)
|
||||
{
|
||||
printerSettings.SetValue("driver_type", driver);
|
||||
}
|
||||
|
||||
public void SetDeviceToken(string token)
|
||||
{
|
||||
if (printerSettings.GetValue(SettingsKey.device_token) != token)
|
||||
{
|
||||
printerSettings.SetValue(SettingsKey.device_token, token);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetName(string name)
|
||||
{
|
||||
printerSettings.SetValue(SettingsKey.printer_name, name);
|
||||
}
|
||||
|
||||
public PrintLevelingData GetPrintLevelingData()
|
||||
{
|
||||
PrintLevelingData printLevelingData = null;
|
||||
var jsonData = printerSettings.GetValue(SettingsKey.print_leveling_data);
|
||||
if (!string.IsNullOrEmpty(jsonData))
|
||||
{
|
||||
printLevelingData = JsonConvert.DeserializeObject<PrintLevelingData>(jsonData);
|
||||
}
|
||||
|
||||
// if it is still null
|
||||
if (printLevelingData == null)
|
||||
{
|
||||
printLevelingData = new PrintLevelingData();
|
||||
}
|
||||
|
||||
return printLevelingData;
|
||||
}
|
||||
|
||||
public void SetPrintLevelingData(PrintLevelingData data, bool clearUserZOffset)
|
||||
{
|
||||
if (clearUserZOffset)
|
||||
{
|
||||
printerSettings.SetValue(SettingsKey.baby_step_z_offset, "0");
|
||||
}
|
||||
|
||||
printerSettings.SetValue(SettingsKey.print_leveling_data, JsonConvert.SerializeObject(data));
|
||||
}
|
||||
|
||||
public void DoPrintLeveling(bool doLeveling)
|
||||
{
|
||||
// Early exit if already set
|
||||
if (doLeveling == printerSettings.GetValue<bool>(SettingsKey.print_leveling_enabled))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
printerSettings.SetValue(SettingsKey.print_leveling_enabled, doLeveling ? "1" : "0");
|
||||
|
||||
printerSettings.OnPrintLevelingEnabledChanged(this, null);
|
||||
}
|
||||
|
||||
public Vector2 ExtruderOffset(int extruderIndex)
|
||||
{
|
||||
string currentOffsets = printerSettings.GetValue("extruder_offset");
|
||||
string[] offsets = currentOffsets.Split(',');
|
||||
int count = 0;
|
||||
foreach (string offset in offsets)
|
||||
{
|
||||
if (count == extruderIndex)
|
||||
{
|
||||
string[] xy = offset.Split('x');
|
||||
return new Vector2(double.Parse(xy[0]), double.Parse(xy[1]));
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
return Vector2.Zero;
|
||||
}
|
||||
|
||||
public void ExportAsCuraConfig()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Vector3 ManualMovementSpeeds()
|
||||
{
|
||||
Vector3 feedRate = new Vector3(3000, 3000, 315);
|
||||
|
||||
string savedSettings = printerSettings.GetValue(SettingsKey.manual_movement_speeds);
|
||||
if (!string.IsNullOrEmpty(savedSettings))
|
||||
{
|
||||
var segments = savedSettings.Split(',');
|
||||
feedRate.X = double.Parse(segments[1]);
|
||||
feedRate.Y = double.Parse(segments[3]);
|
||||
feedRate.Z = double.Parse(segments[5]);
|
||||
}
|
||||
|
||||
return feedRate;
|
||||
}
|
||||
|
||||
public Dictionary<string, double> GetMovementSpeeds()
|
||||
{
|
||||
Dictionary<string, double> speeds = new Dictionary<string, double>();
|
||||
string movementSpeedsString = GetMovementSpeedsString();
|
||||
string[] allSpeeds = movementSpeedsString.Split(',');
|
||||
for (int i = 0; i < allSpeeds.Length / 2; i++)
|
||||
{
|
||||
speeds.Add(allSpeeds[i * 2 + 0], double.Parse(allSpeeds[i * 2 + 1]));
|
||||
}
|
||||
|
||||
return speeds;
|
||||
}
|
||||
|
||||
public string GetMovementSpeedsString()
|
||||
{
|
||||
string presets = "x,3000,y,3000,z,315,e0,150"; // stored x,value,y,value,z,value,e1,value,e2,value,e3,value,...
|
||||
|
||||
string savedSettings = printerSettings.GetValue(SettingsKey.manual_movement_speeds);
|
||||
if (!string.IsNullOrEmpty(savedSettings))
|
||||
{
|
||||
presets = savedSettings;
|
||||
}
|
||||
|
||||
return presets;
|
||||
}
|
||||
|
||||
public int NumberOfHotends()
|
||||
{
|
||||
if (printerSettings.GetValue<bool>(SettingsKey.extruders_share_temperature))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return printerSettings.GetValue<int>(SettingsKey.extruder_count);
|
||||
}
|
||||
|
||||
public bool UseZProbe()
|
||||
{
|
||||
return printerSettings.GetValue<bool>(SettingsKey.has_z_probe) && printerSettings.GetValue<bool>(SettingsKey.use_z_probe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
namespace MatterHackers.MatterControl.SlicerConfiguration
|
||||
{
|
||||
public static class SettingsKey
|
||||
{
|
||||
public const string active_quality_key = nameof(active_quality_key);
|
||||
public const string active_material_key = nameof(active_material_key);
|
||||
public const string auto_connect = nameof(auto_connect);
|
||||
public const string auto_release_motors = nameof(auto_release_motors);
|
||||
public const string baby_step_z_offset = nameof(baby_step_z_offset);
|
||||
public const string backup_firmware_before_update = nameof(backup_firmware_before_update);
|
||||
public const string baud_rate = nameof(baud_rate);
|
||||
public const string bed_remove_part_temperature = nameof(bed_remove_part_temperature);
|
||||
public const string bed_shape = nameof(bed_shape);
|
||||
public const string bed_size = nameof(bed_size);
|
||||
public const string bed_temperature = nameof(bed_temperature);
|
||||
public const string build_height = nameof(build_height);
|
||||
public const string calibration_files = nameof(calibration_files);
|
||||
public const string cancel_gcode = nameof(cancel_gcode);
|
||||
public const string com_port = nameof(com_port);
|
||||
public const string connect_gcode = nameof(connect_gcode);
|
||||
public const string created_date = nameof(created_date);
|
||||
public const string default_material_presets = nameof(default_material_presets);
|
||||
public const string device_token = nameof(device_token);
|
||||
public const string device_type = nameof(device_type);
|
||||
public const string enable_line_splitting = nameof(enable_line_splitting);
|
||||
public const string enable_network_printing = nameof(enable_network_printing);
|
||||
public const string enable_retractions = nameof(enable_retractions);
|
||||
public const string enable_sailfish_communication = nameof(enable_sailfish_communication);
|
||||
public const string end_gcode = nameof(end_gcode);
|
||||
public const string expand_thin_walls = nameof(expand_thin_walls);
|
||||
public const string external_perimeter_extrusion_width = nameof(external_perimeter_extrusion_width);
|
||||
public const string extruder_count = nameof(extruder_count);
|
||||
public const string extruders_share_temperature = nameof(extruders_share_temperature);
|
||||
public const string extrusion_ratio = nameof(extrusion_ratio);
|
||||
public const string feedrate_ratio = nameof(feedrate_ratio);
|
||||
public const string filament_cost = nameof(filament_cost);
|
||||
public const string filament_density = nameof(filament_density);
|
||||
public const string filament_diameter = nameof(filament_diameter);
|
||||
public const string filament_runout_sensor = nameof(filament_runout_sensor);
|
||||
public const string fill_density = nameof(fill_density);
|
||||
public const string fill_thin_gaps = nameof(fill_thin_gaps);
|
||||
public const string first_layer_extrusion_width = nameof(first_layer_extrusion_width);
|
||||
public const string first_layer_height = nameof(first_layer_height);
|
||||
public const string first_layer_speed = nameof(first_layer_speed);
|
||||
public const string g0 = nameof(g0);
|
||||
public const string has_fan = nameof(has_fan);
|
||||
public const string has_hardware_leveling = nameof(has_hardware_leveling);
|
||||
public const string has_heated_bed = nameof(has_heated_bed);
|
||||
public const string has_power_control = nameof(has_power_control);
|
||||
public const string has_sd_card_reader = nameof(has_sd_card_reader);
|
||||
public const string has_z_probe = nameof(has_z_probe);
|
||||
public const string has_z_servo = nameof(has_z_servo);
|
||||
public const string heat_extruder_before_homing = nameof(heat_extruder_before_homing);
|
||||
public const string include_firmware_updater = nameof(include_firmware_updater);
|
||||
public const string infill_overlap_perimeter = nameof(infill_overlap_perimeter);
|
||||
public const string infill_type = nameof(infill_type);
|
||||
public const string insert_filament_markdown2 = nameof(insert_filament_markdown2);
|
||||
public const string ip_address = nameof(ip_address);
|
||||
public const string ip_port = nameof(ip_port);
|
||||
public const string jerk_velocity = nameof(jerk_velocity);
|
||||
public const string print_time_estimate_multiplier = nameof(print_time_estimate_multiplier);
|
||||
public const string laser_speed_025 = nameof(laser_speed_025);
|
||||
public const string laser_speed_100 = nameof(laser_speed_100);
|
||||
public const string layer_gcode = nameof(layer_gcode);
|
||||
public const string layer_height = nameof(layer_height);
|
||||
public const string layer_name = nameof(layer_name);
|
||||
public const string layer_to_pause = nameof(layer_to_pause);
|
||||
public const string load_filament_length = nameof(load_filament_length);
|
||||
public const string make = nameof(make);
|
||||
public const string manual_movement_speeds = nameof(manual_movement_speeds);
|
||||
public const string max_acceleration = nameof(max_acceleration);
|
||||
public const string max_velocity = nameof(max_velocity);
|
||||
public const string merge_overlapping_lines = nameof(merge_overlapping_lines);
|
||||
public const string min_fan_speed = nameof(min_fan_speed);
|
||||
public const string max_fan_speed = nameof(max_fan_speed);
|
||||
public const string model = nameof(model);
|
||||
public const string nozzle_diameter = nameof(nozzle_diameter);
|
||||
public const string number_of_first_layers = nameof(number_of_first_layers);
|
||||
public const string oem_profile_token = nameof(oem_profile_token);
|
||||
public const string pause_gcode = nameof(pause_gcode);
|
||||
public const string perimeter_start_end_overlap = nameof(perimeter_start_end_overlap);
|
||||
public const string print_center = nameof(print_center);
|
||||
public const string print_leveling_data = nameof(print_leveling_data);
|
||||
public const string print_leveling_enabled = nameof(print_leveling_enabled);
|
||||
public const string print_leveling_probe_start = nameof(print_leveling_probe_start);
|
||||
public const string probe_has_been_calibrated = nameof(probe_has_been_calibrated);
|
||||
public const string print_leveling_required_to_print = nameof(print_leveling_required_to_print);
|
||||
public const string print_leveling_solution = nameof(print_leveling_solution);
|
||||
public const string leveling_sample_points = nameof(leveling_sample_points);
|
||||
public const string load_filament_speed = nameof(load_filament_speed);
|
||||
public const string probe_offset_sample_point = nameof(probe_offset_sample_point);
|
||||
public const string printer_name = nameof(printer_name);
|
||||
public const string progress_reporting = nameof(progress_reporting);
|
||||
public const string publish_bed_image = nameof(publish_bed_image);
|
||||
public const string read_regex = nameof(read_regex);
|
||||
public const string recover_first_layer_speed = nameof(recover_first_layer_speed);
|
||||
public const string recover_is_enabled = nameof(recover_is_enabled);
|
||||
public const string recover_position_before_z_home = nameof(recover_position_before_z_home);
|
||||
public const string resume_gcode = nameof(resume_gcode);
|
||||
public const string running_clean_markdown2 = nameof(running_clean_markdown2);
|
||||
public const string selector_ip_address = nameof(selector_ip_address);
|
||||
public const string send_with_checksum = nameof(send_with_checksum);
|
||||
public const string filament_has_been_loaded = nameof(filament_has_been_loaded);
|
||||
public const string show_reset_connection = nameof(show_reset_connection);
|
||||
public const string sla_printer = nameof(sla_printer);
|
||||
public const string spiral_vase = nameof(spiral_vase);
|
||||
public const string start_gcode = nameof(start_gcode);
|
||||
public const string temperature = nameof(temperature);
|
||||
public const string temperature1 = nameof(temperature1);
|
||||
public const string temperature2 = nameof(temperature2);
|
||||
public const string temperature3 = nameof(temperature3);
|
||||
public const string top_solid_infill_speed = nameof(top_solid_infill_speed);
|
||||
public const string trim_filament_markdown = nameof(trim_filament_markdown);
|
||||
public const string unload_filament_length = nameof(unload_filament_length);
|
||||
public const string use_z_probe = nameof(use_z_probe);
|
||||
public const string validate_layer_height = nameof(validate_layer_height);
|
||||
public const string windows_driver = nameof(windows_driver);
|
||||
public const string write_regex = nameof(write_regex);
|
||||
public const string z_homes_to_max = nameof(z_homes_to_max);
|
||||
public const string z_probe_samples = nameof(z_probe_samples);
|
||||
public const string z_probe_xy_offset = nameof(z_probe_xy_offset);
|
||||
public const string z_probe_z_offset = nameof(z_probe_z_offset);
|
||||
public const string z_servo_depolyed_angle = nameof(z_servo_depolyed_angle);
|
||||
public const string z_servo_retracted_angle = nameof(z_servo_retracted_angle);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue