mattercontrol/SlicerConfiguration/Settings/SettingsProfile.cs
2016-05-31 18:02:00 -07:00

1175 lines
No EOL
35 KiB
C#

/*
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 MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.ContactForm;
using MatterHackers.MatterControl.PrinterCommunication;
using MatterHackers.VectorMath;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
namespace MatterHackers.MatterControl.SlicerConfiguration
{
using System.Net;
using ConfigurationPage.PrintLeveling;
using SettingsDictionary = Dictionary<string, string>;
using DataStorage;
using Agg.PlatformAbstract;
using Newtonsoft.Json.Linq;
using System.Collections.ObjectModel;
public class SettingsProfile
{
private static string configFileExtension = "slice";
public RootedObjectEventHandler DoPrintLevelingChanged = new RootedObjectEventHandler();
private LayeredProfile layeredProfile;
public bool PrinterSelected => layeredProfile.OemProfile.OemLayer.Keys.Count > 0;
internal SettingsProfile(LayeredProfile profile)
{
layeredProfile = profile;
}
public string ID => layeredProfile.ID;
public SettingsLayer BaseLayer => layeredProfile.BaseLayer;
public SettingsLayer OemLayer => layeredProfile.OemProfile.OemLayer;
public SettingsLayer UserLayer => layeredProfile.UserLayer;
public string ActiveMaterialKey
{
get
{
return layeredProfile.ActiveMaterialKey;
}
set
{
layeredProfile.ActiveMaterialKey = value;
}
}
public string ActiveQualityKey
{
get
{
return layeredProfile.ActiveQualityKey;
}
set
{
layeredProfile.ActiveQualityKey = value;
}
}
internal void RunInTransaction(Action<SettingsProfile> action)
{
// TODO: Implement RunInTransaction
// Suspend writes
action(this);
// Commit
}
public Dictionary<string, SettingsLayer> MaterialLayers => layeredProfile.MaterialLayers;
public Dictionary<string, SettingsLayer> QualityLayers => layeredProfile.QualityLayers;
public class SettingsConverter
{
public static void LoadConfigurationSettingsFromFileAsUnsaved(string pathAndFileName)
{
try
{
if (File.Exists(pathAndFileName))
{
string[] lines = System.IO.File.ReadAllLines(pathAndFileName);
foreach (string line in lines)
{
//Ignore commented lines
if (line.Trim() != "" && !line.StartsWith("#"))
{
string[] settingLine = line.Split('=');
if (settingLine.Length > 1)
{
string keyName = settingLine[0].Trim();
string settingDefaultValue = settingLine[1].Trim();
//Add the setting to the active layer
//SaveValue(keyName, settingDefaultValue);
throw new NotImplementedException("load to dictionary");
}
}
}
}
}
catch (Exception e)
{
Debug.Print(e.Message);
GuiWidget.BreakInDebugger();
Debug.WriteLine(string.Format("Error loading configuration: {0}", e));
}
}
}
internal void SaveChanges()
{
layeredProfile.Save();
}
public string ExtruderTemperature(int extruderIndex)
{
if (extruderIndex >= layeredProfile.MaterialSettingsKeys.Count)
{
// MaterialSettingsKeys is empty or lacks a value for the given extruder index
//
// If extruder index zero was requested, return the layer cascade temperature value, otherwise null
return (extruderIndex == 0) ? layeredProfile.GetValue("temperature") : null;
}
string materialKey = layeredProfile.MaterialSettingsKeys[extruderIndex];
if (extruderIndex == 0 && (string.IsNullOrEmpty(materialKey) || layeredProfile.UserLayer.ContainsKey("temperature")))
{
// In the case where a user override exists or MaterialSettingsKeys is populated with multiple extruder
// positions but position 0 is empty and thus unassigned, use layer cascade to resolve temp
return layeredProfile.GetValue("temperature");
}
// Otherwise, use the SettingsLayers that is bound to this extruder
SettingsLayer layer = layeredProfile.GetMaterialLayer(materialKey);
string result = "0";
layer?.TryGetValue("temperature", out result);
return result;
}
internal SettingsLayer MaterialLayer(string key)
{
return layeredProfile.GetMaterialLayer(key);
}
internal SettingsLayer QualityLayer(string key)
{
return layeredProfile.GetQualityLayer(key);
}
internal bool PublishBedImage()
{
return ActiveValue("MatterControl.PublishBedImage") == "1";
}
internal void SetMaterialPreset(int extruderIndex, string text)
{
layeredProfile.SetMaterialPreset(extruderIndex, text);
}
public bool HasFan()
{
return ActiveValue("has_fan") == "1";
}
public bool CenterOnBed()
{
return ActiveValue("center_part_on_bed") == "1";
}
public bool ShowResetConnection()
{
return ActiveValue("show_reset_connection") == "1";
}
public bool HasHardwareLeveling()
{
return ActiveValue("has_hardware_leveling") == "1";
}
public bool HasSdCardReader()
{
return ActiveValue("has_sd_card_reader") == "1";
}
public double BedTemperature()
{
double targetTemp = 0;
if (HasHeatedBed())
{
double.TryParse(ActiveValue("bed_temperature"), out targetTemp);
}
return targetTemp;
}
/// <summary>
/// Control the PS_ON pin via M80/81 if enabled in firmware and printer settings, allowing the printer board to toggle off the ATX power supply
/// </summary>
public bool HasPowerControl()
{
return ActiveValue("has_power_control") == "1";
}
public bool HasHeatedBed()
{
return ActiveValue("has_heated_bed") == "1";
}
public bool SupportEnabled()
{
return ActiveValue("support_material") == "1";
}
public bool ShowFirmwareUpdater()
{
return ActiveValue("include_firmware_updater") == "Simple Arduino";
}
public int SupportExtruder()
{
return int.Parse(ActiveValue("support_material_extruder"));
}
public int[] LayerToPauseOn()
{
string[] userValues = ActiveValue("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();
}
public double ProbePaperWidth()
{
return double.Parse(ActiveValue("manual_probe_paper_width"));
}
public bool RaftEnabled()
{
return ActiveValue("create_raft") == "1";
}
public int RaftExtruder()
{
return int.Parse(ActiveValue("raft_extruder"));
}
public double MaxFanSpeed()
{
return ParseDouble(ActiveValue("max_fan_speed"));
}
public double FillDensity()
{
string fillDensityValueString = ActiveValue("fill_density");
if (fillDensityValueString.Contains("%"))
{
string onlyNumber = fillDensityValueString.Replace("%", "");
double ratio = ParseDouble(onlyNumber) / 100;
return ratio;
}
else
{
return ParseDouble(ActiveValue("fill_density"));
}
}
public double MinFanSpeed()
{
return ParseDouble(ActiveValue("min_fan_speed"));
}
public double FirstLayerHeight()
{
string firstLayerValueString = ActiveValue("first_layer_height");
if (firstLayerValueString.Contains("%"))
{
string onlyNumber = firstLayerValueString.Replace("%", "");
double ratio = ParseDouble(onlyNumber) / 100;
return LayerHeight() * ratio;
}
double firstLayerValue;
firstLayerValue = ParseDouble(firstLayerValueString);
return firstLayerValue;
}
internal string MaterialPresetKey(int extruderIndex)
{
return layeredProfile.GetMaterialPresetKey(extruderIndex);
}
public double FirstLayerExtrusionWidth()
{
AsPercentOfReferenceOrDirect mapper = new AsPercentOfReferenceOrDirect("first_layer_extrusion_width", "notused", "nozzle_diameter");
double firstLayerValue = ParseDouble(mapper.Value);
return firstLayerValue;
}
private static 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 double LayerHeight()
{
return ParseDouble(ActiveValue("layer_height"));
}
public Vector2 BedSize()
{
return ActiveVector2("bed_size");
}
public MeshVisualizer.MeshViewerWidget.BedShape BedShape()
{
switch (ActiveValue("bed_shape"))
{
case "rectangular":
return MeshVisualizer.MeshViewerWidget.BedShape.Rectangular;
case "circular":
return MeshVisualizer.MeshViewerWidget.BedShape.Circular;
default:
#if DEBUG
throw new NotImplementedException(string.Format("'{0}' is not a known bed_shape.", ActiveValue("bed_shape")));
#else
return MeshVisualizer.MeshViewerWidget.BedShape.Rectangular;
#endif
}
}
public Vector2 BedCenter()
{
return ActiveVector2("print_center");
}
public double BuildHeight()
{
return ParseDouble(ActiveValue("build_height"));
}
public Vector2 PrintCenter()
{
return ActiveVector2("print_center");
}
public int ExtruderCount()
{
if (ExtrudersShareTemperature())
{
return 1;
}
int extruderCount;
string extruderCountString = ActiveValue("extruder_count");
if (!int.TryParse(extruderCountString, out extruderCount))
{
return 1;
}
return extruderCount;
}
public bool ExtrudersShareTemperature()
{
return (int.Parse(ActiveValue("extruders_share_temperature")) == 1);
}
public Vector2 ExtruderOffset(int extruderIndex)
{
string currentOffsets = ActiveValue("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 double NozzleDiameter()
{
return ParseDouble(ActiveValue("nozzle_diameter"));
}
public double FilamentDiameter()
{
return ParseDouble(ActiveValue("filament_diameter"));
}
public bool LevelingRequiredToPrint()
{
return ActiveValue("print_leveling_required_to_print") == "1";
}
private PrintLevelingData printLevelingData = null;
public PrintLevelingData GetPrintLevelingData()
{
if (printLevelingData == null)
{
printLevelingData = PrintLevelingData.Create(
ActiveSliceSettings.Instance,
layeredProfile.GetValue("MatterControl.PrintLevelingData"),
layeredProfile.GetValue("MatterControl.PrintLevelingProbePositions"));
PrintLevelingPlane.Instance.SetPrintLevelingEquation(
printLevelingData.SampledPosition0,
printLevelingData.SampledPosition1,
printLevelingData.SampledPosition2,
ActiveSliceSettings.Instance.PrintCenter());
}
return printLevelingData;
}
public void SetPrintLevelingData(PrintLevelingData data)
{
printLevelingData = data;
layeredProfile.SetActiveValue("MatterControl.PrintLevelingData", JsonConvert.SerializeObject(data));
}
public bool DoPrintLeveling()
{
return layeredProfile.GetValue("MatterControl.PrintLevelingEnabled") == "1";
}
public void DoPrintLeveling(bool doLeveling)
{
// Early exit if already set
if (doLeveling == this.DoPrintLeveling())
{
return;
}
layeredProfile.SetActiveValue("MatterControl.PrintLevelingEnabled", doLeveling ? "1" : "0");
DoPrintLevelingChanged.CallEvents(this, null);
if (doLeveling)
{
PrintLevelingData levelingData = ActiveSliceSettings.Instance.GetPrintLevelingData();
PrintLevelingPlane.Instance.SetPrintLevelingEquation(
levelingData.SampledPosition0,
levelingData.SampledPosition1,
levelingData.SampledPosition2,
ActiveSliceSettings.Instance.PrintCenter());
}
}
private static readonly SlicingEngineTypes defaultEngineType = SlicingEngineTypes.MatterSlice;
public SlicingEngineTypes ActiveSliceEngineType()
{
string engineType = layeredProfile.GetValue("MatterControl.SlicingEngine");
if (string.IsNullOrEmpty(engineType))
{
return defaultEngineType;
}
var engine = (SlicingEngineTypes)Enum.Parse(typeof(SlicingEngineTypes), engineType);
return engine;
}
public void ActiveSliceEngineType(SlicingEngineTypes type)
{
SetActiveValue("MatterControl.SlicingEngine", type.ToString());
}
public SliceEngineMapping ActiveSliceEngine()
{
switch (ActiveSliceEngineType())
{
case SlicingEngineTypes.CuraEngine:
return EngineMappingCura.Instance;
case SlicingEngineTypes.MatterSlice:
return EngineMappingsMatterSlice.Instance;
case SlicingEngineTypes.Slic3r:
return Slic3rEngineMappings.Instance;
default:
return null;
}
}
///<summary>
///Returns the first matching value discovered while enumerating the settings layers
///</summary>
public string ActiveValue(string sliceSetting)
{
return layeredProfile.GetValue(sliceSetting);
}
public string GetActiveValue(string sliceSetting, IEnumerable<SettingsLayer> layerCascade)
{
return layeredProfile.GetValue(sliceSetting, layerCascade);
}
public void SetActiveValue(string sliceSetting, string sliceValue)
{
layeredProfile.SetActiveValue(sliceSetting, sliceValue);
}
public void SetActiveValue(string sliceSetting, string sliceValue, SettingsLayer persistenceLayer)
{
layeredProfile.SetActiveValue(sliceSetting, sliceValue, persistenceLayer);
}
public void ClearValue(string sliceSetting)
{
layeredProfile.ClearValue(sliceSetting);
}
public void ClearValue(string sliceSetting, SettingsLayer persistenceLayer)
{
layeredProfile.ClearValue(sliceSetting, persistenceLayer);
}
/// <summary>
/// Returns whether or not the setting is overridden by the active layer
/// </summary>
public bool SettingExistsInLayer(string sliceSetting, NamedSettingsLayers layer)
{
if (layeredProfile == null)
{
return false;
}
switch (layer)
{
case NamedSettingsLayers.Quality:
return layeredProfile?.QualityLayer?.ContainsKey(sliceSetting) == true;
case NamedSettingsLayers.Material:
return layeredProfile?.MaterialLayer?.ContainsKey(sliceSetting) == true;
case NamedSettingsLayers.User:
return layeredProfile?.UserLayer?.ContainsKey(sliceSetting) == true;
default:
return false;
}
}
public Vector2 ActiveVector2(string sliceSetting)
{
string[] twoValues = ActiveValue(sliceSetting).Split(',');
if (twoValues.Length != 2)
{
throw new Exception(string.Format("Not parsing {0} as a Vector2", sliceSetting));
}
Vector2 valueAsVector2 = new Vector2();
valueAsVector2.x = ParseDouble(twoValues[0]);
valueAsVector2.y = ParseDouble(twoValues[1]);
return valueAsVector2;
}
public void SaveAs()
{
SaveFileDialogParams saveParams = new SaveFileDialogParams("Save Slice Configuration".Localize() + "|*." + configFileExtension);
saveParams.FileName = "default_settings.ini";
FileDialog.SaveFileDialog(saveParams, onExportFileSelected);
}
private void onExportFileSelected(SaveFileDialogParams saveParams)
{
if (!string.IsNullOrEmpty(saveParams.FileName))
{
GenerateConfigFile(saveParams.FileName, false);
}
}
public long GetLongHashCode()
{
var bigStringForHashCode = new StringBuilder();
foreach (var keyValue in this.BaseLayer)
{
string activeValue = ActiveValue(keyValue.Key);
bigStringForHashCode.Append(keyValue.Key);
bigStringForHashCode.Append(activeValue);
}
string value = bigStringForHashCode.ToString();
return agg_basics.ComputeHash(bigStringForHashCode.ToString());
}
public void GenerateConfigFile(string fileName, bool replaceMacroValues)
{
using (var outstream = new StreamWriter(fileName))
{
foreach (var key in this.KnownSettings.Where(k => !k.StartsWith("MatterControl.")))
{
string activeValue = ActiveValue(key);
if (replaceMacroValues)
{
activeValue = GCodeProcessing.ReplaceMacroValues(activeValue);
}
outstream.Write(string.Format("{0} = {1}\n", key, activeValue));
activeValue = GCodeProcessing.ReplaceMacroValues(activeValue);
}
}
}
public bool IsValid()
{
try
{
if (LayerHeight() > NozzleDiameter())
{
string error = "'Layer Height' must be less than or equal to the 'Nozzle Diameter'.".Localize();
string details = string.Format("Layer Height = {0}\nNozzle Diameter = {1}".Localize(), LayerHeight(), NozzleDiameter());
string location = "Location: 'Settings & Controls' -> 'Settings' -> 'General' -> 'Layers/Surface'".Localize();
StyledMessageBox.ShowMessageBox(null, string.Format("{0}\n\n{1}\n\n{2}", error, details, location), "Slice Error".Localize());
return false;
}
else if (FirstLayerHeight() > NozzleDiameter())
{
string error = "'First Layer Height' must be less than or equal to the 'Nozzle Diameter'.".Localize();
string details = string.Format("First Layer Height = {0}\nNozzle Diameter = {1}".Localize(), FirstLayerHeight(), NozzleDiameter());
string location = "Location: 'Settings & Controls' -> 'Settings' -> 'General' -> 'Layers/Surface'".Localize();
StyledMessageBox.ShowMessageBox(null, string.Format("{0}\n\n{1}\n\n{2}", error, details, location), "Slice Error".Localize());
return false;
}
// If we have print leveling turned on then make sure we don't have any leveling commands in the start gcode.
if (PrinterConnectionAndCommunication.Instance.ActivePrinter.DoPrintLeveling())
{
string[] startGCode = ActiveValue("start_gcode").Replace("\\n", "\n").Split('\n');
foreach (string startGCodeLine in startGCode)
{
if (startGCodeLine.StartsWith("G29"))
{
string error = "Start G-Code cannot contain G29 if Print Leveling is enabled.".Localize();
string details = "Your Start G-Code should not contain a G29 if you are planning on using print leveling. Change your start G-Code or turn off print leveling".Localize();
string location = "Location: 'Settings & Controls' -> 'Settings' -> 'Printer' -> 'Custom G-Code' -> 'Start G-Code'".Localize();
StyledMessageBox.ShowMessageBox(null, string.Format("{0}\n\n{1}\n\n{2}", error, details, location), "Slice Error".Localize());
return false;
}
if (startGCodeLine.StartsWith("G30"))
{
string error = "Start G-Code cannot contain G30 if Print Leveling is enabled.".Localize();
string details = "Your Start G-Code should not contain a G30 if you are planning on using print leveling. Change your start G-Code or turn off print leveling".Localize();
string location = "Location: 'Settings & Controls' -> 'Settings' -> 'Printer' -> 'Custom G-Code' -> 'Start G-Code'".Localize();
StyledMessageBox.ShowMessageBox(null, string.Format("{0}\n\n{1}\n\n{2}", error, details, location), "Slice Error".Localize());
return false;
}
}
}
if (FirstLayerExtrusionWidth() > NozzleDiameter() * 4)
{
string error = "'First Layer Extrusion Width' must be less than or equal to the 'Nozzle Diameter' * 4.".Localize();
string details = string.Format("First Layer Extrusion Width = {0}\nNozzle Diameter = {1}".Localize(), ActiveValue("first_layer_extrusion_width"), NozzleDiameter());
string location = "Location: 'Settings & Controls' -> 'Settings' -> 'Filament' -> 'Extrusion' -> 'First Layer'".Localize();
StyledMessageBox.ShowMessageBox(null, string.Format("{0}\n\n{1}\n\n{2}", error, details, location), "Slice Error".Localize());
return false;
}
if (FirstLayerExtrusionWidth() <= 0)
{
string error = "'First Layer Extrusion Width' must be greater than 0.".Localize();
string details = string.Format("First Layer Extrusion Width = {0}".Localize(), ActiveValue("first_layer_extrusion_width"));
string location = "Location: 'Settings & Controls' -> 'Settings' -> 'Filament' -> 'Extrusion' -> 'First Layer'".Localize();
StyledMessageBox.ShowMessageBox(null, string.Format("{0}\n\n{1}\n\n{2}", error, details, location), "Slice Error".Localize());
return false;
}
if (MinFanSpeed() > 100)
{
string error = "The Minimum Fan Speed can only go as high as 100%.".Localize();
string details = string.Format("It is currently set to {0}.".Localize(), MinFanSpeed());
string location = "Location: 'Settings & Controls' -> 'Settings' -> 'Filament' -> 'Cooling'".Localize();
StyledMessageBox.ShowMessageBox(null, string.Format("{0}\n\n{1}\n\n{2}", error, details, location), "Slice Error".Localize());
return false;
}
if (MaxFanSpeed() > 100)
{
string error = "The Maximum Fan Speed can only go as high as 100%.".Localize();
string details = string.Format("It is currently set to {0}.".Localize(), MaxFanSpeed());
string location = "Location: 'Settings & Controls' -> 'Settings' -> 'Filament' -> 'Cooling'".Localize();
StyledMessageBox.ShowMessageBox(null, string.Format("{0}\n\n{1}\n\n{2}", error, details, location), "Slice Error".Localize());
return false;
}
if (ExtruderCount() < 1)
{
string error = "The Extruder Count must be at least 1.".Localize();
string details = string.Format("It is currently set to {0}.".Localize(), ExtruderCount());
string location = "Location: 'Settings & Controls' -> 'Settings' -> 'Printer' -> 'Features'".Localize();
StyledMessageBox.ShowMessageBox(null, string.Format("{0}\n\n{1}\n\n{2}", error, details, location), "Slice Error".Localize());
return false;
}
if (FillDensity() < 0 || FillDensity() > 1)
{
string error = "The Fill Density must be between 0 and 1.".Localize();
string details = string.Format("It is currently set to {0}.".Localize(), FillDensity());
string location = "Location: 'Settings & Controls' -> 'Settings' -> 'General' -> 'Infill'".Localize();
StyledMessageBox.ShowMessageBox(null, string.Format("{0}\n\n{1}\n\n{2}", error, details, location), "Slice Error".Localize());
return false;
}
if (FillDensity() == 1
&& ActiveValue("infill_type") != "LINES")
{
string error = "Solid Infill works best when set to LINES.".Localize();
string details = string.Format("It is currently set to {0}.".Localize(), ActiveValue("infill_type"));
string location = "Location: 'Settings & Controls' -> 'Settings' -> 'General' -> 'Infill Type'".Localize();
StyledMessageBox.ShowMessageBox(null, string.Format("{0}\n\n{1}\n\n{2}", error, details, location), "Slice Error".Localize());
return true;
}
string normalSpeedLocation = "Location: 'Settings & Controls' -> 'Settings' -> 'General' -> 'Speed'".Localize();
// If the given speed is part of the current slice engine then check that it is greater than 0.
if (!ValidateGoodSpeedSettingGreaterThan0("bridge_speed", normalSpeedLocation)) return false;
if (!ValidateGoodSpeedSettingGreaterThan0("external_perimeter_speed", normalSpeedLocation)) return false;
if (!ValidateGoodSpeedSettingGreaterThan0("first_layer_speed", normalSpeedLocation)) return false;
if (!ValidateGoodSpeedSettingGreaterThan0("gap_fill_speed", normalSpeedLocation)) return false;
if (!ValidateGoodSpeedSettingGreaterThan0("infill_speed", normalSpeedLocation)) return false;
if (!ValidateGoodSpeedSettingGreaterThan0("perimeter_speed", normalSpeedLocation)) return false;
if (!ValidateGoodSpeedSettingGreaterThan0("small_perimeter_speed", normalSpeedLocation)) return false;
if (!ValidateGoodSpeedSettingGreaterThan0("solid_infill_speed", normalSpeedLocation)) return false;
if (!ValidateGoodSpeedSettingGreaterThan0("support_material_speed", normalSpeedLocation)) return false;
if (!ValidateGoodSpeedSettingGreaterThan0("top_solid_infill_speed", normalSpeedLocation)) return false;
if (!ValidateGoodSpeedSettingGreaterThan0("travel_speed", normalSpeedLocation)) return false;
string retractSpeedLocation = "Location: 'Settings & Controls' -> 'Settings' -> 'Filament' -> 'Filament' -> 'Retraction'".Localize();
if (!ValidateGoodSpeedSettingGreaterThan0("retract_speed", retractSpeedLocation)) return false;
}
catch (Exception e)
{
Debug.Print(e.Message);
GuiWidget.BreakInDebugger();
string stackTraceNoBackslashRs = e.StackTrace.Replace("\r", "");
ContactFormWindow.Open("Parse Error while slicing".Localize(), e.Message + stackTraceNoBackslashRs);
return false;
}
return true;
}
private bool ValidateGoodSpeedSettingGreaterThan0(string speedSetting, string speedLocation)
{
string actualSpeedValueString = ActiveValue(speedSetting);
string speedValueString = actualSpeedValueString;
if (speedValueString.EndsWith("%"))
{
speedValueString = speedValueString.Substring(0, speedValueString.Length - 1);
}
bool valueWasNumber = true;
double speedToCheck;
if (!double.TryParse(speedValueString, out speedToCheck))
{
valueWasNumber = false;
}
if (!valueWasNumber
|| (ActiveSliceSettings.Instance.ActiveSliceEngine().MapContains(speedSetting)
&& speedToCheck <= 0))
{
OrganizerSettingsData data = SliceSettingsOrganizer.Instance.GetSettingsData(speedSetting);
if (data != null)
{
string error = string.Format("The '{0}' must be greater than 0.".Localize(), data.PresentationName);
string details = string.Format("It is currently set to {0}.".Localize(), actualSpeedValueString);
StyledMessageBox.ShowMessageBox(null, string.Format("{0}\n\n{1}\n\n{2} -> '{3}'", error, details, speedLocation, data.PresentationName), "Slice Error".Localize());
}
return false;
}
return true;
}
public bool DoAutoConnect()
{
return layeredProfile.GetValue("MatterControl.AutoConnect") == "1";
}
public void SetAutoConnect(bool autoConnectPrinter)
{
layeredProfile.SetActiveValue("MatterControl.AutoConnect", autoConnectPrinter ? "1" : "0");
}
public string BaudRate()
{
return layeredProfile.GetValue("MatterControl.BaudRate");
}
public void SetBaudRate(string baudRate)
{
layeredProfile.SetActiveValue("MatterControl.BaudRate", baudRate);
}
public string ComPort()
{
return layeredProfile.GetValue(string.Format("MatterControl.{0}.ComPort", Environment.MachineName));
}
public void SetComPort(string port)
{
layeredProfile.SetActiveValue(string.Format("MatterControl.{0}.ComPort", Environment.MachineName), port);
}
public void SetComPort(string port, SettingsLayer layer)
{
layeredProfile.SetActiveValue(string.Format("MatterControl.{0}.ComPort", Environment.MachineName), port, layer);
}
public string SlicingEngine()
{
return layeredProfile.GetValue("MatterControl.SlicingEngine");
}
public void SetSlicingEngine(string engine)
{
layeredProfile.SetActiveValue("MatterControl.SlicingEngine", engine);
}
public string DriverType()
{
return layeredProfile.GetValue("MatterControl.DriverType");
}
public void SetDriverType(string driver)
{
layeredProfile.SetActiveValue("MatterControl.DriverType", driver);
}
public string DeviceToken()
{
return layeredProfile.GetValue("MatterControl.DeviceToken");
}
public void SetDeviceToken(string token)
{
layeredProfile.SetActiveValue("MatterControl.DeviceToken", token);
}
public string DeviceType => layeredProfile.GetValue("MatterControl.DeviceType");
public string Make => layeredProfile.GetValue("MatterControl.Make");
// Rename to PrinterName
public string Name()
{
return layeredProfile.GetValue("MatterControl.PrinterName");
}
public void SetName(string name)
{
layeredProfile.SetActiveValue("MatterControl.PrinterName", name);
}
public string Model => layeredProfile.GetValue("MatterControl.Model");
HashSet<string> knownSettings = null;
public HashSet<string> KnownSettings
{
get
{
if (knownSettings == null)
{
string propertiesJson = StaticData.Instance.ReadAllText(Path.Combine("SliceSettings", "Properties.json"));
var settingsData = JArray.Parse(propertiesJson);
knownSettings = new HashSet<string>(settingsData.Select(s => s["SlicerConfigName"].Value<string>()));
}
return knownSettings;
}
}
public string ManualMovementSpeeds()
{
return layeredProfile.GetValue("MatterControl.ManualMovementSpeeds");
}
public void SetManualMovementSpeeds(string speed)
{
layeredProfile.SetActiveValue("MatterControl.ManualMovementSpeeds", speed);
}
private List<string> printerDrivers = null;
public List<string> PrinterDrivers()
{
if(printerDrivers == null)
{
printerDrivers = GetPrintDrivers();
}
return printerDrivers;
}
private List<string> GetPrintDrivers()
{
var drivers = new List<string>();
//Determine what if any drivers are needed
string infFileNames = ActiveValue("windows_driver");
if (!string.IsNullOrEmpty(infFileNames))
{
string[] fileNames = infFileNames.Split(',');
foreach (string fileName in fileNames)
{
switch (OsInformation.OperatingSystem)
{
case OSType.Windows:
string pathForInf = Path.GetFileNameWithoutExtension(fileName);
// TODO: It's really unexpected that the driver gets copied to the temp folder every time a printer is setup. I'd think this only needs
// to happen when the infinstaller is run (More specifically - move this to *after* the user clicks Install Driver)
string infPath = Path.Combine("Drivers", pathForInf);
string infPathAndFileToInstall = Path.Combine(infPath, fileName);
if (StaticData.Instance.FileExists(infPathAndFileToInstall))
{
// Ensure the output directory exists
string destTempPath = Path.GetFullPath(Path.Combine(ApplicationDataStorage.ApplicationUserDataPath, "data", "temp", "inf", pathForInf));
if (!Directory.Exists(destTempPath))
{
Directory.CreateDirectory(destTempPath);
}
string destTempInf = Path.GetFullPath(Path.Combine(destTempPath, fileName));
// Sync each file from StaticData to the location on disk for serial drivers
foreach (string file in StaticData.Instance.GetFiles(infPath))
{
using (Stream outstream = File.OpenWrite(Path.Combine(destTempPath, Path.GetFileName(file))))
using (Stream instream = StaticData.Instance.OpenSteam(file))
{
instream.CopyTo(outstream);
}
}
drivers.Add(destTempInf);
}
break;
default:
break;
}
}
}
return drivers;
}
public List<GCodeMacro> Macros => layeredProfile.Macros;
}
public class SettingsLayer : SettingsDictionary
{
public SettingsLayer() { }
public SettingsLayer(Dictionary<string, string> settingsDictionary)
{
foreach(var keyValue in settingsDictionary)
{
this[keyValue.Key] = keyValue.Value;
}
}
public string ID
{
get
{
// TODO: Short term hack to silently upgrade existing profiles with missing ID
string layerKey = ValueOrDefault("MatterControl.LayerID");
if (string.IsNullOrEmpty(layerKey))
{
layerKey = Guid.NewGuid().ToString();
ID = layerKey;
}
return layerKey;
}
set
{
this["MatterControl.LayerID"] = value;
}
}
public string Name
{
get
{
return ValueOrDefault("MatterControl.LayerName");
}
set
{
this["MatterControl.LayerName"] = value;
}
}
public string Source
{
get
{
return ValueOrDefault("MatterControl.LayerSource");
}
set
{
this["MatterControl.LayerSource"] = value;
}
}
public string ETag
{
get
{
return ValueOrDefault("MatterControl.LayerETag");
}
set
{
this["MatterControl.LayerETag"] = value;
}
}
public string ValueOrDefault(string key, string defaultValue = "")
{
string foundValue;
this.TryGetValue(key, out foundValue);
return foundValue ?? defaultValue;
}
public string ValueOrNull(string key)
{
string foundValue;
this.TryGetValue(key, out foundValue);
return foundValue;
}
public static SettingsLayer LoadFromIni(TextReader reader)
{
var layer = new SettingsLayer();
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 SettingsLayer LoadFromIni(string filePath)
{
var settings = from line in File.ReadAllLines(filePath)
let segments = line.Split('=')
where !line.StartsWith("#") && !string.IsNullOrEmpty(line)
select new
{
Key = segments[0].Trim(),
Value = segments[1].Trim()
};
var layer = new SettingsLayer();
foreach (var setting in settings)
{
layer[setting.Key] = setting.Value;
}
return layer;
}
public SettingsLayer Clone()
{
string id = Guid.NewGuid().ToString();
return new SettingsLayer(this as Dictionary<string, string>)
{
ID = id,
Name = this.Name,
ETag = this.ETag,
Source = this.Source
};
}
}
public class ProfileData
{
public ObservableCollection<PrinterInfo> Profiles { get; set; } = new ObservableCollection<PrinterInfo>();
}
public class PrinterInfo
{
public string Make { get; set; } = "Unknown";
public string Model { get; set; } = "Unknown";
public string Name { get; set; }
public string ComPort { get; set; }
public bool AutoConnect { get; set; }
public string Id { get; set; }
public string BaudRate { get; set; }
public string DriverType { get; internal set; }
internal void Delete()
{
throw new NotImplementedException();
}
}
}