mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-27 19:01:02 +00:00
Initial Commit for Publish Settings workflow
This commit is contained in:
@@ -0,0 +1,245 @@
|
||||
#include "ConfigValueFormatter.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
#include "I18N.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "Field.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
std::string get_pure_opt_key(const std::string& opt_key)
|
||||
{
|
||||
std::string pure_key = opt_key;
|
||||
const int pos = pure_key.find("#");
|
||||
if (pos > 0)
|
||||
boost::erase_tail(pure_key, pure_key.size() - pos);
|
||||
return pure_key;
|
||||
}
|
||||
|
||||
wxString get_string_from_enum(const std::string& opt_key, const DynamicPrintConfig& config, bool is_infill, int idx)
|
||||
{
|
||||
const ConfigOptionDef& def = config.def()->options.at(opt_key);
|
||||
const std::vector<std::string>& names = def.enum_labels;//ConfigOptionEnum<T>::get_enum_names();
|
||||
int val = 0;
|
||||
|
||||
if (idx >= 0)
|
||||
val = dynamic_cast<const ConfigOptionInts*>(config.option(opt_key))->get_at(idx);
|
||||
else
|
||||
val = config.option(opt_key)->getInt();
|
||||
|
||||
// Each infill doesn't use all list of infill declared in PrintConfig.hpp.
|
||||
// So we should "convert" val to the correct one
|
||||
if (is_infill) {
|
||||
for (auto key_val : *def.enum_keys_map)
|
||||
if (int(key_val.second) == val) {
|
||||
auto it = std::find(def.enum_values.begin(), def.enum_values.end(), key_val.first);
|
||||
if (it == def.enum_values.end())
|
||||
return "";
|
||||
return from_u8(_utf8(names[it - def.enum_values.begin()]));
|
||||
}
|
||||
return _L("Undefined");
|
||||
}
|
||||
return from_u8(_utf8(names[val]));
|
||||
}
|
||||
|
||||
wxString get_full_label(const std::string& opt_key, const DynamicPrintConfig& config)
|
||||
{
|
||||
const std::string pure_key = get_pure_opt_key(opt_key);
|
||||
auto option = config.option(pure_key);
|
||||
|
||||
if (!option || option->is_nil())
|
||||
return _L("N/A");
|
||||
|
||||
const ConfigOptionDef* opt = config.def()->get(pure_key);
|
||||
return opt->full_label.empty() ? opt->label : opt->full_label;
|
||||
}
|
||||
|
||||
wxString get_string_value(const std::string& opt_key, const DynamicPrintConfig& config)
|
||||
{
|
||||
int orig_opt_idx = -1;
|
||||
int opt_idx = -1;
|
||||
int pos = opt_key.find("#");
|
||||
std::string temp_str = opt_key;
|
||||
if (pos > 0) {
|
||||
boost::erase_head(temp_str, pos + 1);
|
||||
orig_opt_idx = static_cast<size_t>(atoi(temp_str.c_str()));
|
||||
}
|
||||
opt_idx = orig_opt_idx >= 0 ? orig_opt_idx : 0;
|
||||
const std::string pure_key = get_pure_opt_key(opt_key);
|
||||
auto option = config.option(pure_key);
|
||||
if (!option) {
|
||||
return _L("N/A");
|
||||
}
|
||||
auto opt_vector = dynamic_cast<const ConfigOptionVectorBase *>(option);
|
||||
|
||||
if (option->is_scalar() && config.option(pure_key)->is_nil() ||
|
||||
option->is_vector() && opt_vector && opt_idx >= 0 && opt_idx < opt_vector->size() && opt_vector->is_nil(opt_idx))
|
||||
return _L("N/A");
|
||||
|
||||
wxString out;
|
||||
|
||||
const ConfigOptionDef* opt = config.def()->get(pure_key);
|
||||
bool is_nullable = opt->nullable;
|
||||
|
||||
switch (opt->type) {
|
||||
case coInt:
|
||||
return from_u8((boost::format("%1%") % config.opt_int(pure_key)).str());
|
||||
case coInts: {
|
||||
if (is_nullable) {
|
||||
auto values = config.opt<ConfigOptionIntsNullable>(pure_key);
|
||||
if (opt_idx < values->size())
|
||||
return from_u8((boost::format("%1%") % values->get_at(opt_idx)).str());
|
||||
}
|
||||
else {
|
||||
auto values = config.opt<ConfigOptionInts>(pure_key);
|
||||
if (orig_opt_idx >= 0 && orig_opt_idx < values->size()) {
|
||||
return from_u8((boost::format("%1%") % values->get_at(opt_idx)).str());
|
||||
}
|
||||
else {
|
||||
std::string value_str;
|
||||
for (int i = 0; i < values->size(); i++) {
|
||||
value_str += std::to_string(values->get_at(i));
|
||||
if (i != values->size() - 1) {
|
||||
value_str += ",";
|
||||
}
|
||||
}
|
||||
return from_u8(value_str);
|
||||
}
|
||||
}
|
||||
return _L("Undefined");
|
||||
}
|
||||
case coBool:
|
||||
return config.opt_bool(pure_key) ? "true" : "false";
|
||||
case coBools: {
|
||||
if (is_nullable) {
|
||||
auto values = config.opt<ConfigOptionBoolsNullable>(pure_key);
|
||||
if (opt_idx < values->size())
|
||||
return values->get_at(opt_idx) ? "true" : "false";
|
||||
}
|
||||
else {
|
||||
auto values = config.opt<ConfigOptionBools>(pure_key);
|
||||
if (opt_idx < values->size())
|
||||
return values->get_at(opt_idx) ? "true" : "false";
|
||||
}
|
||||
return _L("Undefined");
|
||||
}
|
||||
case coPercent:
|
||||
return from_u8((boost::format("%1%%%") % int(config.optptr(pure_key)->getFloat())).str());
|
||||
case coPercents: {
|
||||
if (is_nullable) {
|
||||
auto values = config.opt<ConfigOptionPercentsNullable>(pure_key);
|
||||
if (opt_idx < values->size())
|
||||
return from_u8((boost::format("%1%%%") % values->get_at(opt_idx)).str());
|
||||
}
|
||||
else {
|
||||
auto values = config.opt<ConfigOptionPercents>(pure_key);
|
||||
if (opt_idx < values->size())
|
||||
return from_u8((boost::format("%1%%%") % values->get_at(opt_idx)).str());
|
||||
}
|
||||
return _L("Undefined");
|
||||
}
|
||||
case coFloat:
|
||||
return double_to_string(config.opt_float(pure_key));
|
||||
case coFloats: {
|
||||
if (is_nullable) {
|
||||
auto values = config.opt<ConfigOptionFloatsNullable>(pure_key);
|
||||
if (opt_idx < values->size())
|
||||
return double_to_string(values->get_at(opt_idx));
|
||||
}
|
||||
else {
|
||||
auto values = config.opt<ConfigOptionFloats>(pure_key);
|
||||
if (values && opt_idx < values->size())
|
||||
return double_to_string(values->get_at(opt_idx));
|
||||
}
|
||||
return _L("Undefined");
|
||||
}
|
||||
case coString:
|
||||
return from_u8(config.opt_string(pure_key));
|
||||
case coStrings: {
|
||||
const ConfigOptionStrings* strings = config.opt<ConfigOptionStrings>(pure_key);
|
||||
if (strings) {
|
||||
if (pure_key == "compatible_printers" || pure_key == "compatible_prints") {
|
||||
if (strings->empty())
|
||||
return _L("All");
|
||||
for (size_t id = 0; id < strings->size(); id++)
|
||||
out += from_u8(strings->get_at(id)) + "\n";
|
||||
out.RemoveLast(1);
|
||||
return out;
|
||||
}
|
||||
if (!strings->empty() && opt_idx < strings->values.size())
|
||||
return from_u8(strings->get_at(opt_idx));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case coFloatOrPercent: {
|
||||
const ConfigOptionFloatOrPercent* opt = config.opt<ConfigOptionFloatOrPercent>(pure_key);
|
||||
if (opt)
|
||||
out = double_to_string(opt->value) + (opt->percent ? "%" : "");
|
||||
return out;
|
||||
}
|
||||
case coEnum: {
|
||||
return get_string_from_enum(pure_key, config,
|
||||
pure_key == "top_surface_pattern" ||
|
||||
pure_key == "bottom_surface_pattern" ||
|
||||
pure_key == "internal_solid_infill_pattern" ||
|
||||
pure_key == "sparse_infill_pattern" ||
|
||||
pure_key == "ironing_pattern" ||
|
||||
pure_key == "support_ironing_pattern" ||
|
||||
pure_key == "support_pattern" ||
|
||||
pure_key == "support_interface_pattern")
|
||||
;
|
||||
}
|
||||
case coEnums: {
|
||||
return get_string_from_enum(pure_key, config,
|
||||
pure_key == "top_surface_pattern" ||
|
||||
pure_key == "bottom_surface_pattern" ||
|
||||
pure_key == "internal_solid_infill_pattern" ||
|
||||
pure_key == "sparse_infill_pattern" ||
|
||||
pure_key == "ironing_pattern" ||
|
||||
pure_key == "support_ironing_pattern" ||
|
||||
pure_key == "support_pattern" ||
|
||||
pure_key == "support_interface_pattern"
|
||||
, opt_idx);
|
||||
}
|
||||
case coPoint: {
|
||||
Vec2d val = config.opt<ConfigOptionPoint>(pure_key)->value;
|
||||
return from_u8((boost::format("[%1%]") % ConfigOptionPoint(val).serialize()).str());
|
||||
}
|
||||
case coPoints: {
|
||||
//BBS: add bed_exclude_area
|
||||
if (pure_key == "printable_area" || pure_key == "thumbnails") {
|
||||
ConfigOptionPoints points = *config.option<ConfigOptionPoints>(pure_key);
|
||||
//BuildVolume build_volume = {points.values, 0.};
|
||||
return get_thumbnails_string(points.values);
|
||||
}
|
||||
else if (pure_key == "bed_exclude_area") {
|
||||
return get_thumbnails_string(config.option<ConfigOptionPoints>(pure_key)->values);
|
||||
}
|
||||
else if (pure_key == "head_wrap_detect_zone") {
|
||||
return get_thumbnails_string(config.option<ConfigOptionPoints>(pure_key)->values);
|
||||
}
|
||||
else if (pure_key == "wrapping_exclude_area") {
|
||||
return get_thumbnails_string(config.option<ConfigOptionPoints>(pure_key)->values);
|
||||
}
|
||||
Vec2d val = config.opt<ConfigOptionPoints>(pure_key)->get_at(opt_idx);
|
||||
return from_u8((boost::format("[%1%]") % ConfigOptionPoint(val).serialize()).str());
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef slic3r_ConfigValueFormatter_hpp_
|
||||
#define slic3r_ConfigValueFormatter_hpp_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <wx/string.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class DynamicPrintConfig;
|
||||
|
||||
namespace GUI {
|
||||
|
||||
// Return the value of the given option (identified by opt_key, which may contain
|
||||
// a "#<index>" suffix) formatted as a human readable string.
|
||||
wxString get_string_value(const std::string& opt_key, const DynamicPrintConfig& config);
|
||||
|
||||
// Return the full label of the given option (identified by opt_key, which may contain
|
||||
// a "#<index>" suffix). Returns "N/A" when the option is not set.
|
||||
wxString get_full_label(const std::string& opt_key, const DynamicPrintConfig& config);
|
||||
|
||||
// Strip the "#<index>" suffix (if any) from the given option key.
|
||||
std::string get_pure_opt_key(const std::string& opt_key);
|
||||
|
||||
// Return the localized label of the currently selected value of an enum option.
|
||||
wxString get_string_from_enum(const std::string& opt_key, const DynamicPrintConfig& config, bool is_infill = false, int idx = -1);
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_ConfigValueFormatter_hpp_
|
||||
@@ -54,6 +54,7 @@
|
||||
|
||||
#include "GUI_App.hpp"
|
||||
#include "UnsavedChangesDialog.hpp"
|
||||
#include "PublishSettingsDialog.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "Notebook.hpp"
|
||||
#include "GUI_Factories.hpp"
|
||||
@@ -2821,6 +2822,25 @@ void MainFrame::init_menubar_as_editor()
|
||||
[this](){return m_plater != nullptr && can_save_as(); }, this);
|
||||
#endif
|
||||
|
||||
// BBS: publish settings
|
||||
fileMenu->AppendSeparator();
|
||||
auto publish_handler = [this](wxCommandEvent&) {
|
||||
if (!m_plater) return;
|
||||
PublishSettingsDialog dlg(this);
|
||||
if (dlg.ShowModal() != wxID_OK) return;
|
||||
m_plater->export_published_3mf(dlg.GetPublishedKeys(), dlg.GetPublishedMaterialKeys());
|
||||
};
|
||||
|
||||
#ifndef __APPLE__
|
||||
append_menu_item(fileMenu, wxID_ANY, _L("Publish Settings") + dots, _L("Export a 3MF file with the selected settings embedded"),
|
||||
publish_handler, "menu_publish", nullptr,
|
||||
[this](){return can_export_model(); }, this);
|
||||
#else
|
||||
append_menu_item(fileMenu, wxID_ANY, _L("Publish Settings") + dots, _L("Export a 3MF file with the selected settings embedded"),
|
||||
publish_handler, "", nullptr,
|
||||
[this](){return can_export_model(); }, this);
|
||||
#endif
|
||||
|
||||
|
||||
fileMenu->AppendSeparator();
|
||||
|
||||
|
||||
+142
-13
@@ -1,12 +1,10 @@
|
||||
#include "Plater.hpp"
|
||||
#include "../Utils/NetworkAgent.hpp"
|
||||
#include "../Utils/NetworkAgentFactory.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r_version.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <numeric>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
@@ -16,8 +14,6 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
@@ -69,7 +65,6 @@
|
||||
#include "libslic3r/Format/bbs_3mf.hpp"
|
||||
#include "libslic3r/GCode/ThumbnailData.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/SLA/Hollowing.hpp"
|
||||
#include "libslic3r/SLA/SupportPoint.hpp"
|
||||
#include "libslic3r/SLA/ReprojectPointsOnMesh.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
@@ -78,16 +73,15 @@
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/PublishSettings.hpp"
|
||||
#include "slic3r/Utils/CrealityPrint.hpp"
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
#include "libslic3r/ObjColorUtils.hpp"
|
||||
// For stl export
|
||||
#include "libslic3r/CSGMesh/ModelToCSGMesh.hpp"
|
||||
#include "libslic3r/CSGMesh/PerformCSGMeshBooleans.hpp"
|
||||
|
||||
#include "GUI.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "GuiColor.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#ifdef __WXGTK__
|
||||
#include "LinuxDisplayBackend.hpp"
|
||||
@@ -123,7 +117,6 @@
|
||||
#include "SendMultiMachinePage.hpp"
|
||||
#include "SendToPrinter.hpp"
|
||||
#include "PublishDialog.hpp"
|
||||
#include "ModelMall.hpp"
|
||||
#include "ConfigWizard.hpp"
|
||||
#include "SyncAmsInfoDialog.hpp"
|
||||
#include "../Utils/ASCIIFolding.hpp"
|
||||
@@ -149,7 +142,6 @@
|
||||
#include "ParamsDialog.hpp"
|
||||
#include "ImageDPIFrame.hpp"
|
||||
#include "Widgets/Label.hpp"
|
||||
#include "Widgets/RoundedRectangle.hpp"
|
||||
#include "Widgets/RadioGroup.hpp"
|
||||
#include "Widgets/CheckBox.hpp"
|
||||
#include "Widgets/Button.hpp"
|
||||
@@ -5459,7 +5451,7 @@ struct Plater::priv
|
||||
std::vector<size_t> load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false, bool split_object = false, bool auto_drop = true);
|
||||
|
||||
fs::path get_export_file_path(GUI::FileType file_type);
|
||||
wxString get_export_file(GUI::FileType file_type);
|
||||
wxString get_export_file(GUI::FileType file_type, const wxString& title = {});
|
||||
|
||||
// BBS
|
||||
void load_auxiliary_files();
|
||||
@@ -7214,6 +7206,64 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
}
|
||||
}
|
||||
|
||||
// BBS: a "published" 3MF project carries a flag plus a list of author-selected
|
||||
// setting keys. When present, keep the user's currently-selected presets and
|
||||
// overlay only the published keys onto the edited presets on load.
|
||||
PublishedConfig published_config;
|
||||
if (model.model_info != nullptr) {
|
||||
auto published_it = model.model_info->metadata_items.find("published");
|
||||
if (published_it != model.model_info->metadata_items.end() &&
|
||||
(published_it->second == "true" || published_it->second == "1")) {
|
||||
published_config.published = true;
|
||||
auto keys_it = model.model_info->metadata_items.find("published_keys");
|
||||
if (keys_it != model.model_info->metadata_items.end()) {
|
||||
try {
|
||||
auto j = nlohmann::json::parse(keys_it->second);
|
||||
if (j.is_array())
|
||||
for (const auto &k : j)
|
||||
if (k.is_string())
|
||||
published_config.published_keys.emplace_back(k.get<std::string>());
|
||||
} catch (...) {
|
||||
// Ignore malformed published_keys; the project still loads normally.
|
||||
}
|
||||
}
|
||||
|
||||
auto material_keys_it = model.model_info->metadata_items.find("published_material_keys");
|
||||
if (material_keys_it != model.model_info->metadata_items.end()) {
|
||||
try {
|
||||
auto jm = nlohmann::json::parse(material_keys_it->second);
|
||||
if (jm.is_array())
|
||||
for (const auto &m : jm) {
|
||||
// Malformed entries are skipped individually.
|
||||
if (!m.is_object())
|
||||
continue;
|
||||
PublishedMaterialEntry entry;
|
||||
const auto mat_it = m.find("material");
|
||||
if (mat_it != m.end() && mat_it->is_object()) {
|
||||
const auto &mat = *mat_it;
|
||||
if (mat.contains("filament_type") && mat["filament_type"].is_string())
|
||||
entry.filament_type = mat["filament_type"].get<std::string>();
|
||||
if (mat.contains("filament_vendor") && mat["filament_vendor"].is_string())
|
||||
entry.filament_vendor = mat["filament_vendor"].get<std::string>();
|
||||
if (mat.contains("filament_id") && mat["filament_id"].is_string())
|
||||
entry.filament_id = mat["filament_id"].get<std::string>();
|
||||
}
|
||||
if (m.contains("slot") && m["slot"].is_number_integer())
|
||||
entry.slot = m["slot"].get<int>();
|
||||
const auto entry_keys_it = m.find("keys");
|
||||
if (entry_keys_it != m.end() && entry_keys_it->is_array())
|
||||
for (const auto &k : *entry_keys_it)
|
||||
if (k.is_string())
|
||||
entry.keys.emplace_back(k.get<std::string>());
|
||||
published_config.material_keys.emplace_back(std::move(entry));
|
||||
}
|
||||
} catch (...) {
|
||||
// Ignore malformed published_material_keys; the project still loads normally.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (load_config) {
|
||||
if (!config.empty()) {
|
||||
Preset::normalize(config);
|
||||
@@ -7317,7 +7367,16 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
if (wipe_tower_y_opt)
|
||||
file_wipe_tower_y = *wipe_tower_y_opt;
|
||||
|
||||
preset_bundle->load_config_model(filename.string(), std::move(config), file_version);
|
||||
preset_bundle->load_config_model(filename.string(), std::move(config), file_version, &published_config);
|
||||
|
||||
// BBS: notify the user about published settings that could not be applied.
|
||||
if (!published_config.skipped_keys.empty()) {
|
||||
NotificationManager *notify_manager = q->get_notification_manager();
|
||||
std::string message = _u8L("Some published settings could not be applied:");
|
||||
for (const std::string &key : published_config.skipped_keys)
|
||||
message += "\n-" + key;
|
||||
notify_manager->bbl_show_3mf_warn_notification(message);
|
||||
}
|
||||
|
||||
ConfigOption* bed_type_opt = preset_bundle->project_config.option("curr_bed_type");
|
||||
if (bed_type_opt != nullptr) {
|
||||
@@ -8179,7 +8238,7 @@ fs::path Plater::priv::get_export_file_path(GUI::FileType file_type)
|
||||
return output_file;
|
||||
}
|
||||
|
||||
wxString Plater::priv::get_export_file(GUI::FileType file_type)
|
||||
wxString Plater::priv::get_export_file(GUI::FileType file_type, const wxString& title)
|
||||
{
|
||||
wxString wildcard;
|
||||
switch (file_type) {
|
||||
@@ -8222,7 +8281,7 @@ wxString Plater::priv::get_export_file(GUI::FileType file_type)
|
||||
case FT_3MF:
|
||||
{
|
||||
output_file.replace_extension("3mf");
|
||||
dlg_title = _L("Save file as");
|
||||
dlg_title = title.empty() ? _L("Save file as") : title;
|
||||
break;
|
||||
}
|
||||
case FT_OBJ:
|
||||
@@ -16105,6 +16164,76 @@ void Plater::export_core_3mf()
|
||||
export_3mf(path_u8, SaveStrategy::Silence);
|
||||
}
|
||||
|
||||
// Export the current project as a "published" 3MF. This is a pure export: unlike save_project(),
|
||||
// it never touches the project's file name, dirty state, backup path or title, and the
|
||||
// published metadata is attached to the model only for the duration of the export so the
|
||||
// in-memory project stays exactly as it was (a later Save Project produces a normal 3MF).
|
||||
int Plater::export_published_3mf(const std::vector<std::string>& published_keys, const std::vector<Slic3r::PublishedMaterialEntry>& material_keys)
|
||||
{
|
||||
wxString path = p->get_export_file(FT_3MF, _L("Publish 3MF file as:"));
|
||||
if (path.empty() || path == "<cancel>")
|
||||
return wxID_CANCEL;
|
||||
|
||||
nlohmann::json j = nlohmann::json::array();
|
||||
for (const std::string& key : published_keys)
|
||||
j.push_back(key);
|
||||
nlohmann::json jm = nlohmann::json::array();
|
||||
for (const Slic3r::PublishedMaterialEntry& e : material_keys)
|
||||
jm.push_back({ {"material", {{"filament_type", e.filament_type}, {"filament_vendor", e.filament_vendor}, {"filament_id", e.filament_id}}}, {"slot", e.slot}, {"keys", e.keys} });
|
||||
|
||||
Model& model = this->model();
|
||||
// Remember the previous metadata state so it can be restored after the export, keeping the
|
||||
// in-memory project pristine (the published flag lives only in the exported file).
|
||||
const bool had_model_info = (model.model_info != nullptr);
|
||||
const bool had_published = had_model_info && (model.model_info->metadata_items.find("published") != model.model_info->metadata_items.end());
|
||||
const bool had_published_keys = had_model_info && (model.model_info->metadata_items.find("published_keys") != model.model_info->metadata_items.end());
|
||||
const bool had_material_keys = had_model_info && (model.model_info->metadata_items.find("published_material_keys") != model.model_info->metadata_items.end());
|
||||
const std::string prev_published = had_published ? model.model_info->metadata_items.at("published") : std::string();
|
||||
const std::string prev_published_keys = had_published_keys ? model.model_info->metadata_items.at("published_keys") : std::string();
|
||||
const std::string prev_material_keys = had_material_keys ? model.model_info->metadata_items.at("published_material_keys") : std::string();
|
||||
if (model.model_info == nullptr)
|
||||
model.model_info = std::make_shared<ModelInfo>();
|
||||
model.model_info->metadata_items["published"] = "1";
|
||||
model.model_info->metadata_items["published_keys"] = j.dump();
|
||||
model.model_info->metadata_items["published_material_keys"] = jm.dump();
|
||||
|
||||
// Same file layout save_project() uses for its project files, plus SaveStrategy::Silence:
|
||||
// without it export_3mf() calls set_project_filename() on success, which would make this
|
||||
// pure export the current project file. Silence keeps the project state untouched, exactly
|
||||
// like export_core_3mf().
|
||||
auto save_strategy = SaveStrategy::SplitModel | SaveStrategy::ShareMesh | SaveStrategy::Silence;
|
||||
bool full_pathnames = wxGetApp().app_config->get_bool("export_sources_full_pathnames");
|
||||
if (full_pathnames)
|
||||
save_strategy = save_strategy | SaveStrategy::FullPathSources;
|
||||
|
||||
const int ret = export_3mf(into_path(path), save_strategy);
|
||||
|
||||
// Restore the previous metadata state (both on success and on failure).
|
||||
if (!had_model_info) {
|
||||
model.model_info = nullptr;
|
||||
} else {
|
||||
if (had_published)
|
||||
model.model_info->metadata_items["published"] = prev_published;
|
||||
else
|
||||
model.model_info->metadata_items.erase("published");
|
||||
if (had_published_keys)
|
||||
model.model_info->metadata_items["published_keys"] = prev_published_keys;
|
||||
else
|
||||
model.model_info->metadata_items.erase("published_keys");
|
||||
if (had_material_keys)
|
||||
model.model_info->metadata_items["published_material_keys"] = prev_material_keys;
|
||||
else
|
||||
model.model_info->metadata_items.erase("published_material_keys");
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
MessageDialog(this, _L("Failed to export the published 3MF file.\nPlease check whether the folder exists online or if other programs have the file open."),
|
||||
_L("Publish Settings"), wxOK | wxICON_WARNING).ShowModal();
|
||||
return wxID_CANCEL;
|
||||
}
|
||||
return wxID_YES;
|
||||
}
|
||||
|
||||
Preset *get_printer_preset(const MachineObject *obj)
|
||||
{
|
||||
if (!obj)
|
||||
|
||||
@@ -495,6 +495,10 @@ public:
|
||||
void export_gcode_3mf(bool export_all = false);
|
||||
void send_gcode_finish(wxString name);
|
||||
void export_core_3mf();
|
||||
// Export the current project as a "published" 3MF: embeds the author-selected settings
|
||||
// (published_keys / published_material_keys) into the file's metadata. A pure export: the
|
||||
// in-memory project (filename, dirty state, model_info metadata) is left untouched.
|
||||
int export_published_3mf(const std::vector<std::string>& published_keys, const std::vector<Slic3r::PublishedMaterialEntry>& material_keys);
|
||||
static TriangleMesh combine_mesh_fff(const ModelObject& mo, int instance_id, std::function<void(const std::string&)> notify_func = {});
|
||||
void export_stl(bool extended = false, bool selection_only = false, bool multi_stls = false, FileType file_type = FT_STL);
|
||||
//BBS: remove amf
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,183 @@
|
||||
#ifndef slic3r_GUI_PublishSettingsDialog_hpp_
|
||||
#define slic3r_GUI_PublishSettingsDialog_hpp_
|
||||
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
|
||||
#include "libslic3r/PublishSettings.hpp"
|
||||
|
||||
#include <wx/wx.h>
|
||||
#include <wx/scrolwin.h>
|
||||
#include <wx/menu.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
// Forward declarations (all are global classes, see Widgets/TextInput.hpp,
|
||||
// Widgets/StaticLine.hpp and the CollapseChevron definition in the .cpp).
|
||||
class TextInput;
|
||||
class StaticLine;
|
||||
class CollapseChevron;
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
// Dialog that lets a model author select which settings get embedded in a 3MF.
|
||||
// Settings are grouped the way the tabs show them: the process (print) pages,
|
||||
// the printer's per-extruder retraction settings, and one section per material
|
||||
// used in the project (filament overrides). Each main category has a select-all
|
||||
// tri-state header, subcategory (optgroup) headings, one row per setting
|
||||
// (checkbox + grey value label), and both header levels are collapsible (chevron
|
||||
// toggle). A search filter and an All/None / select-visible menu are provided.
|
||||
// Modified (dirty) settings are pre-checked and shown bold. On OK, the print
|
||||
// rows become the "published_keys" list and the material rows become the
|
||||
// per-material "published_material_keys".
|
||||
class PublishSettingsDialog : public DPIDialog
|
||||
{
|
||||
public:
|
||||
PublishSettingsDialog(wxWindow* parent = nullptr);
|
||||
~PublishSettingsDialog();
|
||||
|
||||
// The selected print-section setting keys (in display order). Keys may
|
||||
// contain '#'.
|
||||
std::vector<std::string> GetPublishedKeys() const;
|
||||
|
||||
// The selected keys grouped per material: one entry per material section
|
||||
// with at least one checked key. Keys are base keys (no "#N" suffix).
|
||||
std::vector<Slic3r::PublishedMaterialEntry> GetPublishedMaterialKeys() const;
|
||||
|
||||
protected:
|
||||
void on_dpi_changed(const wxRect& suggested_rect) override;
|
||||
|
||||
private:
|
||||
// Which part of the settings the row/category came from.
|
||||
enum class Section { Print, Printer, Material };
|
||||
|
||||
// One selectable setting row: a checkbox (setting name) plus a value label
|
||||
// and a (optional) grey unit label. key is the full config key and may carry
|
||||
// a "#N" variant suffix (print/printer rows); material rows carry the base key.
|
||||
struct Row
|
||||
{
|
||||
std::string key;
|
||||
wxString category;
|
||||
wxString subcategory;
|
||||
wxString label;
|
||||
wxString value;
|
||||
wxString unit;
|
||||
wxString section_title; // top-level group title, for filter matching
|
||||
Section section{Section::Print};
|
||||
bool dirty{false}; // matches a dirty base key: pre-checked + bold
|
||||
bool matches_filter{false}; // survives the active filter (computed by apply_filter)
|
||||
wxCheckBox* check{nullptr};
|
||||
wxStaticText* value_label{nullptr};
|
||||
wxStaticText* unit_label{nullptr};
|
||||
wxSizerItem* item{nullptr}; // sizer item of this row's h-sizer in m_list_sizer
|
||||
};
|
||||
|
||||
// A subcategory (optgroup) heading. Rows store indices into m_rows.
|
||||
struct Subcategory
|
||||
{
|
||||
wxString title;
|
||||
::StaticLine* header{nullptr}; // null when the title is empty
|
||||
bool collapsed{false};
|
||||
CollapseChevron* chevron{nullptr};
|
||||
wxSizerItem* item{nullptr}; // sizer item of the header h-sizer in m_list_sizer
|
||||
std::vector<size_t> rows;
|
||||
};
|
||||
|
||||
// A main category with its select-all tri-state header.
|
||||
struct Category
|
||||
{
|
||||
wxString title;
|
||||
Section section{Section::Print};
|
||||
size_t group{0}; // index into m_sections
|
||||
std::string icon_name; // bitmap name; empty = no icon
|
||||
wxStaticBitmap* icon{nullptr}; // 18px category icon (null when icon_name empty)
|
||||
wxCheckBox* header{nullptr}; // select-all tri-state
|
||||
// Material opt-in: the master checkbox carries the material title and
|
||||
// gates whether this material's keys may be exported.
|
||||
bool master{false};
|
||||
wxCheckBox* master_check{nullptr};
|
||||
bool collapsed{false};
|
||||
CollapseChevron* chevron{nullptr};
|
||||
wxSizerItem* item{nullptr}; // sizer item of the header h-sizer in m_list_sizer
|
||||
// Material identity, only for Section::Material categories.
|
||||
std::string filament_type;
|
||||
std::string filament_vendor;
|
||||
std::string filament_id;
|
||||
// The author's 0-based filament slot this material section represents.
|
||||
size_t filament_slot{0};
|
||||
std::vector<Subcategory> subs;
|
||||
std::vector<size_t> rows; // flattened rows, for the tri-state math
|
||||
};
|
||||
|
||||
// A top-level section group mirroring the editor sidebar. Categories are
|
||||
// nested inside.
|
||||
struct SectionGroup
|
||||
{
|
||||
wxString title; // _L("Printer") / _L("Filament") / _L("Process")
|
||||
Section kind{Section::Print}; // maps 1:1 to the display group
|
||||
std::string icon_name; // "printer" / "filament" / "process"
|
||||
wxStaticBitmap* icon{nullptr}; // 18px, like Category::icon
|
||||
wxCheckBox* header{nullptr}; // tri-state select-all; nullptr for the Filament group
|
||||
::StaticLine* header_line{nullptr}; // Filament group's clickable title
|
||||
CollapseChevron* chevron{nullptr};
|
||||
wxSizerItem* item{nullptr};
|
||||
bool collapsed{false};
|
||||
std::vector<size_t> categories; // indices into m_categories
|
||||
};
|
||||
|
||||
void build_option_model();
|
||||
void apply_filter(const wxString& filter_text);
|
||||
void select_all(bool value);
|
||||
void select_visible(bool value);
|
||||
void show_menu(wxMouseEvent& evt);
|
||||
void update_category_header(Category& category);
|
||||
void set_row_bold(Row& row, bool bold);
|
||||
void on_category_toggle(size_t category_index);
|
||||
// Material opt-in toggled: enables/disables the material's rows + tri-state
|
||||
// and resyncs the header.
|
||||
void on_master_toggle(size_t category_index);
|
||||
// Collapse/expand a category or subcategory; resyncs visibility + chevrons.
|
||||
void toggle_category(size_t category_index);
|
||||
void toggle_subcategory(size_t category_index, size_t subcategory_index);
|
||||
// Find-or-create the top-level section group for a Section kind (builds its
|
||||
// header row on first use).
|
||||
size_t section_group_for(Section kind);
|
||||
// Top-level section group: select-all tri-state toggled / collapse/expand /
|
||||
// header resync.
|
||||
void on_section_toggle(size_t section_index);
|
||||
void toggle_section(size_t section_index);
|
||||
void update_section_header(SectionGroup& section);
|
||||
// Single pass over categories/subs/rows: shows an item iff it is not hidden
|
||||
// by the filter and (for subs/rows) by a collapsed ancestor. Flips the
|
||||
// header chevrons. Only reads matches_filter; never re-runs filter matching.
|
||||
void apply_visibility();
|
||||
// Creates a collapse chevron with a hand cursor; clicking it (with the given
|
||||
// mouse event, LEFT_DOWN for categories / LEFT_UP for subcategories,
|
||||
// matching the header's own binding) invokes the toggle.
|
||||
CollapseChevron* create_chevron(wxWindow* parent, const wxEventTypeTag<wxMouseEvent>& event_type, std::function<void()> toggle);
|
||||
|
||||
wxScrolledWindow* m_scroll{nullptr};
|
||||
wxBoxSizer* m_list_sizer{nullptr}; // vertical sizer of the scrolled window
|
||||
wxBoxSizer* m_fb_sizer{nullptr}; // "All"/"None" buttons sizer
|
||||
TextInput* m_filter_box{nullptr};
|
||||
wxTextCtrl* m_filter_ctrl{nullptr};
|
||||
wxStaticBitmap* m_menu_button{nullptr};
|
||||
wxStaticText* m_info{nullptr};
|
||||
wxString m_info_nonsel;
|
||||
wxString m_info_allsel;
|
||||
wxString m_info_empty;
|
||||
|
||||
ScalableBitmap m_search;
|
||||
ScalableBitmap m_menu;
|
||||
|
||||
std::vector<Row> m_rows;
|
||||
std::vector<Category> m_categories;
|
||||
// Fixed display order enforced by phase order in build_option_model():
|
||||
// Printer, then Filament, then Process.
|
||||
std::vector<SectionGroup> m_sections;
|
||||
};
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
||||
#endif // slic3r_GUI_PublishSettingsDialog_hpp_
|
||||
@@ -5675,6 +5675,9 @@ if (is_marlin_flavor)
|
||||
optgroup->append_single_option_line("extruder_offset", "printer_extruder_basic_information#extruder-offset-position", extruder_idx);
|
||||
|
||||
//BBS: don't show retract related config menu in machine page
|
||||
// Keep this optgroup's options in sync with publishable_printer_retraction_options()
|
||||
// in libslic3r/PublishSettings.hpp: the published-3MF printer allowlist is its union
|
||||
// with the Z-Hop optgroup below.
|
||||
optgroup = page->new_optgroup(L("Retraction"), L"param_retraction");
|
||||
optgroup->append_single_option_line("retraction_length", "printer_extruder_retraction#length", extruder_idx);
|
||||
optgroup->append_single_option_line("retract_restart_extra", "printer_extruder_retraction#extra-length-on-restart", extruder_idx);
|
||||
@@ -5688,6 +5691,9 @@ if (is_marlin_flavor)
|
||||
// Orca
|
||||
optgroup->append_single_option_line("retract_after_wipe", "printer_extruder_retraction#retract-amount-after-wipe", extruder_idx);
|
||||
|
||||
// Keep this optgroup's options in sync with publishable_printer_z_hop_options()
|
||||
// in libslic3r/PublishSettings.hpp: the published-3MF printer allowlist is its union
|
||||
// with the Retraction optgroup above.
|
||||
optgroup = page->new_optgroup(L("Z-Hop"), L"param_extruder_lift_enforcement");
|
||||
optgroup->append_single_option_line("retract_lift_enforce", "printer_extruder_z_hop#on-surfaces", extruder_idx);
|
||||
optgroup->append_single_option_line("z_hop_types", "printer_extruder_z_hop#z-hop-type", extruder_idx);
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <memory>
|
||||
|
||||
//#include "BedShapeDialog.hpp"
|
||||
#include "Event.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
#include "ConfigManipulation.hpp"
|
||||
#include "OptionsGroup.hpp"
|
||||
@@ -38,7 +37,6 @@
|
||||
//BBS: GUI refactor
|
||||
#include "Notebook.hpp"
|
||||
#include "ParamsPanel.hpp"
|
||||
#include "Widgets/RoundedRectangle.hpp"
|
||||
#include "Widgets/TextInput.hpp"
|
||||
#include "Widgets/CheckBox.hpp" // ORCA
|
||||
|
||||
@@ -472,6 +470,7 @@ protected:
|
||||
std::string m_last_sparse_infill_rotate_template_value;
|
||||
ConfigManipulation get_config_manipulation();
|
||||
friend class EditGCodeDialog;
|
||||
friend class PublishSettingsDialog;
|
||||
};
|
||||
|
||||
class TabPrint : public Tab
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/Color.hpp"
|
||||
#include "format.hpp"
|
||||
#include "ConfigValueFormatter.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "Plater.hpp"
|
||||
#include "Tab.hpp"
|
||||
@@ -571,14 +572,6 @@ void DiffModel::Clear()
|
||||
}
|
||||
|
||||
|
||||
static std::string get_pure_opt_key(std::string opt_key)
|
||||
{
|
||||
const int pos = opt_key.find("#");
|
||||
if (pos > 0)
|
||||
boost::erase_tail(opt_key, opt_key.size() - pos);
|
||||
return opt_key;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DiffViewCtrl
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -1212,32 +1205,6 @@ bool UnsavedChangesDialog::save(PresetCollection* dependent_presets, bool show_s
|
||||
return true;
|
||||
}
|
||||
|
||||
wxString get_string_from_enum(const std::string& opt_key, const DynamicPrintConfig& config, bool is_infill = false, int idx = -1)
|
||||
{
|
||||
const ConfigOptionDef& def = config.def()->options.at(opt_key);
|
||||
const std::vector<std::string>& names = def.enum_labels;//ConfigOptionEnum<T>::get_enum_names();
|
||||
int val = 0;
|
||||
|
||||
if (idx >= 0)
|
||||
val = dynamic_cast<const ConfigOptionInts*>(config.option(opt_key))->get_at(idx);
|
||||
else
|
||||
val = config.option(opt_key)->getInt();
|
||||
|
||||
// Each infill doesn't use all list of infill declared in PrintConfig.hpp.
|
||||
// So we should "convert" val to the correct one
|
||||
if (is_infill) {
|
||||
for (auto key_val : *def.enum_keys_map)
|
||||
if (int(key_val.second) == val) {
|
||||
auto it = std::find(def.enum_values.begin(), def.enum_values.end(), key_val.first);
|
||||
if (it == def.enum_values.end())
|
||||
return "";
|
||||
return from_u8(_utf8(names[it - def.enum_values.begin()]));
|
||||
}
|
||||
return _L("Undefined");
|
||||
}
|
||||
return from_u8(_utf8(names[val]));
|
||||
}
|
||||
|
||||
// BBS
|
||||
#if 0
|
||||
static size_t get_id_from_opt_key(std::string opt_key)
|
||||
@@ -1251,194 +1218,6 @@ static size_t get_id_from_opt_key(std::string opt_key)
|
||||
}
|
||||
#endif
|
||||
|
||||
static wxString get_full_label(std::string opt_key, const DynamicPrintConfig& config)
|
||||
{
|
||||
opt_key = get_pure_opt_key(opt_key);
|
||||
auto option = config.option(opt_key);
|
||||
|
||||
if (!option || option->is_nil())
|
||||
return _L("N/A");
|
||||
|
||||
const ConfigOptionDef* opt = config.def()->get(opt_key);
|
||||
return opt->full_label.empty() ? opt->label : opt->full_label;
|
||||
}
|
||||
|
||||
static wxString get_string_value(std::string opt_key, const DynamicPrintConfig& config)
|
||||
{
|
||||
int orig_opt_idx = -1;
|
||||
int opt_idx = -1;
|
||||
int pos = opt_key.find("#");
|
||||
std::string temp_str = opt_key;
|
||||
if (pos > 0) {
|
||||
boost::erase_head(temp_str, pos + 1);
|
||||
orig_opt_idx = static_cast<size_t>(atoi(temp_str.c_str()));
|
||||
}
|
||||
opt_idx = orig_opt_idx >= 0 ? orig_opt_idx : 0;
|
||||
opt_key = get_pure_opt_key(opt_key);
|
||||
auto option = config.option(opt_key);
|
||||
if (!option) {
|
||||
return _L("N/A");
|
||||
}
|
||||
auto opt_vector = dynamic_cast<const ConfigOptionVectorBase *>(option);
|
||||
|
||||
if (option->is_scalar() && config.option(opt_key)->is_nil() ||
|
||||
option->is_vector() && opt_vector && opt_idx >= 0 && opt_idx < opt_vector->size() && opt_vector->is_nil(opt_idx))
|
||||
return _L("N/A");
|
||||
|
||||
wxString out;
|
||||
|
||||
const ConfigOptionDef* opt = config.def()->get(opt_key);
|
||||
bool is_nullable = opt->nullable;
|
||||
|
||||
switch (opt->type) {
|
||||
case coInt:
|
||||
return from_u8((boost::format("%1%") % config.opt_int(opt_key)).str());
|
||||
case coInts: {
|
||||
if (is_nullable) {
|
||||
auto values = config.opt<ConfigOptionIntsNullable>(opt_key);
|
||||
if (opt_idx < values->size())
|
||||
return from_u8((boost::format("%1%") % values->get_at(opt_idx)).str());
|
||||
}
|
||||
else {
|
||||
auto values = config.opt<ConfigOptionInts>(opt_key);
|
||||
if (orig_opt_idx >= 0 && orig_opt_idx < values->size()) {
|
||||
return from_u8((boost::format("%1%") % values->get_at(opt_idx)).str());
|
||||
}
|
||||
else {
|
||||
std::string value_str;
|
||||
for (int i = 0; i < values->size(); i++) {
|
||||
value_str += std::to_string(values->get_at(i));
|
||||
if (i != values->size() - 1) {
|
||||
value_str += ",";
|
||||
}
|
||||
}
|
||||
return from_u8(value_str);
|
||||
}
|
||||
}
|
||||
return _L("Undefined");
|
||||
}
|
||||
case coBool:
|
||||
return config.opt_bool(opt_key) ? "true" : "false";
|
||||
case coBools: {
|
||||
if (is_nullable) {
|
||||
auto values = config.opt<ConfigOptionBoolsNullable>(opt_key);
|
||||
if (opt_idx < values->size())
|
||||
return values->get_at(opt_idx) ? "true" : "false";
|
||||
}
|
||||
else {
|
||||
auto values = config.opt<ConfigOptionBools>(opt_key);
|
||||
if (opt_idx < values->size())
|
||||
return values->get_at(opt_idx) ? "true" : "false";
|
||||
}
|
||||
return _L("Undefined");
|
||||
}
|
||||
case coPercent:
|
||||
return from_u8((boost::format("%1%%%") % int(config.optptr(opt_key)->getFloat())).str());
|
||||
case coPercents: {
|
||||
if (is_nullable) {
|
||||
auto values = config.opt<ConfigOptionPercentsNullable>(opt_key);
|
||||
if (opt_idx < values->size())
|
||||
return from_u8((boost::format("%1%%%") % values->get_at(opt_idx)).str());
|
||||
}
|
||||
else {
|
||||
auto values = config.opt<ConfigOptionPercents>(opt_key);
|
||||
if (opt_idx < values->size())
|
||||
return from_u8((boost::format("%1%%%") % values->get_at(opt_idx)).str());
|
||||
}
|
||||
return _L("Undefined");
|
||||
}
|
||||
case coFloat:
|
||||
return double_to_string(config.opt_float(opt_key));
|
||||
case coFloats: {
|
||||
if (is_nullable) {
|
||||
auto values = config.opt<ConfigOptionFloatsNullable>(opt_key);
|
||||
if (opt_idx < values->size())
|
||||
return double_to_string(values->get_at(opt_idx));
|
||||
}
|
||||
else {
|
||||
auto values = config.opt<ConfigOptionFloats>(opt_key);
|
||||
if (values && opt_idx < values->size())
|
||||
return double_to_string(values->get_at(opt_idx));
|
||||
}
|
||||
return _L("Undefined");
|
||||
}
|
||||
case coString:
|
||||
return from_u8(config.opt_string(opt_key));
|
||||
case coStrings: {
|
||||
const ConfigOptionStrings* strings = config.opt<ConfigOptionStrings>(opt_key);
|
||||
if (strings) {
|
||||
if (opt_key == "compatible_printers" || opt_key == "compatible_prints") {
|
||||
if (strings->empty())
|
||||
return _L("All");
|
||||
for (size_t id = 0; id < strings->size(); id++)
|
||||
out += from_u8(strings->get_at(id)) + "\n";
|
||||
out.RemoveLast(1);
|
||||
return out;
|
||||
}
|
||||
if (!strings->empty() && opt_idx < strings->values.size())
|
||||
return from_u8(strings->get_at(opt_idx));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case coFloatOrPercent: {
|
||||
const ConfigOptionFloatOrPercent* opt = config.opt<ConfigOptionFloatOrPercent>(opt_key);
|
||||
if (opt)
|
||||
out = double_to_string(opt->value) + (opt->percent ? "%" : "");
|
||||
return out;
|
||||
}
|
||||
case coEnum: {
|
||||
return get_string_from_enum(opt_key, config,
|
||||
opt_key == "top_surface_pattern" ||
|
||||
opt_key == "bottom_surface_pattern" ||
|
||||
opt_key == "internal_solid_infill_pattern" ||
|
||||
opt_key == "sparse_infill_pattern" ||
|
||||
opt_key == "ironing_pattern" ||
|
||||
opt_key == "support_ironing_pattern" ||
|
||||
opt_key == "support_pattern" ||
|
||||
opt_key == "support_interface_pattern")
|
||||
;
|
||||
}
|
||||
case coEnums: {
|
||||
return get_string_from_enum(opt_key, config,
|
||||
opt_key == "top_surface_pattern" ||
|
||||
opt_key == "bottom_surface_pattern" ||
|
||||
opt_key == "internal_solid_infill_pattern" ||
|
||||
opt_key == "sparse_infill_pattern" ||
|
||||
opt_key == "ironing_pattern" ||
|
||||
opt_key == "support_ironing_pattern" ||
|
||||
opt_key == "support_pattern" ||
|
||||
opt_key == "support_interface_pattern"
|
||||
, opt_idx);
|
||||
}
|
||||
case coPoint: {
|
||||
Vec2d val = config.opt<ConfigOptionPoint>(opt_key)->value;
|
||||
return from_u8((boost::format("[%1%]") % ConfigOptionPoint(val).serialize()).str());
|
||||
}
|
||||
case coPoints: {
|
||||
//BBS: add bed_exclude_area
|
||||
if (opt_key == "printable_area" || opt_key == "thumbnails") {
|
||||
ConfigOptionPoints points = *config.option<ConfigOptionPoints>(opt_key);
|
||||
//BuildVolume build_volume = {points.values, 0.};
|
||||
return get_thumbnails_string(points.values);
|
||||
}
|
||||
else if (opt_key == "bed_exclude_area") {
|
||||
return get_thumbnails_string(config.option<ConfigOptionPoints>(opt_key)->values);
|
||||
}
|
||||
else if (opt_key == "head_wrap_detect_zone") {
|
||||
return get_thumbnails_string(config.option<ConfigOptionPoints>(opt_key)->values);
|
||||
}
|
||||
else if (opt_key == "wrapping_exclude_area") {
|
||||
return get_thumbnails_string(config.option<ConfigOptionPoints>(opt_key)->values);
|
||||
}
|
||||
Vec2d val = config.opt<ConfigOptionPoints>(opt_key)->get_at(opt_idx);
|
||||
return from_u8((boost::format("[%1%]") % ConfigOptionPoint(val).serialize()).str());
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void UnsavedChangesDialog::update(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset, const wxString& header)
|
||||
{
|
||||
PresetCollection* presets = dependent_presets;
|
||||
|
||||
Reference in New Issue
Block a user