diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index 3c3a4d18d..be16a2015 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -487,6 +487,46 @@ void AppConfig::save() m_dirty = false; } +bool AppConfig::erase(const std::string §ion, const std::string &key) +{ + if (auto it_storage = m_storage.find(section); it_storage != m_storage.end()) { + auto §ion = it_storage->second; + auto it = section.find(key); + if (it != section.end()) { + section.erase(it); + m_dirty = true; + return true; + } + } + return false; +} + +bool AppConfig::set_section(const std::string §ion, std::map data) +{ + auto it_section = m_storage.find(section); + if (it_section == m_storage.end()) { + if (data.empty()) + return false; + it_section = m_storage.insert({ section, {} }).first; + } + auto &dst = it_section->second; + if (dst == data) + return false; + dst = std::move(data); + m_dirty = true; + return true; +} + +bool AppConfig::clear_section(const std::string §ion) +{ + if (auto it_section = m_storage.find(section); it_section != m_storage.end() && ! it_section->second.empty()) { + it_section->second.clear(); + m_dirty = true; + return true; + } + return false; +} + bool AppConfig::get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const { const auto it_v = m_vendors.find(vendor); @@ -495,28 +535,47 @@ bool AppConfig::get_variant(const std::string &vendor, const std::string &model, return it_m == it_v->second.end() ? false : it_m->second.find(variant) != it_m->second.end(); } -void AppConfig::set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable) +bool AppConfig::set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable) { if (enable) { - if (get_variant(vendor, model, variant)) { return; } + if (get_variant(vendor, model, variant)) + return false; m_vendors[vendor][model].insert(variant); } else { auto it_v = m_vendors.find(vendor); - if (it_v == m_vendors.end()) { return; } + if (it_v == m_vendors.end()) + return false; auto it_m = it_v->second.find(model); - if (it_m == it_v->second.end()) { return; } + if (it_m == it_v->second.end()) + return false; auto it_var = it_m->second.find(variant); - if (it_var == it_m->second.end()) { return; } + if (it_var == it_m->second.end()) + return false; it_m->second.erase(it_var); } // If we got here, there was an update m_dirty = true; + return true; } -void AppConfig::set_vendors(const AppConfig &from) +bool AppConfig::set_vendors(const VendorMap &vendors) { - m_vendors = from.m_vendors; - m_dirty = true; + if (m_vendors != vendors) { + m_vendors = vendors; + m_dirty = true; + return true; + } else + return false; +} + +bool AppConfig::set_vendors(VendorMap &&vendors) +{ + if (m_vendors != vendors) { + m_vendors = std::move(vendors); + m_dirty = true; + return true; + } else + return false; } std::string AppConfig::get_last_dir() const @@ -551,34 +610,52 @@ std::vector AppConfig::get_recent_projects() const return ret; } -void AppConfig::set_recent_projects(const std::vector& recent_projects) +bool AppConfig::set_recent_projects(const std::vector& recent_projects) { - auto it = m_storage.find("recent_projects"); - if (it == m_storage.end()) - it = m_storage.insert(std::map>::value_type("recent_projects", std::map())).first; - - it->second.clear(); - for (unsigned int i = 0; i < (unsigned int)recent_projects.size(); ++i) - { - it->second[std::to_string(i + 1)] = recent_projects[i]; + static constexpr const char *section = "recent_projects"; + auto it_section = m_storage.find(section); + if (it_section == m_storage.end()) { + if (recent_projects.empty()) + return false; + it_section = m_storage.insert({ std::string(section), {} }).first; } + auto &dst = it_section->second; + + std::map src; + for (unsigned int i = 0; i < (unsigned int)recent_projects.size(); ++i) + src[std::to_string(i + 1)] = recent_projects[i]; + + if (src != dst) { + dst = std::move(src); + m_dirty = true; + return true; + } else + return false; } -void AppConfig::set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, +bool AppConfig::set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone, double zoom_speed, bool swap_yz) { - std::string key = std::string("mouse_device:") + name; - auto it = m_storage.find(key); - if (it == m_storage.end()) - it = m_storage.insert(std::map>::value_type(key, std::map())).first; + const std::string key = std::string("mouse_device:") + name; + auto it_section = m_storage.find(key); + if (it_section == m_storage.end()) + it_section = m_storage.insert({ key, {} }).first; + auto &dst = it_section->second; - it->second.clear(); - it->second["translation_speed"] = float_to_string_decimal_point(translation_speed); - it->second["translation_deadzone"] = float_to_string_decimal_point(translation_deadzone); - it->second["rotation_speed"] = float_to_string_decimal_point(rotation_speed); - it->second["rotation_deadzone"] = float_to_string_decimal_point(rotation_deadzone); - it->second["zoom_speed"] = float_to_string_decimal_point(zoom_speed); - it->second["swap_yz"] = swap_yz ? "1" : "0"; + std::map src; + src["translation_speed"] = float_to_string_decimal_point(translation_speed); + src["translation_deadzone"] = float_to_string_decimal_point(translation_deadzone); + src["rotation_speed"] = float_to_string_decimal_point(rotation_speed); + src["rotation_deadzone"] = float_to_string_decimal_point(rotation_deadzone); + src["zoom_speed"] = float_to_string_decimal_point(zoom_speed); + src["swap_yz"] = swap_yz ? "1" : "0"; + + if (src != dst) { + dst = std::move(src); + m_dirty = true; + return true; + } else + return false; } std::vector AppConfig::get_mouse_device_names() const @@ -592,16 +669,16 @@ std::vector AppConfig::get_mouse_device_names() const return out; } -void AppConfig::update_config_dir(const std::string &dir) +bool AppConfig::update_config_dir(const std::string &dir) { - this->set("recent", "config_directory", dir); + return this->set("recent", "config_directory", dir); } -void AppConfig::update_skein_dir(const std::string &dir) +bool AppConfig::update_skein_dir(const std::string &dir) { if (is_shapes_dir(dir)) - return; // do not save "shapes gallery" directory - this->set("recent", "skein_directory", dir); + return false; // do not save "shapes gallery" directory + return this->set("recent", "skein_directory", dir); } /* std::string AppConfig::get_last_output_dir(const std::string &alt) const @@ -636,9 +713,9 @@ std::string AppConfig::get_last_output_dir(const std::string& alt, const bool re return is_shapes_dir(alt) ? get_last_dir() : alt; } -void AppConfig::update_last_output_dir(const std::string& dir, const bool removable) +bool AppConfig::update_last_output_dir(const std::string& dir, const bool removable) { - this->set("", (removable ? "last_output_path_removable" : "last_output_path"), dir); + return this->set("", (removable ? "last_output_path_removable" : "last_output_path"), dir); } @@ -656,7 +733,7 @@ void AppConfig::reset_selections() } } -std::string AppConfig::config_path() +std::string AppConfig::config_path() const { std::string path = (m_mode == EAppMode::Editor) ? (boost::filesystem::path(Slic3r::data_dir()) / (SLIC3R_APP_KEY ".ini")).make_preferred().string() : @@ -691,7 +768,7 @@ std::string AppConfig::profile_folder_url() const return PROFILE_FOLDER_URL; } -bool AppConfig::exists() +bool AppConfig::exists() const { return boost::filesystem::exists(config_path()); } diff --git a/src/libslic3r/AppConfig.hpp b/src/libslic3r/AppConfig.hpp index 78a7065d9..f3e263769 100644 --- a/src/libslic3r/AppConfig.hpp +++ b/src/libslic3r/AppConfig.hpp @@ -58,9 +58,13 @@ public: } std::string get(const std::string §ion, const std::string &key) const { std::string value; this->get(section, key, value); return value; } + bool get_bool(const std::string §ion, const std::string &key) const + { return this->get(section, key) == "1"; } std::string get(const std::string &key) const { std::string value; this->get("", key, value); return value; } - void set(const std::string §ion, const std::string &key, const std::string &value) + bool get_bool(const std::string &key) const + { return this->get(key) == "1"; } + bool set(const std::string §ion, const std::string &key, const std::string &value) { #ifndef NDEBUG { @@ -74,10 +78,12 @@ public: if (old != value) { old = value; m_dirty = true; + return true; } + return false; } - void set(const std::string &key, const std::string &value) - { this->set("", key, value); } + bool set(const std::string &key, const std::string &value) + { return this->set("", key, value); } bool has(const std::string §ion, const std::string &key) const { auto it = m_storage.find(section); @@ -89,40 +95,32 @@ public: bool has(const std::string &key) const { return this->has("", key); } - void erase(const std::string §ion, const std::string &key) - { - auto it = m_storage.find(section); - if (it != m_storage.end()) { - it->second.erase(key); - } - } + bool erase(const std::string §ion, const std::string &key); bool has_section(const std::string §ion) const { return m_storage.find(section) != m_storage.end(); } const std::map& get_section(const std::string §ion) const { auto it = m_storage.find(section); assert(it != m_storage.end()); return it->second; } - void set_section(const std::string §ion, const std::map& data) - { m_storage[section] = data; } - void clear_section(const std::string §ion) - { m_storage[section].clear(); } + bool set_section(const std::string §ion, std::map data); + bool clear_section(const std::string §ion); typedef std::map>> VendorMap; bool get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const; - void set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable); - void set_vendors(const AppConfig &from); - void set_vendors(const VendorMap &vendors) { m_vendors = vendors; m_dirty = true; } - void set_vendors(VendorMap &&vendors) { m_vendors = std::move(vendors); m_dirty = true; } + bool set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable); + bool set_vendors(const AppConfig &from) { return this->set_vendors(from.vendors()); } + bool set_vendors(const VendorMap &vendors); + bool set_vendors(VendorMap &&vendors); const VendorMap& vendors() const { return m_vendors; } // return recent/skein_directory or recent/config_directory or empty string. std::string get_last_dir() const; - void update_config_dir(const std::string &dir); - void update_skein_dir(const std::string &dir); + bool update_config_dir(const std::string &dir); + bool update_skein_dir(const std::string &dir); //std::string get_last_output_dir(const std::string &alt) const; //void update_last_output_dir(const std::string &dir); std::string get_last_output_dir(const std::string& alt, const bool removable = false) const; - void update_last_output_dir(const std::string &dir, const bool removable = false); + bool update_last_output_dir(const std::string &dir, const bool removable = false); // reset the current print / filament / printer selections, so that // the PresetBundle::load_selections(const AppConfig &config) call will select @@ -130,7 +128,7 @@ public: void reset_selections(); // Get the default config path from Slic3r::data_dir(). - std::string config_path(); + std::string config_path() const; // Returns true if the user's data directory comes from before Slic3r 1.40.0 (no updating) bool legacy_datadir() const { return m_legacy_datadir; } @@ -140,9 +138,9 @@ public: // This returns a hardcoded string unless it is overriden by "version_check_url" in the ini file. std::string version_check_url() const; // Get the Slic3r url to vendor index archive zip. - std::string index_archive_url() const; + std::string index_archive_url() const; // Get the Slic3r url to folder with vendor profile files. - std::string profile_folder_url() const; + std::string profile_folder_url() const; // Returns the original Slic3r version found in the ini file before it was overwritten @@ -150,12 +148,12 @@ public: Semver orig_version() const { return m_orig_version; } // Does the config file exist? - bool exists(); + bool exists() const; std::vector get_recent_projects() const; - void set_recent_projects(const std::vector& recent_projects); + bool set_recent_projects(const std::vector& recent_projects); - void set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone, double zoom_speed, bool swap_yz); + bool set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone, double zoom_speed, bool swap_yz); std::vector get_mouse_device_names() const; bool get_mouse_device_translation_speed(const std::string& name, double& speed) const { return get_3dmouse_device_numeric_value(name, "translation_speed", speed); } diff --git a/src/libslic3r/Geometry/ConvexHull.cpp b/src/libslic3r/Geometry/ConvexHull.cpp index 015d47de6..b8bf5eb69 100644 --- a/src/libslic3r/Geometry/ConvexHull.cpp +++ b/src/libslic3r/Geometry/ConvexHull.cpp @@ -398,7 +398,7 @@ bool inside_convex_polygon(const std::pair, std::vectorx()); assert(pt.x() == it_top->x()); - assert(it_bottom->y() <= pt.y() <= it_top->y()); + assert(it_bottom->y() <= pt.y() && pt.y() <= it_top->y()); return pt.y() >= it_bottom->y() && pt.y() <= it_top->y(); } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 3a5a772ad..f66bf7086 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4710,12 +4710,6 @@ CLIMiscConfigDef::CLIMiscConfigDef() "or an existing PrusaSlicer window is activated. " "Overrides the \"single_instance\" configuration value from application preferences."); -/* - def = this->add("autosave", coString); - def->label = L("Autosave"); - def->tooltip = L("Automatically export current configuration to the specified file."); -*/ - def = this->add("datadir", coString); def->label = L("Data directory"); def->tooltip = L("Load and store settings at the given directory. This is useful for maintaining different profiles or including configurations from a network storage."); diff --git a/src/libslic3r/TreeModelVolumes.cpp b/src/libslic3r/TreeModelVolumes.cpp index f29193dbf..1cb857878 100644 --- a/src/libslic3r/TreeModelVolumes.cpp +++ b/src/libslic3r/TreeModelVolumes.cpp @@ -505,7 +505,7 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex // 1) Calculate offsets of collision areas in parallel. std::vector collision_areas_offsetted(max_required_layer + 1 - min_layer_bottom); tbb::parallel_for(tbb::blocked_range(min_layer_bottom, max_required_layer + 1), - [&outlines, &machine_border = m_machine_border, offset_value = radius + xy_distance, min_layer_bottom, &collision_areas_offsetted, &throw_on_cancel] + [&outlines, &machine_border = std::as_const(m_machine_border), offset_value = radius + xy_distance, min_layer_bottom, &collision_areas_offsetted, &throw_on_cancel] (const tbb::blocked_range &range) { for (LayerIndex layer_idx = range.begin(); layer_idx != range.end(); ++ layer_idx) { Polygons collision_areas = machine_border; @@ -520,14 +520,54 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex // 2) Sum over top / bottom ranges. const bool last = outline_idx == layer_outline_indices.size(); tbb::parallel_for(tbb::blocked_range(min_layer_last + 1, max_layer_idx + 1), - [&collision_areas_offsetted, &anti_overhang = m_anti_overhang, min_layer_bottom, radius, z_distance_bottom_layers, z_distance_top_layers, min_resolution = m_min_resolution, &data, min_layer_last, last, &throw_on_cancel] + [&collision_areas_offsetted, &outlines, &machine_border = m_machine_border, &anti_overhang = m_anti_overhang, min_layer_bottom, radius, + xy_distance, z_distance_bottom_layers, z_distance_top_layers, min_resolution = m_min_resolution, &data, min_layer_last, last, &throw_on_cancel] (const tbb::blocked_range& range) { for (LayerIndex layer_idx = range.begin(); layer_idx != range.end(); ++layer_idx) { Polygons collisions; for (int i = -z_distance_bottom_layers; i <= z_distance_top_layers; ++ i) { int j = layer_idx + i - min_layer_bottom; - if (j >= 0 && j < int(collision_areas_offsetted.size())) + if (j >= 0 && j < int(collision_areas_offsetted.size()) && i <= 0) append(collisions, collision_areas_offsetted[j]); + else if (j >= 0 && layer_idx + i < int(outlines.size()) && i > 0) { + Polygons collision_areas_original = machine_border; + append(collision_areas_original, outlines[layer_idx + i]); + + // If just the collision (including the xy distance) of the layers above is accumulated, it leads to the + // following issue: + // Example: assuming the z distance is 2 layer + // + = xy_distance + // - = model + // o = overhang of the area two layers above that should result in tips on this layer + // + // +-----+ + // +-----+ + // +-----+ + // o +-----+ + // If just the collision above is accumulated the overhang will get overwritten by the xy_distance of the + // layer below the overhang... + // + // This only causes issues if the overhang area is thinner than xy_distance + // Just accumulating areas of the model above without the xy distance is also problematic, as then support + // may get closer to the model (on the diagonal downwards) than the user intended. Example (s = support): + // +-----+ + // +-----+ + // +-----+ + // s+-----+ + + // technically the calculation below is off by one layer, as the actual distance between plastic one layer + // down is 0 not layer height, as this layer is filled with said plastic. But otherwise a part of the + // overhang that is expected to be supported is overwritten by the remaining part of the xy distance of the + // layer below the to be supported area. + coord_t required_range_x = + (xy_distance - ((i - (z_distance_top_layers == 1 ? 0.5 : 0)) * xy_distance / z_distance_top_layers)); + // the conditional -0.5 ensures that plastic can never touch on the diagonal + // downward when the z_distance_top_layers = 1. It is assumed to be better to + // not support an overhang<90 degree than to risk fusing to it. + + collision_areas_original = offset(union_ex(collision_areas_original), radius + required_range_x, ClipperLib::jtMiter, 1.2); + append(collisions, collision_areas_original); + } } collisions = last && layer_idx < int(anti_overhang.size()) ? union_(collisions, offset(union_ex(anti_overhang[layer_idx]), radius, ClipperLib::jtMiter, 1.2)) : union_(collisions); auto &dst = data[layer_idx - (min_layer_last + 1)]; @@ -644,7 +684,8 @@ void TreeModelVolumes::calculateAvoidance(const std::vector &ke BOOST_LOG_TRIVIAL(debug) << "Calculation requested for value already calculated?"; continue; } - if (! task.holefree() || task.radius < m_increase_until_radius + m_current_min_xy_dist_delta) + if ((task.to_model ? to_model : to_build_plate) && + (! task.holefree() || task.radius < m_increase_until_radius + m_current_min_xy_dist_delta)) avoidance_tasks.emplace_back(task); } diff --git a/src/libslic3r/TreeSupport.cpp b/src/libslic3r/TreeSupport.cpp index 00eec7df0..71dda3a6a 100644 --- a/src/libslic3r/TreeSupport.cpp +++ b/src/libslic3r/TreeSupport.cpp @@ -496,15 +496,15 @@ static std::optional> polyline_sample_next_point_at_dis Vec2d xf = p0f - foot_pt; // Squared distance of "start_pt" from the ray (p0, p1). double l2_from_line = xf.squaredNorm(); - double det = dist2 - l2_from_line; - - if (det > - SCALED_EPSILON) { + // Squared distance of an intersection point of a circle with center at the foot point. + if (double l2_intersection = dist2 - l2_from_line; + l2_intersection > - SCALED_EPSILON) { // The ray (p0, p1) touches or intersects a circle centered at "start_pt" with radius "dist". // Distance of the circle intersection point from the foot point. - double dist_circle_intersection = std::sqrt(std::max(0., det)); - if ((v - foot_pt).cast().norm() > dist_circle_intersection) { + l2_intersection = std::max(l2_intersection, 0.); + if ((v - foot_pt).cast().squaredNorm() >= l2_intersection) { // Intersection of the circle with the segment (p0, p1) is on the right side (close to p1) from the foot point. - Point p = p0 + (foot_pt + v * (dist_circle_intersection / sqrt(l2v))).cast(); + Point p = p0 + (foot_pt + v * sqrt(l2_intersection / l2v)).cast(); validate_range(p); return std::pair{ p, i - 1 }; } @@ -916,7 +916,7 @@ static void generate_initial_areas( //FIXME Vojtech: This is not sufficient for support enforcers to work. //FIXME There is no account for the support overhang angle. //FIXME There is no account for the width of the collision regions. - const coord_t extra_outset = std::max(coord_t(0), mesh_config.min_radius - mesh_config.support_line_width) + (min_xy_dist ? mesh_config.support_line_width / 2 : 0) + const coord_t extra_outset = std::max(coord_t(0), mesh_config.min_radius - mesh_config.support_line_width / 2) + (min_xy_dist ? mesh_config.support_line_width / 2 : 0) //FIXME this is a heuristic value for support enforcers to work. // + 10 * mesh_config.support_line_width; ; @@ -1079,9 +1079,8 @@ static void generate_initial_areas( Polygons overhang_regular; { const Polygons &overhang_raw = overhangs[layer_idx + z_distance_delta]; - overhang_regular = mesh_group_settings.support_offset == 0 ? - overhang_raw : - safe_offset_inc(overhang_raw, mesh_group_settings.support_offset, relevant_forbidden, mesh_config.min_radius * 1.75 + mesh_config.xy_min_distance, 0, 1); + // When support_offset = 0 safe_offset_inc will only be the difference between overhang_raw and relevant_forbidden, that has to be calculated anyway. + overhang_regular = safe_offset_inc(overhang_raw, mesh_group_settings.support_offset, relevant_forbidden, mesh_config.min_radius * 1.75 + mesh_config.xy_min_distance, 0, 1); //check_self_intersections(overhang_regular, "overhang_regular1"); // offset ensures that areas that could be supported by a part of a support line, are not considered unsupported overhang diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index 7a79b8cbf..62b9729ec 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -36,10 +36,8 @@ void Camera::set_type(EType type) { if (m_type != type && (type == EType::Ortho || type == EType::Perspective)) { m_type = type; - if (m_update_config_on_type_change_enabled) { + if (m_update_config_on_type_change_enabled) wxGetApp().app_config->set("use_perspective_camera", (m_type == EType::Perspective) ? "1" : "0"); - wxGetApp().app_config->save(); - } } } diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 69167c9fd..99a83cf42 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -804,7 +804,7 @@ void GUI_App::post_init() } // show "Did you know" notification - if (app_config->get("show_hints") == "1" && ! is_gcode_viewer()) + if (app_config->get_bool("show_hints") && ! is_gcode_viewer()) plater_->get_notification_manager()->push_hint_notification(true); // The extra CallAfter() is needed because of Mac, where this is the only way @@ -832,7 +832,6 @@ void GUI_App::post_init() // Set PrusaSlicer version and save to PrusaSlicer.ini or PrusaSlicerGcodeViewer.ini. app_config->set("version", SLIC3R_VERSION); - app_config->save(); #ifdef _WIN32 // Sets window property to mainframe so other instances can indentify it. @@ -859,14 +858,9 @@ GUI_App::GUI_App(EAppMode mode) GUI_App::~GUI_App() { - if (app_config != nullptr) - delete app_config; - - if (preset_bundle != nullptr) - delete preset_bundle; - - if (preset_updater != nullptr) - delete preset_updater; + delete app_config; + delete preset_bundle; + delete preset_updater; } // If formatted for github, plaintext with OpenGL extensions enclosed into
. @@ -1145,8 +1139,8 @@ bool GUI_App::on_init_inner() // 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"; + bool init_dark_color_mode = app_config->get_bool("dark_color_mode"); + bool init_sys_menu_enabled = app_config->get_bool("sys_menu_enabled"); NppDarkMode::InitDarkMode(init_dark_color_mode, init_sys_menu_enabled); #endif // initialize label colors and fonts @@ -1169,13 +1163,13 @@ bool GUI_App::on_init_inner() #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"; + if (bool new_dark_color_mode = app_config->get_bool("dark_color_mode"); init_dark_color_mode != new_dark_color_mode) { NppDarkMode::SetDarkMode(new_dark_color_mode); init_ui_colours(); update_ui_colours_from_appconfig(); } - if (bool new_sys_menu_enabled = app_config->get("sys_menu_enabled") == "1"; + if (bool new_sys_menu_enabled = app_config->get_bool("sys_menu_enabled"); init_sys_menu_enabled != new_sys_menu_enabled) NppDarkMode::SetSystemMenuForApp(new_sys_menu_enabled); #endif @@ -1201,7 +1195,7 @@ bool GUI_App::on_init_inner() } SplashScreen* scrn = nullptr; - if (app_config->get("show_splash_screen") == "1") { + if (app_config->get_bool("show_splash_screen")) { // make a bitmap with dark grey banner on the left side wxBitmap bmp = SplashScreen::MakeBitmap(wxBitmap(from_u8(var(is_editor() ? "splashscreen.jpg" : "splashscreen-gcodepreview.jpg")), wxBITMAP_TYPE_JPEG)); @@ -1248,9 +1242,9 @@ bool GUI_App::on_init_inner() if (is_editor()) { #ifdef __WXMSW__ - if (app_config->get("associate_3mf") == "1") + if (app_config->get_bool("associate_3mf")) associate_3mf_files(); - if (app_config->get("associate_stl") == "1") + if (app_config->get_bool("associate_stl")) associate_stl_files(); #endif // __WXMSW__ @@ -1290,14 +1284,14 @@ bool GUI_App::on_init_inner() } else { #ifdef __WXMSW__ - if (app_config->get("associate_gcode") == "1") + if (app_config->get_bool("associate_gcode")) associate_gcode_files(); #endif // __WXMSW__ } std::string delayed_error_load_presets; // Suppress the '- default -' presets. - preset_bundle->set_default_suppressed(app_config->get("no_defaults") == "1"); + preset_bundle->set_default_suppressed(app_config->get_bool("no_defaults")); try { // Enable all substitutions (in both user and system profiles), but log the substitutions in user profiles only. // If there are substitutions in system profiles, then a "reconfigure" event shall be triggered, which will force @@ -1387,7 +1381,7 @@ bool GUI_App::on_init_inner() this->post_init(); } - if (m_post_initialized && app_config->dirty() && app_config->get("autosave") == "1") + if (m_post_initialized && app_config->dirty()) app_config->save(); }); @@ -1448,7 +1442,7 @@ bool GUI_App::dark_mode() return wxPlatformInfo::Get().CheckOSVersion(10, 14) && mac_dark_mode(); #else if (wxGetApp().app_config->has("dark_color_mode")) - return wxGetApp().app_config->get("dark_color_mode") == "1"; + return wxGetApp().app_config->get_bool("dark_color_mode"); return check_dark_mode(); #endif } @@ -1685,7 +1679,6 @@ void GUI_App::set_label_clr_modified(const wxColour& clr) m_color_label_modified = clr; const std::string str = encode_color(ColorRGB(clr.Red(), clr.Green(), clr.Blue())); app_config->set("label_clr_modified", str); - app_config->save(); } void GUI_App::set_label_clr_sys(const wxColour& clr) @@ -1695,7 +1688,6 @@ void GUI_App::set_label_clr_sys(const wxColour& clr) m_color_label_sys = clr; const std::string str = encode_color(ColorRGB(clr.Red(), clr.Green(), clr.Blue())); app_config->set("label_clr_sys", str); - app_config->save(); } const std::string& GUI_App::get_mode_btn_color(int mode_id) @@ -1727,13 +1719,12 @@ void GUI_App::set_mode_palette(const std::vector& palette) if (save) { mainframe->update_mode_markers(); app_config->set("mode_palette", escape_strings_cstyle(m_mode_palette)); - app_config->save(); } } bool GUI_App::tabs_as_menu() const { - return app_config->get("tabs_as_menu") == "1"; // || dark_mode(); + return app_config->get_bool("tabs_as_menu"); // || dark_mode(); } wxSize GUI_App::get_min_size() const @@ -1902,14 +1893,14 @@ static void update_scrolls(wxWindow* window) #ifdef _MSW_DARK_MODE void GUI_App::force_menu_update() { - NppDarkMode::SetSystemMenuForApp(app_config->get("sys_menu_enabled") == "1"); + NppDarkMode::SetSystemMenuForApp(app_config->get_bool("sys_menu_enabled")); } #endif //_MSW_DARK_MODE void GUI_App::force_colors_update() { #ifdef _MSW_DARK_MODE - NppDarkMode::SetDarkMode(app_config->get("dark_color_mode") == "1"); + NppDarkMode::SetDarkMode(app_config->get_bool("dark_color_mode")); if (WXHWND wxHWND = wxToolTip::GetToolTipCtrl()) NppDarkMode::SetDarkExplorerTheme((HWND)wxHWND); NppDarkMode::SetDarkTitleBar(mainframe->GetHWND()); @@ -2158,7 +2149,6 @@ bool GUI_App::select_language() // m_wxLocale->GetCanonicalName() // 3) new_language_info->CanonicalName is a safe bet. It points to a valid dictionary name. app_config->set("translation_language", new_language_info->CanonicalName.ToUTF8().data()); - app_config->save(); return true; } } @@ -2367,7 +2357,6 @@ bool GUI_App::save_mode(const /*ConfigOptionMode*/int mode) return false; } app_config->set("view_mode", mode_str); - app_config->save(); update_mode(); return true; } @@ -2569,13 +2558,13 @@ void GUI_App::open_preferences(const std::string& highlight_option /*= std::stri #ifdef _WIN32 if (is_editor()) { - if (app_config->get("associate_3mf") == "1") + if (app_config->get_bool("associate_3mf")) associate_3mf_files(); - if (app_config->get("associate_stl") == "1") + if (app_config->get_bool("associate_stl")) associate_stl_files(); } else { - if (app_config->get("associate_gcode") == "1") + if (app_config->get_bool("associate_gcode")) associate_gcode_files(); } #endif // _WIN32 @@ -3178,7 +3167,6 @@ void GUI_App::window_pos_save(wxTopLevelWindow* window, const std::string &name) WindowMetrics metrics = WindowMetrics::from_window(window); app_config->set(config_key, metrics.serialize()); - app_config->save(); } void GUI_App::window_pos_restore(wxTopLevelWindow* window, const std::string &name, bool default_maximized) @@ -3372,7 +3360,6 @@ void GUI_App::associate_gcode_files() void GUI_App::on_version_read(wxCommandEvent& evt) { app_config->set("version_online", into_u8(evt.GetString())); - app_config->save(); std::string opt = app_config->get("notify_release"); if (this->plater_ == nullptr || (!m_app_updater->get_triggered_by_user() && opt != "all" && opt != "release")) { BOOST_LOG_TRIVIAL(info) << "Version online: " << evt.GetString() << ". User does not wish to be notified."; diff --git a/src/slic3r/GUI/GUI_Init.cpp b/src/slic3r/GUI/GUI_Init.cpp index 5b5cca7dc..882c28816 100644 --- a/src/slic3r/GUI/GUI_Init.cpp +++ b/src/slic3r/GUI/GUI_Init.cpp @@ -56,7 +56,6 @@ int GUI_Run(GUI_InitParams ¶ms) } } -// gui->autosave = m_config.opt_string("autosave"); GUI::GUI_App::SetInstance(gui); gui->init_params = ¶ms; return wxEntry(params.argc, params.argv); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 69c566819..22c9256bd 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -652,7 +652,8 @@ void MainFrame::shutdown() wxGetApp().other_instance_message_handler()->shutdown(this); // Save the slic3r.ini.Usually the ini file is saved from "on idle" callback, // but in rare cases it may not have been called yet. - wxGetApp().app_config->save(); + if (wxGetApp().app_config->dirty()) + wxGetApp().app_config->save(); // if (m_plater) // m_plater->print = undef; // Slic3r::GUI::deregister_on_request_update_callback(); @@ -1253,7 +1254,6 @@ void MainFrame::init_menubar_as_editor() recent_projects.push_back(into_u8(m_recent_projects.GetHistoryFile(i))); } wxGetApp().app_config->set_recent_projects(recent_projects); - wxGetApp().app_config->save(); } } }, wxID_FILE1, wxID_FILE9); @@ -2182,7 +2182,6 @@ void MainFrame::add_to_recent_projects(const wxString& filename) recent_projects.push_back(into_u8(m_recent_projects.GetHistoryFile(i))); } wxGetApp().app_config->set_recent_projects(recent_projects); - wxGetApp().app_config->save(); } } diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 61229ba43..1895572ae 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -464,7 +464,6 @@ void PreferencesDialog::build() m_icon_size_sizer->ShowItems(boost::any_cast(value)); refresh_og(m_optgroup_gui); get_app_config()->set("use_custom_toolbar_size", boost::any_cast(value) ? "1" : "0"); - get_app_config()->save(); wxGetApp().plater()->get_current_canvas3D()->render(); return; } @@ -768,7 +767,6 @@ void PreferencesDialog::accept(wxEvent&) for (std::map::iterator it = m_values.begin(); it != m_values.end(); ++it) app_config->set(it->first, it->second); - app_config->save(); if (wxGetApp().is_editor()) { wxGetApp().set_label_clr_sys(m_sys_colour->GetColour()); wxGetApp().set_label_clr_modified(m_mod_colour->GetColour()); @@ -797,23 +795,17 @@ void PreferencesDialog::revert(wxEvent&) { auto app_config = get_app_config(); - bool save_app_config = false; if (m_custom_toolbar_size != atoi(app_config->get("custom_toolbar_size").c_str())) { app_config->set("custom_toolbar_size", (boost::format("%d") % m_custom_toolbar_size).str()); m_icon_size_slider->SetValue(m_custom_toolbar_size); - save_app_config |= true; } if (m_use_custom_toolbar_size != (get_app_config()->get("use_custom_toolbar_size") == "1")) { app_config->set("use_custom_toolbar_size", m_use_custom_toolbar_size ? "1" : "0"); - save_app_config |= true; m_optgroup_gui->set_value("use_custom_toolbar_size", m_use_custom_toolbar_size); m_icon_size_sizer->ShowItems(m_use_custom_toolbar_size); refresh_og(m_optgroup_gui); } - if (save_app_config) - app_config->save(); - for (auto value : m_values) { const std::string& key = value.first; @@ -955,7 +947,6 @@ void PreferencesDialog::create_icon_size_slider() auto val = m_icon_size_slider->GetValue(); app_config->set("custom_toolbar_size", (boost::format("%d") % val).str()); - app_config->save(); wxGetApp().plater()->get_current_canvas3D()->render(); if (val_label) diff --git a/src/slic3r/Utils/EmbossStylesSerializable.cpp b/src/slic3r/Utils/EmbossStylesSerializable.cpp index a1c3c599a..111bb597b 100644 --- a/src/slic3r/Utils/EmbossStylesSerializable.cpp +++ b/src/slic3r/Utils/EmbossStylesSerializable.cpp @@ -121,37 +121,37 @@ void EmbossStylesSerializable::store_style(AppConfig & cfg, const EmbossStyle &fi, unsigned index) { - std::string section_name = create_section_name(index); - cfg.clear_section(section_name); - cfg.set(section_name, APP_CONFIG_FONT_NAME, fi.name); - cfg.set(section_name, APP_CONFIG_FONT_DESCRIPTOR, fi.path); + std::map data; + data[APP_CONFIG_FONT_NAME] = fi.name; + data[APP_CONFIG_FONT_DESCRIPTOR] = fi.path; const FontProp &fp = fi.prop; - cfg.set(section_name, APP_CONFIG_FONT_LINE_HEIGHT, std::to_string(fp.size_in_mm)); - cfg.set(section_name, APP_CONFIG_FONT_DEPTH, std::to_string(fp.emboss)); + data[APP_CONFIG_FONT_LINE_HEIGHT] = std::to_string(fp.size_in_mm); + data[APP_CONFIG_FONT_DEPTH] = std::to_string(fp.emboss); if (fp.use_surface) - cfg.set(section_name, APP_CONFIG_FONT_USE_SURFACE, "true"); + data[APP_CONFIG_FONT_USE_SURFACE] = "true"; if (fp.boldness.has_value()) - cfg.set(section_name, APP_CONFIG_FONT_BOLDNESS, std::to_string(*fp.boldness)); + data[APP_CONFIG_FONT_BOLDNESS] = std::to_string(*fp.boldness); if (fp.skew.has_value()) - cfg.set(section_name, APP_CONFIG_FONT_SKEW, std::to_string(*fp.skew)); + data[APP_CONFIG_FONT_SKEW] = std::to_string(*fp.skew); if (fp.distance.has_value()) - cfg.set(section_name, APP_CONFIG_FONT_DISTANCE, std::to_string(*fp.distance)); + data[APP_CONFIG_FONT_DISTANCE] = std::to_string(*fp.distance); if (fp.angle.has_value()) - cfg.set(section_name, APP_CONFIG_FONT_ANGLE, std::to_string(*fp.angle)); + data[APP_CONFIG_FONT_ANGLE] = std::to_string(*fp.angle); if (fp.collection_number.has_value()) - cfg.set(section_name, APP_CONFIG_FONT_COLLECTION, std::to_string(*fp.collection_number)); + data[APP_CONFIG_FONT_COLLECTION] = std::to_string(*fp.collection_number); if (fp.char_gap.has_value()) - cfg.set(section_name, APP_CONFIG_FONT_CHAR_GAP, std::to_string(*fp.char_gap)); + data[APP_CONFIG_FONT_CHAR_GAP] = std::to_string(*fp.char_gap); if (fp.line_gap.has_value()) - cfg.set(section_name, APP_CONFIG_FONT_LINE_GAP, std::to_string(*fp.line_gap)); + data[APP_CONFIG_FONT_LINE_GAP] = std::to_string(*fp.line_gap); + cfg.set_section(create_section_name(index), std::move(data)); } void EmbossStylesSerializable::store_style_index(AppConfig &cfg, unsigned index) { // store actual font index - cfg.clear_section(AppConfig::SECTION_EMBOSS_STYLE); - // activ font first index is +1 to correspond with section name - std::string active_font = std::to_string(index); - cfg.set(AppConfig::SECTION_EMBOSS_STYLE, APP_CONFIG_ACTIVE_FONT, active_font); + // active font first index is +1 to correspond with section name + std::map data; + data[APP_CONFIG_ACTIVE_FONT] = std::to_string(index); + cfg.set_section(AppConfig::SECTION_EMBOSS_STYLE, std::move(data)); } std::optional EmbossStylesSerializable::load_style_index(const AppConfig &cfg) @@ -198,5 +198,4 @@ void EmbossStylesSerializable::store_styles(AppConfig &cfg, const EmbossStyles& cfg.clear_section(section_name); section_name = create_section_name(++index); } - cfg.save(); } \ No newline at end of file