2017-11-02 16:21:34 +01:00
#include <cassert>
2017-10-30 18:41:50 +01:00
#include "PresetBundle.hpp"
2018-03-12 16:04:32 +01:00
#include "BitmapCache.hpp"
2018-10-10 13:53:45 +02:00
#include "Plater.hpp"
2018-11-26 14:41:58 +01:00
#include "I18N.hpp"
2019-04-08 09:37:23 +02:00
#include "wxExtensions.hpp"
2017-10-30 18:41:50 +01:00
2018-03-13 12:39:57 +01:00
#include <algorithm>
2017-10-30 18:41:50 +01:00
#include <fstream>
#include <boost/filesystem.hpp>
2017-11-01 19:30:05 +01:00
#include <boost/algorithm/clamp.hpp>
2017-10-30 18:41:50 +01:00
#include <boost/algorithm/string/predicate.hpp>
#include <boost/nowide/cenv.hpp>
#include <boost/nowide/cstdio.hpp>
#include <boost/nowide/fstream.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/locale.hpp>
2018-03-07 16:48:28 +01:00
#include <boost/log/trivial.hpp>
2017-10-30 18:41:50 +01:00
2017-11-10 17:27:05 +01:00
#include <wx/dcmemory.h>
2017-10-30 18:41:50 +01:00
#include <wx/image.h>
#include <wx/choice.h>
#include <wx/bmpcbox.h>
#include <wx/wupdlock.h>
2018-11-26 14:41:58 +01:00
#include "libslic3r/libslic3r.h"
#include "libslic3r/Utils.hpp"
2017-10-30 18:41:50 +01:00
2017-12-14 09:40:45 +01:00
// Store the print/filament/printer presets into a "presets" subdirectory of the Slic3rPE config dir.
// This breaks compatibility with the upstream Slic3r if the --datadir is used to switch between the two versions.
// #define SLIC3R_PROFILE_USE_PRESETS_SUBDIR
2017-10-30 18:41:50 +01:00
namespace Slic3r {
2018-04-04 10:18:26 +02:00
static std :: vector < std :: string > s_project_options {
2018-11-07 14:44:47 +01:00
"colorprint_heights" ,
2018-04-04 10:18:26 +02:00
"wiping_volumes_extruders" ,
"wiping_volumes_matrix"
2018-03-14 11:54:11 +01:00
};
2017-10-30 18:41:50 +01:00
PresetBundle :: PresetBundle () :
2018-08-03 14:14:25 +02:00
prints ( Preset :: TYPE_PRINT , Preset :: print_options (), static_cast < const HostConfig &> ( FullPrintConfig :: defaults ())),
filaments ( Preset :: TYPE_FILAMENT , Preset :: filament_options (), static_cast < const HostConfig &> ( FullPrintConfig :: defaults ())),
sla_materials ( Preset :: TYPE_SLA_MATERIAL , Preset :: sla_material_options (), static_cast < const SLAMaterialConfig &> ( SLAFullPrintConfig :: defaults ())),
2018-11-16 17:36:23 +01:00
sla_prints ( Preset :: TYPE_SLA_PRINT , Preset :: sla_print_options (), static_cast < const SLAPrintObjectConfig &> ( SLAFullPrintConfig :: defaults ())),
2018-08-03 14:14:25 +02:00
printers ( Preset :: TYPE_PRINTER , Preset :: printer_options (), static_cast < const HostConfig &> ( FullPrintConfig :: defaults ()), "- default FFF -" ),
2017-10-30 18:41:50 +01:00
m_bitmapCompatible ( new wxBitmap ),
2018-03-12 16:04:32 +01:00
m_bitmapIncompatible ( new wxBitmap ),
m_bitmapLock ( new wxBitmap ),
m_bitmapLockOpen ( new wxBitmap ),
m_bitmapCache ( new GUI :: BitmapCache )
2017-10-30 18:41:50 +01:00
{
2017-11-30 20:25:59 +01:00
if ( wxImage :: FindHandler ( wxBITMAP_TYPE_PNG ) == nullptr )
wxImage :: AddHandler ( new wxPNGHandler );
2017-10-30 18:41:50 +01:00
2018-06-26 10:50:50 +02:00
// The following keys are handled by the UI, they do not have a counterpart in any StaticPrintConfig derived classes,
// therefore they need to be handled differently. As they have no counterpart in StaticPrintConfig, they are not being
// initialized based on PrintConfigDef(), but to empty values (zeros, empty vectors, empty strings).
//
// "compatible_printers", "compatible_printers_condition", "inherits",
// "print_settings_id", "filament_settings_id", "printer_settings_id",
// "printer_vendor", "printer_model", "printer_variant", "default_print_profile", "default_filament_profile"
// Create the ID config keys, as they are not part of the Static print config classes.
this -> prints . default_preset (). config . optptr ( "print_settings_id" , true );
2018-06-27 16:57:42 +02:00
this -> prints . default_preset (). compatible_printers_condition ();
this -> prints . default_preset (). inherits ();
2018-06-26 10:50:50 +02:00
this -> filaments . default_preset (). config . option < ConfigOptionStrings > ( "filament_settings_id" , true ) -> values = { "" };
2018-06-27 16:57:42 +02:00
this -> filaments . default_preset (). compatible_printers_condition ();
this -> filaments . default_preset (). inherits ();
2019-07-23 14:15:42 +02:00
// Set all the nullable values to nils.
this -> filaments . default_preset (). config . null_nullables ();
2018-06-26 10:50:50 +02:00
2018-07-31 15:09:57 +02:00
this -> sla_materials . default_preset (). config . optptr ( "sla_material_settings_id" , true );
this -> sla_materials . default_preset (). compatible_printers_condition ();
this -> sla_materials . default_preset (). inherits ();
2018-11-16 17:36:23 +01:00
this -> sla_prints . default_preset (). config . optptr ( "sla_print_settings_id" , true );
2019-05-16 15:55:26 +02:00
this -> sla_prints . default_preset (). config . opt_string ( "output_filename_format" , true ) = "[input_filename_base].sl1" ;
2018-11-16 17:36:23 +01:00
this -> sla_prints . default_preset (). compatible_printers_condition ();
this -> sla_prints . default_preset (). inherits ();
2018-08-03 14:14:25 +02:00
this -> printers . add_default_preset ( Preset :: sla_printer_options (), static_cast < const SLAMaterialConfig &> ( SLAFullPrintConfig :: defaults ()), "- default SLA -" );
2019-01-10 18:08:38 +01:00
this -> printers . preset ( 1 ). printer_technology_ref () = ptSLA ;
2018-08-01 11:09:51 +02:00
for ( size_t i = 0 ; i < 2 ; ++ i ) {
2018-10-24 14:45:22 +02:00
// The following ugly switch is to avoid printers.preset(0) to return the edited instance, as the 0th default is the current one.
2018-10-31 16:22:36 +01:00
Preset & preset = this -> printers . default_preset ( i );
2018-08-01 11:09:51 +02:00
preset . config . optptr ( "printer_settings_id" , true );
preset . config . optptr ( "printer_vendor" , true );
preset . config . optptr ( "printer_model" , true );
preset . config . optptr ( "printer_variant" , true );
2018-10-31 16:22:36 +01:00
if ( i == 0 ) {
preset . config . optptr ( "default_print_profile" , true );
preset . config . option < ConfigOptionStrings > ( "default_filament_profile" , true ) -> values = { "" };
2018-11-16 17:36:23 +01:00
}
else {
preset . config . optptr ( "default_sla_print_profile" , true );
2018-12-03 13:14:28 +01:00
preset . config . optptr ( "default_sla_material_profile" , true );
2018-11-16 17:36:23 +01:00
}
2018-10-31 16:22:36 +01:00
// default_sla_material_profile
2018-08-01 11:09:51 +02:00
preset . inherits ();
}
2018-06-26 10:50:50 +02:00
// Load the default preset bitmaps.
2019-04-08 09:37:23 +02:00
// #ys_FIXME_to_delete we'll load them later, using em_unit()
// this->prints .load_bitmap_default("cog");
// this->sla_prints .load_bitmap_default("package_green.png");
// this->filaments .load_bitmap_default("spool.png");
// this->sla_materials.load_bitmap_default("package_green.png");
// this->printers .load_bitmap_default("printer_empty.png");
// this->printers .load_bitmap_add("add.png");
// this->load_compatible_bitmaps();
2018-06-26 10:50:50 +02:00
2018-05-22 14:17:27 +02:00
// Re-activate the default presets, so their "edited" preset copies will be updated with the additional configuration values above.
2018-07-31 15:09:57 +02:00
this -> prints . select_preset ( 0 );
2018-11-16 17:36:23 +01:00
this -> sla_prints . select_preset ( 0 );
2018-07-31 15:09:57 +02:00
this -> filaments . select_preset ( 0 );
this -> sla_materials . select_preset ( 0 );
this -> printers . select_preset ( 0 );
2018-03-14 11:54:11 +01:00
this -> project_config . apply_only ( FullPrintConfig :: defaults (), s_project_options );
2017-10-30 18:41:50 +01:00
}
PresetBundle ::~ PresetBundle ()
{
assert ( m_bitmapCompatible != nullptr );
assert ( m_bitmapIncompatible != nullptr );
2018-03-12 16:04:32 +01:00
assert ( m_bitmapLock != nullptr );
assert ( m_bitmapLockOpen != nullptr );
2017-10-30 18:41:50 +01:00
delete m_bitmapCompatible ;
m_bitmapCompatible = nullptr ;
delete m_bitmapIncompatible ;
m_bitmapIncompatible = nullptr ;
2018-03-12 16:04:32 +01:00
delete m_bitmapLock ;
m_bitmapLock = nullptr ;
delete m_bitmapLockOpen ;
m_bitmapLockOpen = nullptr ;
delete m_bitmapCache ;
m_bitmapCache = nullptr ;
2017-10-30 18:41:50 +01:00
}
2017-12-19 19:51:22 +01:00
void PresetBundle :: reset ( bool delete_files )
{
// Clear the existing presets, delete their respective files.
2018-06-06 10:52:19 +02:00
this -> vendors . clear ();
2018-07-31 15:09:57 +02:00
this -> prints . reset ( delete_files );
2018-11-16 17:36:23 +01:00
this -> sla_prints . reset ( delete_files );
2018-07-31 15:09:57 +02:00
this -> filaments . reset ( delete_files );
this -> sla_materials . reset ( delete_files );
this -> printers . reset ( delete_files );
2017-12-19 19:51:22 +01:00
this -> filament_presets . clear ();
2018-07-31 15:09:57 +02:00
this -> filament_presets . emplace_back ( this -> filaments . get_selected_preset_name ());
2018-05-16 16:34:07 +02:00
this -> obsolete_presets . prints . clear ();
2018-11-16 17:36:23 +01:00
this -> obsolete_presets . sla_prints . clear ();
2018-05-16 16:34:07 +02:00
this -> obsolete_presets . filaments . clear ();
2018-07-31 15:09:57 +02:00
this -> obsolete_presets . sla_materials . clear ();
2018-05-16 16:34:07 +02:00
this -> obsolete_presets . printers . clear ();
2017-12-19 19:51:22 +01:00
}
2017-10-30 18:41:50 +01:00
void PresetBundle :: setup_directories ()
{
2017-11-30 15:51:51 +01:00
boost :: filesystem :: path data_dir = boost :: filesystem :: path ( Slic3r :: data_dir ());
2017-12-10 22:11:00 +01:00
std :: initializer_list < boost :: filesystem :: path > paths = {
2018-03-09 16:37:33 +01:00
data_dir ,
data_dir / "vendor" ,
2018-04-11 13:12:08 +02:00
data_dir / "cache" ,
2017-12-14 09:40:45 +01:00
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
// Store the print/filament/printer presets into a "presets" directory.
2017-12-10 22:11:00 +01:00
data_dir / "presets" ,
data_dir / "presets" / "print" ,
data_dir / "presets" / "filament" ,
2018-11-19 11:10:22 +01:00
data_dir / "presets" / "sla_print" ,
2018-07-31 15:09:57 +02:00
data_dir / "presets" / "sla_material" ,
2017-12-14 09:40:45 +01:00
data_dir / "presets" / "printer"
#else
// Store the print/filament/printer presets at the same location as the upstream Slic3r.
data_dir / "print" ,
data_dir / "filament" ,
2018-11-19 11:10:22 +01:00
data_dir / "sla_print" ,
2018-07-31 15:09:57 +02:00
data_dir / "sla_material" ,
2017-12-14 09:40:45 +01:00
data_dir / "printer"
#endif
};
2017-11-30 15:51:51 +01:00
for ( const boost :: filesystem :: path & path : paths ) {
boost :: filesystem :: path subdir = path ;
subdir . make_preferred ();
2017-10-30 18:41:50 +01:00
if ( ! boost :: filesystem :: is_directory ( subdir ) &&
! boost :: filesystem :: create_directory ( subdir ))
throw std :: runtime_error ( std :: string ( "Slic3r was unable to create its data directory at " ) + subdir . string ());
}
}
2019-04-26 16:53:04 +02:00
void PresetBundle :: load_presets ( const AppConfig & config , const std :: string & preferred_model_id )
2017-10-30 18:41:50 +01:00
{
2018-03-09 16:37:33 +01:00
// First load the vendor specific system presets.
std :: string errors_cummulative = this -> load_system_presets ();
const std :: string dir_user_presets = data_dir ()
2017-12-14 09:40:45 +01:00
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
// Store the print/filament/printer presets into a "presets" directory.
+ "/presets"
#else
// Store the print/filament/printer presets at the same location as the upstream Slic3r.
#endif
;
2017-11-28 10:08:01 +01:00
try {
2018-03-09 16:37:33 +01:00
this -> prints . load_presets ( dir_user_presets , "print" );
2017-11-28 10:08:01 +01:00
} catch ( const std :: runtime_error & err ) {
errors_cummulative += err . what ();
}
2018-11-16 17:36:23 +01:00
try {
this -> sla_prints . load_presets ( dir_user_presets , "sla_print" );
} catch ( const std :: runtime_error & err ) {
errors_cummulative += err . what ();
}
2017-11-28 10:08:01 +01:00
try {
2018-03-09 16:37:33 +01:00
this -> filaments . load_presets ( dir_user_presets , "filament" );
2017-11-28 10:08:01 +01:00
} catch ( const std :: runtime_error & err ) {
errors_cummulative += err . what ();
}
2018-07-31 15:09:57 +02:00
try {
this -> sla_materials . load_presets ( dir_user_presets , "sla_material" );
} catch ( const std :: runtime_error & err ) {
errors_cummulative += err . what ();
}
2017-11-28 10:08:01 +01:00
try {
2018-03-09 16:37:33 +01:00
this -> printers . load_presets ( dir_user_presets , "printer" );
2017-11-28 10:08:01 +01:00
} catch ( const std :: runtime_error & err ) {
errors_cummulative += err . what ();
}
2017-10-30 18:41:50 +01:00
this -> update_multi_material_filament_presets ();
2018-12-04 17:56:49 +01:00
this -> update_compatible ( false );
2017-11-28 10:08:01 +01:00
if ( ! errors_cummulative . empty ())
throw std :: runtime_error ( errors_cummulative );
2018-03-09 16:37:33 +01:00
2019-04-26 16:53:04 +02:00
this -> load_selections ( config , preferred_model_id );
2018-03-09 16:37:33 +01:00
}
// Load system presets into this PresetBundle.
// For each vendor, there will be a single PresetBundle loaded.
std :: string PresetBundle :: load_system_presets ()
{
// Here the vendor specific read only Config Bundles are stored.
boost :: filesystem :: path dir = ( boost :: filesystem :: path ( data_dir ()) / "vendor" ). make_preferred ();
std :: string errors_cummulative ;
2018-04-18 13:35:51 +02:00
bool first = true ;
2018-03-09 16:37:33 +01:00
for ( auto & dir_entry : boost :: filesystem :: directory_iterator ( dir ))
2019-02-03 15:30:37 +01:00
if ( Slic3r :: is_ini_file ( dir_entry )) {
2018-03-09 16:37:33 +01:00
std :: string name = dir_entry . path (). filename (). string ();
// Remove the .ini suffix.
name . erase ( name . size () - 4 );
try {
// Load the config bundle, flatten it.
2018-04-18 13:35:51 +02:00
if ( first ) {
// Reset this PresetBundle and load the first vendor config.
this -> load_configbundle ( dir_entry . path (). string (), LOAD_CFGBNDLE_SYSTEM );
first = false ;
} else {
// Load the other vendor configs, merge them with this PresetBundle.
// Report duplicate profiles.
PresetBundle other ;
other . load_configbundle ( dir_entry . path (). string (), LOAD_CFGBNDLE_SYSTEM );
std :: vector < std :: string > duplicates = this -> merge_presets ( std :: move ( other ));
if ( ! duplicates . empty ()) {
errors_cummulative += "Vendor configuration file " + name + " contains the following presets with names used by other vendors: " ;
for ( size_t i = 0 ; i < duplicates . size (); ++ i ) {
if ( i > 0 )
errors_cummulative += ", " ;
errors_cummulative += duplicates [ i ];
}
}
}
2018-03-09 16:37:33 +01:00
} catch ( const std :: runtime_error & err ) {
errors_cummulative += err . what ();
errors_cummulative += " \n " ;
}
}
2018-05-16 10:11:00 +02:00
if ( first ) {
// No config bundle loaded, reset.
this -> reset ( false );
}
2018-03-09 16:37:33 +01:00
return errors_cummulative ;
2017-10-30 18:41:50 +01:00
}
2018-04-18 13:35:51 +02:00
// Merge one vendor's presets with the other vendor's presets, report duplicates.
std :: vector < std :: string > PresetBundle :: merge_presets ( PresetBundle && other )
{
this -> vendors . insert ( other . vendors . begin (), other . vendors . end ());
2018-07-31 15:09:57 +02:00
std :: vector < std :: string > duplicate_prints = this -> prints . merge_presets ( std :: move ( other . prints ), this -> vendors );
2018-11-16 17:36:23 +01:00
std :: vector < std :: string > duplicate_sla_prints = this -> sla_prints . merge_presets ( std :: move ( other . sla_prints ), this -> vendors );
2018-07-31 15:09:57 +02:00
std :: vector < std :: string > duplicate_filaments = this -> filaments . merge_presets ( std :: move ( other . filaments ), this -> vendors );
std :: vector < std :: string > duplicate_sla_materials = this -> sla_materials . merge_presets ( std :: move ( other . sla_materials ), this -> vendors );
std :: vector < std :: string > duplicate_printers = this -> printers . merge_presets ( std :: move ( other . printers ), this -> vendors );
append ( this -> obsolete_presets . prints , std :: move ( other . obsolete_presets . prints ));
2018-11-16 17:36:23 +01:00
append ( this -> obsolete_presets . sla_prints , std :: move ( other . obsolete_presets . sla_prints ));
2018-07-31 15:09:57 +02:00
append ( this -> obsolete_presets . filaments , std :: move ( other . obsolete_presets . filaments ));
append ( this -> obsolete_presets . sla_materials , std :: move ( other . obsolete_presets . sla_materials ));
append ( this -> obsolete_presets . printers , std :: move ( other . obsolete_presets . printers ));
2018-11-16 17:36:23 +01:00
append ( duplicate_prints , std :: move ( duplicate_sla_prints ));
2018-05-16 16:34:07 +02:00
append ( duplicate_prints , std :: move ( duplicate_filaments ));
2018-07-31 15:09:57 +02:00
append ( duplicate_prints , std :: move ( duplicate_sla_materials ));
2018-04-18 13:35:51 +02:00
append ( duplicate_prints , std :: move ( duplicate_printers ));
return duplicate_prints ;
}
2017-11-02 17:31:24 +01:00
static inline std :: string remove_ini_suffix ( const std :: string & name )
{
std :: string out = name ;
if ( boost :: iends_with ( out , ".ini" ))
out . erase ( out . end () - 4 , out . end ());
return out ;
}
2018-03-09 16:37:33 +01:00
// Set the "enabled" flag for printer vendors, printer models and printer variants
// based on the user configuration.
// If the "vendor" section is missing, enable all models and variants of the particular vendor.
void PresetBundle :: load_installed_printers ( const AppConfig & config )
{
2018-03-29 17:54:43 +02:00
for ( auto & preset : printers ) {
preset . set_visible_from_appconfig ( config );
}
2018-03-09 16:37:33 +01:00
}
2017-10-30 18:41:50 +01:00
// Load selections (current print, current filaments, current printer) from config.ini
2018-07-23 14:19:40 +02:00
// This is done on application start up or after updates are applied.
2019-04-26 16:53:04 +02:00
void PresetBundle :: load_selections ( const AppConfig & config , const std :: string & preferred_model_id )
2017-10-30 18:41:50 +01:00
{
2018-04-13 14:49:33 +02:00
// Update visibility of presets based on application vendor / model / variant configuration.
this -> load_installed_printers ( config );
// Parse the initial print / filament / printer profile names.
2018-07-31 15:09:57 +02:00
std :: string initial_print_profile_name = remove_ini_suffix ( config . get ( "presets" , "print" ));
2018-11-16 17:36:23 +01:00
std :: string initial_sla_print_profile_name = remove_ini_suffix ( config . get ( "presets" , "sla_print" ));
2018-07-31 15:09:57 +02:00
std :: string initial_filament_profile_name = remove_ini_suffix ( config . get ( "presets" , "filament" ));
std :: string initial_sla_material_profile_name = remove_ini_suffix ( config . get ( "presets" , "sla_material" ));
std :: string initial_printer_profile_name = remove_ini_suffix ( config . get ( "presets" , "printer" ));
2018-03-29 17:54:43 +02:00
2019-04-26 16:53:04 +02:00
// Activate print / filament / printer profiles from either the config,
// or from the preferred_model_id suggestion passed in by ConfigWizard.
// If the printer profile enumerated by the config are not visible, select an alternate preset.
2018-04-13 14:49:33 +02:00
// Do not select alternate profiles for the print / filament profiles as those presets
2018-12-04 17:56:49 +01:00
// will be selected by the following call of this->update_compatible(true).
2019-04-26 16:53:04 +02:00
const Preset * initial_printer = printers . find_preset ( initial_printer_profile_name );
const Preset * preferred_printer = printers . find_by_model_id ( preferred_model_id );
2019-05-15 17:15:52 +02:00
printers . select_preset_by_name (
( preferred_printer != nullptr && ( initial_printer == nullptr || ! initial_printer -> is_visible )) ?
preferred_printer -> name :
initial_printer_profile_name ,
true );
2019-04-26 16:53:04 +02:00
2019-05-15 17:15:52 +02:00
// Selects the profile, leaves it to -1 if the initial profile name is empty or if it was not found.
prints . select_preset_by_name_strict ( initial_print_profile_name );
filaments . select_preset_by_name_strict ( initial_filament_profile_name );
sla_prints . select_preset_by_name_strict ( initial_sla_print_profile_name );
sla_materials . select_preset_by_name_strict ( initial_sla_material_profile_name );
2019-04-26 16:53:04 +02:00
2019-05-15 17:15:52 +02:00
// Load the names of the other filament profiles selected for a multi-material printer.
// Load it even if the current printer technology is SLA.
// The possibly excessive filament names will be later removed with this->update_multi_material_filament_presets()
// once the FFF technology gets selected.
this -> filament_presets = { filaments . get_selected_preset_name () };
for ( unsigned int i = 1 ; i < 1000 ; ++ i ) {
char name [ 64 ];
sprintf ( name , "filament_%d" , i );
if ( ! config . has ( "presets" , name ))
break ;
this -> filament_presets . emplace_back ( remove_ini_suffix ( config . get ( "presets" , name )));
2018-07-02 20:25:37 +02:00
}
2017-11-10 17:27:05 +01:00
// Update visibility of presets based on their compatibility with the active printer.
2017-12-20 11:28:16 +01:00
// Always try to select a compatible print and filament preset to the current printer preset,
// as the application may have been closed with an active "external" preset, which does not
// exist.
2018-12-04 17:56:49 +01:00
this -> update_compatible ( true );
2018-07-02 20:25:37 +02:00
this -> update_multi_material_filament_presets ();
2017-10-30 18:41:50 +01:00
}
// Export selections (current print, current filaments, current printer) into config.ini
void PresetBundle :: export_selections ( AppConfig & config )
{
2018-10-31 16:22:36 +01:00
assert ( this -> printers . get_edited_preset (). printer_technology () != ptFFF || filament_presets . size () >= 1 );
assert ( this -> printers . get_edited_preset (). printer_technology () != ptFFF || filament_presets . size () > 1 || filaments . get_selected_preset_name () == filament_presets . front ());
2017-11-01 19:30:05 +01:00
config . clear_section ( "presets" );
2018-07-31 15:09:57 +02:00
config . set ( "presets" , "print" , prints . get_selected_preset_name ());
config . set ( "presets" , "filament" , filament_presets . front ());
2017-11-01 19:30:05 +01:00
for ( int i = 1 ; i < filament_presets . size (); ++ i ) {
2017-10-30 18:41:50 +01:00
char name [ 64 ];
sprintf ( name , "filament_%d" , i );
config . set ( "presets" , name , filament_presets [ i ]);
}
2018-11-19 11:10:22 +01:00
config . set ( "presets" , "sla_print" , sla_prints . get_selected_preset_name ());
2018-07-31 15:09:57 +02:00
config . set ( "presets" , "sla_material" , sla_materials . get_selected_preset_name ());
2018-12-03 13:14:28 +01:00
config . set ( "presets" , "printer" , printers . get_selected_preset_name ());
2017-11-02 16:21:34 +01:00
}
2019-04-09 17:40:14 +02:00
void PresetBundle :: load_compatible_bitmaps ( wxWindow * window )
2017-10-30 18:41:50 +01:00
{
2019-04-12 10:57:30 +02:00
// We don't actually pass the window pointer here and instead generate
2019-04-12 11:28:07 +02:00
// a low DPI bitmap, because the wxBitmapComboBox and wxDataViewCtrl don't support
2019-04-12 10:57:30 +02:00
// high DPI bitmaps very well, they compute their dimensions wrong.
// TODO: Update this when fixed in wxWidgets
// See also PresetCollection::load_bitmap_default() and PresetCollection::load_bitmap_add()
( void ) window ;
* m_bitmapCompatible = create_scaled_bitmap ( nullptr , "flag_green" );
* m_bitmapIncompatible = create_scaled_bitmap ( nullptr , "flag_red" );
* m_bitmapLock = create_scaled_bitmap ( nullptr , "lock_closed" );
2019-05-13 12:13:28 +02:00
* m_bitmapLockOpen = create_scaled_bitmap ( nullptr , "lock_open" );
2019-04-08 09:37:23 +02:00
2019-04-09 14:18:03 +02:00
prints . set_bitmap_compatible ( m_bitmapCompatible );
filaments . set_bitmap_compatible ( m_bitmapCompatible );
sla_prints . set_bitmap_compatible ( m_bitmapCompatible );
sla_materials . set_bitmap_compatible ( m_bitmapCompatible );
2019-04-08 09:37:23 +02:00
2019-04-09 14:18:03 +02:00
prints . set_bitmap_incompatible ( m_bitmapIncompatible );
filaments . set_bitmap_incompatible ( m_bitmapIncompatible );
sla_prints . set_bitmap_incompatible ( m_bitmapIncompatible );
sla_materials . set_bitmap_incompatible ( m_bitmapIncompatible );
prints . set_bitmap_lock ( m_bitmapLock );
filaments . set_bitmap_lock ( m_bitmapLock );
sla_prints . set_bitmap_lock ( m_bitmapLock );
sla_materials . set_bitmap_lock ( m_bitmapLock );
printers . set_bitmap_lock ( m_bitmapLock );
prints . set_bitmap_lock_open ( m_bitmapLock );
filaments . set_bitmap_lock_open ( m_bitmapLock );
sla_prints . set_bitmap_lock_open ( m_bitmapLock );
sla_materials . set_bitmap_lock_open ( m_bitmapLock );
printers . set_bitmap_lock_open ( m_bitmapLock );
2017-10-30 18:41:50 +01:00
}
DynamicPrintConfig PresetBundle :: full_config () const
2018-07-31 15:09:57 +02:00
{
return ( this -> printers . get_edited_preset (). printer_technology () == ptFFF ) ?
this -> full_fff_config () :
this -> full_sla_config ();
}
2018-12-06 14:42:15 +01:00
DynamicPrintConfig PresetBundle :: full_config_secure () const
{
DynamicPrintConfig config = this -> full_config ();
2019-08-26 16:39:08 +02:00
config . erase ( "print_host" );
2018-12-06 14:42:15 +01:00
config . erase ( "printhost_apikey" );
config . erase ( "printhost_cafile" );
return config ;
}
2018-07-31 15:09:57 +02:00
DynamicPrintConfig PresetBundle :: full_fff_config () const
2017-10-30 18:41:50 +01:00
{
DynamicPrintConfig out ;
2018-08-03 14:14:25 +02:00
out . apply ( FullPrintConfig :: defaults ());
2017-10-30 18:41:50 +01:00
out . apply ( this -> prints . get_edited_preset (). config );
2018-05-23 13:19:25 +02:00
// Add the default filament preset to have the "filament_preset_id" defined.
out . apply ( this -> filaments . default_preset (). config );
out . apply ( this -> printers . get_edited_preset (). config );
2018-03-14 11:54:11 +01:00
out . apply ( this -> project_config );
2017-10-30 18:41:50 +01:00
auto * nozzle_diameter = dynamic_cast < const ConfigOptionFloats *> ( out . option ( "nozzle_diameter" ));
size_t num_extruders = nozzle_diameter -> values . size ();
2018-06-26 10:50:50 +02:00
// Collect the "compatible_printers_condition" and "inherits" values over all presets (print, filaments, printers) into a single vector.
std :: vector < std :: string > compatible_printers_condition ;
2018-12-04 17:56:49 +01:00
std :: vector < std :: string > compatible_prints_condition ;
2018-06-26 10:50:50 +02:00
std :: vector < std :: string > inherits ;
2018-06-27 16:57:42 +02:00
compatible_printers_condition . emplace_back ( this -> prints . get_edited_preset (). compatible_printers_condition ());
inherits . emplace_back ( this -> prints . get_edited_preset (). inherits ());
2017-10-30 18:41:50 +01:00
if ( num_extruders <= 1 ) {
out . apply ( this -> filaments . get_edited_preset (). config );
2018-06-27 16:57:42 +02:00
compatible_printers_condition . emplace_back ( this -> filaments . get_edited_preset (). compatible_printers_condition ());
2018-12-04 17:56:49 +01:00
compatible_prints_condition . emplace_back ( this -> filaments . get_edited_preset (). compatible_prints_condition ());
2018-06-27 16:57:42 +02:00
inherits . emplace_back ( this -> filaments . get_edited_preset (). inherits ());
2017-10-30 18:41:50 +01:00
} else {
// Retrieve filament presets and build a single config object for them.
// First collect the filament configurations based on the user selection of this->filament_presets.
2018-05-16 16:34:07 +02:00
// Here this->filaments.find_preset() and this->filaments.first_visible() return the edited copy of the preset if active.
2017-10-30 18:41:50 +01:00
std :: vector < const DynamicPrintConfig *> filament_configs ;
for ( const std :: string & filament_preset_name : this -> filament_presets )
filament_configs . emplace_back ( & this -> filaments . find_preset ( filament_preset_name , true ) -> config );
while ( filament_configs . size () < num_extruders )
filament_configs . emplace_back ( & this -> filaments . first_visible (). config );
2018-06-26 10:50:50 +02:00
for ( const DynamicPrintConfig * cfg : filament_configs ) {
2018-06-27 16:57:42 +02:00
compatible_printers_condition . emplace_back ( Preset :: compatible_printers_condition ( * const_cast < DynamicPrintConfig *> ( cfg )));
2018-12-04 17:56:49 +01:00
compatible_prints_condition . emplace_back ( Preset :: compatible_prints_condition ( * const_cast < DynamicPrintConfig *> ( cfg )));
2018-06-27 16:57:42 +02:00
inherits . emplace_back ( Preset :: inherits ( * const_cast < DynamicPrintConfig *> ( cfg )));
2018-06-26 10:50:50 +02:00
}
2017-10-30 18:41:50 +01:00
// Option values to set a ConfigOptionVector from.
std :: vector < const ConfigOption *> filament_opts ( num_extruders , nullptr );
// loop through options and apply them to the resulting config.
for ( const t_config_option_key & key : this -> filaments . default_preset (). config . keys ()) {
2018-12-04 17:56:49 +01:00
if ( key == "compatible_prints" || key == "compatible_printers" )
2017-11-10 17:27:05 +01:00
continue ;
2017-10-30 18:41:50 +01:00
// Get a destination option.
ConfigOption * opt_dst = out . option ( key , false );
if ( opt_dst -> is_scalar ()) {
// Get an option, do not create if it does not exist.
const ConfigOption * opt_src = filament_configs . front () -> option ( key );
if ( opt_src != nullptr )
opt_dst -> set ( opt_src );
} else {
// Setting a vector value from all filament_configs.
for ( size_t i = 0 ; i < filament_opts . size (); ++ i )
filament_opts [ i ] = filament_configs [ i ] -> option ( key );
static_cast < ConfigOptionVectorBase *> ( opt_dst ) -> set ( filament_opts );
}
}
}
2017-12-01 18:55:57 +01:00
2018-06-26 10:50:50 +02:00
// Don't store the "compatible_printers_condition" for the printer profile, there is none.
2018-06-27 16:57:42 +02:00
inherits . emplace_back ( this -> printers . get_edited_preset (). inherits ());
2018-06-26 10:50:50 +02:00
2018-12-04 17:56:49 +01:00
// These value types clash between the print and filament profiles. They should be renamed.
out . erase ( "compatible_prints" );
out . erase ( "compatible_prints_condition" );
2017-12-01 18:55:57 +01:00
out . erase ( "compatible_printers" );
2018-05-23 13:19:25 +02:00
out . erase ( "compatible_printers_condition" );
2018-06-26 10:50:50 +02:00
out . erase ( "inherits" );
2017-10-30 18:41:50 +01:00
static const char * keys [] = { "perimeter" , "infill" , "solid_infill" , "support_material" , "support_material_interface" };
for ( size_t i = 0 ; i < sizeof ( keys ) / sizeof ( keys [ 0 ]); ++ i ) {
std :: string key = std :: string ( keys [ i ]) + "_extruder" ;
auto * opt = dynamic_cast < ConfigOptionInt *> ( out . option ( key , false ));
assert ( opt != nullptr );
2017-11-01 19:30:05 +01:00
opt -> value = boost :: algorithm :: clamp < int > ( opt -> value , 0 , int ( num_extruders ));
2017-10-30 18:41:50 +01:00
}
2019-05-22 11:31:36 +02:00
out . option < ConfigOptionString > ( "print_settings_id" , true ) -> value = this -> prints . get_selected_preset_name ();
2018-06-22 14:17:03 +02:00
out . option < ConfigOptionStrings > ( "filament_settings_id" , true ) -> values = this -> filament_presets ;
2019-05-22 11:31:36 +02:00
out . option < ConfigOptionString > ( "printer_settings_id" , true ) -> value = this -> printers . get_selected_preset_name ();
2018-06-26 10:50:50 +02:00
// Serialize the collected "compatible_printers_condition" and "inherits" fields.
// There will be 1 + num_exturders fields for "inherits" and 2 + num_extruders for "compatible_printers_condition" stored.
// The vector will not be stored if all fields are empty strings.
auto add_if_some_non_empty = [ & out ]( std :: vector < std :: string > && values , const std :: string & key ) {
bool nonempty = false ;
for ( const std :: string & v : values )
if ( ! v . empty ()) {
nonempty = true ;
break ;
}
if ( nonempty )
out . set_key_value ( key , new ConfigOptionStrings ( std :: move ( values )));
};
2018-06-28 20:13:01 +02:00
add_if_some_non_empty ( std :: move ( compatible_printers_condition ), "compatible_printers_condition_cummulative" );
2018-12-04 17:56:49 +01:00
add_if_some_non_empty ( std :: move ( compatible_prints_condition ), "compatible_prints_condition_cummulative" );
2018-06-28 20:13:01 +02:00
add_if_some_non_empty ( std :: move ( inherits ), "inherits_cummulative" );
2018-11-08 20:18:40 +01:00
out . option < ConfigOptionEnumGeneric > ( "printer_technology" , true ) -> value = ptFFF ;
2017-10-30 18:41:50 +01:00
return out ;
}
2018-07-31 15:09:57 +02:00
DynamicPrintConfig PresetBundle :: full_sla_config () const
{
DynamicPrintConfig out ;
2018-08-03 14:14:25 +02:00
out . apply ( SLAFullPrintConfig :: defaults ());
2018-11-16 17:36:23 +01:00
out . apply ( this -> sla_prints . get_edited_preset (). config );
2018-07-31 15:09:57 +02:00
out . apply ( this -> sla_materials . get_edited_preset (). config );
out . apply ( this -> printers . get_edited_preset (). config );
// There are no project configuration values as of now, the project_config is reserved for FFF printers.
// out.apply(this->project_config);
2018-11-16 17:36:23 +01:00
// Collect the "compatible_printers_condition" and "inherits" values over all presets (sla_prints, sla_materials, printers) into a single vector.
2018-07-31 15:09:57 +02:00
std :: vector < std :: string > compatible_printers_condition ;
2018-12-04 17:56:49 +01:00
std :: vector < std :: string > compatible_prints_condition ;
2018-07-31 15:09:57 +02:00
std :: vector < std :: string > inherits ;
2018-12-04 17:56:49 +01:00
compatible_printers_condition . emplace_back ( this -> sla_prints . get_edited_preset (). compatible_printers_condition ());
inherits . emplace_back ( this -> sla_prints . get_edited_preset (). inherits ());
compatible_printers_condition . emplace_back ( this -> sla_materials . get_edited_preset (). compatible_printers_condition ());
compatible_prints_condition . emplace_back ( this -> sla_materials . get_edited_preset (). compatible_prints_condition ());
inherits . emplace_back ( this -> sla_materials . get_edited_preset (). inherits ());
2018-07-31 15:09:57 +02:00
inherits . emplace_back ( this -> printers . get_edited_preset (). inherits ());
// These two value types clash between the print and filament profiles. They should be renamed.
out . erase ( "compatible_printers" );
out . erase ( "compatible_printers_condition" );
out . erase ( "inherits" );
2019-05-22 11:31:36 +02:00
out . option < ConfigOptionString > ( "sla_print_settings_id" , true ) -> value = this -> sla_prints . get_selected_preset_name ();
out . option < ConfigOptionString > ( "sla_material_settings_id" , true ) -> value = this -> sla_materials . get_selected_preset_name ();
out . option < ConfigOptionString > ( "printer_settings_id" , true ) -> value = this -> printers . get_selected_preset_name ();
2018-07-31 15:09:57 +02:00
// Serialize the collected "compatible_printers_condition" and "inherits" fields.
// There will be 1 + num_exturders fields for "inherits" and 2 + num_extruders for "compatible_printers_condition" stored.
// The vector will not be stored if all fields are empty strings.
auto add_if_some_non_empty = [ & out ]( std :: vector < std :: string > && values , const std :: string & key ) {
bool nonempty = false ;
for ( const std :: string & v : values )
if ( ! v . empty ()) {
nonempty = true ;
break ;
}
if ( nonempty )
out . set_key_value ( key , new ConfigOptionStrings ( std :: move ( values )));
};
add_if_some_non_empty ( std :: move ( compatible_printers_condition ), "compatible_printers_condition_cummulative" );
2018-12-04 17:56:49 +01:00
add_if_some_non_empty ( std :: move ( compatible_prints_condition ), "compatible_prints_condition_cummulative" );
2018-07-31 15:09:57 +02:00
add_if_some_non_empty ( std :: move ( inherits ), "inherits_cummulative" );
2018-11-08 20:18:40 +01:00
out . option < ConfigOptionEnumGeneric > ( "printer_technology" , true ) -> value = ptSLA ;
return out ;
2018-07-31 15:09:57 +02:00
}
2017-10-30 18:41:50 +01:00
// Load an external config file containing the print, filament and printer presets.
// Instead of a config file, a G-code may be loaded containing the full set of parameters.
// In the future the configuration will likely be read from an AMF file as well.
// If the file is loaded successfully, its print / filament / printer profiles will be activated.
void PresetBundle :: load_config_file ( const std :: string & path )
2017-11-01 19:30:05 +01:00
{
2017-11-02 16:21:34 +01:00
if ( boost :: iends_with ( path , ".gcode" ) || boost :: iends_with ( path , ".g" )) {
DynamicPrintConfig config ;
config . apply ( FullPrintConfig :: defaults ());
2018-02-13 15:19:55 +01:00
config . load_from_gcode_file ( path );
Preset :: normalize ( config );
2017-12-20 11:28:16 +01:00
load_config_file_config ( path , true , std :: move ( config ));
2017-11-02 16:21:34 +01:00
return ;
}
2017-11-01 19:30:05 +01:00
// 1) Try to load the config file into a boost property tree.
boost :: property_tree :: ptree tree ;
try {
boost :: nowide :: ifstream ifs ( path );
boost :: property_tree :: read_ini ( ifs , tree );
2017-11-28 10:08:01 +01:00
} catch ( const std :: ifstream :: failure & err ) {
throw std :: runtime_error ( std :: string ( "The config file cannot be loaded: " ) + path + " \n\t Reason: " + err . what ());
} catch ( const std :: runtime_error & err ) {
throw std :: runtime_error ( std :: string ( "Failed loading the preset file: " ) + path + " \n\t Reason: " + err . what ());
2017-11-01 19:30:05 +01:00
}
// 2) Continue based on the type of the configuration file.
ConfigFileType config_file_type = guess_config_file_type ( tree );
switch ( config_file_type ) {
case CONFIG_FILE_TYPE_UNKNOWN :
throw std :: runtime_error ( std :: string ( "Unknown configuration file type: " ) + path );
case CONFIG_FILE_TYPE_APP_CONFIG :
throw std :: runtime_error ( std :: string ( "Invalid configuration file: " ) + path + ". This is an application config file." );
2017-11-02 16:21:34 +01:00
case CONFIG_FILE_TYPE_CONFIG :
{
// Initialize a config from full defaults.
DynamicPrintConfig config ;
config . apply ( FullPrintConfig :: defaults ());
config . load ( tree );
Preset :: normalize ( config );
2017-12-20 11:28:16 +01:00
load_config_file_config ( path , true , std :: move ( config ));
2017-11-02 16:21:34 +01:00
break ;
}
2017-11-01 19:30:05 +01:00
case CONFIG_FILE_TYPE_CONFIG_BUNDLE :
2017-11-02 16:21:34 +01:00
load_config_file_config_bundle ( path , tree );
2017-11-01 19:30:05 +01:00
break ;
}
}
// Load a config file from a boost property_tree. This is a private method called from load_config_file.
2017-12-20 11:28:16 +01:00
void PresetBundle :: load_config_file_config ( const std :: string & name_or_path , bool is_external , DynamicPrintConfig && config )
2017-10-30 18:41:50 +01:00
{
2018-07-31 15:09:57 +02:00
PrinterTechnology printer_technology = Preset :: printer_technology ( config );
2017-12-01 18:55:57 +01:00
// The "compatible_printers" field should not have been exported into a config.ini or a G-code anyway,
// but some of the alpha versions of Slic3r did.
{
ConfigOption * opt_compatible = config . optptr ( "compatible_printers" );
if ( opt_compatible != nullptr ) {
assert ( opt_compatible -> type () == coStrings );
if ( opt_compatible -> type () == coStrings )
static_cast < ConfigOptionStrings *> ( opt_compatible ) -> values . clear ();
}
}
2018-07-31 15:09:57 +02:00
size_t num_extruders = ( printer_technology == ptFFF ) ?
std :: min ( config . option < ConfigOptionFloats > ( "nozzle_diameter" ) -> values . size (),
config . option < ConfigOptionFloats > ( "filament_diameter" ) -> values . size ()) :
2018-12-03 13:14:28 +01:00
// 1 SLA material
1 ;
2018-06-28 20:13:01 +02:00
// Make a copy of the "compatible_printers_condition_cummulative" and "inherits_cummulative" vectors, which
2018-06-26 10:50:50 +02:00
// accumulate values over all presets (print, filaments, printers).
// These values will be distributed into their particular presets when loading.
2018-06-28 20:13:01 +02:00
std :: vector < std :: string > compatible_printers_condition_values = std :: move ( config . option < ConfigOptionStrings > ( "compatible_printers_condition_cummulative" , true ) -> values );
2018-12-04 17:56:49 +01:00
std :: vector < std :: string > compatible_prints_condition_values = std :: move ( config . option < ConfigOptionStrings > ( "compatible_prints_condition_cummulative" , true ) -> values );
2018-06-28 20:13:01 +02:00
std :: vector < std :: string > inherits_values = std :: move ( config . option < ConfigOptionStrings > ( "inherits_cummulative" , true ) -> values );
std :: string & compatible_printers_condition = Preset :: compatible_printers_condition ( config );
2018-12-04 17:56:49 +01:00
std :: string & compatible_prints_condition = Preset :: compatible_prints_condition ( config );
2018-06-28 20:13:01 +02:00
std :: string & inherits = Preset :: inherits ( config );
compatible_printers_condition_values . resize ( num_extruders + 2 , std :: string ());
2018-12-04 17:56:49 +01:00
compatible_prints_condition_values . resize ( num_extruders , std :: string ());
2018-06-28 20:13:01 +02:00
inherits_values . resize ( num_extruders + 2 , std :: string ());
2018-07-27 09:53:12 +02:00
// The "default_filament_profile" will be later extracted into the printer profile.
2018-12-03 13:14:28 +01:00
switch ( printer_technology ) {
case ptFFF :
config . option < ConfigOptionString > ( "default_print_profile" , true );
config . option < ConfigOptionStrings > ( "default_filament_profile" , true ) -> values . resize ( num_extruders , std :: string ());
break ;
case ptSLA :
config . option < ConfigOptionString > ( "default_sla_print_profile" , true );
config . option < ConfigOptionString > ( "default_sla_material_profile" , true );
break ;
2019-09-03 10:27:16 +02:00
default : break ;
2018-12-03 13:14:28 +01:00
}
2018-06-26 10:50:50 +02:00
2017-11-02 16:21:34 +01:00
// 1) Create a name from the file name.
2017-10-30 18:41:50 +01:00
// Keep the suffix (.ini, .gcode, .amf, .3mf etc) to differentiate it from the normal profiles.
2017-12-20 11:28:16 +01:00
std :: string name = is_external ? boost :: filesystem :: path ( name_or_path ). filename (). string () : name_or_path ;
2017-10-30 18:41:50 +01:00
2017-11-02 16:21:34 +01:00
// 2) If the loading succeeded, split and load the config into print / filament / printer settings.
2017-10-30 18:41:50 +01:00
// First load the print and printer presets.
2018-11-16 17:36:23 +01:00
2018-12-03 13:14:28 +01:00
auto load_preset =
2018-12-04 17:56:49 +01:00
[ & config , & inherits , & inherits_values ,
& compatible_printers_condition , & compatible_printers_condition_values ,
& compatible_prints_condition , & compatible_prints_condition_values ,
is_external , & name , & name_or_path ]
2018-12-03 13:14:28 +01:00
( PresetCollection & presets , size_t idx , const std :: string & key ) {
// Split the "compatible_printers_condition" and "inherits" values one by one from a single vector to the print & printer profiles.
inherits = inherits_values [ idx ];
compatible_printers_condition = compatible_printers_condition_values [ idx ];
2018-12-04 17:56:49 +01:00
if ( idx > 0 && idx - 1 < compatible_prints_condition_values . size ())
compatible_prints_condition = compatible_prints_condition_values [ idx - 1 ];
2018-07-17 10:41:17 +02:00
if ( is_external )
2018-12-03 13:14:28 +01:00
presets . load_external_preset ( name_or_path , name , config . opt_string ( key , true ), config );
else
presets . load_preset ( presets . path_from_name ( name ), name , config ). save ();
};
switch ( Preset :: printer_technology ( config )) {
case ptFFF :
{
load_preset ( this -> prints , 0 , "print_settings_id" );
load_preset ( this -> printers , num_extruders + 1 , "printer_settings_id" );
2017-10-30 18:41:50 +01:00
2018-07-31 15:09:57 +02:00
// 3) Now load the filaments. If there are multiple filament presets, split them and load them.
auto old_filament_profile_names = config . option < ConfigOptionStrings > ( "filament_settings_id" , true );
old_filament_profile_names -> values . resize ( num_extruders , std :: string ());
2018-06-28 20:13:01 +02:00
2018-07-31 15:09:57 +02:00
if ( num_extruders <= 1 ) {
2018-06-28 20:13:01 +02:00
// Split the "compatible_printers_condition" and "inherits" from the cummulative vectors to separate filament presets.
2018-07-31 15:09:57 +02:00
inherits = inherits_values [ 1 ];
compatible_printers_condition = compatible_printers_condition_values [ 1 ];
2018-12-04 17:56:49 +01:00
compatible_prints_condition = compatible_prints_condition_values . front ();
2018-12-03 13:14:28 +01:00
Preset * loaded = nullptr ;
if ( is_external ) {
loaded = & this -> filaments . load_external_preset ( name_or_path , name , old_filament_profile_names -> values . front (), config );
} else {
loaded = & this -> filaments . load_preset ( this -> filaments . path_from_name ( name ), name , config );
loaded -> save ();
}
2018-07-31 15:09:57 +02:00
this -> filament_presets . clear ();
2018-12-03 13:14:28 +01:00
this -> filament_presets . emplace_back ( loaded -> name );
2018-07-31 15:09:57 +02:00
} else {
// Split the filament presets, load each of them separately.
std :: vector < DynamicPrintConfig > configs ( num_extruders , this -> filaments . default_preset (). config );
// loop through options and scatter them into configs.
for ( const t_config_option_key & key : this -> filaments . default_preset (). config . keys ()) {
const ConfigOption * other_opt = config . option ( key );
if ( other_opt == nullptr )
continue ;
if ( other_opt -> is_scalar ()) {
for ( size_t i = 0 ; i < configs . size (); ++ i )
configs [ i ]. option ( key , false ) -> set ( other_opt );
2018-12-04 17:56:49 +01:00
} else if ( key != "compatible_printers" && key != "compatible_prints" ) {
2018-07-31 15:09:57 +02:00
for ( size_t i = 0 ; i < configs . size (); ++ i )
static_cast < ConfigOptionVectorBase *> ( configs [ i ]. option ( key , false )) -> set_at ( other_opt , 0 , i );
}
}
// Load the configs into this->filaments and make them active.
2019-08-20 18:45:12 +02:00
this -> filament_presets = std :: vector < std :: string > ( configs . size ());
// To avoid incorrect selection of the first filament preset (means a value of Preset->m_idx_selected)
// in a case when next added preset take a place of previosly selected preset,
// we should add presets from last to first
for ( int i = ( int ) configs . size () - 1 ; i >= 0 ; i -- ) {
2018-07-31 15:09:57 +02:00
DynamicPrintConfig & cfg = configs [ i ];
// Split the "compatible_printers_condition" and "inherits" from the cummulative vectors to separate filament presets.
cfg . opt_string ( "compatible_printers_condition" , true ) = compatible_printers_condition_values [ i + 1 ];
2018-12-04 17:56:49 +01:00
cfg . opt_string ( "compatible_prints_condition" , true ) = compatible_prints_condition_values [ i ];
2018-07-31 15:09:57 +02:00
cfg . opt_string ( "inherits" , true ) = inherits_values [ i + 1 ];
// Load all filament presets, but only select the first one in the preset dialog.
Preset * loaded = nullptr ;
if ( is_external )
loaded = & this -> filaments . load_external_preset ( name_or_path , name ,
( i < old_filament_profile_names -> values . size ()) ? old_filament_profile_names -> values [ i ] : "" ,
std :: move ( cfg ), i == 0 );
else {
// Used by the config wizard when creating a custom setup.
// Therefore this block should only be called for a single extruder.
char suffix [ 64 ];
if ( i == 0 )
suffix [ 0 ] = 0 ;
else
2019-06-10 18:30:54 +02:00
sprintf ( suffix , "%d" , ( int ) i );
2018-07-31 15:09:57 +02:00
std :: string new_name = name + suffix ;
loaded = & this -> filaments . load_preset ( this -> filaments . path_from_name ( new_name ),
new_name , std :: move ( cfg ), i == 0 );
loaded -> save ();
}
2019-08-20 18:45:12 +02:00
this -> filament_presets [ i ] = loaded -> name ;
2018-06-26 11:31:01 +02:00
}
2017-10-30 18:41:50 +01:00
}
2018-07-31 15:09:57 +02:00
// 4) Load the project config values (the per extruder wipe matrix etc).
this -> project_config . apply_only ( config , s_project_options );
2018-12-03 13:14:28 +01:00
break ;
}
case ptSLA :
load_preset ( this -> sla_prints , 0 , "sla_print_settings_id" );
load_preset ( this -> sla_materials , 1 , "sla_material_settings_id" );
load_preset ( this -> printers , 2 , "printer_settings_id" );
break ;
2019-09-03 10:27:16 +02:00
default : break ;
2018-07-31 15:09:57 +02:00
}
2018-03-14 11:54:11 +01:00
2018-12-04 17:56:49 +01:00
this -> update_compatible ( false );
2017-10-30 18:41:50 +01:00
}
2017-11-01 19:30:05 +01:00
// Load the active configuration of a config bundle from a boost property_tree. This is a private method called from load_config_file.
void PresetBundle :: load_config_file_config_bundle ( const std :: string & path , const boost :: property_tree :: ptree & tree )
{
// 1) Load the config bundle into a temp data.
PresetBundle tmp_bundle ;
2017-12-19 19:51:22 +01:00
// Load the config bundle, don't save the loaded presets to user profile directory.
tmp_bundle . load_configbundle ( path , 0 );
2017-11-28 11:57:33 +01:00
std :: string bundle_name = std :: string ( " - " ) + boost :: filesystem :: path ( path ). filename (). string ();
2017-11-01 19:30:05 +01:00
// 2) Extract active configs from the config bundle, copy them and activate them in this bundle.
2017-11-28 11:57:33 +01:00
auto load_one = [ this , & path , & bundle_name ]( PresetCollection & collection_dst , PresetCollection & collection_src , const std :: string & preset_name_src , bool activate ) -> std :: string {
Preset * preset_src = collection_src . find_preset ( preset_name_src , false );
Preset * preset_dst = collection_dst . find_preset ( preset_name_src , false );
assert ( preset_src != nullptr );
std :: string preset_name_dst ;
if ( preset_dst != nullptr && preset_dst -> is_default ) {
// No need to copy a default preset, it always exists in collection_dst.
if ( activate )
collection_dst . select_preset ( 0 );
return preset_name_src ;
} else if ( preset_dst != nullptr && preset_src -> config == preset_dst -> config ) {
2017-11-01 19:30:05 +01:00
// Don't save as the config exists in the current bundle and its content is the same.
2017-11-28 11:57:33 +01:00
return preset_name_src ;
2017-11-01 19:30:05 +01:00
} else {
// Generate a new unique name.
2017-11-28 11:57:33 +01:00
preset_name_dst = preset_name_src + bundle_name ;
Preset * preset_dup = nullptr ;
for ( size_t i = 1 ; ( preset_dup = collection_dst . find_preset ( preset_name_dst , false )) != nullptr ; ++ i ) {
if ( preset_src -> config == preset_dup -> config )
// The preset has been already copied into collection_dst.
return preset_name_dst ;
// Try to generate another name.
char buf [ 64 ];
2019-06-10 19:45:38 +02:00
sprintf ( buf , " (%d)" , ( int ) i );
2017-11-28 11:57:33 +01:00
preset_name_dst = preset_name_src + buf + bundle_name ;
}
2017-11-01 19:30:05 +01:00
}
2017-11-28 11:57:33 +01:00
assert ( ! preset_name_dst . empty ());
// Save preset_src->config into collection_dst under preset_name_dst.
2017-12-01 18:55:57 +01:00
// The "compatible_printers" field should not have been exported into a config.ini or a G-code anyway,
// but some of the alpha versions of Slic3r did.
ConfigOption * opt_compatible = preset_src -> config . optptr ( "compatible_printers" );
if ( opt_compatible != nullptr ) {
assert ( opt_compatible -> type () == coStrings );
if ( opt_compatible -> type () == coStrings )
static_cast < ConfigOptionStrings *> ( opt_compatible ) -> values . clear ();
}
2017-11-28 11:57:33 +01:00
collection_dst . load_preset ( path , preset_name_dst , std :: move ( preset_src -> config ), activate ). is_external = true ;
return preset_name_dst ;
};
2019-05-22 11:31:36 +02:00
load_one ( this -> prints , tmp_bundle . prints , tmp_bundle . prints . get_selected_preset_name (), true );
load_one ( this -> sla_prints , tmp_bundle . sla_prints , tmp_bundle . sla_prints . get_selected_preset_name (), true );
load_one ( this -> filaments , tmp_bundle . filaments , tmp_bundle . filaments . get_selected_preset_name (), true );
load_one ( this -> sla_materials , tmp_bundle . sla_materials , tmp_bundle . sla_materials . get_selected_preset_name (), true );
load_one ( this -> printers , tmp_bundle . printers , tmp_bundle . printers . get_selected_preset_name (), true );
2017-11-28 11:57:33 +01:00
this -> update_multi_material_filament_presets ();
for ( size_t i = 1 ; i < std :: min ( tmp_bundle . filament_presets . size (), this -> filament_presets . size ()); ++ i )
this -> filament_presets [ i ] = load_one ( this -> filaments , tmp_bundle . filaments , tmp_bundle . filament_presets [ i ], false );
2017-12-20 11:28:16 +01:00
2018-12-04 17:56:49 +01:00
this -> update_compatible ( false );
2017-11-01 19:30:05 +01:00
}
2018-03-07 16:48:28 +01:00
// Process the Config Bundle loaded as a Boost property tree.
// For each print, filament and printer preset (group defined by group_name), apply the inherited presets.
// The presets starting with '*' are considered non-terminal and they are
// removed through the flattening process by this function.
// This function will never fail, but it will produce error messages through boost::log.
2019-01-08 10:52:11 +01:00
// system_profiles will not be flattened, and they will be kept inside the "inherits" field
static void flatten_configbundle_hierarchy ( boost :: property_tree :: ptree & tree , const std :: string & group_name , const std :: vector < std :: string > & system_profiles )
2018-03-07 16:48:28 +01:00
{
namespace pt = boost :: property_tree ;
typedef std :: pair < pt :: ptree :: key_type , pt :: ptree > ptree_child_type ;
// 1) For the group given by group_name, initialize the presets.
struct Prst {
Prst ( const std :: string & name , pt :: ptree * node ) : name ( name ), node ( node ) {}
// Name of this preset. If the name starts with '*', it is an intermediate preset,
// which will not make it into the result.
const std :: string name ;
// Link to the source boost property tree node, owned by tree.
pt :: ptree * node ;
// Link to the presets, from which this preset inherits.
std :: vector < Prst *> inherits ;
// Link to the presets, for which this preset is a direct parent.
std :: vector < Prst *> parent_of ;
// When running the Kahn's Topological sorting algorithm, this counter is decreased from inherits.size() to zero.
// A cycle is indicated, if the number does not drop to zero after the Kahn's algorithm finishes.
size_t num_incoming_edges_left = 0 ;
// Sorting by the name, to be used when inserted into std::set.
bool operator == ( const Prst & rhs ) const { return this -> name == rhs . name ; }
bool operator < ( const Prst & rhs ) const { return this -> name < rhs . name ; }
};
// Find the presets, store them into a std::map, addressed by their names.
std :: set < Prst > presets ;
std :: string group_name_preset = group_name + ":" ;
for ( auto & section : tree )
if ( boost :: starts_with ( section . first , group_name_preset ) && section . first . size () > group_name_preset . size ())
presets . emplace ( section . first . substr ( group_name_preset . size ()), & section . second );
// Fill in the "inherits" and "parent_of" members, report invalid inheritance fields.
for ( const Prst & prst : presets ) {
// Parse the list of comma separated values, possibly enclosed in quotes.
std :: vector < std :: string > inherits_names ;
2019-01-08 10:52:11 +01:00
std :: vector < std :: string > inherits_system ;
2018-03-07 16:48:28 +01:00
if ( Slic3r :: unescape_strings_cstyle ( prst . node -> get < std :: string > ( "inherits" , "" ), inherits_names )) {
// Resolve the inheritance by name.
std :: vector < Prst *> & inherits_nodes = const_cast < Prst &> ( prst ). inherits ;
for ( const std :: string & node_name : inherits_names ) {
2019-01-08 10:52:11 +01:00
auto it_system = std :: lower_bound ( system_profiles . begin (), system_profiles . end (), node_name );
if ( it_system != system_profiles . end () && * it_system == node_name ) {
// Loading a user config budnle, this preset is derived from a system profile.
inherits_system . emplace_back ( node_name );
} else {
auto it = presets . find ( Prst ( node_name , nullptr ));
if ( it == presets . end ())
BOOST_LOG_TRIVIAL ( error ) << "flatten_configbundle_hierarchy: The preset " << prst . name << " inherits an unknown preset \" " << node_name << " \" " ;
else {
inherits_nodes . emplace_back ( const_cast < Prst *> ( & ( * it )));
inherits_nodes . back () -> parent_of . emplace_back ( const_cast < Prst *> ( & prst ));
}
2018-03-07 16:48:28 +01:00
}
}
} else {
BOOST_LOG_TRIVIAL ( error ) << "flatten_configbundle_hierarchy: The preset " << prst . name << " has an invalid \" inherits \" field" ;
}
2019-01-08 10:52:11 +01:00
// Remove the "inherits" key, it has no meaning outside of the config bundle.
2018-03-07 16:48:28 +01:00
const_cast < pt :: ptree *> ( prst . node ) -> erase ( "inherits" );
2019-01-08 10:52:11 +01:00
if ( ! inherits_system . empty ()) {
// Loaded a user config bundle, where a profile inherits a system profile.
// User profile should be derived from a single system profile only.
assert ( inherits_system . size () == 1 );
if ( inherits_system . size () > 1 )
BOOST_LOG_TRIVIAL ( error ) << "flatten_configbundle_hierarchy: The preset " << prst . name << " inherits from more than single system preset" ;
prst . node -> put ( "inherits" , Slic3r :: escape_string_cstyle ( inherits_system . front ()));
}
2018-03-07 16:48:28 +01:00
}
// 2) Create a linear ordering for the directed acyclic graph of preset inheritance.
// https://en.wikipedia.org/wiki/Topological_sorting
// Kahn's algorithm.
std :: vector < Prst *> sorted ;
{
// Initialize S with the set of all nodes with no incoming edge.
std :: deque < Prst *> S ;
for ( const Prst & prst : presets )
if ( prst . inherits . empty ())
S . emplace_back ( const_cast < Prst *> ( & prst ));
else
const_cast < Prst *> ( & prst ) -> num_incoming_edges_left = prst . inherits . size ();
while ( ! S . empty ()) {
Prst * n = S . front ();
S . pop_front ();
sorted . emplace_back ( n );
for ( Prst * m : n -> parent_of ) {
assert ( m -> num_incoming_edges_left > 0 );
if ( -- m -> num_incoming_edges_left == 0 ) {
// We have visited all parents of m.
S . emplace_back ( m );
}
}
}
if ( sorted . size () < presets . size ()) {
for ( const Prst & prst : presets )
if ( prst . num_incoming_edges_left )
BOOST_LOG_TRIVIAL ( error ) << "flatten_configbundle_hierarchy: The preset " << prst . name << " has cyclic dependencies" ;
}
}
// Apply the dependencies in their topological ordering.
for ( Prst * prst : sorted ) {
// Merge the preset nodes in their order of application.
// Iterate in a reverse order, so the last change will be placed first in merged.
for ( auto it_inherits = prst -> inherits . rbegin (); it_inherits != prst -> inherits . rend (); ++ it_inherits )
for ( auto it = ( * it_inherits ) -> node -> begin (); it != ( * it_inherits ) -> node -> end (); ++ it )
if ( prst -> node -> find ( it -> first ) == prst -> node -> not_found ())
prst -> node -> add_child ( it -> first , it -> second );
}
// Remove the "internal" presets from the ptree. These presets are marked with '*'.
group_name_preset += '*' ;
for ( auto it_section = tree . begin (); it_section != tree . end (); ) {
if ( boost :: starts_with ( it_section -> first , group_name_preset ) && it_section -> first . size () > group_name_preset . size ())
// Remove the "internal" preset from the ptree.
it_section = tree . erase ( it_section );
else
// Keep the preset.
++ it_section ;
}
}
2019-01-08 10:52:11 +01:00
// preset_bundle is set when loading user config bundles, which must not overwrite the system profiles.
static void flatten_configbundle_hierarchy ( boost :: property_tree :: ptree & tree , const PresetBundle * preset_bundle )
2018-03-07 16:48:28 +01:00
{
2019-01-08 10:52:11 +01:00
flatten_configbundle_hierarchy ( tree , "print" , preset_bundle ? preset_bundle -> prints . system_preset_names () : std :: vector < std :: string > ());
flatten_configbundle_hierarchy ( tree , "filament" , preset_bundle ? preset_bundle -> filaments . system_preset_names () : std :: vector < std :: string > ());
flatten_configbundle_hierarchy ( tree , "sla_print" , preset_bundle ? preset_bundle -> sla_prints . system_preset_names () : std :: vector < std :: string > ());
flatten_configbundle_hierarchy ( tree , "sla_material" , preset_bundle ? preset_bundle -> sla_materials . system_preset_names () : std :: vector < std :: string > ());
flatten_configbundle_hierarchy ( tree , "printer" , preset_bundle ? preset_bundle -> printers . system_preset_names () : std :: vector < std :: string > ());
2018-03-07 16:48:28 +01:00
}
2017-10-30 18:41:50 +01:00
// Load a config bundle file, into presets and store the loaded presets into separate files
// of the local configuration directory.
2017-12-19 19:51:22 +01:00
size_t PresetBundle :: load_configbundle ( const std :: string & path , unsigned int flags )
2017-10-30 18:41:50 +01:00
{
2018-03-09 16:37:33 +01:00
if ( flags & ( LOAD_CFGBNDLE_RESET_USER_PROFILE | LOAD_CFGBNDLE_SYSTEM ))
// Reset this bundle, delete user profile files if LOAD_CFGBNDLE_SAVE.
2017-12-19 19:51:22 +01:00
this -> reset ( flags & LOAD_CFGBNDLE_SAVE );
2017-10-30 18:41:50 +01:00
// 1) Read the complete config file into a boost::property_tree.
namespace pt = boost :: property_tree ;
pt :: ptree tree ;
boost :: nowide :: ifstream ifs ( path );
pt :: read_ini ( ifs , tree );
2018-03-09 16:37:33 +01:00
const VendorProfile * vendor_profile = nullptr ;
2018-03-13 12:39:57 +01:00
if ( flags & ( LOAD_CFGBNDLE_SYSTEM | LOAD_CFGBUNDLE_VENDOR_ONLY )) {
2018-04-12 20:04:48 +02:00
auto vp = VendorProfile :: from_ini ( tree , path );
2018-03-09 16:37:33 +01:00
if ( vp . num_variants () == 0 )
return 0 ;
vendor_profile = & ( * this -> vendors . insert ( vp ). first );
}
2018-03-13 12:39:57 +01:00
if ( flags & LOAD_CFGBUNDLE_VENDOR_ONLY ) {
return 0 ;
}
// 1.5) Flatten the config bundle by applying the inheritance rules. Internal profiles (with names starting with '*') are removed.
2019-01-08 10:52:11 +01:00
// If loading a user config bundle, do not flatten with the system profiles, but keep the "inherits" flag intact.
flatten_configbundle_hierarchy ( tree , (( flags & LOAD_CFGBNDLE_SYSTEM ) == 0 ) ? this : nullptr );
2018-03-09 16:37:33 +01:00
2017-10-30 18:41:50 +01:00
// 2) Parse the property_tree, extract the active preset names and the profiles, save them into local config files.
2018-05-16 16:34:07 +02:00
// Parse the obsolete preset names, to be deleted when upgrading from the old configuration structure.
2017-10-30 18:41:50 +01:00
std :: vector < std :: string > loaded_prints ;
std :: vector < std :: string > loaded_filaments ;
2018-11-16 17:36:23 +01:00
std :: vector < std :: string > loaded_sla_prints ;
2018-07-31 15:09:57 +02:00
std :: vector < std :: string > loaded_sla_materials ;
2017-10-30 18:41:50 +01:00
std :: vector < std :: string > loaded_printers ;
std :: string active_print ;
std :: vector < std :: string > active_filaments ;
2018-11-16 17:36:23 +01:00
std :: string active_sla_print ;
2018-07-31 15:09:57 +02:00
std :: string active_sla_material ;
2017-10-30 18:41:50 +01:00
std :: string active_printer ;
size_t presets_loaded = 0 ;
for ( const auto & section : tree ) {
PresetCollection * presets = nullptr ;
std :: vector < std :: string > * loaded = nullptr ;
std :: string preset_name ;
if ( boost :: starts_with ( section . first , "print:" )) {
2018-03-09 16:37:33 +01:00
presets = & this -> prints ;
2017-10-30 18:41:50 +01:00
loaded = & loaded_prints ;
preset_name = section . first . substr ( 6 );
} else if ( boost :: starts_with ( section . first , "filament:" )) {
2018-03-09 16:37:33 +01:00
presets = & this -> filaments ;
2017-10-30 18:41:50 +01:00
loaded = & loaded_filaments ;
preset_name = section . first . substr ( 9 );
2018-11-16 17:36:23 +01:00
} else if ( boost :: starts_with ( section . first , "sla_print:" )) {
presets = & this -> sla_prints ;
loaded = & loaded_sla_prints ;
2018-11-19 11:10:22 +01:00
preset_name = section . first . substr ( 10 );
2018-07-31 15:09:57 +02:00
} else if ( boost :: starts_with ( section . first , "sla_material:" )) {
presets = & this -> sla_materials ;
loaded = & loaded_sla_materials ;
2018-10-31 16:22:36 +01:00
preset_name = section . first . substr ( 13 );
2017-10-30 18:41:50 +01:00
} else if ( boost :: starts_with ( section . first , "printer:" )) {
2018-03-09 16:37:33 +01:00
presets = & this -> printers ;
2017-10-30 18:41:50 +01:00
loaded = & loaded_printers ;
preset_name = section . first . substr ( 8 );
} else if ( section . first == "presets" ) {
// Load the names of the active presets.
for ( auto & kvp : section . second ) {
if ( kvp . first == "print" ) {
active_print = kvp . second . data ();
} else if ( boost :: starts_with ( kvp . first , "filament" )) {
int idx = 0 ;
if ( kvp . first == "filament" || sscanf ( kvp . first . c_str (), "filament_%d" , & idx ) == 1 ) {
if ( int ( active_filaments . size ()) <= idx )
active_filaments . resize ( idx + 1 , std :: string ());
active_filaments [ idx ] = kvp . second . data ();
}
2018-11-16 17:36:23 +01:00
} else if ( kvp . first == "sla_print" ) {
active_sla_print = kvp . second . data ();
2018-07-31 15:09:57 +02:00
} else if ( kvp . first == "sla_material" ) {
active_sla_material = kvp . second . data ();
2017-10-30 18:41:50 +01:00
} else if ( kvp . first == "printer" ) {
active_printer = kvp . second . data ();
}
}
2018-05-16 16:34:07 +02:00
} else if ( section . first == "obsolete_presets" ) {
// Parse the names of obsolete presets. These presets will be deleted from user's
// profile directory on installation of this vendor preset.
for ( auto & kvp : section . second ) {
std :: vector < std :: string > * dst = nullptr ;
if ( kvp . first == "print" )
dst = & this -> obsolete_presets . prints ;
else if ( kvp . first == "filament" )
dst = & this -> obsolete_presets . filaments ;
2018-11-16 17:36:23 +01:00
else if ( kvp . first == "sla_print" )
dst = & this -> obsolete_presets . sla_prints ;
2018-07-31 15:09:57 +02:00
else if ( kvp . first == "sla_material" )
dst = & this -> obsolete_presets . sla_materials ;
2018-05-16 16:34:07 +02:00
else if ( kvp . first == "printer" )
dst = & this -> obsolete_presets . printers ;
if ( dst )
unescape_strings_cstyle ( kvp . second . data (), * dst );
}
2017-10-30 18:41:50 +01:00
} else if ( section . first == "settings" ) {
// Load the settings.
for ( auto & kvp : section . second ) {
if ( kvp . first == "autocenter" ) {
}
}
} else
// Ignore an unknown section.
continue ;
if ( presets != nullptr ) {
// Load the print, filament or printer preset.
2018-10-31 16:22:36 +01:00
const DynamicPrintConfig * default_config = nullptr ;
DynamicPrintConfig config ;
if ( presets == & this -> printers ) {
// Select the default config based on the printer_technology field extracted from kvp.
DynamicPrintConfig config_src ;
for ( auto & kvp : section . second )
config_src . set_deserialize ( kvp . first , kvp . second . data ());
default_config = & presets -> default_preset_for ( config_src ). config ;
config = * default_config ;
config . apply ( config_src );
} else {
default_config = & presets -> default_preset (). config ;
config = * default_config ;
for ( auto & kvp : section . second )
config . set_deserialize ( kvp . first , kvp . second . data ());
}
2017-11-02 16:21:34 +01:00
Preset :: normalize ( config );
2018-05-22 14:17:27 +02:00
// Report configuration fields, which are misplaced into a wrong group.
2018-10-31 16:22:36 +01:00
std :: string incorrect_keys = Preset :: remove_invalid_keys ( config , * default_config );
2018-05-22 14:17:27 +02:00
if ( ! incorrect_keys . empty ())
BOOST_LOG_TRIVIAL ( error ) << "Error in a Vendor Config Bundle \" " << path << " \" : The printer preset \" " <<
section . first << " \" contains the following incorrect keys: " << incorrect_keys << ", which were removed" ;
2018-03-09 16:37:33 +01:00
if (( flags & LOAD_CFGBNDLE_SYSTEM ) && presets == & printers ) {
// Filter out printer presets, which are not mentioned in the vendor profile.
// These presets are considered not installed.
auto printer_model = config . opt_string ( "printer_model" );
if ( printer_model . empty ()) {
BOOST_LOG_TRIVIAL ( error ) << "Error in a Vendor Config Bundle \" " << path << " \" : The printer preset \" " <<
section . first << " \" defines no printer model, it will be ignored." ;
continue ;
}
auto printer_variant = config . opt_string ( "printer_variant" );
if ( printer_variant . empty ()) {
BOOST_LOG_TRIVIAL ( error ) << "Error in a Vendor Config Bundle \" " << path << " \" : The printer preset \" " <<
section . first << " \" defines no printer variant, it will be ignored." ;
continue ;
}
2018-03-13 12:39:57 +01:00
auto it_model = std :: find_if ( vendor_profile -> models . cbegin (), vendor_profile -> models . cend (),
[ & ]( const VendorProfile :: PrinterModel & m ) { return m . id == printer_model ; }
);
2018-03-09 16:37:33 +01:00
if ( it_model == vendor_profile -> models . end ()) {
BOOST_LOG_TRIVIAL ( error ) << "Error in a Vendor Config Bundle \" " << path << " \" : The printer preset \" " <<
section . first << " \" defines invalid printer model \" " << printer_model << " \" , it will be ignored." ;
continue ;
}
auto it_variant = it_model -> variant ( printer_variant );
if ( it_variant == nullptr ) {
BOOST_LOG_TRIVIAL ( error ) << "Error in a Vendor Config Bundle \" " << path << " \" : The printer preset \" " <<
section . first << " \" defines invalid printer variant \" " << printer_variant << " \" , it will be ignored." ;
continue ;
}
const Preset * preset_existing = presets -> find_preset ( section . first , false );
if ( preset_existing != nullptr ) {
BOOST_LOG_TRIVIAL ( error ) << "Error in a Vendor Config Bundle \" " << path << " \" : The printer preset \" " <<
section . first << " \" has already been loaded from another Confing Bundle." ;
continue ;
}
2019-01-03 16:36:45 +01:00
} else if (( flags & LOAD_CFGBNDLE_SYSTEM ) == 0 ) {
// This is a user config bundle.
const Preset * existing = presets -> find_preset ( preset_name , false );
if ( existing != nullptr ) {
if ( existing -> is_system ) {
assert ( existing -> vendor != nullptr );
BOOST_LOG_TRIVIAL ( error ) << "Error in a user provided Config Bundle \" " << path << " \" : The " << presets -> name () << " preset \" " <<
existing -> name << " \" is a system preset of vendor " << existing -> vendor -> name << " and it will be ignored." ;
continue ;
} else {
assert ( existing -> vendor == nullptr );
BOOST_LOG_TRIVIAL ( trace ) << "A " << presets -> name () << " preset \" " << existing -> name << " \" was overwritten with a preset from user Config Bundle \" " << path << " \" " ;
}
} else {
BOOST_LOG_TRIVIAL ( trace ) << "A new " << presets -> name () << " preset \" " << preset_name << " \" was imported from user Config Bundle \" " << path << " \" " ;
}
2018-03-09 16:37:33 +01:00
}
2017-12-10 22:11:00 +01:00
// Decide a full path to this .ini file.
auto file_name = boost :: algorithm :: iends_with ( preset_name , ".ini" ) ? preset_name : preset_name + ".ini" ;
2017-12-14 09:40:45 +01:00
auto file_path = ( boost :: filesystem :: path ( data_dir ())
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
// Store the print/filament/printer presets into a "presets" directory.
/ "presets"
#else
// Store the print/filament/printer presets at the same location as the upstream Slic3r.
#endif
2019-02-03 20:17:55 +01:00
/ presets -> section_name () / file_name ). make_preferred ();
2017-10-30 18:41:50 +01:00
// Load the preset into the list of presets, save it to disk.
2017-12-19 19:51:22 +01:00
Preset & loaded = presets -> load_preset ( file_path . string (), preset_name , std :: move ( config ), false );
if ( flags & LOAD_CFGBNDLE_SAVE )
loaded . save ();
2018-03-09 16:37:33 +01:00
if ( flags & LOAD_CFGBNDLE_SYSTEM ) {
loaded . is_system = true ;
loaded . vendor = vendor_profile ;
}
2017-10-30 18:41:50 +01:00
++ presets_loaded ;
}
}
// 3) Activate the presets.
2018-03-09 16:37:33 +01:00
if (( flags & LOAD_CFGBNDLE_SYSTEM ) == 0 ) {
if ( ! active_print . empty ())
prints . select_preset_by_name ( active_print , true );
2018-11-16 17:36:23 +01:00
if ( ! active_sla_print . empty ())
sla_materials . select_preset_by_name ( active_sla_print , true );
2018-07-31 15:09:57 +02:00
if ( ! active_sla_material . empty ())
sla_materials . select_preset_by_name ( active_sla_material , true );
2018-03-09 16:37:33 +01:00
if ( ! active_printer . empty ())
printers . select_preset_by_name ( active_printer , true );
// Activate the first filament preset.
if ( ! active_filaments . empty () && ! active_filaments . front (). empty ())
filaments . select_preset_by_name ( active_filaments . front (), true );
this -> update_multi_material_filament_presets ();
for ( size_t i = 0 ; i < std :: min ( this -> filament_presets . size (), active_filaments . size ()); ++ i )
this -> filament_presets [ i ] = filaments . find_preset ( active_filaments [ i ], true ) -> name ;
2018-12-04 17:56:49 +01:00
this -> update_compatible ( false );
2018-03-09 16:37:33 +01:00
}
2017-10-30 18:41:50 +01:00
return presets_loaded ;
}
void PresetBundle :: update_multi_material_filament_presets ()
{
2018-08-01 11:09:51 +02:00
if ( printers . get_edited_preset (). printer_technology () != ptFFF )
return ;
2017-10-30 18:41:50 +01:00
// Verify and select the filament presets.
2017-11-01 19:30:05 +01:00
auto * nozzle_diameter = static_cast < const ConfigOptionFloats *> ( printers . get_edited_preset (). config . option ( "nozzle_diameter" ));
2017-10-30 18:41:50 +01:00
size_t num_extruders = nozzle_diameter -> values . size ();
// Verify validity of the current filament presets.
for ( size_t i = 0 ; i < std :: min ( this -> filament_presets . size (), num_extruders ); ++ i )
this -> filament_presets [ i ] = this -> filaments . find_preset ( this -> filament_presets [ i ], true ) -> name ;
// Append the rest of filament presets.
2018-07-02 20:25:37 +02:00
this -> filament_presets . resize ( num_extruders , this -> filament_presets . empty () ? this -> filaments . first_visible (). name : this -> filament_presets . back ());
2018-03-21 09:36:27 +01:00
// Now verify if wiping_volumes_matrix has proper size (it is used to deduce number of extruders in wipe tower generator):
2018-04-04 10:18:26 +02:00
std :: vector < double > old_matrix = this -> project_config . option < ConfigOptionFloats > ( "wiping_volumes_matrix" ) -> values ;
2018-03-21 09:36:27 +01:00
size_t old_number_of_extruders = int ( sqrt ( old_matrix . size ()) + EPSILON );
2018-03-21 10:20:36 +01:00
if ( num_extruders != old_number_of_extruders ) {
// First verify if purging volumes presets for each extruder matches number of extruders
2018-04-04 10:18:26 +02:00
std :: vector < double >& extruders = this -> project_config . option < ConfigOptionFloats > ( "wiping_volumes_extruders" ) -> values ;
2018-03-21 09:36:27 +01:00
while ( extruders . size () < 2 * num_extruders ) {
2018-03-21 10:20:36 +01:00
extruders . push_back ( extruders . size () > 1 ? extruders [ 0 ] : 50. ); // copy the values from the first extruder
extruders . push_back ( extruders . size () > 1 ? extruders [ 1 ] : 50. );
2018-03-21 09:36:27 +01:00
}
while ( extruders . size () > 2 * num_extruders ) {
extruders . pop_back ();
extruders . pop_back ();
}
2018-03-21 10:20:36 +01:00
2018-03-21 09:36:27 +01:00
std :: vector < double > new_matrix ;
for ( unsigned int i = 0 ; i < num_extruders ; ++ i )
for ( unsigned int j = 0 ; j < num_extruders ; ++ j ) {
// append the value for this pair from the old matrix (if it's there):
if ( i < old_number_of_extruders && j < old_number_of_extruders )
new_matrix . push_back ( old_matrix [ i * old_number_of_extruders + j ]);
else
new_matrix . push_back ( i == j ? 0. : extruders [ 2 * i ] + extruders [ 2 * j + 1 ]); // so it matches new extruder volumes
}
2018-04-04 10:18:26 +02:00
this -> project_config . option < ConfigOptionFloats > ( "wiping_volumes_matrix" ) -> values = new_matrix ;
2018-03-21 09:36:27 +01:00
}
2017-10-30 18:41:50 +01:00
}
2018-12-04 17:56:49 +01:00
void PresetBundle :: update_compatible ( bool select_other_if_incompatible )
2017-11-10 17:27:05 +01:00
{
2018-12-04 17:56:49 +01:00
const Preset & printer_preset = this -> printers . get_edited_preset ();
2018-08-01 11:09:51 +02:00
2019-03-13 15:44:50 +01:00
switch ( printer_preset . printer_technology ()) {
2018-08-01 11:09:51 +02:00
case ptFFF :
{
2018-12-03 13:14:28 +01:00
assert ( printer_preset . config . has ( "default_print_profile" ));
assert ( printer_preset . config . has ( "default_filament_profile" ));
2018-12-04 17:56:49 +01:00
const Preset & print_preset = this -> prints . get_edited_preset ();
2018-12-03 13:14:28 +01:00
const std :: string & prefered_print_profile = printer_preset . config . opt_string ( "default_print_profile" );
2018-08-01 11:09:51 +02:00
const std :: vector < std :: string > & prefered_filament_profiles = printer_preset . config . option < ConfigOptionStrings > ( "default_filament_profile" ) -> values ;
prefered_print_profile . empty () ?
2018-12-04 17:56:49 +01:00
this -> prints . update_compatible ( printer_preset , nullptr , select_other_if_incompatible ) :
this -> prints . update_compatible ( printer_preset , nullptr , select_other_if_incompatible ,
2018-10-31 12:56:08 +01:00
[ & prefered_print_profile ]( const std :: string & profile_name ) { return profile_name == prefered_print_profile ; });
2018-08-01 11:09:51 +02:00
prefered_filament_profiles . empty () ?
2018-12-04 17:56:49 +01:00
this -> filaments . update_compatible ( printer_preset , & print_preset , select_other_if_incompatible ) :
this -> filaments . update_compatible ( printer_preset , & print_preset , select_other_if_incompatible ,
2018-08-01 11:09:51 +02:00
[ & prefered_filament_profiles ]( const std :: string & profile_name )
{ return std :: find ( prefered_filament_profiles . begin (), prefered_filament_profiles . end (), profile_name ) != prefered_filament_profiles . end (); });
if ( select_other_if_incompatible ) {
// Verify validity of the current filament presets.
2019-03-18 15:10:40 +01:00
if ( this -> filament_presets . size () == 1 )
this -> filament_presets . front () = this -> filaments . get_edited_preset (). name ;
else
{
for ( size_t idx = 0 ; idx < this -> filament_presets . size (); ++ idx ) {
std :: string & filament_name = this -> filament_presets [ idx ];
Preset * preset = this -> filaments . find_preset ( filament_name , false );
if ( preset == nullptr || ! preset -> is_compatible ) {
// Pick a compatible profile. If there are prefered_filament_profiles, use them.
if ( prefered_filament_profiles . empty ())
filament_name = this -> filaments . first_compatible (). name ;
else {
const std :: string & preferred = ( idx < prefered_filament_profiles . size ()) ?
prefered_filament_profiles [ idx ] : prefered_filament_profiles . front ();
filament_name = this -> filaments . first_compatible (
[ & preferred ]( const std :: string & profile_name ) { return profile_name == preferred ; }). name ;
}
2018-08-01 11:09:51 +02:00
}
2018-04-13 14:49:33 +02:00
}
}
2017-11-10 17:27:05 +01:00
}
2018-10-31 18:05:25 +01:00
break ;
2017-11-10 17:27:05 +01:00
}
2018-08-01 11:09:51 +02:00
case ptSLA :
{
2018-12-03 13:14:28 +01:00
assert ( printer_preset . config . has ( "default_sla_print_profile" ));
assert ( printer_preset . config . has ( "default_sla_material_profile" ));
2018-12-04 17:56:49 +01:00
const Preset & sla_print_preset = this -> sla_prints . get_edited_preset ();
2018-12-03 13:14:28 +01:00
const std :: string & prefered_sla_print_profile = printer_preset . config . opt_string ( "default_sla_print_profile" );
( prefered_sla_print_profile . empty ()) ?
2018-12-04 17:56:49 +01:00
this -> sla_prints . update_compatible ( printer_preset , nullptr , select_other_if_incompatible ) :
this -> sla_prints . update_compatible ( printer_preset , nullptr , select_other_if_incompatible ,
2018-12-03 13:14:28 +01:00
[ & prefered_sla_print_profile ]( const std :: string & profile_name ){ return profile_name == prefered_sla_print_profile ; });
const std :: string & prefered_sla_material_profile = printer_preset . config . opt_string ( "default_sla_material_profile" );
2018-10-31 16:22:36 +01:00
prefered_sla_material_profile . empty () ?
2018-12-04 17:56:49 +01:00
this -> sla_materials . update_compatible ( printer_preset , & sla_print_preset , select_other_if_incompatible ) :
this -> sla_materials . update_compatible ( printer_preset , & sla_print_preset , select_other_if_incompatible ,
2018-10-31 16:25:55 +01:00
[ & prefered_sla_material_profile ]( const std :: string & profile_name ){ return profile_name == prefered_sla_material_profile ; });
2018-10-31 18:05:25 +01:00
break ;
}
2019-09-03 10:27:16 +02:00
default : break ;
2018-08-01 11:09:51 +02:00
}
2017-11-10 17:27:05 +01:00
}
2018-12-12 18:37:10 +01:00
void PresetBundle :: export_configbundle ( const std :: string & path , bool export_system_settings )
2017-10-30 18:41:50 +01:00
{
boost :: nowide :: ofstream c ;
c . open ( path , std :: ios :: out | std :: ios :: trunc );
// Put a comment at the first line including the time stamp and Slic3r version.
c << "# " << Slic3r :: header_slic3r_generated () << std :: endl ;
// Export the print, filament and printer profiles.
2018-11-16 17:36:23 +01:00
2018-12-12 18:37:10 +01:00
for ( const PresetCollection * presets : {
( const PresetCollection * ) & this -> prints , ( const PresetCollection * ) & this -> filaments ,
( const PresetCollection * ) & this -> sla_prints , ( const PresetCollection * ) & this -> sla_materials ,
( const PresetCollection * ) & this -> printers }) {
for ( const Preset & preset : ( * presets )()) {
if ( preset . is_default || preset . is_external || ( preset . is_system && ! export_system_settings ))
2017-10-30 18:41:50 +01:00
// Only export the common presets, not external files or the default preset.
continue ;
2019-02-03 20:17:55 +01:00
c << std :: endl << "[" << presets -> section_name () << ":" << preset . name << "]" << std :: endl ;
2017-10-30 18:41:50 +01:00
for ( const std :: string & opt_key : preset . config . keys ())
2019-06-26 13:26:49 +02:00
c << opt_key << " = " << preset . config . opt_serialize ( opt_key ) << std :: endl ;
2017-10-30 18:41:50 +01:00
}
}
// Export the names of the active presets.
2017-11-01 19:30:05 +01:00
c << std :: endl << "[presets]" << std :: endl ;
2019-05-22 11:31:36 +02:00
c << "print = " << this -> prints . get_selected_preset_name () << std :: endl ;
c << "sla_print = " << this -> sla_prints . get_selected_preset_name () << std :: endl ;
c << "sla_material = " << this -> sla_materials . get_selected_preset_name () << std :: endl ;
c << "printer = " << this -> printers . get_selected_preset_name () << std :: endl ;
2017-10-30 18:41:50 +01:00
for ( size_t i = 0 ; i < this -> filament_presets . size (); ++ i ) {
char suffix [ 64 ];
if ( i > 0 )
2019-06-10 18:30:54 +02:00
sprintf ( suffix , "_%d" , ( int ) i );
2017-10-30 18:41:50 +01:00
else
suffix [ 0 ] = 0 ;
c << "filament" << suffix << " = " << this -> filament_presets [ i ] << std :: endl ;
}
2017-11-01 19:30:05 +01:00
#if 0
2017-10-30 18:41:50 +01:00
// Export the following setting values from the provided setting repository.
static const char *settings_keys[] = { "autocenter" };
2017-11-01 19:30:05 +01:00
c << "[settings]" << std::endl;
2017-10-30 18:41:50 +01:00
for (size_t i = 0; i < sizeof(settings_keys) / sizeof(settings_keys[0]); ++ i)
c << settings_keys[i] << " = " << settings.serialize(settings_keys[i]) << std::endl;
2017-11-01 19:30:05 +01:00
#endif
2017-10-30 18:41:50 +01:00
c . close ();
}
// Set the filament preset name. As the name could come from the UI selection box,
// an optional "(modified)" suffix will be removed from the filament name.
void PresetBundle :: set_filament_preset ( size_t idx , const std :: string & name )
{
2019-03-22 17:07:12 +01:00
if ( name . find_first_of ( PresetCollection :: separator_head ()) == 0 )
2018-04-20 17:32:08 +02:00
return ;
2017-10-30 18:41:50 +01:00
if ( idx >= filament_presets . size ())
filament_presets . resize ( idx + 1 , filaments . default_preset (). name );
filament_presets [ idx ] = Preset :: remove_suffix_modified ( name );
}
static inline int hex_digit_to_int ( const char c )
{
return
( c >= '0' && c <= '9' ) ? int ( c - '0' ) :
( c >= 'A' && c <= 'F' ) ? int ( c - 'A' ) + 10 :
( c >= 'a' && c <= 'f' ) ? int ( c - 'a' ) + 10 : - 1 ;
}
2018-04-05 12:52:29 +02:00
bool PresetBundle :: parse_color ( const std :: string & scolor , unsigned char * rgb_out )
2017-10-30 18:41:50 +01:00
{
rgb_out [ 0 ] = rgb_out [ 1 ] = rgb_out [ 2 ] = 0 ;
if ( scolor . size () != 7 || scolor . front () != '#' )
return false ;
2017-11-30 17:55:39 +01:00
const char * c = scolor . data () + 1 ;
2017-10-30 18:41:50 +01:00
for ( size_t i = 0 ; i < 3 ; ++ i ) {
int digit1 = hex_digit_to_int ( * c ++ );
int digit2 = hex_digit_to_int ( * c ++ );
if ( digit1 == - 1 || digit2 == - 1 )
return false ;
rgb_out [ i ] = ( unsigned char )( digit1 * 16 + digit2 );
}
return true ;
}
2019-04-09 17:40:14 +02:00
void PresetBundle :: load_default_preset_bitmaps ( wxWindow * window )
2019-04-08 09:37:23 +02:00
{
2019-04-10 09:56:32 +02:00
// Clear bitmap cache, before load new scaled default preset bitmaps
m_bitmapCache -> clear ();
this -> prints . clear_bitmap_cache ();
this -> sla_prints . clear_bitmap_cache ();
this -> filaments . clear_bitmap_cache ();
this -> sla_materials . clear_bitmap_cache ();
this -> printers . clear_bitmap_cache ();
2019-04-09 17:40:14 +02:00
this -> prints . load_bitmap_default ( window , "cog" );
this -> sla_prints . load_bitmap_default ( window , "cog" );
this -> filaments . load_bitmap_default ( window , "spool.png" );
2019-04-10 09:41:04 +02:00
this -> sla_materials . load_bitmap_default ( window , "resin" );
2019-04-09 17:40:14 +02:00
this -> printers . load_bitmap_default ( window , "printer" );
this -> printers . load_bitmap_add ( window , "add.png" );
this -> load_compatible_bitmaps ( window );
2019-04-08 09:37:23 +02:00
}
2019-04-23 16:33:06 +02:00
void PresetBundle :: update_platter_filament_ui ( unsigned int idx_extruder , GUI :: PresetComboBox * ui )
2017-10-30 18:41:50 +01:00
{
2019-02-22 09:38:56 +01:00
if ( ui == nullptr || this -> printers . get_edited_preset (). printer_technology () == ptSLA ||
2019-03-16 22:23:51 +01:00
this -> filament_presets . size () <= idx_extruder )
2017-10-30 18:41:50 +01:00
return ;
unsigned char rgb [ 3 ];
std :: string extruder_color = this -> printers . get_edited_preset (). config . opt_string ( "extruder_colour" , idx_extruder );
if ( ! parse_color ( extruder_color , rgb ))
// Extruder color is not defined.
extruder_color . clear ();
// Fill in the list from scratch.
ui -> Freeze ();
ui -> Clear ();
2018-06-29 11:29:23 +02:00
size_t selected_preset_item = 0 ;
2017-11-10 17:27:05 +01:00
const Preset * selected_preset = this -> filaments . find_preset ( this -> filament_presets [ idx_extruder ]);
// Show wide icons if the currently selected preset is not compatible with the current printer,
// and draw a red flag in front of the selected preset.
bool wide_icons = selected_preset != nullptr && ! selected_preset -> is_compatible && m_bitmapIncompatible != nullptr ;
assert ( selected_preset != nullptr );
2018-04-19 12:08:59 +02:00
std :: map < wxString , wxBitmap *> nonsys_presets ;
2018-04-11 13:56:37 +02:00
wxString selected_str = "" ;
2018-04-19 12:08:59 +02:00
if ( ! this -> filaments (). front (). is_visible )
2019-03-22 17:07:12 +01:00
ui -> set_label_marker ( ui -> Append ( PresetCollection :: separator ( L ( "System presets" )), wxNullBitmap ));
2019-04-14 10:57:03 +02:00
/* It's supposed that standard size of an icon is 16px*16px for 100% scaled display.
* So set sizes for solid_colored icons used for filament preset
2019-04-23 16:33:06 +02:00
* and scale them in respect to em_unit value
2019-04-14 10:57:03 +02:00
*/
2019-04-23 16:33:06 +02:00
const float scale_f = ui -> em_unit () * 0.1f ;
2019-08-25 10:31:18 +02:00
// To avoid the errors of number rounding for different combination of monitor configuration,
// let use scaled 8px, as a smallest icon unit
const int icon_unit = 8 * scale_f + 0.5f ;
const int normal_icon_width = 2 * icon_unit ; //16 * scale_f + 0.5f;
const int thin_icon_width = icon_unit ; //8 * scale_f + 0.5f;
const int wide_icon_width = 3 * icon_unit ; //24 * scale_f + 0.5f;
2019-04-14 10:57:03 +02:00
const int space_icon_width = 2 * scale_f + 0.5f ;
2019-09-03 15:30:37 +02:00
// To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size, so
// set a bitmap height to m_bitmapLock->GetHeight()
const int icon_height = m_bitmapLock -> GetHeight (); //2 * icon_unit; //16 * scale_f + 0.5f;
2018-04-19 12:08:59 +02:00
for ( int i = this -> filaments (). front (). is_visible ? 0 : 1 ; i < int ( this -> filaments (). size ()); ++ i ) {
2017-11-10 17:27:05 +01:00
const Preset & preset = this -> filaments . preset ( i );
bool selected = this -> filament_presets [ idx_extruder ] == preset . name ;
if ( ! preset . is_visible || ( ! preset . is_compatible && ! selected ))
2017-10-30 18:41:50 +01:00
continue ;
// Assign an extruder color to the selected item if the extruder color is defined.
std :: string filament_rgb = preset . config . opt_string ( "filament_colour" , 0 );
std :: string extruder_rgb = ( selected && ! extruder_color . empty ()) ? extruder_color : filament_rgb ;
2017-11-10 17:27:05 +01:00
bool single_bar = filament_rgb == extruder_rgb ;
std :: string bitmap_key = single_bar ? filament_rgb : filament_rgb + extruder_rgb ;
// If the filament preset is not compatible and there is a "red flag" icon loaded, show it left
// to the filament color image.
if ( wide_icons )
2018-03-12 16:04:32 +01:00
bitmap_key += preset . is_compatible ? ",cmpt" : ",ncmpt" ;
bitmap_key += ( preset . is_system || preset . is_default ) ? ",syst" : ",nsyst" ;
2018-03-13 09:45:04 +01:00
if ( preset . is_dirty )
bitmap_key += ",drty" ;
2018-03-12 16:04:32 +01:00
wxBitmap * bitmap = m_bitmapCache -> find ( bitmap_key );
2017-11-10 17:27:05 +01:00
if ( bitmap == nullptr ) {
// Create the bitmap with color bars.
2018-03-12 16:04:32 +01:00
std :: vector < wxBitmap > bmps ;
if ( wide_icons )
// Paint a red flag for incompatible presets.
2019-04-14 10:57:03 +02:00
bmps . emplace_back ( preset . is_compatible ? m_bitmapCache -> mkclear ( normal_icon_width , icon_height ) : * m_bitmapIncompatible );
2017-11-10 17:27:05 +01:00
// Paint the color bars.
parse_color ( filament_rgb , rgb );
2019-04-14 10:57:03 +02:00
bmps . emplace_back ( m_bitmapCache -> mksolid ( single_bar ? wide_icon_width : normal_icon_width , icon_height , rgb ));
2017-11-10 17:27:05 +01:00
if ( ! single_bar ) {
parse_color ( extruder_rgb , rgb );
2019-04-14 10:57:03 +02:00
bmps . emplace_back ( m_bitmapCache -> mksolid ( thin_icon_width , icon_height , rgb ));
2017-11-10 17:27:05 +01:00
}
2018-03-12 16:04:32 +01:00
// Paint a lock at the system presets.
2019-04-14 10:57:03 +02:00
bmps . emplace_back ( m_bitmapCache -> mkclear ( space_icon_width , icon_height ));
2019-09-02 10:53:07 +02:00
// To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size, so
// for nonsystem presets set a width of empty bitmap to m_bitmapLock->GetWidth()
bmps . emplace_back (( preset . is_system || preset . is_default ) ? * m_bitmapLock : m_bitmapCache -> mkclear ( m_bitmapLock -> GetWidth (), icon_height ));
2018-04-19 12:08:59 +02:00
// (preset.is_dirty ? *m_bitmapLockOpen : *m_bitmapLock) : m_bitmapCache->mkclear(16, 16));
2018-03-12 16:04:32 +01:00
bitmap = m_bitmapCache -> insert ( bitmap_key , bmps );
2017-10-30 18:41:50 +01:00
}
2018-04-11 13:56:37 +02:00
2018-10-31 12:56:08 +01:00
if ( preset . is_default || preset . is_system ) {
2018-04-11 13:56:37 +02:00
ui -> Append ( wxString :: FromUTF8 (( preset . name + ( preset . is_dirty ? Preset :: suffix_modified () : "" )). c_str ()),
( bitmap == 0 ) ? wxNullBitmap : * bitmap );
if ( selected )
2018-06-29 11:29:23 +02:00
selected_preset_item = ui -> GetCount () - 1 ;
2018-04-11 13:56:37 +02:00
}
else
{
nonsys_presets . emplace ( wxString :: FromUTF8 (( preset . name + ( preset . is_dirty ? Preset :: suffix_modified () : "" )). c_str ()),
2018-04-19 12:08:59 +02:00
( bitmap == 0 ) ? & wxNullBitmap : bitmap );
2018-04-11 13:56:37 +02:00
if ( selected )
selected_str = wxString :: FromUTF8 (( preset . name + ( preset . is_dirty ? Preset :: suffix_modified () : "" )). c_str ());
}
if ( preset . is_default )
2019-03-22 17:07:12 +01:00
ui -> set_label_marker ( ui -> Append ( PresetCollection :: separator ( L ( "System presets" )), wxNullBitmap ));
2017-10-30 18:41:50 +01:00
}
2018-04-11 13:56:37 +02:00
if ( ! nonsys_presets . empty ())
{
2019-03-22 17:07:12 +01:00
ui -> set_label_marker ( ui -> Append ( PresetCollection :: separator ( L ( "User presets" )), wxNullBitmap ));
2018-04-19 12:08:59 +02:00
for ( std :: map < wxString , wxBitmap *>:: iterator it = nonsys_presets . begin (); it != nonsys_presets . end (); ++ it ) {
ui -> Append ( it -> first , * it -> second );
2018-04-11 13:56:37 +02:00
if ( it -> first == selected_str )
2018-06-29 11:29:23 +02:00
selected_preset_item = ui -> GetCount () - 1 ;
2018-04-11 13:56:37 +02:00
}
}
2018-06-29 11:29:23 +02:00
ui -> SetSelection ( selected_preset_item );
ui -> SetToolTip ( ui -> GetString ( selected_preset_item ));
2019-03-23 10:04:44 +01:00
ui -> check_selection ();
2017-10-30 18:41:50 +01:00
ui -> Thaw ();
2019-04-23 16:33:06 +02:00
// Update control min size after rescale (changed Display DPI under MSW)
if ( ui -> GetMinWidth () != 20 * ui -> em_unit ())
ui -> SetMinSize ( wxSize ( 20 * ui -> em_unit (), ui -> GetSize (). GetHeight ()));
2017-10-30 18:41:50 +01:00
}
void PresetBundle :: set_default_suppressed ( bool default_suppressed )
{
prints . set_default_suppressed ( default_suppressed );
filaments . set_default_suppressed ( default_suppressed );
2018-11-16 17:36:23 +01:00
sla_prints . set_default_suppressed ( default_suppressed );
2018-08-09 09:25:23 +02:00
sla_materials . set_default_suppressed ( default_suppressed );
2017-10-30 18:41:50 +01:00
printers . set_default_suppressed ( default_suppressed );
}
} // namespace Slic3r