diff options
author | enricoturri1966 <enricoturri@seznam.cz> | 2021-12-17 13:47:07 +0300 |
---|---|---|
committer | enricoturri1966 <enricoturri@seznam.cz> | 2021-12-17 13:47:07 +0300 |
commit | f7513b61e7032567b02b3e459c6538a70a29b0b3 (patch) | |
tree | 1b08fafcd2a7d860fb47ac9aa11cde415769435c /src | |
parent | c30f5823f5b86e486abab9e84dabbd8e89e7c4f1 (diff) | |
parent | 93c4b941b560fb1d690e890594b05b435ea11e85 (diff) |
Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into dev
Diffstat (limited to 'src')
-rw-r--r-- | src/libslic3r/AppConfig.cpp | 33 | ||||
-rw-r--r-- | src/libslic3r/AppConfig.hpp | 12 | ||||
-rw-r--r-- | src/libslic3r/GCode/AvoidCrossingPerimeters.cpp | 66 | ||||
-rw-r--r-- | src/libslic3r/Preset.cpp | 2 | ||||
-rw-r--r-- | src/libslic3r/PresetBundle.cpp | 32 | ||||
-rw-r--r-- | src/libslic3r/PresetBundle.hpp | 2 | ||||
-rw-r--r-- | src/slic3r/Config/Snapshot.cpp | 6 | ||||
-rw-r--r-- | src/slic3r/Config/Snapshot.hpp | 2 | ||||
-rw-r--r-- | src/slic3r/GUI/GLCanvas3D.cpp | 6 | ||||
-rw-r--r-- | src/slic3r/GUI/GUI_App.cpp | 137 | ||||
-rw-r--r-- | src/slic3r/GUI/GUI_App.hpp | 10 | ||||
-rw-r--r-- | src/slic3r/GUI/GUI_ObjectList.cpp | 4 | ||||
-rw-r--r-- | src/slic3r/GUI/MsgDialog.cpp | 18 | ||||
-rw-r--r-- | src/slic3r/GUI/Tab.cpp | 9 | ||||
-rw-r--r-- | src/slic3r/GUI/UpdateDialogs.cpp | 2 |
15 files changed, 215 insertions, 126 deletions
diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index ab636a03e..ec5ce3702 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -43,6 +43,10 @@ const std::string AppConfig::SECTION_MATERIALS = "sla_materials"; void AppConfig::reset() { m_storage.clear(); + m_vendors.clear(); + m_dirty = false; + m_orig_version = Semver::invalid(); + m_legacy_datadir = false; set_defaults(); }; @@ -243,8 +247,10 @@ static bool verify_config_file_checksum(boost::nowide::ifstream &ifs) } #endif -std::string AppConfig::load() +std::string AppConfig::load(const std::string &path) { + this->reset(); + // 1) Read the complete config file into a boost::property_tree. namespace pt = boost::property_tree; pt::ptree tree; @@ -252,11 +258,11 @@ std::string AppConfig::load() bool recovered = false; try { - ifs.open(AppConfig::loading_path()); + ifs.open(path); #ifdef WIN32 // Verify the checksum of the config file without taking just for debugging purpose. if (!verify_config_file_checksum(ifs)) - BOOST_LOG_TRIVIAL(info) << "The configuration file " << AppConfig::loading_path() << + BOOST_LOG_TRIVIAL(info) << "The configuration file " << path << " has a wrong MD5 checksum or the checksum is missing. This may indicate a file corruption or a harmless user edit."; ifs.seekg(0, boost::nowide::ifstream::beg); @@ -266,32 +272,32 @@ std::string AppConfig::load() #ifdef WIN32 // The configuration file is corrupted, try replacing it with the backup configuration. ifs.close(); - std::string backup_path = (boost::format("%1%.bak") % AppConfig::loading_path()).str(); + std::string backup_path = (boost::format("%1%.bak") % path).str(); if (boost::filesystem::exists(backup_path)) { // Compute checksum of the configuration backup file and try to load configuration from it when the checksum is correct. boost::nowide::ifstream backup_ifs(backup_path); if (!verify_config_file_checksum(backup_ifs)) { - BOOST_LOG_TRIVIAL(error) << format("Both \"%1%\" and \"%2%\" are corrupted. It isn't possible to restore configuration from the backup.", AppConfig::loading_path(), backup_path); + BOOST_LOG_TRIVIAL(error) << format("Both \"%1%\" and \"%2%\" are corrupted. It isn't possible to restore configuration from the backup.", path, backup_path); backup_ifs.close(); boost::filesystem::remove(backup_path); - } else if (std::string error_message; copy_file(backup_path, AppConfig::loading_path(), error_message, false) != SUCCESS) { - BOOST_LOG_TRIVIAL(error) << format("Configuration file \"%1%\" is corrupted. Failed to restore from backup \"%2%\": %3%", AppConfig::loading_path(), backup_path, error_message); + } else if (std::string error_message; copy_file(backup_path, path, error_message, false) != SUCCESS) { + BOOST_LOG_TRIVIAL(error) << format("Configuration file \"%1%\" is corrupted. Failed to restore from backup \"%2%\": %3%", path, backup_path, error_message); backup_ifs.close(); boost::filesystem::remove(backup_path); } else { - BOOST_LOG_TRIVIAL(info) << format("Configuration file \"%1%\" was corrupted. It has been succesfully restored from the backup \"%2%\".", AppConfig::loading_path(), backup_path); + BOOST_LOG_TRIVIAL(info) << format("Configuration file \"%1%\" was corrupted. It has been succesfully restored from the backup \"%2%\".", path, backup_path); // Try parse configuration file after restore from backup. try { - ifs.open(AppConfig::loading_path()); + ifs.open(path); pt::read_ini(ifs, tree); recovered = true; } catch (pt::ptree_error& ex) { - BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\" after it has been restored from backup: %2%", AppConfig::loading_path(), ex.what()); + BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\" after it has been restored from backup: %2%", path, ex.what()); } } } else #endif // WIN32 - BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\": %2%", AppConfig::loading_path(), ex.what()); + BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\": %2%", path, ex.what()); if (! recovered) { // Report the initial error of parsing PrusaSlicer.ini. // Error while parsing config file. We'll customize the error message and rethrow to be displayed. @@ -367,6 +373,11 @@ std::string AppConfig::load() return ""; } +std::string AppConfig::load() +{ + return this->load(AppConfig::config_path()); +} + void AppConfig::save() { { diff --git a/src/libslic3r/AppConfig.hpp b/src/libslic3r/AppConfig.hpp index 5d9f32ab7..418f3427b 100644 --- a/src/libslic3r/AppConfig.hpp +++ b/src/libslic3r/AppConfig.hpp @@ -22,10 +22,7 @@ public: }; explicit AppConfig(EAppMode mode) : - m_dirty(false), - m_orig_version(Semver::invalid()), - m_mode(mode), - m_legacy_datadir(false) + m_mode(mode) { this->reset(); } @@ -38,6 +35,8 @@ public: // Load the slic3r.ini from a user profile directory (or a datadir, if configured). // return error string or empty strinf std::string load(); + // Load from an explicit path. + std::string load(const std::string &path); // Store the slic3r.ini into a user profile directory (or a datadir, if configured). void save(); @@ -148,9 +147,6 @@ public: // Does the config file exist? bool exists(); - void set_loading_path(const std::string& path) { m_loading_path = path; } - std::string loading_path() { return (m_loading_path.empty() ? config_path() : m_loading_path); } - std::vector<std::string> get_recent_projects() const; void set_recent_projects(const std::vector<std::string>& recent_projects); @@ -199,8 +195,6 @@ private: Semver m_orig_version; // Whether the existing version is before system profiles & configuration updating bool m_legacy_datadir; - - std::string m_loading_path; }; } // namespace Slic3r diff --git a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp index 48b9515f7..417322584 100644 --- a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp +++ b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp @@ -731,34 +731,50 @@ static bool need_wipe(const GCode &gcodegen, } // Adds points around all vertices so that the offset affects only small sections around these vertices. -static void resample_polygon(Polygon &polygon, double dist_from_vertex) +static void resample_polygon(Polygon &polygon, double dist_from_vertex, double max_allowed_distance) { Points resampled_poly; resampled_poly.reserve(3 * polygon.size()); - resampled_poly.emplace_back(polygon.first_point()); - for (size_t pt_idx = 1; pt_idx < polygon.size(); ++pt_idx) { - const Point &p1 = polygon[pt_idx - 1]; - const Point &p2 = polygon[pt_idx]; - double line_length = (p2 - p1).cast<double>().norm(); - Vector line_vec = ((p2 - p1).cast<double>().normalized() * dist_from_vertex).cast<coord_t>(); - if (line_length > 2 * dist_from_vertex) { - resampled_poly.emplace_back(p1 + line_vec); - resampled_poly.emplace_back(p2 - line_vec); - } + for (size_t pt_idx = 0; pt_idx < polygon.size(); ++pt_idx) { resampled_poly.emplace_back(polygon[pt_idx]); + + const Point &p1 = polygon[pt_idx]; + const Point &p2 = polygon[next_idx_modulo(pt_idx, polygon.size())]; + const Vec2d line_vec = (p2 - p1).cast<double>(); + double line_length = line_vec.norm(); + const Vector vertex_offset_vec = (line_vec.normalized() * dist_from_vertex).cast<coord_t>(); + if (line_length > 2 * dist_from_vertex && vertex_offset_vec != Vector(0, 0)) { + resampled_poly.emplace_back(p1 + vertex_offset_vec); + + const Vec2d new_vertex_vec = (p2 - p1 - 2 * vertex_offset_vec).cast<double>(); + const double new_vertex_vec_length = new_vertex_vec.norm(); + if (new_vertex_vec_length > max_allowed_distance) { + const Vec2d &prev_point = resampled_poly.back().cast<double>(); + const size_t parts_count = size_t(ceil(new_vertex_vec_length / max_allowed_distance)); + for (size_t part_idx = 1; part_idx < parts_count; ++part_idx) { + const double part_param = double(part_idx) / double(parts_count); + const Vec2d new_point = prev_point + new_vertex_vec * part_param; + resampled_poly.emplace_back(new_point.cast<coord_t>()); + } + } + + resampled_poly.emplace_back(p2 - vertex_offset_vec); + } } polygon.points = std::move(resampled_poly); } -static void resample_expolygon(ExPolygon &ex_polygon, double dist_from_vertex) +static void resample_expolygon(ExPolygon &ex_polygon, double dist_from_vertex, double max_allowed_distance) { - resample_polygon(ex_polygon.contour, dist_from_vertex); - for (Polygon &polygon : ex_polygon.holes) resample_polygon(polygon, dist_from_vertex); + resample_polygon(ex_polygon.contour, dist_from_vertex, max_allowed_distance); + for (Polygon &polygon : ex_polygon.holes) + resample_polygon(polygon, dist_from_vertex, max_allowed_distance); } -static void resample_expolygons(ExPolygons &ex_polygons, double dist_from_vertex) +static void resample_expolygons(ExPolygons &ex_polygons, double dist_from_vertex, double max_allowed_distance) { - for (ExPolygon &ex_poly : ex_polygons) resample_expolygon(ex_poly, dist_from_vertex); + for (ExPolygon &ex_poly : ex_polygons) + resample_expolygon(ex_poly, dist_from_vertex, max_allowed_distance); } static void precompute_polygon_distances(const Polygon &polygon, std::vector<float> &polygon_distances_out) @@ -834,7 +850,7 @@ static std::vector<float> contour_distance(const EdgeGrid::Grid &grid, double param_end = boundary_parameters.back(); const size_t ipt = it_contour_and_segment->second; if (contour.begin() + ipt + 1 < contour.end()) - param_hi += boundary_parameters[ipt > 0 ? ipt - 1 : 0]; + param_hi += boundary_parameters[ipt]; if (param_lo > param_hi) std::swap(param_lo, param_hi); assert(param_lo > -SCALED_EPSILON && param_lo <= param_end + SCALED_EPSILON); @@ -932,7 +948,7 @@ static ExPolygons inner_offset(const ExPolygons &ex_polygons, double offset) double min_contour_width = 2. * offset + SCALED_EPSILON; double search_radius = 2. * (offset + min_contour_width); ExPolygons ex_poly_result = ex_polygons; - resample_expolygons(ex_poly_result, offset / 2); + resample_expolygons(ex_poly_result, offset / 2, scaled<double>(0.5)); for (ExPolygon &ex_poly : ex_poly_result) { BoundingBox bbox(get_extents(ex_poly)); @@ -1034,24 +1050,30 @@ static Polygons get_boundary_external(const Layer &layer) #endif // Collect all holes for all printed objects and their instances, which will be printed at the same time as passed "layer". for (const PrintObject *object : layer.object()->print()->objects()) { - Polygons polygons_per_obj; + Polygons holes_per_obj; #ifdef INCLUDE_SUPPORTS_IN_BOUNDARY ExPolygons supports_per_obj; #endif if (const Layer *l = object->get_layer_at_printz(layer.print_z, EPSILON); l) - for (const ExPolygon &island : l->lslices) append(polygons_per_obj, island.holes); + for (const ExPolygon &island : l->lslices) + append(holes_per_obj, island.holes); if (support_layer) { auto *layer_below = object->get_first_layer_bellow_printz(layer.print_z, EPSILON); if (layer_below) - for (const ExPolygon &island : layer_below->lslices) append(polygons_per_obj, island.holes); + for (const ExPolygon &island : layer_below->lslices) + append(holes_per_obj, island.holes); #ifdef INCLUDE_SUPPORTS_IN_BOUNDARY append(supports_per_obj, support_layer->support_islands.expolygons); #endif } + // After 7ff76d07684858fd937ef2f5d863f105a10f798e, when expand is called on CW polygons (holes), they are shrunk + // instead of expanded because union that makes CCW from CW isn't called anymore. So let's make it CCW. + polygons_reverse(holes_per_obj); + for (const PrintInstance &instance : object->instances()) { size_t boundary_idx = boundary.size(); - append(boundary, polygons_per_obj); + append(boundary, holes_per_obj); for (; boundary_idx < boundary.size(); ++boundary_idx) boundary[boundary_idx].translate(instance.shift); #ifdef INCLUDE_SUPPORTS_IN_BOUNDARY diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 65027a390..2397a7d19 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1391,7 +1391,7 @@ const Preset* PrinterPresetCollection::find_system_preset_by_model_and_variant(c bool PrinterPresetCollection::only_default_printers() const { for (const auto& printer : get_presets()) { - if (!boost::starts_with(printer.name,"- default")) + if (! printer.is_default) return false; } return true; diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index b6e7fbd5e..874b775cd 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -209,18 +209,34 @@ static void copy_dir(const boost::filesystem::path& from_dir, const boost::files } } -void PresetBundle::copy_files(const std::string& from) +// Import newer configuration from alternate PrusaSlicer configuration directory. +// AppConfig from the alternate location is already loaded. +// User profiles are being merged (old files are not being deleted), +// while old vendors and cache folders are being deleted before newer are copied. +void PresetBundle::import_newer_configs(const std::string& from) { boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir()); + // Clean-up vendors from the target directory, as the existing vendors will not be referenced + // by the copied PrusaSlicer.ini + try { + boost::filesystem::remove_all(data_dir / "cache"); + } catch (const std::exception &ex) { + BOOST_LOG_TRIVIAL(error) << "Error deleting old cache " << (data_dir / "cache").string() << ": " << ex.what(); + } + try { + boost::filesystem::remove_all(data_dir / "vendor"); + } catch (const std::exception &ex) { + BOOST_LOG_TRIVIAL(error) << "Error deleting old vendors " << (data_dir / "vendor").string() << ": " << ex.what(); + } // list of searched paths based on current directory system in setup_directories() // do not copy cache and snapshots boost::filesystem::path from_data_dir = boost::filesystem::path(from); std::initializer_list<boost::filesystem::path> from_dirs= { + from_data_dir / "cache", from_data_dir / "vendor", from_data_dir / "shapes", #ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR // Store the print/filament/printer presets into a "presets" directory. - data_dir / "presets", data_dir / "presets" / "print", data_dir / "presets" / "filament", data_dir / "presets" / "sla_print", @@ -1235,11 +1251,13 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_configbundle( // 1) Read the complete config file into a boost::property_tree. namespace pt = boost::property_tree; pt::ptree tree; - boost::nowide::ifstream ifs(path); - try { - pt::read_ini(ifs, tree); - } catch (const boost::property_tree::ini_parser::ini_parser_error &err) { - throw Slic3r::RuntimeError(format("Failed loading config bundle \"%1%\"\nError: \"%2%\" at line %3%", path, err.message(), err.line()).c_str()); + { + boost::nowide::ifstream ifs(path); + try { + pt::read_ini(ifs, tree); + } catch (const boost::property_tree::ini_parser::ini_parser_error &err) { + throw Slic3r::RuntimeError(format("Failed loading config bundle \"%1%\"\nError: \"%2%\" at line %3%", path, err.message(), err.line()).c_str()); + } } const VendorProfile *vendor_profile = nullptr; diff --git a/src/libslic3r/PresetBundle.hpp b/src/libslic3r/PresetBundle.hpp index a975e37fe..2a5ce6839 100644 --- a/src/libslic3r/PresetBundle.hpp +++ b/src/libslic3r/PresetBundle.hpp @@ -24,7 +24,7 @@ public: void reset(bool delete_files); void setup_directories(); - void copy_files(const std::string& from); + void import_newer_configs(const std::string& from); struct PresetPreferences { std::string printer_model_id;// name of a preferred printer model diff --git a/src/slic3r/Config/Snapshot.cpp b/src/slic3r/Config/Snapshot.cpp index 77a74bffe..a0f386339 100644 --- a/src/slic3r/Config/Snapshot.cpp +++ b/src/slic3r/Config/Snapshot.cpp @@ -586,10 +586,12 @@ const Snapshot* take_config_snapshot_report_error(const AppConfig &app_config, S } } -bool take_config_snapshot_cancel_on_error(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment, const std::string &message) +bool take_config_snapshot_cancel_on_error(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment, const std::string &message, Snapshot const **psnapshot) { try { - SnapshotDB::singleton().take_snapshot(app_config, reason, comment); + const Snapshot *snapshot = &SnapshotDB::singleton().take_snapshot(app_config, reason, comment); + if (psnapshot) + *psnapshot = snapshot; return true; } catch (std::exception &err) { RichMessageDialog dlg(static_cast<wxWindow*>(wxGetApp().mainframe), diff --git a/src/slic3r/Config/Snapshot.hpp b/src/slic3r/Config/Snapshot.hpp index f45300633..5793aa548 100644 --- a/src/slic3r/Config/Snapshot.hpp +++ b/src/slic3r/Config/Snapshot.hpp @@ -132,7 +132,7 @@ const Snapshot* take_config_snapshot_report_error(const AppConfig &app_config, S // Take snapshot on SnapshotDB::singleton(). If taking snapshot fails, report "message", and present a "Continue" or "Abort" buttons to respond. // Return true on success and on "Continue" to continue with the process (for example installation of presets). -bool take_config_snapshot_cancel_on_error(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment, const std::string &message); +bool take_config_snapshot_cancel_on_error(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment, const std::string &message, Snapshot const **psnapshot = nullptr); } // namespace Config } // namespace GUI diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 622f5b3e2..a3b54a841 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1869,6 +1869,12 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // updates volumes transformations volume->set_instance_transformation(mvs->model_volume->get_object()->instances[mvs->composite_id.instance_id]->get_transformation()); volume->set_volume_transformation(mvs->model_volume->get_transformation()); + + // updates volumes convex hull + if (mvs->model_volume->is_model_part() && ! volume->convex_hull()) + // Model volume was likely changed from modifier or support blocker / enforcer to a model part. + // Only model parts require convex hulls. + volume->set_convex_hull(mvs->model_volume->get_convex_hull_shared_ptr()); } } } diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index e4078c9c1..cf14fc735 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -862,9 +862,9 @@ static boost::optional<Semver> parse_semver_from_ini(std::string path) void GUI_App::init_app_config() { // Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release. -// SetAppName(SLIC3R_APP_KEY); + SetAppName(SLIC3R_APP_KEY); // SetAppName(SLIC3R_APP_KEY "-alpha"); - SetAppName(SLIC3R_APP_KEY "-beta"); +// SetAppName(SLIC3R_APP_KEY "-beta"); // SetAppDisplayName(SLIC3R_APP_NAME); // Set the Slic3r data directory at the Slic3r XS module. @@ -909,17 +909,18 @@ void GUI_App::init_app_config() "\n\n" + app_config->config_path() + "\n\n" + error); } } - // Save orig_version here, so its empty if no app_config existed before this run. - m_last_config_version = app_config->orig_version();//parse_semver_from_ini(app_config->config_path()); } } -// returns true if found newer version and user agreed to use it -bool GUI_App::check_older_app_config(Semver current_version, bool backup) +// returns old config path to copy from if such exists, +// returns an empty string if such config path does not exists or if it cannot be loaded. +std::string GUI_App::check_older_app_config(Semver current_version, bool backup) { + std::string older_data_dir_path; + // If the config folder is redefined - do not check if (m_datadir_redefined) - return false; + return {}; // find other version app config (alpha / beta / release) std::string config_path = app_config->config_path(); @@ -940,13 +941,13 @@ bool GUI_App::check_older_app_config(Semver current_version, bool backup) boost::optional<Semver>other_semver = parse_semver_from_ini(candidate.string()); if (other_semver && *other_semver > last_semver) { last_semver = *other_semver; - m_older_data_dir_path = candidate.parent_path().string(); + older_data_dir_path = candidate.parent_path().string(); } } } - if (m_older_data_dir_path.empty()) - return false; - BOOST_LOG_TRIVIAL(info) << "last app config file used: " << m_older_data_dir_path; + if (older_data_dir_path.empty()) + return {}; + BOOST_LOG_TRIVIAL(info) << "last app config file used: " << older_data_dir_path; // ask about using older data folder InfoDialog msg(nullptr @@ -959,13 +960,13 @@ bool GUI_App::check_older_app_config(Semver current_version, bool backup) "\n\nShall the newer configuration be imported?" "\nIf so, your active configuration will be backed up before importing the new configuration." ) - , SLIC3R_APP_NAME, current_version.to_string(), m_older_data_dir_path, last_semver.to_string()) + , SLIC3R_APP_NAME, current_version.to_string(), older_data_dir_path, last_semver.to_string()) : format_wxstr(_L( "An existing configuration was found in <b>%3%</b>" "\ncreated by <b>%1% %2%</b>." "\n\nShall this configuration be imported?" ) - , SLIC3R_APP_NAME, last_semver.to_string(), m_older_data_dir_path) + , SLIC3R_APP_NAME, last_semver.to_string(), older_data_dir_path) , true, wxYES_NO); if (backup) { @@ -976,24 +977,21 @@ bool GUI_App::check_older_app_config(Semver current_version, bool backup) if (msg.ShowModal() == wxID_YES) { std::string snapshot_id; if (backup) { - // configuration snapshot - std::string comment; - if (const Config::Snapshot* snapshot = Config::take_config_snapshot_report_error( - *app_config, - Config::Snapshot::SNAPSHOT_USER, - comment); - snapshot != nullptr) - // Is thos correct? Save snapshot id for later, when new app config is loaded. + const Config::Snapshot* snapshot{ nullptr }; + if (! GUI::Config::take_config_snapshot_cancel_on_error(*app_config, Config::Snapshot::SNAPSHOT_USER, "", + _u8L("Continue and import newer configuration?"), &snapshot)) + return {}; + if (snapshot) { + // Save snapshot ID before loading the alternate AppConfig, as loading the alternate AppConfig may fail. snapshot_id = snapshot->id; - else - BOOST_LOG_TRIVIAL(error) << "Failed to take congiguration snapshot: "; + assert(! snapshot_id.empty()); + app_config->set("on_snapshot", snapshot_id); + } else + BOOST_LOG_TRIVIAL(error) << "Failed to take congiguration snapshot"; } - // This will tell later (when config folder structure is sure to exists) to copy files from m_older_data_dir_path - m_init_app_config_from_older = true; // load app config from older file - app_config->set_loading_path((boost::filesystem::path(m_older_data_dir_path) / filename).string()); - std::string error = app_config->load(); + std::string error = app_config->load((boost::filesystem::path(older_data_dir_path) / filename).string()); if (!error.empty()) { // Error while parsing config file. We'll customize the error message and rethrow to be displayed. if (is_editor()) { @@ -1012,14 +1010,9 @@ bool GUI_App::check_older_app_config(Semver current_version, bool backup) if (!snapshot_id.empty()) app_config->set("on_snapshot", snapshot_id); m_app_conf_exists = true; - return true; + return older_data_dir_path; } - return false; -} - -void GUI_App::copy_older_config() -{ - preset_bundle->copy_files(m_older_data_dir_path); + return {}; } void GUI_App::init_single_instance_checker(const std::string &name, const std::string &path) @@ -1085,6 +1078,42 @@ bool GUI_App::on_init_inner() // Slic3r::debugf "wxWidgets version %s, Wx version %s\n", wxVERSION_STRING, wxVERSION; + // !!! Initialization of UI settings as a language, application color mode, fonts... have to be done before first UI action. + // Like here, before the show InfoDialog in check_older_app_config() + + // If load_language() fails, the application closes. + load_language(wxString(), true); +#ifdef _MSW_DARK_MODE + bool init_dark_color_mode = app_config->get("dark_color_mode") == "1"; + bool init_sys_menu_enabled = app_config->get("sys_menu_enabled") == "1"; + NppDarkMode::InitDarkMode(init_dark_color_mode, init_sys_menu_enabled); +#endif + // initialize label colors and fonts + init_label_colours(); + init_fonts(); + + std::string older_data_dir_path; + if (m_app_conf_exists) { + if (app_config->orig_version().valid() && app_config->orig_version() < *Semver::parse(SLIC3R_VERSION)) + // Only copying configuration if it was saved with a newer slicer than the one currently running. + older_data_dir_path = check_older_app_config(app_config->orig_version(), true); + } else { + // No AppConfig exists, fresh install. Always try to copy from an alternate location, don't make backup of the current configuration. + older_data_dir_path = check_older_app_config(Semver(), false); + } + +#ifdef _MSW_DARK_MODE + // app_config can be updated in check_older_app_config(), so check if dark_color_mode and sys_menu_enabled was changed + if (bool new_dark_color_mode = app_config->get("dark_color_mode") == "1"; + init_dark_color_mode != new_dark_color_mode) { + NppDarkMode::SetDarkMode(new_dark_color_mode); + init_label_colours(); + update_label_colours_from_appconfig(); + } + if (bool new_sys_menu_enabled = app_config->get("sys_menu_enabled") == "1"; + init_sys_menu_enabled != new_sys_menu_enabled) + NppDarkMode::SetSystemMenuForApp(new_sys_menu_enabled); +#endif if (is_editor()) { std::string msg = Http::tls_global_init(); @@ -1106,24 +1135,6 @@ bool GUI_App::on_init_inner() } } - // Set language and color mode before check_older_app_config() call - - // If load_language() fails, the application closes. - load_language(wxString(), true); -#ifdef _MSW_DARK_MODE - NppDarkMode::InitDarkMode(app_config->get("dark_color_mode") == "1", app_config->get("sys_menu_enabled") == "1"); -#endif - - if (m_last_config_version) { - if (*m_last_config_version < *Semver::parse(SLIC3R_VERSION)) - check_older_app_config(*m_last_config_version, true); - } else { - check_older_app_config(Semver(), false); - } - - app_config->set("version", SLIC3R_VERSION); - app_config->save(); - SplashScreen* scrn = nullptr; if (app_config->get("show_splash_screen") == "1") { // make a bitmap with dark grey banner on the left side @@ -1152,10 +1163,13 @@ bool GUI_App::on_init_inner() // just checking for existence of Slic3r::data_dir is not enough : it may be an empty directory // supplied as argument to --datadir; in that case we should still run the wizard preset_bundle->setup_directories(); - - if (m_init_app_config_from_older) - copy_older_config(); + if (! older_data_dir_path.empty()) + preset_bundle->import_newer_configs(older_data_dir_path); + + // Save PrusaSlicer.ini after possibly copying the config from the alternate location and after all the configs from the alternate location were copied. + app_config->set("version", SLIC3R_VERSION); + app_config->save(); if (is_editor()) { #ifdef __WXMSW__ @@ -1204,10 +1218,6 @@ bool GUI_App::on_init_inner() #endif // __WXMSW__ } - // initialize label colors and fonts - init_label_colours(); - init_fonts(); - // Suppress the '- default -' presets. preset_bundle->set_default_suppressed(app_config->get("no_defaults") == "1"); try { @@ -1708,6 +1718,7 @@ void GUI_App::force_colors_update() if (WXHWND wxHWND = wxToolTip::GetToolTipCtrl()) NppDarkMode::SetDarkExplorerTheme((HWND)wxHWND); NppDarkMode::SetDarkTitleBar(mainframe->GetHWND()); + NppDarkMode::SetDarkTitleBar(mainframe->m_settings_dialog.GetHWND()); #endif //_MSW_DARK_MODE m_force_colors_update = true; } @@ -1727,6 +1738,14 @@ void GUI_App::update_ui_from_settings() mainframe->printhost_queue_dlg()->force_color_changed(); #ifdef _MSW_DARK_MODE update_scrolls(mainframe); + if (mainframe->is_dlg_layout()) { + // update for tabs bar + UpdateDarkUI(&mainframe->m_settings_dialog); + mainframe->m_settings_dialog.Fit(); + mainframe->m_settings_dialog.Refresh(); + // update scrollbars + update_scrolls(&mainframe->m_settings_dialog); + } #endif //_MSW_DARK_MODE } #endif diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index b1b0a7786..9c65bc024 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -341,8 +341,9 @@ public: private: bool on_init_inner(); void init_app_config(); - bool check_older_app_config(Semver current_version, bool backup); - void copy_older_config(); + // returns old config path to copy from if such exists, + // returns an empty string if such config path does not exists or if it cannot be loaded. + std::string check_older_app_config(Semver current_version, bool backup); void window_pos_save(wxTopLevelWindow* window, const std::string &name); void window_pos_restore(wxTopLevelWindow* window, const std::string &name, bool default_maximized = false); void window_pos_sanitize(wxTopLevelWindow* window); @@ -351,10 +352,7 @@ private: bool config_wizard_startup(); void check_updates(const bool verbose); - bool m_init_app_config_from_older { false }; - bool m_datadir_redefined { false }; - std::string m_older_data_dir_path; - boost::optional<Semver> m_last_config_version; + bool m_datadir_redefined { false }; }; DECLARE_APP(GUI_App) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 160999db3..85ab42119 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1398,6 +1398,8 @@ void ObjectList::load_subobject(ModelVolumeType type, bool from_galery/* = false if (m_objects_model->GetItemType(item)&itInstance) item = m_objects_model->GetItemById(obj_idx); + take_snapshot((type == ModelVolumeType::MODEL_PART) ? _L("Load Part") : _L("Load Modifier")); + std::vector<ModelVolume*> volumes; // ! ysFIXME - delete commented code after testing and rename "load_modifier" to something common /* @@ -1409,8 +1411,6 @@ void ObjectList::load_subobject(ModelVolumeType type, bool from_galery/* = false if (volumes.empty()) return; - take_snapshot((type == ModelVolumeType::MODEL_PART) ? _L("Load Part") : _L("Load Modifier")); - wxDataViewItemArray items = reorder_volumes_and_get_selection(obj_idx, [volumes](const ModelVolume* volume) { return std::find(volumes.begin(), volumes.end(), volume) != volumes.end(); }); diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp index 4e2462d4b..a70a9b172 100644 --- a/src/slic3r/GUI/MsgDialog.cpp +++ b/src/slic3r/GUI/MsgDialog.cpp @@ -131,7 +131,11 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); wxFont monospace = wxGetApp().code_font(); +#ifdef _WIN32 wxColour text_clr = wxGetApp().get_label_clr_default(); +#else + wxColour text_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); +#endif wxColour bgr_clr = parent->GetBackgroundColour(); //wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue()); auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()); @@ -143,6 +147,20 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin // calculate html page size from text wxSize page_size; int em = wxGetApp().em_unit(); + if (!wxGetApp().mainframe) { + // If mainframe is nullptr, it means that GUI_App::on_init_inner() isn't completed + // (We just show information dialog about configuration version now) + // And as a result the em_unit value wasn't created yet + // So, calculate it from the scale factor of Dialog +#if defined(__WXGTK__) + // Linux specific issue : get_dpi_for_window(this) still doesn't responce to the Display's scale in new wxWidgets(3.1.3). + // So, initialize default width_unit according to the width of the one symbol ("m") of the currently active font of this window. + em = std::max<size_t>(10, parent->GetTextExtent("m").x - 1); +#else + double scale_factor = (double)get_dpi_for_window(parent) / (double)DPI_DEFAULT; + em = std::max<size_t>(10, 10.0f * scale_factor); +#endif // __WXGTK__ + } // if message containes the table if (msg.Contains("<tr>")) { diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 417ab60fa..2f2db22a7 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1769,14 +1769,13 @@ void TabPrint::update() // Note: This workaround works till "support_material" and "overhangs" is exclusive sets of mutually no-exclusive parameters. // But it should be corrected when we will have more such sets. // Disable check of the compatibility of the "support_material" and "overhangs" options for saved user profile - // or for profile which was loaded from 3mf -// if (!m_config_manipulation.is_initialized_support_material_overhangs_queried()) - if (bool support_material_overhangs_queried = m_config->opt_bool("support_material") && !m_config->opt_bool("overhangs")) + // NOTE: Initialization of the support_material_overhangs_queried value have to be processed just ones + if (!m_config_manipulation.is_initialized_support_material_overhangs_queried()) { const Preset& selected_preset = m_preset_bundle->prints.get_selected_preset(); bool is_user_and_saved_preset = !selected_preset.is_system && !selected_preset.is_dirty; - bool is_saved_in_3mf_preset = selected_preset.is_dirty && !wxGetApp().plater()->is_presets_dirty(); - m_config_manipulation.initialize_support_material_overhangs_queried((is_user_and_saved_preset || is_saved_in_3mf_preset) && support_material_overhangs_queried); + bool support_material_overhangs_queried = m_config->opt_bool("support_material") && !m_config->opt_bool("overhangs"); + m_config_manipulation.initialize_support_material_overhangs_queried(is_user_and_saved_preset && support_material_overhangs_queried); } m_config_manipulation.update_print_fff_config(m_config, true); diff --git a/src/slic3r/GUI/UpdateDialogs.cpp b/src/slic3r/GUI/UpdateDialogs.cpp index 367c290d9..f80975ce5 100644 --- a/src/slic3r/GUI/UpdateDialogs.cpp +++ b/src/slic3r/GUI/UpdateDialogs.cpp @@ -132,6 +132,7 @@ MsgUpdateConfig::MsgUpdateConfig(const std::vector<Update> &updates, bool force_ line->AddSpacer(3*VERT_SPACING); line->Add(new wxHyperlinkCtrl(this, wxID_ANY, _(L("Open changelog page")), changelog_url)); versions->Add(line); + versions->AddSpacer(1); // empty value for the correct alignment inside a GridSizer } } @@ -189,6 +190,7 @@ MsgUpdateForced::MsgUpdateForced(const std::vector<Update>& updates) : line->AddSpacer(3 * VERT_SPACING); line->Add(new wxHyperlinkCtrl(this, wxID_ANY, _(L("Open changelog page")), changelog_url)); versions->Add(line); + versions->AddSpacer(1); // empty value for the correct alignment inside a GridSizer } } |