2016-07-18 15:20:19 -07:00
/ *
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 .
* /
2016-09-20 09:39:57 -07:00
using System ;
2016-07-18 15:20:19 -07:00
using System.Collections.Generic ;
2016-09-20 09:39:57 -07:00
using System.Collections.ObjectModel ;
using System.Diagnostics ;
using System.IO ;
2016-07-18 15:20:19 -07:00
using System.Linq ;
using System.Runtime.Serialization ;
using System.Text ;
2016-09-20 09:39:57 -07:00
using System.Threading.Tasks ;
using MatterHackers.Agg ;
2017-08-20 02:34:39 -07:00
using MatterHackers.Agg.Platform ;
2016-07-18 15:20:19 -07:00
using MatterHackers.Agg.UI ;
2018-03-12 17:02:18 -07:00
using MatterHackers.DataConverters3D ;
2016-07-18 15:20:19 -07:00
using MatterHackers.Localizations ;
2018-04-03 18:17:27 -07:00
using MatterHackers.MatterControl.ConfigurationPage.PrintLeveling ;
2016-09-20 09:39:57 -07:00
using MatterHackers.MatterControl.ContactForm ;
2018-10-07 11:36:52 -07:00
using MatterHackers.MatterControl.PrinterControls.PrinterConnections ;
2016-09-20 09:39:57 -07:00
using MatterHackers.MatterControl.SettingsManagement ;
2016-07-18 15:20:19 -07:00
using MatterHackers.MeshVisualizer ;
2016-09-20 09:39:57 -07:00
using MatterHackers.VectorMath ;
using Newtonsoft.Json ;
using Newtonsoft.Json.Linq ;
2016-07-18 15:20:19 -07:00
namespace MatterHackers.MatterControl.SlicerConfiguration
{
2018-10-05 09:59:23 -07:00
public enum NamedSettingsLayers { MHBaseSettings , OEMSettings , Quality , Material , User , All }
2016-07-18 15:20:19 -07:00
public class PrinterSettings
{
2016-07-20 15:23:26 -07:00
// Latest version should be in the form of:
2016-07-18 15:20:19 -07:00
// Year|month|day|versionForDay (to support multiple revisions on a given day)
public static int LatestVersion { get ; } = 201606271 ;
2018-10-05 09:55:46 -07:00
// TODO: Change to instance based, revise listeners and register to expect specific printer settings
public static RootedObjectEventHandler SettingChanged = new RootedObjectEventHandler ( ) ;
2018-10-05 16:03:31 -07:00
public event EventHandler MaterialPresetChanged ;
2018-10-05 09:59:23 -07:00
2018-10-05 16:03:31 -07:00
public void OnMaterialPresetChanged ( )
2018-10-05 09:59:23 -07:00
{
MaterialPresetChanged ? . Invoke ( null , null ) ;
}
2018-10-05 09:55:46 -07:00
public static void OnSettingChanged ( string slicerConfigName )
{
SettingChanged . CallEvents ( null , new StringEventArgs ( slicerConfigName ) ) ;
}
2018-10-05 16:03:31 -07:00
public event EventHandler PrintLevelingEnabledChanged ;
2016-07-18 16:18:12 -07:00
2018-10-05 16:03:31 -07:00
public event EventHandler MacrosChanged ;
2018-09-05 07:43:28 -07:00
2016-12-14 17:19:19 -08:00
public static PrinterSettings Empty { get ; }
2016-07-19 12:49:53 -07:00
public int DocumentVersion { get ; set ; } = LatestVersion ;
2016-07-18 15:20:19 -07:00
public string ID { get ; set ; }
2016-08-30 10:41:38 -07:00
private static object writeLock = new object ( ) ;
2016-07-18 15:20:19 -07:00
[JsonIgnore]
internal PrinterSettingsLayer QualityLayer { get ; private set ; }
[JsonIgnore]
internal PrinterSettingsLayer MaterialLayer { get ; private set ; }
2016-11-07 11:24:49 -08:00
public PrinterSettingsLayer StagedUserSettings { get ; set ; } = new PrinterSettingsLayer ( ) ;
2017-09-17 13:30:05 -07:00
internal PrinterConfig printer { get ; set ; }
2016-12-14 17:19:19 -08:00
static PrinterSettings ( )
{
Empty = new PrinterSettings ( ) { ID = "EmptyProfile" } ;
Empty . UserLayer [ SettingsKey . printer_name ] = "Printers..." . Localize ( ) ;
}
2016-07-18 15:20:19 -07:00
public PrinterSettings ( )
{
this . Helpers = new SettingsHelpers ( this ) ;
}
public List < GCodeMacro > Macros { get ; set ; } = new List < GCodeMacro > ( ) ;
2016-12-14 17:19:19 -08:00
2017-01-11 13:22:59 -08:00
/// <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 ;
}
}
2018-09-05 07:43:28 -07:00
internal void NotifyMacrosChanged ( )
{
2018-10-05 16:03:31 -07:00
this . MacrosChanged ? . Invoke ( this , null ) ;
2018-09-05 07:43:28 -07:00
}
2017-01-11 13:22:59 -08:00
/// <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 ) ;
}
}
2017-05-19 14:39:57 -07:00
/// <summary>
2018-09-06 08:19:49 -07:00
/// Determines if a given field should be shown given its filter
2017-05-19 14:39:57 -07:00
/// </summary>
2018-09-06 08:19:49 -07:00
/// <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 )
2017-05-19 14:39:57 -07:00
{
2018-09-06 08:19:49 -07:00
if ( ! string . IsNullOrEmpty ( filter ) )
2017-05-19 14:39:57 -07:00
{
2018-09-06 08:19:49 -07:00
string [ ] splitOnAnd = filter . Split ( '&' ) ;
2017-05-19 14:39:57 -07:00
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 ( '=' ) ;
2018-09-06 07:58:02 -07:00
sliceSettingValue = this . GetValue ( splitOnEquals [ 0 ] ) ;
2017-05-19 14:39:57 -07:00
matchString = splitOnEquals [ 1 ] ;
}
2018-09-02 10:52:25 -07:00
else if ( orItem . Contains ( ">" ) )
{
matchString = "no_match" ;
string [ ] splitOnGreater = orItem . Split ( '>' ) ;
2018-09-06 07:58:02 -07:00
sliceSettingValue = this . GetValue ( splitOnGreater [ 0 ] ) ;
2018-09-02 10:52:25 -07:00
if ( double . TryParse ( sliceSettingValue , out double doubleValue ) )
{
if ( double . TryParse ( splitOnGreater [ 1 ] , out double greater ) )
{
if ( doubleValue > greater )
{
matchString = sliceSettingValue ;
}
}
}
}
2017-05-19 14:39:57 -07:00
else
{
2018-09-06 07:58:02 -07:00
sliceSettingValue = this . GetValue ( orItem ) ;
2017-05-19 14:39:57 -07:00
}
if ( ( ! negate & & sliceSettingValue = = matchString )
| | ( negate & & sliceSettingValue ! = matchString ) )
{
orResult = true ;
}
}
2018-10-24 18:08:41 -07:00
if ( orResult = = false )
2017-05-19 14:39:57 -07:00
{
return false ;
}
}
}
return true ;
}
2017-01-11 13:22:59 -08:00
/// <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 ) ;
}
}
2016-07-18 15:20:19 -07:00
[OnDeserialized]
internal void OnDeserializedMethod ( StreamingContext context )
{
QualityLayer = GetQualityLayer ( ActiveQualityKey ) ;
2018-01-10 14:41:14 -08:00
if ( ! string . IsNullOrEmpty ( ActiveMaterialKey ) )
2016-07-18 15:20:19 -07:00
{
2018-01-10 14:41:14 -08:00
MaterialLayer = GetMaterialLayer ( ActiveMaterialKey ) ;
2016-07-18 15:20:19 -07:00
}
}
public PrinterSettingsLayer OemLayer { get ; set ; }
2016-11-07 12:27:56 -08:00
public void Merge ( PrinterSettingsLayer destinationLayer , PrinterSettings settingsToImport , List < PrinterSettingsLayer > rawSourceFilter , bool setLayerName )
2016-10-05 14:57:31 -07:00
{
HashSet < string > skipKeys = new HashSet < string >
{
"layer_id" ,
} ;
2016-12-20 10:43:39 -08:00
if ( ! setLayerName )
2016-11-07 12:27:56 -08:00
{
skipKeys . Add ( SettingsKey . layer_name ) ;
}
2016-10-05 14:57:31 -07:00
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 ! = keyName
& & ! skipKeys . Contains ( keyName ) )
{
destinationLayer [ keyName ] = importValue ;
}
}
}
2016-11-07 12:27:56 -08:00
if ( setLayerName )
{
destinationLayer [ SettingsKey . layer_name ] = settingsToImport . GetValue ( SettingsKey . layer_name , sourceFilter ) ;
}
2016-10-05 14:57:31 -07:00
this . Save ( ) ;
}
2016-07-18 15:20:19 -07:00
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
{
2016-12-20 10:43:39 -08:00
return GetValue ( SettingsKey . active_quality_key ) ;
2016-07-18 15:20:19 -07:00
}
internal set
{
2016-12-20 10:43:39 -08:00
SetValue ( SettingsKey . active_quality_key , value ) ;
2016-07-18 15:20:19 -07:00
QualityLayer = GetQualityLayer ( value ) ;
Save ( ) ;
}
}
2018-01-10 12:55:41 -08:00
public string ActiveMaterialKey
{
get
{
2018-01-10 14:56:33 -08:00
if ( MaterialSettingsKeys . Count > 0 )
{
return MaterialSettingsKeys [ 0 ] ;
}
return null ;
2018-01-10 12:55:41 -08:00
}
internal set
{
SetMaterialPreset ( 0 , value ) ;
}
}
private void SetMaterialPreset ( int extruderIndex , string materialKey )
2016-07-18 15:20:19 -07:00
{
2017-06-13 17:22:49 -07:00
if ( extruderIndex > = PrinterCommunication . PrinterConnection . MAX_EXTRUDERS )
2016-07-18 15:20:19 -07:00
{
throw new ArgumentOutOfRangeException ( "Requested extruder index is outside of bounds: " + extruderIndex ) ;
}
2016-07-19 13:28:10 -07:00
// TODO: This should really be in PrinterProfile and should be run when the extruder count changes
2016-07-18 15:20:19 -07:00
if ( MaterialSettingsKeys . Count < = extruderIndex )
{
var resizedArray = new string [ extruderIndex + 1 ] ;
MaterialSettingsKeys . CopyTo ( resizedArray ) ;
MaterialSettingsKeys = new List < string > ( resizedArray ) ;
}
MaterialSettingsKeys [ extruderIndex ] = materialKey ;
if ( extruderIndex = = 0 )
{
MaterialLayer = GetMaterialLayer ( materialKey ) ;
2017-06-10 11:24:21 -07:00
2018-10-05 16:03:31 -07:00
this . OnMaterialPresetChanged ( ) ;
2016-07-18 15:20:19 -07:00
}
Save ( ) ;
}
public List < string > MaterialSettingsKeys { get ; set ; } = new List < string > ( ) ;
2017-06-04 16:17:30 -07:00
[JsonIgnore]
2017-06-02 17:04:02 -07:00
public string DocumentPath = > ProfileManager . Instance . ProfilePath ( this . ID ) ;
2016-07-18 15:20:19 -07:00
2016-12-20 10:43:39 -08:00
[JsonIgnore]
public bool AutoSave { get ; set ; } = true ;
2018-10-24 18:08:41 -07:00
Dictionary < string , string > blackListSettings = new Dictionary < string , string > ( )
{
["spiral_vase"] = "0" ,
["bottom_clip_amount"] = "0" ,
["layer_to_pause"] = "" ,
["print_leveling_data"] = "" ,
["print_leveling_enabled"] = "0" ,
["probe_has_been_calibrated"] = "0"
} ;
public void Save ( bool clearBlackListSettings = false )
2016-07-18 15:20:19 -07:00
{
2016-08-31 18:49:29 -07:00
// Skip save operation if on the EmptyProfile
2016-12-20 10:43:39 -08:00
if ( ! this . PrinterSelected | | ! this . AutoSave )
2016-08-31 18:49:29 -07:00
{
return ;
}
2018-10-24 18:08:41 -07:00
if ( clearBlackListSettings )
{
2018-10-24 18:43:27 -07:00
foreach ( var kvp in blackListSettings )
2018-10-24 18:08:41 -07:00
{
2018-10-24 18:43:27 -07:00
if ( UserLayer . ContainsKey ( kvp . Key ) )
{
UserLayer . Remove ( kvp . Key ) ;
}
OemLayer [ kvp . Key ] = kvp . Value ;
2018-10-24 18:08:41 -07:00
}
}
2016-12-20 10:43:39 -08:00
Save ( DocumentPath ) ;
}
public void Save ( string filePath )
{
2016-08-30 10:41:38 -07:00
lock ( writeLock )
{
2016-10-30 11:47:26 -07:00
string json = this . ToJson ( ) ;
var printerInfo = ProfileManager . Instance [ this . ID ] ;
if ( printerInfo ! = null )
{
2018-03-12 17:02:18 -07:00
printerInfo . ContentSHA1 = this . ComputeSHA1 ( json ) ;
2016-10-30 11:47:26 -07:00
ProfileManager . Instance . Save ( ) ;
}
2016-12-20 10:43:39 -08:00
File . WriteAllText ( filePath , json ) ;
2016-08-30 10:41:38 -07:00
}
2016-07-18 15:20:19 -07:00
2018-10-05 09:24:57 -07:00
if ( ApplicationController . Instance . ActivePrinter . Settings . ID = = this . ID )
2016-07-18 15:20:19 -07:00
{
2018-10-05 09:34:43 -07:00
ApplicationController . Instance . ActiveProfileModified . CallEvents ( null , null ) ;
2016-07-18 15:20:19 -07:00
}
}
2018-03-12 17:02:18 -07:00
internal string ComputeSHA1 ( )
2016-09-20 09:39:57 -07:00
{
2018-03-12 17:02:18 -07:00
return ComputeSHA1 ( this . ToJson ( ) ) ;
2016-09-20 09:39:57 -07:00
}
2018-03-12 17:02:18 -07:00
private string ComputeSHA1 ( string json )
2016-09-20 09:39:57 -07:00
{
// SHA1 value is based on UTF8 encoded file contents
using ( var memoryStream = new MemoryStream ( Encoding . UTF8 . GetBytes ( json ) ) )
{
2018-03-12 17:02:18 -07:00
return Object3D . ComputeSHA1 ( memoryStream ) ;
2016-09-20 09:39:57 -07:00
}
}
2016-07-18 15:20:19 -07:00
/// <summary>
/// User settings overrides
/// </summary>
public PrinterSettingsLayer UserLayer { get ; } = new PrinterSettingsLayer ( ) ;
2016-08-10 09:44:50 -07:00
public static PrinterSettings LoadFile ( string printerProfilePath , bool performMigrations = false )
2016-07-18 15:20:19 -07:00
{
2016-08-10 09:44:50 -07:00
if ( performMigrations )
2016-07-18 15:20:19 -07:00
{
2016-08-10 09:44:50 -07:00
JObject jObject = null ;
2016-07-19 15:29:14 -07:00
2016-08-10 09:44:50 -07:00
try
2016-07-19 13:27:20 -07:00
{
2016-08-10 09:44:50 -07:00
jObject = JObject . Parse ( File . ReadAllText ( printerProfilePath ) ) ;
2016-07-19 13:27:20 -07:00
}
2016-08-10 09:44:50 -07:00
catch
2016-07-19 13:27:20 -07:00
{
2016-08-10 09:44:50 -07:00
return null ;
2016-07-19 13:27:20 -07:00
}
2016-07-18 15:20:19 -07:00
2016-08-10 09:44:50 -07:00
int documentVersion = jObject ? . GetValue ( "DocumentVersion" ) ? . Value < int > ( ) ? ? PrinterSettings . LatestVersion ;
if ( documentVersion < PrinterSettings . LatestVersion )
{
printerProfilePath = ProfileMigrations . MigrateDocument ( printerProfilePath , documentVersion ) ;
}
2016-07-18 15:20:19 -07:00
}
try
{
return JsonConvert . DeserializeObject < PrinterSettings > ( File . ReadAllText ( printerProfilePath ) ) ;
}
catch
{
2016-08-10 09:44:50 -07:00
return null ;
2016-07-19 15:29:14 -07:00
}
}
2016-08-10 09:44:50 -07:00
public async static Task < PrinterSettings > RecoverProfile ( PrinterInfo printerInfo )
{
2018-10-07 11:36:52 -07:00
bool userIsLoggedIn = ! ApplicationController . GuestUserActive ? . Invoke ( ) ? ? false ;
2016-08-10 09:44:50 -07:00
if ( userIsLoggedIn & & printerInfo ! = null )
{
// Attempt to load from MCWS history
2016-08-11 10:35:23 -07:00
var printerSettings = await GetFirstValidHistoryItem ( printerInfo ) ;
2016-08-10 09:44:50 -07:00
if ( printerSettings = = null )
{
// Fall back to OemProfile defaults if load from history fails
printerSettings = RestoreFromOemProfile ( printerInfo ) ;
}
2016-08-12 13:20:05 -07:00
if ( printerSettings = = null )
{
// If we still have failed to recover a profile, create an empty profile with
// just enough data to delete the printer
2016-12-14 17:19:19 -08:00
printerSettings = PrinterSettings . Empty ;
2016-08-12 13:20:05 -07:00
printerSettings . ID = printerInfo . ID ;
printerSettings . UserLayer [ SettingsKey . device_token ] = printerInfo . DeviceToken ;
printerSettings . Helpers . SetComPort ( printerInfo . ComPort ) ;
printerSettings . SetValue ( SettingsKey . printer_name , printerInfo . Name ) ;
// Add any setting value to the OemLayer to pass the .PrinterSelected property
printerSettings . OemLayer = new PrinterSettingsLayer ( ) ;
printerSettings . OemLayer . Add ( "empty" , "setting" ) ;
printerSettings . Save ( ) ;
}
2016-08-10 09:44:50 -07:00
if ( printerSettings ! = null )
{
// Persist any profile recovered above as the current
printerSettings . Save ( ) ;
WarnAboutRevert ( printerInfo ) ;
}
return printerSettings ;
}
return null ;
}
private static bool warningWindowOpen = false ;
2016-07-19 17:21:59 -07:00
public static void WarnAboutRevert ( PrinterInfo profile )
2018-03-12 15:26:29 -07:00
{
2016-08-10 09:44:50 -07:00
if ( ! warningWindowOpen )
2016-07-19 15:29:14 -07:00
{
2016-08-10 09:44:50 -07:00
warningWindowOpen = true ;
2016-07-19 15:29:14 -07:00
UiThread . RunOnIdle ( ( ) = >
{
2018-03-12 15:26:29 -07:00
StyledMessageBox . ShowMessageBox ( ( clicedOk ) = >
2016-07-19 15:29:14 -07:00
{
2016-08-10 09:44:50 -07:00
warningWindowOpen = false ;
2018-10-26 14:51:04 -07:00
} ,
"The profile you are attempting to load has been corrupted. We loaded your last usable {0} {1} profile from your recent profile history instead." . Localize ( )
. FormatWith ( profile . Make , profile . Model ) ,
"Recovered printer profile" . Localize ( ) ,
messageType : StyledMessageBox . MessageType . OK ) ;
2016-07-19 15:29:14 -07:00
} ) ;
2016-07-18 15:20:19 -07:00
}
}
2018-10-05 16:03:31 -07:00
internal void OnPrintLevelingEnabledChanged ( object s , EventArgs e )
{
PrintLevelingEnabledChanged ? . Invoke ( s , e ) ;
}
2016-08-10 09:44:50 -07:00
public static PrinterSettings RestoreFromOemProfile ( PrinterInfo profile )
2016-07-18 15:20:19 -07:00
{
2016-08-12 13:18:45 -07:00
PrinterSettings oemProfile = null ;
2016-07-19 13:27:20 -07:00
2016-08-12 13:18:45 -07:00
try
{
2016-09-01 17:24:09 -07:00
var publicDevice = OemSettings . Instance . OemProfiles [ profile . Make ] [ profile . Model ] ;
string cacheScope = Path . Combine ( "public-profiles" , profile . Make ) ;
string publicProfileToLoad = ApplicationController . CacheablePath ( cacheScope , publicDevice . CacheKey ) ;
2016-07-18 15:20:19 -07:00
2016-08-12 13:18:45 -07:00
oemProfile = JsonConvert . DeserializeObject < PrinterSettings > ( File . ReadAllText ( publicProfileToLoad ) ) ;
oemProfile . ID = profile . ID ;
oemProfile . SetValue ( SettingsKey . printer_name , profile . Name ) ;
oemProfile . DocumentVersion = PrinterSettings . LatestVersion ;
2016-07-18 15:20:19 -07:00
2016-08-12 13:18:45 -07:00
oemProfile . Helpers . SetComPort ( profile . ComPort ) ;
oemProfile . Save ( ) ;
}
catch { }
2016-08-10 09:44:50 -07:00
2016-07-18 15:20:19 -07:00
return oemProfile ;
}
2016-08-11 10:35:23 -07:00
private static async Task < PrinterSettings > GetFirstValidHistoryItem ( PrinterInfo printerInfo )
2016-07-19 13:27:20 -07:00
{
2016-10-28 16:31:50 -07:00
var recentProfileHistoryItems = await ApplicationController . GetProfileHistory ? . Invoke ( printerInfo . DeviceToken ) ;
2016-07-19 15:29:14 -07:00
if ( recentProfileHistoryItems ! = null )
2016-07-19 13:27:20 -07:00
{
2016-08-11 10:35:23 -07:00
// Iterate history, skipping the first item, limiting to the next five, attempt to load and return the first success
foreach ( var keyValue in recentProfileHistoryItems . OrderByDescending ( kvp = > kvp . Key ) . Skip ( 1 ) . Take ( 5 ) )
{
// Attempt to download and parse each profile, returning if successful
try
{
var printerSettings = await ApplicationController . GetPrinterProfileAsync ( printerInfo , keyValue . Value ) ;
if ( printerSettings ! = null )
{
return printerSettings ;
}
}
catch { }
2018-09-05 13:51:03 -07:00
}
2016-07-19 13:27:20 -07:00
}
2016-08-10 09:44:50 -07:00
return null ;
2016-07-18 15:20:19 -07:00
}
/// <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 "" ;
}
2018-06-05 16:15:20 -07:00
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
2018-09-06 08:19:49 -07:00
& & firstPresetValue ! = null
2018-06-05 16:15:20 -07:00
& & firstPresetValue ! = currentValue ;
bool differsFromBase = currentValue ! = firstBaseValue ;
2018-09-06 08:19:49 -07:00
return currentValue ! = null
2018-06-05 16:15:20 -07:00
& & ( differsFromPreset | | differsFromBase ) ;
}
2018-06-05 16:15:40 -07:00
// 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 ;
}
2018-01-14 10:36:05 -08:00
public ( string currentValue , string layerName ) GetValueAndLayerName ( string sliceSetting , IEnumerable < PrinterSettingsLayer > layerCascade = null )
2017-03-02 13:45:03 -08:00
{
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" ;
}
2018-01-14 10:36:05 -08:00
return ( value , layerName ) ;
2017-03-02 13:45:03 -08:00
}
}
2018-01-14 10:36:05 -08:00
return ( "" , "" ) ;
2017-03-02 13:45:03 -08:00
}
2016-08-10 16:38:58 -07:00
public bool Contains ( string sliceSetting , IEnumerable < PrinterSettingsLayer > layerCascade = null )
{
if ( layerCascade = = null )
{
layerCascade = defaultLayerCascade ;
}
foreach ( PrinterSettingsLayer layer in layerCascade )
{
2016-08-11 13:01:34 -07:00
if ( layer . ContainsKey ( sliceSetting ) )
2016-08-10 16:38:58 -07:00
{
return true ;
}
}
return false ;
}
2016-07-18 15:20:19 -07:00
[JsonIgnore]
2017-09-19 11:42:46 -07:00
PrinterSettingsLayer _baseLayer ;
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 ;
}
}
2016-07-18 15:20:19 -07:00
2017-03-02 13:45:03 -08:00
internal IEnumerable < PrinterSettingsLayer > defaultLayerCascade
2016-07-18 15:20:19 -07:00
{
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 ;
}
}
2016-07-19 12:49:53 -07:00
[JsonIgnore]
2016-07-18 15:20:19 -07:00
public SettingsHelpers Helpers { get ; set ; }
2016-12-14 14:40:24 -08:00
2016-07-19 12:49:53 -07:00
[JsonIgnore]
2016-07-18 15:20:19 -07:00
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 ) ) ;
2016-09-23 18:11:31 -07:00
// Print leveling data has no SliceSettingsWidget editor but should be removed on 'Reset to Defaults'
keysToRetain . Remove ( SettingsKey . print_leveling_data ) ;
2016-09-27 12:47:15 -07:00
keysToRetain . Remove ( SettingsKey . print_leveling_enabled ) ;
2016-09-23 18:11:31 -07:00
2016-07-20 14:04:54 -07:00
// Iterate all items that have .ShowAsOverride = false and conditionally add to the retention list
2018-01-13 18:54:40 -08:00
foreach ( var item in SettingsOrganizer . SettingsData . Values . Where ( settingsItem = > settingsItem . ShowAsOverride = = false ) )
2016-07-18 15:20:19 -07:00
{
switch ( item . SlicerConfigName )
{
case SettingsKey . baud_rate :
case SettingsKey . auto_connect :
2016-07-20 14:04:54 -07:00
// Items *should* reset to defaults
2016-07-18 15:20:19 -07:00
break ;
default :
2016-07-20 14:04:54 -07:00
//Items should *not* reset to defaults
2016-07-18 15:20:19 -07:00
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 ) ;
}
}
2018-03-12 15:26:29 -07:00
#region Migrate to LayeredProfile
2016-07-18 15:20:19 -07:00
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
2017-09-06 18:16:45 -07:00
if ( typeof ( T ) = = typeof ( string ) )
{
2018-07-12 22:49:39 -07:00
// this way we can use the common pattern without error
2017-09-06 18:16:45 -07:00
return ( T ) ( object ) this . GetValue ( settingsKey ) ;
}
2018-04-03 18:17:27 -07:00
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 ) ;
2018-04-28 16:59:21 -07:00
case "100 Point Disk" :
return ( T ) ( object ) ( LevelingSystem . Probe100PointRadial ) ;
2018-04-03 18:17:27 -07:00
case "3x3 Mesh" :
return ( T ) ( object ) ( LevelingSystem . Probe3x3Mesh ) ;
2018-04-04 13:45:10 -07:00
case "5x5 Mesh" :
return ( T ) ( object ) ( LevelingSystem . Probe5x5Mesh ) ;
2018-04-27 18:28:49 -07:00
case "10x10 Mesh" :
return ( T ) ( object ) ( LevelingSystem . Probe10x10Mesh ) ;
2018-08-27 14:57:55 -07:00
case "Custom Points" :
return ( T ) ( object ) ( LevelingSystem . ProbeCustom ) ;
2018-04-03 18:17:27 -07:00
default :
#if DEBUG
throw new NotImplementedException ( ) ;
2018-04-04 15:05:06 -07:00
#else
break ;
2018-04-03 18:17:27 -07:00
#endif
}
return ( T ) ( object ) ( LevelingSystem . Probe3Points ) ;
}
2017-09-06 18:16:45 -07:00
else if ( typeof ( T ) = = typeof ( bool ) )
2016-07-18 15:20:19 -07:00
{
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 )
{
2018-10-26 14:51:04 -07:00
throw new Exception ( "Not parsing {0} as a Vector2" . FormatWith ( settingsKey ) ) ;
2016-07-18 15:20:19 -07:00
}
Vector2 valueAsVector2 = new Vector2 ( ) ;
2017-10-31 12:51:16 -07:00
valueAsVector2 . X = Helpers . ParseDouble ( twoValues [ 0 ] ) ;
valueAsVector2 . Y = Helpers . ParseDouble ( twoValues [ 1 ] ) ;
2016-07-18 15:20:19 -07:00
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 ) ;
}
2018-03-12 15:26:29 -07:00
else if ( settingsKey = = SettingsKey . first_layer_extrusion_width
2017-02-27 10:23:11 -08:00
| | settingsKey = = SettingsKey . external_perimeter_extrusion_width )
2016-07-18 15:20:19 -07:00
{
return ( T ) ( object ) ( GetValue < double > ( SettingsKey . nozzle_diameter ) * ratio ) ;
}
return ( T ) ( object ) ( ratio ) ;
}
2017-02-27 10:23:11 -08:00
else if ( settingsKey = = SettingsKey . first_layer_extrusion_width
| | settingsKey = = SettingsKey . external_perimeter_extrusion_width )
2016-07-18 15:20:19 -07:00
{
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
2018-10-26 14:51:04 -07:00
throw new NotImplementedException ( "{0} is not a known bed_shape." . FormatWith ( GetValue ( SettingsKey . bed_shape ) ) ) ;
2016-07-18 15:20:19 -07:00
#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 )
{
2017-10-30 21:59:43 -07:00
// Add key/value to accumulating string for hash
2018-01-13 18:54:40 -08:00
SliceSettingData data = SettingsOrganizer . Instance . GetSettingsData ( keyValue . Key ) ;
2017-10-30 21:59:43 -07:00
if ( data ? . RebuildGCodeOnChange = = true )
2017-09-22 16:31:49 -07:00
{
2017-10-30 21:59:43 -07:00
bigStringForHashCode . Append ( keyValue . Key ) ;
bigStringForHashCode . Append ( this . GetValue ( keyValue . Key ) ) ;
2016-07-18 15:20:19 -07:00
}
}
return agg_basics . ComputeHash ( bigStringForHashCode . ToString ( ) ) ;
}
2018-10-26 14:51:04 -07:00
string GetSettingsLocation ( string settingsKey )
{
var settingData = SettingsOrganizer . Instance . GetSettingsData ( settingsKey ) ;
var setingsSectionName = settingData . OrganizerSubGroup . Group . Category . SettingsSection . Name ;
var rootLevel = SettingsOrganizer . Instance . UserLevels [ setingsSectionName ] ;
var subGroup = rootLevel . GetContainerForSetting ( settingsKey ) ;
var category = subGroup . Group . Category ;
if ( setingsSectionName = = "Advanced" )
{
setingsSectionName = "Slice Settings" ;
}
var location = "Location" . Localize ( ) + ":" ;
location + = "\n" + setingsSectionName . Localize ( ) ;
location + = "\n • " + category . Name . Localize ( ) ;
location + = "\n • " + subGroup . Group . Name . Localize ( ) ;
location + = "\n • " + settingData . PresentationName . Localize ( ) ;
return location ;
}
string GetSettingsName ( string settingsKey )
{
var settingData = SettingsOrganizer . Instance . GetSettingsData ( settingsKey ) ;
return settingData . PresentationName . Localize ( ) ;
}
2016-07-18 15:20:19 -07:00
public bool IsValid ( )
{
try
{
2017-08-21 15:45:43 -07:00
if ( GetValue < bool > ( SettingsKey . validate_layer_height ) )
2016-07-18 15:20:19 -07:00
{
2017-08-21 15:45:43 -07:00
if ( GetValue < double > ( SettingsKey . layer_height ) > GetValue < double > ( SettingsKey . nozzle_diameter ) )
{
2018-10-26 14:51:04 -07:00
var error = "{0} must be less than or equal to the {1}." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . layer_height ) , GetSettingsName ( SettingsKey . nozzle_diameter ) ) ;
var details = "{0} = {1}\n{2} = {3}" . FormatWith ( GetSettingsName ( SettingsKey . layer_height ) ,
GetValue < double > ( SettingsKey . layer_height ) ,
GetSettingsName ( SettingsKey . nozzle_diameter ) ,
GetValue < double > ( SettingsKey . nozzle_diameter ) ) ;
var location = GetSettingsLocation ( SettingsKey . layer_height ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}"
. FormatWith ( error , details , location ) , "Slice Error" . Localize ( ) ) ;
return false ;
}
else if ( GetValue < double > ( SettingsKey . layer_height ) < = 0 )
{
var error = "{0} must be greate than 0." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . layer_height ) ) ;
var location = GetSettingsLocation ( SettingsKey . layer_height ) ;
StyledMessageBox . ShowMessageBox ( $"{error}\n\n{location}" , "Slice Error" . Localize ( ) ) ;
2017-08-21 15:45:43 -07:00
return false ;
}
else if ( GetValue < double > ( SettingsKey . first_layer_height ) > GetValue < double > ( SettingsKey . nozzle_diameter ) )
{
2018-10-26 14:51:04 -07:00
var error = "{0} must be less than or equal to the {1}." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . layer_height ) ,
GetSettingsName ( SettingsKey . nozzle_diameter ) ) ;
var details = "{0} = {1}\n{2} = {3}" . FormatWith (
GetSettingsName ( SettingsKey . first_layer_height ) ,
GetValue < double > ( SettingsKey . first_layer_height ) ,
GetSettingsName ( SettingsKey . nozzle_diameter ) ,
GetValue < double > ( SettingsKey . nozzle_diameter ) ) ;
var location = GetSettingsLocation ( SettingsKey . first_layer_height ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}" . FormatWith ( error , details , location ) , "Slice Error" . Localize ( ) ) ;
2017-08-21 15:45:43 -07:00
return false ;
}
2016-07-18 15:20:19 -07:00
}
2016-10-05 11:06:40 -07:00
// Print recovery can only work with a manually leveled or software leveled bed. Hardware leveling does not work.
if ( GetValue < bool > ( SettingsKey . recover_is_enabled ) )
{
2017-06-29 09:47:34 -07:00
string [ ] startGCode = GetValue ( SettingsKey . start_gcode ) . Replace ( "\\n" , "\n" ) . Split ( '\n' ) ;
2016-10-05 11:06:40 -07:00
foreach ( string startGCodeLine in startGCode )
{
if ( startGCodeLine . StartsWith ( "G29" ) )
{
2018-10-26 14:51:04 -07:00
var location = GetSettingsLocation ( SettingsKey . start_gcode ) ;
var error = "Start G-Code cannot contain G29 if Print Recovery is enabled." . Localize ( ) ;
var details = "Your Start G-Code should not contain a G29 if you are planning on using Print Recovery. Change your start G-Code or turn off Print Recovery." . Localize ( ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}" . FormatWith ( error , details , location ) , "Slice Error" . Localize ( ) ) ;
2016-10-05 11:06:40 -07:00
return false ;
}
if ( startGCodeLine . StartsWith ( "G30" ) )
{
2018-10-26 14:51:04 -07:00
var location = GetSettingsLocation ( SettingsKey . start_gcode ) ;
var error = "Start G-Code cannot contain G30 if Print Leveling is enabled." . Localize ( ) ;
var details = "Your Start G-Code should not contain a G30 if you are planning on using Print Recovery. Change your start G-Code or turn off Print Recovery." . Localize ( ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}" . FormatWith ( error , details , location ) , "Slice Error" . Localize ( ) ) ;
2016-10-05 11:06:40 -07:00
return false ;
}
}
}
2016-07-18 15:20:19 -07:00
// If we have print leveling turned on then make sure we don't have any leveling commands in the start gcode.
2016-09-27 12:47:15 -07:00
if ( GetValue < bool > ( SettingsKey . print_leveling_enabled ) )
2016-07-18 15:20:19 -07:00
{
2017-06-29 09:47:34 -07:00
string [ ] startGCode = GetValue ( SettingsKey . start_gcode ) . Replace ( "\\n" , "\n" ) . Split ( '\n' ) ;
2016-07-18 15:20:19 -07:00
foreach ( string startGCodeLine in startGCode )
{
if ( startGCodeLine . StartsWith ( "G29" ) )
{
2018-10-26 14:51:04 -07:00
var location = GetSettingsLocation ( SettingsKey . start_gcode ) ;
var error = "Start G-Code cannot contain G29 if Print Leveling is enabled." . Localize ( ) ;
var 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 ( ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}" . FormatWith ( error , details , location ) , "Slice Error" . Localize ( ) ) ;
2016-07-18 15:20:19 -07:00
return false ;
}
if ( startGCodeLine . StartsWith ( "G30" ) )
{
2018-10-26 14:51:04 -07:00
var location = GetSettingsLocation ( SettingsKey . start_gcode ) ;
var error = "Start G-Code cannot contain G30 if Print Leveling is enabled." . Localize ( ) ;
var 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 ( ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}" . FormatWith ( error , details , location ) , "Slice Error" . Localize ( ) ) ;
2016-07-18 15:20:19 -07:00
return false ;
}
}
}
2017-06-07 15:56:02 -07:00
// If we have print leveling turned on then make sure we don't have any leveling commands in the start gcode.
if ( Math . Abs ( GetValue < double > ( SettingsKey . baby_step_z_offset ) ) > 2 )
{
2018-10-26 14:51:04 -07:00
var location = "Location" . Localize ( ) + ":" ;
location + = "\n" + "Controls" . Localize ( ) ;
location + = "\n • " + "Movement" . Localize ( ) ;
location + = "\n • " + "Z Offset" . Localize ( ) ;
var error = "Z Offset is too large." . Localize ( ) ;
var details = "The Z Offset for your printer, sometimes called Baby Stepping, is greater than 2mm and invalid. Clear the value and re-level the bed." . Localize ( ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}" . FormatWith ( error , details , location ) , "Calibration Error" . Localize ( ) ) ;
2017-06-07 15:56:02 -07:00
return false ;
}
2016-07-18 15:20:19 -07:00
if ( GetValue < double > ( SettingsKey . first_layer_extrusion_width ) > GetValue < double > ( SettingsKey . nozzle_diameter ) * 4 )
{
2018-10-26 14:51:04 -07:00
var error = "{0} must be less than or equal to the {1} * 4." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . first_layer_extrusion_width ) ,
GetSettingsName ( SettingsKey . nozzle_diameter ) ) ;
var details = "{0} = {1}\n{2} = {3}" . FormatWith (
GetSettingsName ( SettingsKey . first_layer_extrusion_width ) ,
GetValue < double > ( SettingsKey . first_layer_extrusion_width ) ,
GetSettingsName ( SettingsKey . nozzle_diameter ) ,
GetValue < double > ( SettingsKey . nozzle_diameter ) ) ;
string location = GetSettingsLocation ( SettingsKey . first_layer_extrusion_width ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}" . FormatWith ( error , details , location ) , "Slice Error" . Localize ( ) ) ;
2016-07-18 15:20:19 -07:00
return false ;
}
if ( GetValue < double > ( SettingsKey . first_layer_extrusion_width ) < = 0 )
{
2018-10-26 14:51:04 -07:00
var error = "{0} must be greater than 0." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . first_layer_extrusion_width ) ) ;
var details = "{0} = {1}" . FormatWith (
GetSettingsName ( SettingsKey . first_layer_extrusion_width ) ,
GetValue < double > ( SettingsKey . first_layer_extrusion_width ) ) ;
string location = GetSettingsLocation ( SettingsKey . first_layer_extrusion_width ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}" . FormatWith ( error , details , location ) , "Slice Error" . Localize ( ) ) ;
2016-07-18 15:20:19 -07:00
return false ;
}
2017-01-30 16:45:39 -08:00
if ( GetValue < double > ( SettingsKey . external_perimeter_extrusion_width ) > GetValue < double > ( SettingsKey . nozzle_diameter ) * 4 )
{
2018-10-26 14:51:04 -07:00
var error = "{0} must be less than or equal to the {1} * 4." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . external_perimeter_extrusion_width ) ,
GetSettingsName ( SettingsKey . nozzle_diameter ) ) ;
var details = "{0} = {1}\n{2} = {3}" . FormatWith (
GetSettingsName ( SettingsKey . external_perimeter_extrusion_width ) ,
GetValue < double > ( SettingsKey . external_perimeter_extrusion_width ) ,
GetSettingsName ( SettingsKey . nozzle_diameter ) ,
GetValue < double > ( SettingsKey . nozzle_diameter ) ) ;
string location = GetSettingsLocation ( SettingsKey . external_perimeter_extrusion_width ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}" . FormatWith ( error , details , location ) , "Slice Error" . Localize ( ) ) ;
2017-01-30 16:45:39 -08:00
return false ;
}
if ( GetValue < double > ( SettingsKey . external_perimeter_extrusion_width ) < = 0 )
{
2018-10-26 14:51:04 -07:00
var error = "{0} must be greater than 0." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . external_perimeter_extrusion_width ) ) ;
var details = "{0} = {1}" . FormatWith (
GetSettingsName ( SettingsKey . external_perimeter_extrusion_width ) ,
GetValue < double > ( SettingsKey . external_perimeter_extrusion_width ) ) ;
var location = GetSettingsLocation ( SettingsKey . external_perimeter_extrusion_width ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}" . FormatWith ( error , details , location ) , "Slice Error" . Localize ( ) ) ;
2017-01-30 16:45:39 -08:00
return false ;
}
2016-07-18 15:20:19 -07:00
if ( GetValue < double > ( SettingsKey . min_fan_speed ) > 100 )
{
2018-10-26 14:51:04 -07:00
var error = "The {0} can only go as high as 100%." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . min_fan_speed ) ) ;
var details = "It is currently set to {0}." . Localize ( ) . FormatWith (
GetValue < double > ( SettingsKey . min_fan_speed ) ) ;
var location = GetSettingsLocation ( SettingsKey . min_fan_speed ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}" . FormatWith ( error , details , location ) , "Slice Error" . Localize ( ) ) ;
2016-07-18 15:20:19 -07:00
return false ;
}
2018-10-26 14:51:04 -07:00
if ( GetValue < double > ( SettingsKey . max_fan_speed ) > 100 )
2016-07-18 15:20:19 -07:00
{
2018-10-26 14:51:04 -07:00
var error = "The {0} can only go as high as 100%." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . max_fan_speed ) ) ;
var details = "It is currently set to {0}." . Localize ( ) . FormatWith (
GetValue < double > ( SettingsKey . max_fan_speed ) ) ;
var location = GetSettingsLocation ( SettingsKey . max_fan_speed ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}" . FormatWith ( error , details , location ) , "Slice Error" . Localize ( ) ) ;
2016-07-18 15:20:19 -07:00
return false ;
}
if ( GetValue < int > ( SettingsKey . extruder_count ) < 1 )
{
2018-10-26 14:51:04 -07:00
var error = "The {0} must be at least 1." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . extruder_count ) ) ;
var details = "It is currently set to {0}." . Localize ( ) . FormatWith (
GetValue < int > ( SettingsKey . extruder_count ) ) ;
var location = GetSettingsLocation ( SettingsKey . extruder_count ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}" . FormatWith ( error , details , location ) , "Slice Error" . Localize ( ) ) ;
2016-07-18 15:20:19 -07:00
return false ;
}
if ( GetValue < double > ( SettingsKey . fill_density ) < 0 | | GetValue < double > ( SettingsKey . fill_density ) > 1 )
{
2018-10-26 14:51:04 -07:00
var error = "The {0} must be between 0 and 1." . Localize ( ) . FormatWith (
GetSettingsName ( SettingsKey . fill_density ) ) ;
var details = "It is currently set to {0}." . Localize ( ) . FormatWith (
GetValue < double > ( SettingsKey . fill_density ) ) ;
var location = GetSettingsLocation ( SettingsKey . filament_density ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}" . FormatWith ( error , details , location ) , "Slice Error" . Localize ( ) ) ;
2016-07-18 15:20:19 -07:00
return false ;
}
if ( GetValue < double > ( SettingsKey . fill_density ) = = 1
2018-10-26 14:51:04 -07:00
& & GetValue ( SettingsKey . infill_type ) ! = "LINES" )
2016-07-18 15:20:19 -07:00
{
2018-10-26 14:51:04 -07:00
var error = "{0} works best when set to LINES." . Localize ( )
. FormatWith ( GetSettingsName ( SettingsKey . infill_type ) ) ;
var details = "It is currently set to {0}." . Localize ( ) . FormatWith (
GetValue ( SettingsKey . infill_type ) ) ;
var location = GetSettingsLocation ( SettingsKey . infill_type ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}" . FormatWith ( error , details , location ) , "Slice Error" . Localize ( ) ) ;
2016-07-18 15:20:19 -07:00
return true ;
}
// If the given speed is part of the current slice engine then check that it is greater than 0.
2018-10-26 14:51:04 -07:00
if ( ! ValidateGoodSpeedSettingGreaterThan0 ( "bridge_speed" ) ) return false ;
if ( ! ValidateGoodSpeedSettingGreaterThan0 ( "air_gap_speed" ) ) return false ;
if ( ! ValidateGoodSpeedSettingGreaterThan0 ( "external_perimeter_speed" ) ) return false ;
if ( ! ValidateGoodSpeedSettingGreaterThan0 ( SettingsKey . first_layer_speed ) ) return false ;
if ( ! ValidateGoodSpeedSettingGreaterThan0 ( "infill_speed" ) ) return false ;
if ( ! ValidateGoodSpeedSettingGreaterThan0 ( "perimeter_speed" ) ) return false ;
if ( ! ValidateGoodSpeedSettingGreaterThan0 ( "small_perimeter_speed" ) ) return false ;
if ( ! ValidateGoodSpeedSettingGreaterThan0 ( "solid_infill_speed" ) ) return false ;
if ( ! ValidateGoodSpeedSettingGreaterThan0 ( "support_material_speed" ) ) return false ;
if ( ! ValidateGoodSpeedSettingGreaterThan0 ( SettingsKey . top_solid_infill_speed ) ) return false ;
if ( ! ValidateGoodSpeedSettingGreaterThan0 ( "travel_speed" ) ) return false ;
if ( ! ValidateGoodSpeedSettingGreaterThan0 ( "retract_speed" ) ) return false ;
2016-07-18 15:20:19 -07:00
}
catch ( Exception e )
{
Debug . Print ( e . Message ) ;
GuiWidget . BreakInDebugger ( ) ;
string stackTraceNoBackslashRs = e . StackTrace . Replace ( "\r" , "" ) ;
2018-05-03 06:49:25 -07:00
2018-05-03 10:49:47 -07:00
var widget = new ContactFormPage ( ) ;
2018-05-03 06:49:25 -07:00
widget . questionInput . Text = "Parse Error while slicing" . Localize ( ) ;
widget . detailInput . Text = e . Message + stackTraceNoBackslashRs ;
DialogWindow . Show ( widget ) ;
2016-07-18 15:20:19 -07:00
return false ;
}
return true ;
}
2018-10-26 14:51:04 -07:00
private bool ValidateGoodSpeedSettingGreaterThan0 ( string speedSetting )
2016-07-18 15:20:19 -07:00
{
2018-10-26 14:51:04 -07:00
var actualSpeedValueString = GetValue ( speedSetting ) ;
var speedValueString = actualSpeedValueString ;
2016-07-18 15:20:19 -07:00
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
2017-06-15 16:54:36 -07:00
| | ( EngineMappingsMatterSlice . Instance . MapContains ( speedSetting )
2016-07-18 15:20:19 -07:00
& & speedToCheck < = 0 ) )
{
2018-01-13 18:54:40 -08:00
SliceSettingData data = SettingsOrganizer . Instance . GetSettingsData ( speedSetting ) ;
2016-07-18 15:20:19 -07:00
if ( data ! = null )
{
2018-10-26 14:51:04 -07:00
var location = GetSettingsLocation ( speedSetting ) ;
var error = "The {0} must be greater than 0." . Localize ( ) . FormatWith ( data . PresentationName ) ;
var details = "It is currently set to {0}." . Localize ( ) . FormatWith ( actualSpeedValueString ) ;
StyledMessageBox . ShowMessageBox ( "{0}\n\n{1}\n\n{2}" . FormatWith ( error , details , location ) , "Slice Error" . Localize ( ) ) ;
2016-07-18 15:20:19 -07:00
}
return false ;
}
return true ;
}
#endregion
[JsonIgnore]
2016-07-18 18:24:01 -07:00
private static HashSet < string > knownSettings ;
public static HashSet < string > KnownSettings
{
get
{
if ( knownSettings = = null )
{
knownSettings = LoadSettingsNamesFromPropertiesJson ( ) ;
}
return knownSettings ;
}
}
2016-07-18 15:20:19 -07:00
private static HashSet < string > LoadSettingsNamesFromPropertiesJson ( )
{
2017-08-20 02:34:39 -07:00
string propertiesJson = AggContext . StaticData . ReadAllText ( Path . Combine ( "SliceSettings" , "Properties.json" ) ) ;
2016-07-18 15:20:19 -07:00
var settingsData = JArray . Parse ( propertiesJson ) ;
return new HashSet < string > ( settingsData . Select ( s = > s [ "SlicerConfigName" ] . Value < string > ( ) ) ) ;
}
2016-07-18 15:21:15 -07:00
public void SetValue ( string settingsKey , string settingsValue , PrinterSettingsLayer layer = null )
2016-07-18 15:20:19 -07:00
{
2017-01-11 13:22:59 -08:00
// 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 ) ;
}
}
2016-07-18 15:20:19 -07:00
var persistenceLayer = layer ? ? UserLayer ;
2017-02-01 17:36:33 -08:00
// If the setting exists and is set to the requested value, exit without setting or saving
2016-07-18 15:20:19 -07:00
string existingValue ;
if ( persistenceLayer . TryGetValue ( settingsKey , out existingValue ) & & existingValue = = settingsValue )
{
return ;
}
// Otherwise, set and save
persistenceLayer [ settingsKey ] = settingsValue ;
Save ( ) ;
2017-02-01 13:38:14 -08:00
2018-10-05 09:55:46 -07:00
PrinterSettings . OnSettingChanged ( settingsKey ) ;
2016-07-18 15:20:19 -07:00
}
Move to new library model and view
- Add new listview control for library content
- Migrate library providers to containers
- Cloud, Sqlite, Directories, Queue, History
- Migrate SideBar components to containers
- Primatives, Text, Braille, ImageConverter
- Create new library container types
- Zip files, Calibration parts, Printer SDCards
- Reduce leftnav to Library, Settings, Controls, Options
- Add DragDrop support for image content
2017-05-19 22:33:55 -07:00
public string ToJson ( )
2016-09-20 09:39:57 -07:00
{
Move to new library model and view
- Add new listview control for library content
- Migrate library providers to containers
- Cloud, Sqlite, Directories, Queue, History
- Migrate SideBar components to containers
- Primatives, Text, Braille, ImageConverter
- Create new library container types
- Zip files, Calibration parts, Printer SDCards
- Reduce leftnav to Library, Settings, Controls, Options
- Add DragDrop support for image content
2017-05-19 22:33:55 -07:00
return JsonConvert . SerializeObject ( this , Formatting . Indented ) ;
2016-09-20 09:39:57 -07:00
}
2017-01-11 13:22:59 -08:00
internal void ClearValue ( string settingsKey , PrinterSettingsLayer layer = null )
2016-07-18 15:20:19 -07:00
{
var persistenceLayer = layer ? ? UserLayer ;
2017-01-11 13:22:59 -08:00
if ( persistenceLayer . ContainsKey ( settingsKey ) )
2016-07-18 15:20:19 -07:00
{
2017-01-11 13:22:59 -08:00
persistenceLayer . Remove ( settingsKey ) ;
// Restore user overrides if a non-user override is being cleared
if ( layer ! = null & & layer ! = UserLayer )
{
RestoreUserOverride ( layer , settingsKey ) ;
}
2018-07-17 16:01:12 -07:00
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 ) ;
}
}
}
}
}
2016-07-18 15:20:19 -07:00
Save ( ) ;
2017-02-01 13:38:14 -08:00
2018-10-05 09:55:46 -07:00
PrinterSettings . OnSettingChanged ( settingsKey ) ;
2016-07-18 15:20:19 -07:00
}
}
}
2018-05-03 06:49:25 -07:00
}