Compare commits

..
Author SHA1 Message Date
Ian Chua 15aa9fe6c3 fix: avoid substring denies in audit path keywords 2026-10-07 15:11:55 +08:00
60 changed files with 332 additions and 800 deletions
@@ -105,12 +105,11 @@ Rules:
`single_extruder_multi_material` off, and in the app when the printer tab loads a printer with a
different number of extruders, the pair is rebuilt from `extruder_variant_list` (one
`Direct Drive Standard` per extruder when the list is absent) and the variant arrays are resized to
the rebuilt pair, padded with their first value or cut. The `machine_max_*` limits are padded the
same way, so extruder 2 and up of a list-less printer take extruder 1's normal limit as their
silent one too. The resize skips `hotend_heating_rate` / `hotend_cooling_rate`: they keep their
width, and an extruder beyond it reads their first value. With the three in agreement that changes
nothing; a pair written without the list is replaced. A listed variant the pair lacks is a menu
choice that reads variant index 0.
the rebuilt pair, padded with their first value or cut. The resize skips the `machine_max_*` limits
and `hotend_heating_rate` / `hotend_cooling_rate`: they keep their width, and an extruder beyond it
reads their first value, so extruder 2 and up of a list-less printer take extruder 1's normal limit
as their silent one too. With the three in agreement that changes nothing; a pair written without
the list is replaced. A listed variant the pair lacks is a menu choice that reads variant index 0.
- The pair without `extruder_variant_list` slices, but the sidebar offers no variant switch and
the app cannot add variants to a list-less process: nothing is lost while every extruder
has exactly one variant, and every further variant is unreachable.
+4 -6
View File
@@ -4,17 +4,15 @@ OrcaSlicer — open-source C++17 3D slicer. wxWidgets GUI, CMake build system.
## Build Commands
Build the Release configuration unless asked otherwise.
```bash
# macOS
cmake --build build/arm64 --config Release --target all --
cmake --build build/arm64 --config RelWithDebInfo --target all --
# Linux
cmake --build build --config Release --target all --
cmake --build build --config RelWithDebInfo --target all --
# Windows
cmake --build . --config Release --target ALL_BUILD -- -m
# Windows (replace %build_type% with Debug/Release/RelWithDebInfo)
cmake --build . --config %build_type% --target ALL_BUILD -- -m
```
## Testing
+1 -1
View File
@@ -311,7 +311,7 @@ function CreatePrinterBlock(OneModel)
return '<div class="PrinterBlock" onClick="ChooseModel(\''+vendor+'\',\''+OneModel['model']+'\')">'+
' <div class="PImg">'+
' <img class="ModelThumbnail" src="' + OneModel['cover'] + '" onerror="this.onerror=null;this.src=\'../img/printer-dummy.png\';"/>'+
' <img class="ModelThumbnail" src="' + OneModel['cover'] + '" />'+
' </div>'+
' <div class="PrinterInfoMark">?</div>'+
' <div class="PrinterInfo">'+
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

+1 -7
View File
@@ -23,13 +23,7 @@ appimage_is_host_library() {
}
appimage_is_elf_file() {
# Read the four-byte ELF magic rather than asking file(1): this runs once per candidate, and an
# AppDir holds thousands of them (the bundled Python runtime alone is ~5k files, none of them
# ELF). Two processes per call made this ~14 s of a ~95 s image build on its own.
local magic
[[ -f "$1" && -r "$1" ]] || return 1
IFS= read -r -n 4 -d '' magic < "$1" 2>/dev/null
[[ $magic == $'\177ELF' ]]
file -b "$1" 2>/dev/null | grep -q '^ELF '
}
appimage_list_direct_dependencies() {
-5
View File
@@ -4,10 +4,5 @@
<dict>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<!-- The Bambu network plug-in's code protector rewrites one of its own signed code pages
after loading. Under the hardened runtime macOS kills the process when that page is
paged back in; this lets it run, as Bambu Studio's signature does. -->
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
</dict>
</plist>
-11
View File
@@ -3618,9 +3618,6 @@ int CLI::run(int argc, char **argv)
{
if (opt_key == "compatible_prints" || opt_key == "compatible_printers" || opt_key == "model_id" || opt_key == "dev_model_name" || opt_key == "filament_settings_id")
continue;
// rebuilt from every filament after this loop
if (filament_dev_options.find(opt_key) != filament_dev_options.end())
continue;
ConfigOption *opt = m_print_config.option(opt_key, true);
if (opt == nullptr) {
// opt_key does not exist in this ConfigBase and it cannot be created, because it is not defined by this->def().
@@ -3684,14 +3681,6 @@ int CLI::run(int argc, char **argv)
}
}
// The stored values cannot be told apart per filament, so they are kept as they are unless every slot has a config.
std::vector<const DynamicPrintConfig *> filament_configs(filament_count, nullptr);
for (size_t index = 0; index < load_filaments_config.size(); index++)
if (load_filaments_index[index] >= 1 && load_filaments_index[index] <= filament_count)
filament_configs[load_filaments_index[index] - 1] = &load_filaments_config[index];
if (std::find(filament_configs.begin(), filament_configs.end(), nullptr) == filament_configs.end())
set_filament_dev_options(m_print_config, filament_configs);
if (m_print_config.option<ConfigOptionStrings>("filament_extruder_variant")) {
std::vector<int>& filament_self_indice = m_print_config.option<ConfigOptionInts>("filament_self_index", true)->values;
int index_size = m_print_config.option<ConfigOptionStrings>("filament_extruder_variant")->size();
@@ -5,10 +5,5 @@
<!-- for dynamic loading of libraries without signature validation. Used for 3dconnection drivers.-->
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<!-- The Bambu network plug-in's code protector rewrites one of its own signed code pages
after loading. Under the hardened runtime macOS kills the process when that page is
paged back in; this lets it run, as Bambu Studio's signature does. -->
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
</dict>
</plist>
@@ -118,13 +118,9 @@ bundle_dependency_closure() {
# (scripts/check_appimage_libs.sh).
local -a search_dirs=("$dst_dir")
# Walked with a read index rather than by reslicing the array: "${queue[@]:1}" rebuilds the whole
# queue on every pop, so draining it costs O(n^2). At the ~5k entries this bundle reaches that was
# ~22 s of the image build spent copying an array around.
local head=0
while [ "$head" -lt ${#queue[@]} ]; do
target="${queue[$head]}"
head=$((head + 1))
while [ ${#queue[@]} -gt 0 ]; do
target="${queue[0]}"
queue=("${queue[@]:1}")
if [ ! -e "$target" ] || ! appimage_is_elf_file "$target"; then
continue
+13 -38
View File
@@ -10030,13 +10030,6 @@ static void extend_extruder_variant(DynamicPrintConfig& config, const unsigned i
printer_extruder_variant_opt->values.insert(printer_extruder_variant_opt->values.end(), variants_list.begin(), variants_list.end());
}
}
// 3. Size the machine limits to the rebuilt variants, padded with their first value like the other variant keys.
// They are not extruder option keys, so the resize loop in set_num_extruders skips them.
const auto &defaults = FullPrintConfig::defaults();
for (const std::string &key : printer_options_with_variant_2)
if (auto *opt = config.option<ConfigOptionFloats>(key))
opt->resize(config.get_parameter_size(key, num_extruders), defaults.option(key));
}
void DynamicPrintConfig::set_num_extruders(unsigned int num_extruders)
@@ -10829,22 +10822,6 @@ void normalize_filament_values_to_variants(DynamicPrintConfig &config)
}
}
void set_filament_dev_options(DynamicPrintConfig &config, const std::vector<const DynamicPrintConfig *> &filament_configs)
{
for (const std::string &key : filament_dev_options) {
if (std::none_of(filament_configs.begin(), filament_configs.end(), [&key](const DynamicPrintConfig *filament) { return filament->has(key); }))
continue;
const ConfigOption *default_value = print_config_def.get(key)->default_value.get();
auto *dst = static_cast<ConfigOptionVectorBase *>(config.option(key, true));
dst->clear();
for (const DynamicPrintConfig *filament : filament_configs) {
const auto *src = static_cast<const ConfigOptionVectorBase *>(filament->has(key) ? filament->option(key) : default_value);
if (!src->empty())
dst->append(src);
}
}
}
//used for object/region config
//use the smallest of multiple to single
@@ -11543,18 +11520,12 @@ void DynamicPrintConfig::update_non_diff_values_to_base_config(DynamicPrintConfi
int cur_variant_count = cur_extruder_variants.size();
int target_variant_count = target_extruder_variants.size();
// A base variant this config does not list (the base gained it after the config was saved, or the
// config lists none) takes this config's first variant of the same extruder, as a user preset's
// values do in update_diff_values_to_child_config. Left unmatched, the base's value would silently
// replace the user's.
variant_index.resize(target_variant_count, -1);
if (cur_variant_count == 0) {
// Defensive: target_variant_count may be 0 if the preset doesn't carry extruder_variant_name.
// In that case keep variant_index empty and let the downstream size checks produce a useful error.
if (!variant_index.empty())
// This config's one value belongs to the extruder of the base's first variant.
variant_index = map_variant_indices(target_extruder_variants, target_extruder_ids, {},
target_extruder_ids.empty() ? std::vector<int>() : std::vector<int>{target_extruder_ids[0]});
variant_index[0] = 0;
}
else if ((cur_extruder_ids.size() > 0) && cur_variant_count != cur_extruder_ids.size()){
//should not happen
@@ -11567,7 +11538,18 @@ void DynamicPrintConfig::update_non_diff_values_to_base_config(DynamicPrintConfi
%extruder_variant_name %target_variant_count %extruder_id_name %target_extruder_ids.size();
}
else {
variant_index = map_variant_indices(target_extruder_variants, target_extruder_ids, cur_extruder_variants, cur_extruder_ids);
for (int i = 0; i < target_variant_count; i++)
{
for (int j = 0; j < cur_variant_count; j++)
{
if ((target_extruder_variants[i] == cur_extruder_variants[j])
&&(target_extruder_ids.empty() || (target_extruder_ids[i] == cur_extruder_ids[j])))
{
variant_index[i] = j;
break;
}
}
}
}
for (auto& opt : keys) {
@@ -11592,13 +11574,6 @@ void DynamicPrintConfig::update_non_diff_values_to_base_config(DynamicPrintConfi
if (cur_variant_count > target_variant_count)
continue;
// The variant lists are the base's layout itself, which every other value is
// carried onto: a variant this config lacks keeps its own name and id.
if (opt == extruder_id_name || opt == extruder_variant_name) {
opt_src->set(opt_target);
continue;
}
int stride = 1;
if (key_set2.find(opt) != key_set2.end())
stride = 2;
-5
View File
@@ -928,11 +928,6 @@ void normalize_filament_values_to_variants(DynamicPrintConfig &config);
extern std::set<std::string> filament_dev_options;
// Orca: a filament_dev_options option holds several values per filament, and how many is up to the
// filament preset, so one filament's values cannot be replaced in place. This rebuilds each option from
// filament_configs, one config per filament in slot order, as the filaments' values one after another.
void set_filament_dev_options(DynamicPrintConfig &config, const std::vector<const DynamicPrintConfig *> &filament_configs);
extern void update_static_print_config_from_dynamic(ConfigBase& config, const DynamicPrintConfig& dest_config, std::vector<int> variant_index, std::set<std::string>& key_set1, int stride = 1);
extern void compute_filament_override_value(const std::string& opt_key, const ConfigOption *opt_old_machine, const ConfigOption *opt_new_machine, const ConfigOption *opt_new_filament, const DynamicPrintConfig& new_full_config,
t_config_option_keys& diff_keys, DynamicPrintConfig& filament_overrides, std::vector<int>& f_map_indices);
+2 -2
View File
@@ -974,8 +974,8 @@ bool AMSMaterialsSetting::Show(bool show)
static void _collect_filament_info(const wxString& shown_name,
const Preset& filament,
std::unordered_map<wxString, wxString>& query_filament_vendors,
std::unordered_map<wxString, wxString>& query_filament_types)
unordered_map<wxString, wxString>& query_filament_vendors,
unordered_map<wxString, wxString>& query_filament_types)
{
query_filament_vendors[shown_name] = filament.config.get_filament_vendor();
query_filament_types[shown_name] = filament.config.get_filament_type();
+3 -3
View File
@@ -856,14 +856,14 @@ void AuxiliaryPanel::Split(const std::string &src, const std::string &separator,
dest.clear();
index = str.find_first_of(separator, start);
do {
if (index != std::string::npos) {
if (index != string::npos) {
substring = str.substr(start, index - start);
dest.push_back(substring);
start = index + separator.size();
index = str.find(separator, start);
if (start == std::string::npos) break;
if (start == string::npos) break;
}
} while (index != std::string::npos);
} while (index != string::npos);
// the last part
substring = str.substr(start);
@@ -1307,7 +1307,7 @@ void CalibrationPresetPage::stripWhiteSpace(std::string& str)
{
if (str == "") { return; }
std::string::iterator cur_it;
string::iterator cur_it;
cur_it = str.begin();
while (cur_it != str.end()) {
@@ -2597,7 +2597,7 @@ void CalibrationPresetPage::update_multi_extruder_filament_combobox(const std::s
int ams_id_int = 0;
try {
if (!ams_id.empty())
ams_id_int = std::stoi(ams_id.c_str());
ams_id_int = stoi(ams_id.c_str());
} catch (...) {}
@@ -2685,7 +2685,7 @@ void CalibrationPresetPage::update_filament_combobox(std::string ams_id)
int ams_id_int = 0;
try {
if (!ams_id.empty())
ams_id_int = std::stoi(ams_id.c_str());
ams_id_int = stoi(ams_id.c_str());
} catch (...) {}
+4 -4
View File
@@ -347,7 +347,7 @@ static std::string get_curr_timestmp()
// return timestampString;
}
static void get_filament_compatible_printer(Preset* preset, std::vector<std::string>& printers)
static void get_filament_compatible_printer(Preset* preset, vector<std::string>& printers)
{
auto compatible_printers = dynamic_cast<ConfigOptionStrings *>(preset->config.option("compatible_printers"));
if (compatible_printers == nullptr) return;
@@ -1581,7 +1581,7 @@ void CreateFilamentPresetDialog::sort_printer_by_nozzle(std::vector<std::pair<st
{
std::unordered_map<std::string, float> nozzle_diameter = nozzle_diameter_map;
std::sort(printer_name_to_filament_preset.begin(), printer_name_to_filament_preset.end(),
[&nozzle_diameter](const std::pair<std::string, T> &a, const std::pair<std::string, T> &b) {
[&nozzle_diameter](const std::pair<string, T> &a, const std::pair<string, T> &b) {
size_t nozzle_index_a = a.first.find(" nozzle");
size_t nozzle_index_b = b.first.find(" nozzle");
if (nozzle_index_a == std::string::npos || nozzle_index_b == std::string::npos) return a.first < b.first;
@@ -3143,7 +3143,7 @@ void CreatePrinterPresetDialog::set_current_visible_printer()
wxArrayString CreatePrinterPresetDialog::printer_preset_sort_with_nozzle_diameter(const VendorProfile &vendor_profile, float nozzle_diameter)
{
std::vector<std::pair<float, std::string>> preset_sort;
std::vector<pair<float, std::string>> preset_sort;
auto get_nozzle_size_for_printer_model = [this](const std::string & model_name) -> size_t {
auto iter = m_printer_name_to_preset.find(model_name);
@@ -4964,7 +4964,7 @@ wxBoxSizer *CreatePresetForPrinterDialog::create_selected_filament_preset_sizer(
m_selected_printer->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &e) {
wxString printer_name = m_selected_printer->GetStringSelection();
std::unordered_map<std::string, std::vector<std::shared_ptr<Preset>>>::iterator filament_iter = m_printer_compatible_filament_presets.find(into_u8(printer_name));
std::unordered_map<string, std::vector<std::shared_ptr<Preset>>>::iterator filament_iter = m_printer_compatible_filament_presets.find(into_u8(printer_name));
if (m_printer_compatible_filament_presets.end() != filament_iter) {
filament_choice_to_filament_preset.clear();
wxArrayString filament_choices;
+1 -1
View File
@@ -160,7 +160,7 @@ DevAms::~DevAms()
m_trays.clear();
}
static std::unordered_map<int, wxString> s_ams_display_formats = {
static unordered_map<int, wxString> s_ams_display_formats = {
{DevAms::AMS, "AMS-%d"},
{DevAms::AMS_LITE, "AMS Lite-%d"},
{DevAms::N3F, "AMS 2 PRO-%d"},
@@ -250,7 +250,7 @@ int DevNozzleMappingCtrl::CtrlGetAutoNozzleMappingV1(Slic3r::GUI::Plater* plater
void DevNozzleMappingCtrl::ParseAutoNozzleMapping(const json& print_jj)
{
if (print_jj.contains("command") && print_jj["command"].get<std::string>() == "get_auto_nozzle_mapping") {
if (print_jj.contains("command") && print_jj["command"].get<string>() == "get_auto_nozzle_mapping") {
if (print_jj.contains("sequence_id") && print_jj["sequence_id"] == m_sequence_id) {
Clear();
DevJsonValParser::ParseVal(print_jj, "result", m_result);
@@ -426,7 +426,7 @@ void DevNozzleSystem::ClearNozzles()
// ---- parsing ----------------------------------------------------------------------------------------
static std::unordered_map<std::string, NozzleFlowType> _str2_nozzle_flow_type = {
static unordered_map<string, NozzleFlowType> _str2_nozzle_flow_type = {
{"S", NozzleFlowType::S_FLOW},
{"H", NozzleFlowType::H_FLOW},
{"A", NozzleFlowType::S_FLOW},
@@ -436,7 +436,7 @@ static std::unordered_map<std::string, NozzleFlowType> _str2_nozzle_flow_type =
{"B", NozzleFlowType::E_FLOW}, // E3D High Flow -> nvtE3DHighFlow
};
static std::unordered_map<std::string, NozzleType> _str2_nozzle_type = {
static unordered_map<string, NozzleType> _str2_nozzle_type = {
{"00", NozzleType::ntStainlessSteel},
{"01", NozzleType::ntHardenedSteel},
{"05", NozzleType::ntTungstenCarbide}
+1 -1
View File
@@ -368,7 +368,7 @@ wxString DeviceErrorDialog::parse_error_level(int error_code)
}
}
static const std::unordered_set<std::string> s_jump_liveview_error_codes = { "0300-8003", "0300-8002", "0300-800A"};
static const std::unordered_set<string> s_jump_liveview_error_codes = { "0300-8003", "0300-8002", "0300-800A"};
wxString DeviceErrorDialog::show_error_code(int error_code)
{
if (m_error_code == error_code) { return wxEmptyString;}
+1 -2
View File
@@ -110,7 +110,6 @@ using json = nlohmann::json;
class wxWindow;
namespace fs = boost::filesystem;
using namespace std::chrono_literals;
#define CALI_DEBUG
#define MINUTE_30 1800000 //ms
@@ -3104,7 +3103,7 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_
DevFirmwareVersionInfo ver_info;
ver_info.name = (*it)["name"].get<std::string>();
if ((*it).contains("product_name"))
ver_info.product_name = wxString::FromUTF8((*it)["product_name"].get<std::string>());
ver_info.product_name = wxString::FromUTF8((*it)["product_name"].get<string>());
if ((*it).contains("sw_ver"))
ver_info.sw_ver = (*it)["sw_ver"].get<std::string>();
if ((*it).contains("sw_new_ver"))
+3 -3
View File
@@ -294,8 +294,8 @@ wxDataViewItem EditGCodeDialog::add_presets_placeholders()
// Orca: create subgroups from the pages of the tabs
auto init_from_tab = [this, full_config](wxDataViewItem parent, Tab* tab, const std::set<std::string>& preset_keys){
std::set extra_keys(preset_keys);
auto init_from_tab = [this, full_config](wxDataViewItem parent, Tab* tab, const set<string>& preset_keys){
set extra_keys(preset_keys);
for (const auto& page : tab->m_pages) {
// ORCA: Pull icons from tabs for subgroups, icons are hidden on tabs
std::string icon_name = "empty"; // use empty icon if not defined
@@ -549,7 +549,7 @@ void ParamsNode::RefreshSearch(const wxString& search_text)
if (GetEnabledChildren().empty())
if (auto pos = text.find(search_text); IsParamNode() && pos != wxString::npos) {
m_highlight_index = make_unique<std::pair<int, int>>(pos, search_text.Len());
m_highlight_index = make_unique<pair<int, int>>(pos, search_text.Len());
Enable();
} else {
Disable();
+4 -4
View File
@@ -702,11 +702,11 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
set_value(str, true);
}
} else if (m_opt.opt_key == "sparse_infill_rotate_template" || m_opt.opt_key == "solid_infill_rotate_template") {
std::string ustr(str.utf8_string());
string ustr(str.utf8_string());
if (!ConfigOptionFloats::validate_string(ustr)) {
std::string v;
string v;
std::smatch match;
std::string ps = (m_opt.opt_key == "sparse_infill_rotate_template") ?
string ps = (m_opt.opt_key == "sparse_infill_rotate_template") ?
u8"[BT][!]?|[#][\\d]+[!]?|[+\\-]?[\\d.]+[%]?[*]?[\\d]*[/NnZz$LlUuQq~^|#]?[+\\-]?[\\d.]*[%#\'\"cm]?[m]?[BT]?[!*]?" :
u8"[#][\\d]+[!]?|[+\\-]?[\\d.]+[%]?[*]?[\\d]*[/NnZz$LlUuQq~^|#]?[+\\-]?[\\d.]*[%#\'\"cm]?[m]?[!*]?";
@@ -729,7 +729,7 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
}
break;
} else if (m_opt.opt_key == "extra_solid_infills") {
std::string ustr(str.utf8_string());
string ustr(str.utf8_string());
// New rule: accept either interval form (N or N#K) or explicit list (e.g. 1,7,9), with optional quotes.
const std::regex rx_interval(u8R"(^\s*['"]?\s*\d+\s*(?:#\s*\d*)?\s*['"]?\s*$)");
// List entries may be plain numbers or number with optional #K count, e.g., 5, 9#2, 18
+1 -3
View File
@@ -94,8 +94,6 @@
#include "slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp"
#include "slic3r/GUI/PartPlate.hpp"
using namespace std::string_view_literals;
namespace Slic3r { class PrintBase; }
@@ -3186,7 +3184,7 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding)
float ams_item_height = 0;
float filament_group_item_align_width = 0;
{
float three_words_width = imgui.calc_text_size("ABC"sv).x;
float three_words_width = imgui.calc_text_size(std::string_view("ABC")).x;
const int line_capacity = 4;
for (const auto& extruder_filaments : {m_left_extruder_filament,m_right_extruder_filament })
-2
View File
@@ -177,8 +177,6 @@ extern wxPopupWindow* wxCurrentPopupWindow;
#endif
#endif
using namespace std::string_view_literals;
static constexpr const float TRACKBALLSIZE = 0.8f;
static Slic3r::ColorRGBA DEFAULT_BG_LIGHT_COLOR = { 0.906f, 0.906f, 0.906f, 1.0f };
+3 -3
View File
@@ -9040,7 +9040,7 @@ std::map<std::string, std::string> GUI_App::get_delete_cache_presets_lock()
void GUI_App::process_delete_presets()
{
std::map<std::string, std::string> delete_cache_presets = get_delete_cache_presets_lock();
std::map<string, string> delete_cache_presets = get_delete_cache_presets_lock();
for (auto it = delete_cache_presets.begin(); it != delete_cache_presets.end();) {
if (it->first.empty()) continue;
std::string del_setting_id = it->first;
@@ -10068,7 +10068,7 @@ bool is_soluble_filament(int extruder_id)
return support_option->get_at(0);
};
bool has_filaments(const std::vector<std::string>& model_filaments) {
bool has_filaments(const std::vector<string>& model_filaments) {
auto &filament_presets = Slic3r::GUI::wxGetApp().preset_bundle->filament_presets;
if (!Slic3r::GUI::wxGetApp().plater()) return false;
auto model_objects = Slic3r::GUI::wxGetApp().plater()->model().objects;
@@ -10103,7 +10103,7 @@ bool is_support_filament(int extruder_id, bool strict_check)
Slic3r::ConfigOptionBools *support_option = dynamic_cast<Slic3r::ConfigOptionBools *>(filament->config.option("filament_is_support"));
if(!strict_check &&(filament_type == "PETG" || filament_type == "PLA")) {
std::vector<std::string> model_filaments;
std::vector<string> model_filaments;
if (filament_type == "PETG")
model_filaments.emplace_back("PLA");
else {
+2 -2
View File
@@ -1108,7 +1108,7 @@ void ObjectList::update_name_column_width() const
}
}
GetColumn(colName)->SetWidth(std::max(0, client_size.x - (others_width)*em));
GetColumn(colName)->SetWidth(max(0, client_size.x - (others_width)*em));
}
void ObjectList::set_filament_column_hidden(const bool hide) const
@@ -3970,7 +3970,7 @@ wxDataViewItem ObjectList::add_settings_item(wxDataViewItem parent_item, const D
if (config->opt_float("layer_height") == object_cfg->opt_float("layer_height")) {
SettingsFactory::Bundle new_cat_options;
for (auto cat_opt : cat_options) {
std::vector<std::string> temp;
std::vector<string> temp;
for (auto value : cat_opt.second) {
if (value != "layer_height")
temp.push_back(value);
@@ -44,8 +44,6 @@
#define MAX_NUM 9999.99
#define MAX_SIZE std::string_view{"9999.99"}
using namespace std::string_view_literals;
namespace Slic3r
{
namespace GUI
+7 -7
View File
@@ -33,7 +33,7 @@ static const char* HMS_LOCAL_IMG_PATH = "hms/local_image";
// the local HMS info
// Orca: dev-id-type set trimmed to the devices Orca ships local HMS images for
static std::unordered_set<std::string> package_dev_id_types {"094", "239", "093", "22E"};
static unordered_set<string> package_dev_id_types {"094", "239", "093", "22E"};
// Orca: HMS should be disabled when stealth mode is on or networking is not installed
static bool should_disable_hms()
@@ -345,17 +345,17 @@ wxString HMSQuery::query_hms_msg(const std::string& dev_id, const std::string& l
return _query_hms_msg(dev_id.substr(0, 3), long_error_code, lang_code);
}
std::string HMSQuery::get_dev_id_type(const MachineObject* obj) const
string HMSQuery::get_dev_id_type(const MachineObject* obj) const
{
if (obj)
{
return obj->get_dev_id().substr(0, 3);
}
return std::string();
return string();
}
wxString HMSQuery::_query_hms_msg(const std::string& dev_id_type, const std::string& long_error_code, const std::string& lang_code)
wxString HMSQuery::_query_hms_msg(const string& dev_id_type, const string& long_error_code, const string& lang_code)
{
if (long_error_code.empty())
{
@@ -426,9 +426,9 @@ wxString HMSQuery::_query_hms_msg(const std::string& dev_id_type, const std::str
return wxEmptyString;
}
bool HMSQuery::_is_internal_error(const std::string &dev_id_type,
const std::string &error_code,
const std::string &lang_code)
bool HMSQuery::_is_internal_error(const string &dev_id_type,
const string &error_code,
const string &lang_code)
{
init_hms_info(dev_id_type);
auto iter = m_hms_info_jsons.find(dev_id_type);
+1 -1
View File
@@ -335,7 +335,7 @@ void PrintJob::process(Ctl &ctl)
auto origin_profile_id = model_info->metadata_items.find(BBL_DESIGNER_PROFILE_ID_TAG);
if (origin_profile_id != model_info->metadata_items.end()) {
try {
params.origin_profile_id = std::stoi(origin_profile_id->second.c_str());
params.origin_profile_id = stoi(origin_profile_id->second.c_str());
}
catch(...) {}
}
+5 -5
View File
@@ -536,12 +536,12 @@ void NotificationManager::PopNotification::count_lines()
return;
// handle with marks
if (pos_start == std::string::npos && pos_end == std::string::npos) {
if (pos_start == string::npos && pos_end == string::npos) {
pos_start = text.find(error_start);
if (pos_start != std::string::npos) {
if (pos_start != string::npos) {
text.erase(pos_start, error_start.length());
pos_end = text.find(error_end);
if (pos_end != std::string::npos) {
if (pos_end != string::npos) {
text.erase(pos_end, error_end.length());
}
}
@@ -675,7 +675,7 @@ void NotificationManager::PopNotification::bbl_render_block_notif_text(ImGuiWrap
if (m_text1.size() > m_endlines[i])
last_end += (m_text1[m_endlines[i]] == '\n' || m_text1[m_endlines[i]] == ' ' ? 1 : 0);
if (pos_start != std::string::npos && pos_end != std::string::npos && m_endlines[i] - line.length() >= pos_start && m_endlines[i] <= pos_end) {
if (pos_start != string::npos && pos_end != string::npos && m_endlines[i] - line.length() >= pos_start && m_endlines[i] <= pos_end) {
push_style_color(ImGuiCol_Text, m_ErrorColor, m_state == EState::FadingOut, m_current_fade_opacity);
imgui.text(line.c_str());
ImGui::PopStyleColor();
@@ -737,7 +737,7 @@ void NotificationManager::PopNotification::render_text(ImGuiWrapper& imgui, cons
if (m_text1.size() > m_endlines[i])
last_end += (m_text1[m_endlines[i]] == '\n' || m_text1[m_endlines[i]] == ' ' ? 1 : 0);
if (pos_start != std::string::npos && pos_end != std::string::npos&& m_endlines[i] - line.length() >= pos_start && m_endlines[i] <= pos_end) {
if (pos_start != string::npos && pos_end != string::npos&& m_endlines[i] - line.length() >= pos_start && m_endlines[i] <= pos_end) {
push_style_color(ImGuiCol_Text, m_ErrorColor, m_state == EState::FadingOut, m_current_fade_opacity);
imgui.text(line.c_str());
ImGui::PopStyleColor();
+4 -4
View File
@@ -86,7 +86,7 @@ PartSkipDialog::PartSkipDialog(wxWindow *parent) : DPIDialog(parent, wxID_ANY, _
{
std::time_t t = std::time(0);
std::stringstream buf;
buf << std::put_time(std::localtime(&t), "%a_%b_%d_%H_%M_%S/");
buf << put_time(std::localtime(&t), "%a_%b_%d_%H_%M_%S/");
m_timestamp = buf.str();
SetBackgroundColour(*wxWHITE);
@@ -402,7 +402,7 @@ std::string PartSkipDialog::create_tmp_path()
return tmp_path;
}
bool PartSkipDialog::is_local_file_existed(const std::vector<std::string> &local_paths)
bool PartSkipDialog::is_local_file_existed(const std::vector<string> &local_paths)
{
for (auto path : local_paths) {
if (!std::filesystem::exists(path)) { return false; }
@@ -703,8 +703,8 @@ void PartSkipDialog::InitDialogUI()
m_parts_state.clear();
m_parts_name.clear();
std::string pick_img = m_local_paths[0];
std::string slice_info = m_local_paths[2];
string pick_img = m_local_paths[0];
string slice_info = m_local_paths[2];
m_switch_drag_btn->SetIcon("canvas_drag");
m_switch_drag_btn->SetBackgroundColor(*wxWHITE);
+3 -3
View File
@@ -139,11 +139,11 @@ private:
boost::shared_ptr<PrinterFileSystem> m_file_sys;
std::string m_timestamp;
std::string m_tmp_path;
std::vector<std::string> m_local_paths;
std::vector<std::string> m_target_paths;
std::vector<string> m_local_paths;
std::vector<string> m_target_paths;
std::string create_tmp_path();
bool is_local_file_existed(const std::vector<std::string> &local_paths);
bool is_local_file_existed(const std::vector<string> &local_paths);
void DownloadPartsFile();
void OnFileSystemEvent(wxCommandEvent &event);
+4 -4
View File
@@ -357,7 +357,7 @@ wxDEFINE_EVENT(EVT_NOTICE_FULL_SCREEN_CHANGED, IntEvent);
#define PRINTER_PANEL_RADIUS (6) // ORCA
#define BTN_SYNC_SIZE (wxSize(FromDIP(96), FromDIP(98)))
static std::string get_diameter_string(float diameter)
static string get_diameter_string(float diameter)
{
std::ostringstream stream; // ORCA ensure 0.25 returned as 0.25. previous code returned as 0.2 because of std::setprecision(1)
stream << std::fixed << std::setprecision(2) << diameter; // Use 2 decimals to capture 0.25 / 0.15 reliably
@@ -6323,7 +6323,7 @@ void Sidebar::sync_ams_list(bool is_from_big_sync_btn)
}
// BBS:Record consumables information before synchronization
std::vector<std::string> color_before_sync;
std::vector<string> color_before_sync;
std::vector<bool> is_support_before;
DynamicPrintConfig& project_config = wxGetApp().preset_bundle->project_config;
ConfigOptionStrings* color_opt = project_config.option<ConfigOptionStrings>("filament_colour");
@@ -12762,7 +12762,7 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
Vec3d old_plate_pos = old_plate->get_center_origin();
// BBS: Save the model in the current platelist
std::vector<std::vector<int> > plate_object;
std::vector<vector<int> > plate_object;
for (size_t i = 0; i < old_plate_list.get_plate_count(); ++i) {
PartPlate* plate = old_plate_list.get_plate(i);
std::vector<int> obj_idxs;
@@ -17975,7 +17975,7 @@ bool Plater::load_files(const wxArrayString& filenames)
// Orca: Iters through given paths and imports files from zip then remove zip from paths
// returns true if zip files were found
auto handle_zips = [this](std::vector<fs::path>& paths) { // NOLINT(*-no-recursion) - Recursion is intended and should be managed properly
auto handle_zips = [this](vector<fs::path>& paths) { // NOLINT(*-no-recursion) - Recursion is intended and should be managed properly
bool res = false;
for (auto it = paths.begin(); it != paths.end();) {
if (boost::algorithm::iends_with(it->string(), ".zip")) {
+2 -2
View File
@@ -378,7 +378,7 @@ wxBoxSizer *PreferencesDialog::create_item_combobox(wxString title, wxString too
auto current_setting = app_config->get(param);
if (!current_setting.empty()) {
auto compare = [current_setting](std::string possible_setting) { return current_setting == possible_setting; };
auto compare = [current_setting](string possible_setting) { return current_setting == possible_setting; };
auto iterator = find_if(config_name_index.begin(), config_name_index.end(), compare);
if (iterator != config_name_index.end())
current_index = static_cast<unsigned int>(iterator - config_name_index.begin());
@@ -1714,7 +1714,7 @@ void PreferencesDialog::create_items()
g_sizer->Add(create_item_title(_L("Project")), 1, wxEXPAND);
std::vector<wxString> projectLoadSettingsBehaviourOptions = {_L("Load All"), _L("Ask When Relevant"), _L("Always Ask"), _L("Load Geometry Only")};
std::vector<std::string> projectLoadSettingsConfigOptions = { OPTION_PROJECT_LOAD_BEHAVIOUR_LOAD_ALL, OPTION_PROJECT_LOAD_BEHAVIOUR_ASK_WHEN_RELEVANT, OPTION_PROJECT_LOAD_BEHAVIOUR_ALWAYS_ASK, OPTION_PROJECT_LOAD_BEHAVIOUR_LOAD_GEOMETRY };
std::vector<string> projectLoadSettingsConfigOptions = { OPTION_PROJECT_LOAD_BEHAVIOUR_LOAD_ALL, OPTION_PROJECT_LOAD_BEHAVIOUR_ASK_WHEN_RELEVANT, OPTION_PROJECT_LOAD_BEHAVIOUR_ALWAYS_ASK, OPTION_PROJECT_LOAD_BEHAVIOUR_LOAD_GEOMETRY };
auto item_project_load = create_item_combobox(_L("Load behavior"), _L("Should printer/filament/process settings be loaded when opening a 3MF file?"), SETTING_PROJECT_LOAD_BEHAVIOUR, projectLoadSettingsBehaviourOptions, projectLoadSettingsConfigOptions);
g_sizer->Add(item_project_load);
+1 -1
View File
@@ -239,7 +239,7 @@ void ProjectPanel::on_reload(wxCommandEvent& evt)
}
bool has_content = false;
for (const std::string& v : {
for (const string& v : {
update_type,
license,
model_name,
+25 -58
View File
@@ -14,7 +14,6 @@
#include "Widgets/DialogButtons.hpp"
#include "Widgets/StaticLine.hpp"
#include "Widgets/StateColor.hpp"
#include "Widgets/SwitchButton.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/Preset.hpp"
@@ -865,25 +864,34 @@ void PublishSettingsDialog::build_option_model()
};
// --- Phase 1: printer per-extruder retraction settings (first, mirroring the sidebar's
// Printer group), from the printer tab's "Extruder" page. One inner tab per extruder (named
// as on the printer tab's switch, e.g. "Left Extruder"/"Right Extruder" via
// Tab::translate_category), each holding that extruder's Retraction and Z-Hop rows with
// per-extruder "#N" values.
// Printer group), from the printer tab's "Extruder"/"Extruder N" pages. One inner tab per
// extruder (e.g. "Left Extruder"/"Right Extruder" via Tab::translate_category), each holding
// that extruder's Retraction and Z-Hop rows with per-extruder "#N" values.
{
size_t g = section_group_for(Section::Printer);
std::set<std::string> printer_added;
for (Tab* tab : wxGetApp().tabs_list) {
// The page's controls edit the extruder chosen on the printer tab's switch, so its
// option list is read once per extruder.
auto* printer_tab = dynamic_cast<TabPrinter*>(tab);
const Page* page = printer_tab ? printer_tab->extruder_page() : nullptr;
if (page == nullptr)
if (tab->m_type != Preset::TYPE_PRINTER)
continue;
const size_t extruders_count = printer_tab->m_extruders_count;
for (size_t extruder_idx = 0; extruder_idx < extruders_count; ++extruder_idx) {
const wxString page_title = Tab::translate_category(extruders_count > 1 ? wxString::Format("Extruder %d", int(extruder_idx + 1)) : wxString("Extruder"), tab->m_type);
// Retraction and Z-Hop values are stored per variant column, not per extruder.
const int variant_index = printer_tab->extruder_variant_index(int(extruder_idx));
for (const PageShp& page : tab->m_pages) {
if (!page->title().StartsWith("Extruder"))
continue;
// The extruder index of this page: its options are appended with the same
// "#N" opt_index (opt.second.second), so derive the tab's index from the first
// allowlisted option; skip the page when none is found (defensive).
int extruder_idx = -1;
for (const ConfigOptionsGroupShp& optgroup : page->m_optgroups) {
if (optgroup->title != "Retraction" && optgroup->title != "Z-Hop")
continue;
for (const auto& opt : optgroup->opt_map())
if (extruder_idx < 0)
extruder_idx = opt.second.second;
if (extruder_idx >= 0)
break;
}
if (extruder_idx < 0)
continue;
const wxString page_title = Tab::translate_category(page->title(), tab->m_type);
for (const ConfigOptionsGroupShp& optgroup : page->m_optgroups) {
// Allowlist on the untranslated optgroup title; the "Retraction when
// switching material" group is intentionally skipped.
@@ -891,17 +899,17 @@ void PublishSettingsDialog::build_option_model()
continue;
const wxString subcategory = _(optgroup->title);
for (const auto& opt : optgroup->opt_map()) {
const std::string& opt_id = opt.first;
const std::string& pure_key = opt.second.first;
// Rows are keyed by the full per-extruder "#N" opt_id so each extruder
// tab publishes its own value; GetPublishedKeys() emits the checked rows
// as-is.
const std::string opt_id = pure_key + "#" + std::to_string(variant_index);
if (!printer_added.insert(opt_id).second)
continue;
wxString label, value, unit;
if (!option_text(opt_id, pure_key, label, value, unit))
continue;
size_t cat_index = category_index_for(page_title, Section::Printer, g, extruder_idx);
size_t cat_index = category_index_for(page_title, Section::Printer, g, size_t(extruder_idx));
size_t sub_index = subcategory_index_for(cat_index, subcategory, optgroup->icon);
add_row_ui(opt_id, label, value, unit, cat_index, sub_index);
}
@@ -1090,10 +1098,6 @@ void PublishSettingsDialog::build_option_model()
for (SectionGroup& section : m_sections)
if (!section.categories.empty())
section.tabs->SelectItem(0);
// Orca: the Printer section shows its extruders on the same switch as the printer tab's Extruder page.
for (size_t s = 0; s < m_sections.size(); ++s)
if (m_sections[s].kind == Section::Printer && m_sections[s].categories.size() > 1)
setup_variant_switch(s);
if (!m_sections.empty()) {
m_outer_tabs->SelectItem(0);
show_outer_page(0);
@@ -1626,8 +1630,6 @@ void PublishSettingsDialog::show_inner_page(size_t section_index, int inner_inde
section.selected_mixed = -1;
}
section.selected_inner = inner_index;
if (section.variant_switch != nullptr)
section.variant_switch->SetSelection(inner_index); // fires its event, which ignores the shown page
Category& category = m_categories[section.categories[inner_index]];
category.page->Show();
category.scroll->FitInside();
@@ -1637,32 +1639,6 @@ void PublishSettingsDialog::show_inner_page(size_t section_index, int inner_inde
section.page_host_sizer->Layout();
}
void PublishSettingsDialog::setup_variant_switch(size_t section_index)
{
SectionGroup& section = m_sections[section_index];
std::vector<wxString> titles;
for (size_t category : section.categories)
titles.push_back(m_categories[category].title);
section.variant_switch = new MultiSwitchButton(section.page);
section.variant_switch->SetFitToOptions();
section.variant_switch->SetOptions(titles);
section.variant_switch->SetSelection(section.selected_inner);
section.variant_switch->Bind(wxCUSTOMEVT_MULTISWITCH_SELECTION, [this, section_index](wxCommandEvent& evt) {
evt.Skip();
// The hidden tab strip stays the selection model; its event shows the page.
SectionGroup& sec = m_sections[section_index];
if (evt.GetInt() != sec.selected_inner)
sec.tabs->SelectItem(evt.GetInt());
});
// The switch takes the place of the tab strip, centered like on the printer tab.
wxSizer* page_sizer = section.page->GetSizer();
page_sizer->Insert(1, section.variant_switch, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, FromDIP(4));
section.tabs->Hide();
section.page->Layout();
}
void PublishSettingsDialog::show_mixed_page(size_t section_index, int mixed_index)
{
if (section_index >= m_sections.size())
@@ -2208,13 +2184,6 @@ void PublishSettingsDialog::refresh_tab_indicators()
for (size_t i = 0; i < section.categories.size(); ++i) {
const bool on = category_has_selection(m_categories[section.categories[i]]);
section.tabs->SetItemIndicator(static_cast<unsigned int>(i), on);
// The switch has no indicator dot; mark its option text instead.
if (section.variant_switch != nullptr) {
const wxString& title = m_categories[section.categories[i]].title;
const wxString text = on ? title + wxString(" ") + wxString(wxUniChar(0x2022)) : title;
if (section.variant_switch->GetOptionText(static_cast<unsigned int>(i)) != text)
section.variant_switch->SetOptionText(static_cast<unsigned int>(i), text);
}
any = any || on;
}
if (section.mixed_tabs != nullptr)
@@ -2279,8 +2248,6 @@ void PublishSettingsDialog::on_dpi_changed(const wxRect& suggested_rect)
section.tabs->Rescale();
if (section.mixed_tabs != nullptr)
section.mixed_tabs->Rescale();
if (section.variant_switch != nullptr)
section.variant_switch->Rescale();
}
// Refresh the per-row Color chips at the new DPI (they carry the slot number too).
-7
View File
@@ -37,7 +37,6 @@ namespace Slic3r { class DynamicPrintConfig; }
class TextInput;
class StaticLine;
class CheckBox;
class MultiSwitchButton;
namespace Slic3r { namespace GUI {
@@ -196,10 +195,6 @@ private:
ScalableBitmap icon_bmp; // tab icon next to the title; rescaled on DPI change
wxPanel* page{nullptr};
TabCtrl* tabs{nullptr};
// Printer section with several extruders: the extruder switch shown instead of `tabs`, the
// same MultiSwitchButton (and option names) as the printer tab's Extruder page. One option
// per entry of `categories`, named by its title; `tabs` stays as the hidden selection model.
MultiSwitchButton* variant_switch{nullptr};
// Second tab strip, below the main one, listing only the mixed-color filament slots.
// Present on the Material section only (null elsewhere).
TabCtrl* mixed_tabs{nullptr};
@@ -282,8 +277,6 @@ private:
bool row_is_visible(const Row& row) const;
void apply_visibility();
void bind_tab_events();
// Replaces a section's inner tab strip with a variant switch (see SectionGroup::variant_switch).
void setup_variant_switch(size_t section_index);
TabCtrl* m_outer_tabs{nullptr};
wxPanel* m_outer_host{nullptr};
+4 -4
View File
@@ -182,7 +182,7 @@ std::string get_nozzle_volume_type_cloud_string(NozzleVolumeType nozzle_volume_t
static int s_nozzle_mapping_last_request_time = 0;
std::vector<wxString> SelectMachineDialog::MACHINE_BED_TYPE_STRING;
std::vector<std::string> SelectMachineDialog::MachineBedTypeString;
std::vector<string> SelectMachineDialog::MachineBedTypeString;
void SelectMachineDialog::init_machine_bed_types()
{
if (MACHINE_BED_TYPE_STRING.size() == 0) {
@@ -2748,8 +2748,8 @@ void SelectMachineDialog::on_ok_btn(wxCommandEvent &event)
std::vector<ConfirmBeforeSendInfo> confirm_text;
// check more than one using in same external spool
std::unordered_set<std::string> main_external_spool_filas;
std::unordered_set<std::string> deputy_external_spool_filas;
std::unordered_set<string> main_external_spool_filas;
std::unordered_set<string> deputy_external_spool_filas;
for (const auto& mapping_info : m_ams_mapping_result) {
if (mapping_info.ams_id == VIRTUAL_AMS_MAIN_ID_STR){
main_external_spool_filas.insert(mapping_info.filament_id);
@@ -5239,7 +5239,7 @@ void SelectMachineDialog::update_show_status(MachineObject* obj_)
/*Check high temperture slicing*/
if (m_print_type == PrintFromType::FROM_NORMAL) {
std::set<std::string> high_temp_filaments;
std::set<string> high_temp_filaments;
std::unordered_set<int> known_fila_soften_extruders;
std::unordered_set<int> unknown_fila_soften_extruders;
auto preset_full_config = wxGetApp().preset_bundle->full_config();
+1 -1
View File
@@ -337,7 +337,7 @@ private:
wxColour m_colour_bold_color{wxColour(38, 46, 48)};
StateColor m_btn_bg_enable;
std::unordered_map<std::string, PrintOption*> m_checkbox_list;
std::unordered_map<string, PrintOption*> m_checkbox_list;
std::list<PrintOption*> m_checkbox_list_order;
std::shared_ptr<int> m_token = std::make_shared<int>(0);
+1 -1
View File
@@ -126,7 +126,7 @@ void SendToPrinterDialog::stripWhiteSpace(std::string& str)
{
if (str == "") { return; }
std::string::iterator cur_it;
string::iterator cur_it;
cur_it = str.begin();
while (cur_it != str.end()) {
+2 -2
View File
@@ -171,7 +171,7 @@ public:
std::string current_nozzle_loc = "";
wxColour m_colour;
std::string m_file_name;
string m_file_name;
bool m_ams_loading{false};
void doRender(wxDC &dc);
ExtruderImage(wxWindow *parent, wxWindowID id, int nozzle_num, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);
@@ -244,7 +244,7 @@ protected:
{
wxString local_image_url; //local image path
std::string img_url_paths; // oss url path
std::vector<wxPanel *> image_broad;
vector<wxPanel *> image_broad;
bool is_selected;
bool is_uploaded; // load
wxBoxSizer * image_tb_broad = nullptr;
+2 -2
View File
@@ -1576,7 +1576,7 @@ bool SyncAmsInfoDialog::is_nozzle_type_match(DevExtderSystem data, wxString &err
}
}
std::vector<int> map_extruders = {1, 0};
vector<int> map_extruders = {1, 0};
// The default two extruders are left, right, but the order of the extruders on the machine is right, left.
std::vector<std::string> flow_type_of_machine;
@@ -1676,7 +1676,7 @@ void SyncAmsInfoDialog::stripWhiteSpace(std::string &str)
{
if (str == "") { return; }
std::string::iterator cur_it;
string::iterator cur_it;
cur_it = str.begin();
while (cur_it != str.end()) {
+105 -242
View File
@@ -811,12 +811,6 @@ wxString Tab::translate_category(const wxString& title, Preset::Type preset_type
}
return _("Extruder") + title.SubString(8, title.Last());
}
// Orca: one "Extruder" page serves all extruders; name it "Extruders" when there are several.
if (preset_type == Preset::TYPE_PRINTER && title == "Extruder") {
auto preset = wxGetApp().preset_bundle;
if (preset && preset->get_printer_extruder_count() > 1)
return _("Extruders");
}
return _(title);
}
@@ -1159,38 +1153,6 @@ std::string Tab::options_list_storage_key(const std::string& opt_key) const
return (serialized || is_plugin_field) ? opt_key : opt_key + "#0";
}
// Orca: deep_diff() flags every vector entry at or past the reference vector's length as changed,
// whatever its value (e.g. the values of an extruder added by raising the extruder count). A vector
// grows by copying its first entry (ConfigOptionVector::resize), so such an entry only counts as
// changed when it differs from the reference's first entry, as before Orca's deep_diff() change.
// The change of the count itself shows on "extruders_count".
static void drop_unchanged_added_entries(std::vector<std::string> &options, const DynamicPrintConfig &current, const Preset *reference)
{
if (reference == nullptr)
return;
// deep_diff() lists a key's entries one after another, so serialize each key's vectors once.
std::string serialized_key;
std::vector<std::string> cur_values;
std::string ref_first;
options.erase(std::remove_if(options.begin(), options.end(), [&](const std::string &opt) {
const auto pos = opt.find('#');
if (pos == std::string::npos)
return false;
const std::string key = opt.substr(0, pos);
const size_t idx = size_t(std::atoi(opt.c_str() + pos + 1));
auto ref = dynamic_cast<const ConfigOptionVectorBase *>(reference->config.option(key));
auto cur = dynamic_cast<const ConfigOptionVectorBase *>(current.option(key));
if (ref == nullptr || cur == nullptr || idx < ref->size() || ref->size() == 0 || idx >= cur->size())
return false;
if (key != serialized_key) {
serialized_key = key;
cur_values = cur->vserialize();
ref_first = ref->vserialize().front();
}
return cur_values[idx] == ref_first;
}), options.end());
}
void Tab::update_all_extruder_options_status()
{
if (!m_extruder_switch && !m_variant_combo) {
@@ -1221,8 +1183,6 @@ void Tab::update_all_extruder_options_status()
auto dirty_options = m_presets->current_dirty_options(true);
auto nonsys_options = m_presets->current_different_from_parent_options(true);
if (m_type == Preset::TYPE_PRINTER)
update_custom_dirty(dirty_options, nonsys_options);
auto filter_extruder_options = [](const std::vector<std::string>& options) {
std::vector<std::string> filtered_options;
for (const auto& opt : options) {
@@ -1271,7 +1231,7 @@ void Tab::update_extruder_switch_colors()
if (m_active_page) {
if (m_active_page->title() == "Speed" || m_active_page->title() == "Motion ability" || m_active_page->title() == "Filament" ||
m_active_page->title() == "Setting Overrides" || m_active_page->title() == "Multimaterial" || is_printer_extruder_page(m_active_page)) {
m_active_page->title() == "Setting Overrides" || m_active_page->title() == "Multimaterial") {
for (auto page_ptr : m_pages) {
if (page_ptr.get() == m_active_page) {
pages_to_check.push_back(page_ptr);
@@ -1302,8 +1262,8 @@ void Tab::update_extruder_switch_colors()
void Tab::check_extruder_options_status(int index, bool &sys_extruder, bool &modified_extruder, const std::vector<PageShp>& pages_to_check)
{
int config_index = index;
int extruder_id = index;
if (m_type == Preset::TYPE_PRINT || m_type == Preset::TYPE_PRINTER || m_type == Preset::TYPE_MODEL) {
int extruder_id;
NozzleVolumeType nozzle_type;
parse_extruder_selection(index, extruder_id, nozzle_type);
@@ -1336,10 +1296,6 @@ void Tab::check_extruder_options_status(int index, bool &sys_extruder, bool &mod
}
std::string target_opt_key = base_opt_key + "#" + std::to_string(config_index * stride);
// Orca: on the printer's Extruder page only per-variant options use the variant column,
// the others (nozzle_diameter, extruder_offset, ...) are indexed by the extruder.
if (is_printer_extruder_page(page.get()) && printer_options_with_variant_1.count(base_opt_key) == 0)
target_opt_key = base_opt_key + "#" + std::to_string(extruder_id);
auto status_iter = m_all_extruder_options_status.find(target_opt_key);
if (status_iter != m_all_extruder_options_status.end()) {
@@ -1380,6 +1336,18 @@ void TabPrinter::init_options_list()
Tab::init_options_list();
if (m_printer_technology == ptFFF)
m_options_list.emplace("extruders_count", m_opt_status_value);
for (size_t i = 1; i < m_extruders_count; ++i) {
wxString target_title = wxString::Format("Extruder %d", int(i + 1));
for (auto &page : m_pages) {
if (page->title() == target_title) {
for (auto group : page->m_optgroups) {
for (auto &opt : group->opt_map())
m_options_list.emplace(opt.first, m_opt_status_value);
}
break;
}
}
}
}
void TabPrinter::msw_rescale()
@@ -1469,7 +1437,7 @@ void Tab::update_changed_tree_ui()
get_sys_and_mod_flags("compatible_printers", sys_page, modified_page);
}
}
if (page->title() == "Speed" || page->title() == "Motion ability" || page->title() == "Filament" || page->title() == "Setting Overrides" || page->title() == "Multimaterial" || is_printer_extruder_page(page.get())) {
if (page->title() == "Speed" || page->title() == "Motion ability" || page->title() == "Filament" || page->title() == "Setting Overrides" || page->title() == "Multimaterial") {
auto options = generate_extruder_options();
for (size_t switch_index = 0; switch_index < options.size(); ++switch_index) {
std::vector<PageShp> pages_to_check = { page };
@@ -1572,10 +1540,6 @@ void Tab::on_roll_back_value(const bool to_sys /*= true*/)
m_postpone_update_ui = false;
// Orca: the restored config may have another extruder count than the tab shows.
if (auto printer_tab = dynamic_cast<TabPrinter *>(this))
printer_tab->sync_extruders_count();
// When all values are rolled, then we have to update whole tab in respect to the reverted values
update();
if (m_active_page)
@@ -1913,17 +1877,6 @@ static wxString pad_combo_value_for_config(const DynamicPrintConfig &config)
return config.opt_bool("pad_enable") ? (config.opt_bool("pad_around_object") ? _("Around object") : _("Below object")) : _("None");
}
// Rebuilds the variant switch of every tab that has one, e.g. after the extruder count or a nozzle volume type changed.
static void update_all_extruder_variants(int extruder_idx = -1)
{
for (auto tab : wxGetApp().tabs_list)
tab->update_extruder_variants(extruder_idx);
if (auto tab = wxGetApp().plate_tab)
tab->update_extruder_variants(extruder_idx);
for (auto tab : wxGetApp().model_tabs_list)
tab->update_extruder_variants(extruder_idx);
}
void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
{
// Orca:
@@ -2304,7 +2257,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
wxGetApp().plater()->update();
}
std::string opt_key_without_idx = opt_key.substr(0, opt_key.find('#'));
string opt_key_without_idx = opt_key.substr(0, opt_key.find('#'));
if (opt_key_without_idx == "long_retractions_when_cut") {
unsigned char activate = boost::any_cast<unsigned char>(value);
@@ -2366,7 +2319,15 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
if (opt_key.find("nozzle_volume_type") != std::string::npos) {
int extruder_idx = std::atoi(opt_key.substr(opt_key.find_last_of('#') + 1).c_str());
update_all_extruder_variants(extruder_idx);
for (auto tab : wxGetApp().tabs_list) {
tab->update_extruder_variants(extruder_idx);
}
if (auto tab = wxGetApp().plate_tab) {
tab->update_extruder_variants(extruder_idx);
}
for (auto tab : wxGetApp().model_tabs_list) {
tab->update_extruder_variants(extruder_idx);
}
if (wxGetApp().app_config->get("auto_calculate_flush") == "all") {
wxGetApp().plater()->sidebar().auto_calc_flushing_volumes(-1,extruder_idx);
}
@@ -5724,13 +5685,9 @@ if (is_marlin_flavor)
size_t extruders_count = size_t(boost::any_cast<int>(v));
wxTheApp->CallAfter([this, opt_key, value, extruders_count]() {
if (opt_key == "extruders_count" || opt_key == "single_extruder_multi_material") {
const size_t old_extruders_count = m_extruders_count;
extruders_count_changed(extruders_count);
init_options_list(); // m_options_list should be updated before UI updating
update_dirty();
// Orca: the variant switches (here, Process in the sidebar, ...) list one option per extruder.
if (m_extruders_count != old_extruders_count)
update_all_extruder_variants();
if (opt_key == "single_extruder_multi_material") { // the single_extruder_multimaterial was added to force pages
on_value_change(opt_key, value); // rebuild - let's make sure the on_value_change is not skipped
@@ -5740,7 +5697,6 @@ if (is_marlin_flavor)
// Orca: we use a different logic here. If SEMM is enabled, we set extruder count to 1.
#if 1
extruders_count_changed(1);
update_all_extruder_variants();
#else
std::vector<double> nozzle_diameters =
@@ -5812,13 +5768,14 @@ if (is_marlin_flavor)
m_pages.insert(m_pages.end() - n_after_single_extruder_MM, page);
}
// Orca: a single "Extruder" page serves all extruders. Its controls are created once for extruder 0;
// switch_excluder() re-targets them to the extruder selected on the variant switch (m_extruder_switch),
// which the printer tab shows on this page too.
if (extruder_page() == nullptr && m_extruders_count > 0) {
const size_t extruder_idx = 0;
auto page = add_options_page(L("Extruder"), "custom-gcode_extruder", true); // ORCA: icon only visible on placeholders
m_pages.insert(m_pages.begin() + n_before_extruders, page);
// Orca: build missed extruder pages
for (auto extruder_idx = m_extruders_count_old; extruder_idx < m_extruders_count; ++extruder_idx) {
const wxString& page_name = (m_extruders_count > 1) ? wxString::Format("Extruder %d", int(extruder_idx + 1)) : wxString::Format("Extruder");
//# build page
//const wxString& page_name = wxString::Format("Extruder %d", int(extruder_idx + 1));
auto page = add_options_page(page_name, "custom-gcode_extruder", true); // ORCA: icon only visible on placeholders
m_pages.insert(m_pages.begin() + n_before_extruders + extruder_idx, page);
auto optgroup = page->new_optgroup(L("Basic information"), L"param_information", -1, true);
optgroup->append_single_option_line("nozzle_diameter", "printer_extruder_basic_information#nozzle-diameter", extruder_idx);
@@ -5831,10 +5788,8 @@ if (is_marlin_flavor)
option.opt.full_width = true;
optgroup->append_single_option_line(option, "printer_extruder_basic_information#extruder-offset-position");
optgroup->m_on_change = [this](const t_config_option_key& opt_key, boost::any value)
optgroup->m_on_change = [this, extruder_idx](const t_config_option_key& opt_key, boost::any value)
{
// The page edits the extruder selected on the variant switch.
const size_t extruder_idx = size_t(get_current_active_extruder());
bool is_SEMM = m_config->opt_bool("single_extruder_multi_material");
if (is_SEMM && m_extruders_count > 1 && boost::starts_with(opt_key, "nozzle_diameter"))
{
@@ -5929,22 +5884,22 @@ if (is_marlin_flavor)
//optgroup->append_line(line);
#endif
}
// The page holds only the "#0" controls, so register every extruder's options with the search
// index under "Extruder N"; a search hit selects that extruder (TabPrinter::activate_option()).
if (Page *page = extruder_page()) {
auto &index = wxGetApp().sidebar().settings_index();
for (auto &group : page->m_optgroups) {
group->set_config_category_and_type(page->title(), m_type);
for (auto &opt : group->opt_map()) {
if (opt.second.second < 0)
continue;
for (size_t i = 0; i < m_extruders_count; ++i) {
const wxString category = m_extruders_count > 1 ? wxString::Format("Extruder %d", int(i + 1)) : wxString("Extruder");
index.add_key(opt.second.first + "#" + std::to_string(i), m_type, group->title, category, group->icon);
}
}
}
// BBS. No extra extruder page for single physical extruder machine
// # remove extra pages
auto &first_extruder_title = const_cast<wxString &>(m_pages[n_before_extruders]->title());
if (m_extruders_count < m_extruders_count_old) {
m_pages.erase( m_pages.begin() + n_before_extruders + m_extruders_count,
m_pages.begin() + n_before_extruders + m_extruders_count_old);
if (m_extruders_count == 1)
first_extruder_title = wxString::Format("Extruder");
} else if (m_extruders_count_old == 1) {
first_extruder_title = wxString::Format("Extruder %d", 1);
}
auto & index = wxGetApp().sidebar().settings_index();
for (auto &group : m_pages[n_before_extruders]->m_optgroups) {
group->set_config_category_and_type(first_extruder_title, m_type);
for (auto &opt : group->opt_map())
index.add_key(opt.first + "#0", m_type, group->title, first_extruder_title, group->icon);
}
Thaw();
@@ -6225,6 +6180,12 @@ void TabPrinter::toggle_options()
return;
auto nozzle_volumes = m_preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
auto extruders = m_config->option<ConfigOptionEnumsGeneric>("extruder_type");
auto get_index_for_extruder =
[this, &extruders](int extruder_id, int stride = 1) {
return m_config->get_index_for_extruder(extruder_id + 1, "printer_extruder_id",
ExtruderType(extruders->values[extruder_id]), get_actual_nozzle_volume_type(extruder_id), "printer_extruder_variant", stride);
};
//BBS: whether the preset is Bambu Lab printer
bool is_BBL_printer = false;
@@ -6299,13 +6260,14 @@ void TabPrinter::toggle_options()
toggle_option("tool_change_on_wipe_tower", !bSEMM && supports_wipe_tower_2 && extruders_count > 1);
toggle_option("wait_for_temp_on_wipe_tower", !bSEMM && supports_wipe_tower_2 && extruders_count > 1);
}
if (m_active_page->title() == L("Extruder") && m_extruders_count > 0)
wxString extruder_number;
long val = 1;
if ( m_active_page->title().IsSameAs(L("Extruder")) ||
(m_active_page->title().StartsWith("Extruder ", &extruder_number) && extruder_number.ToLong(&val) &&
val > 0 && (size_t)val <= m_extruders_count))
{
// Orca: the single Extruder page edits the extruder selected on the variant switch; its
// controls carry field index 0 (i), the values are read for `extruder`.
const size_t i = 0;
const size_t extruder = std::min<size_t>(size_t(get_current_active_extruder()), m_extruders_count - 1);
const int variant_index = extruder_variant_index(int(extruder));
size_t i = size_t(val - 1);
int variant_index = get_index_for_extruder(i);
bool have_retract_length = m_config->opt_float("retraction_length", variant_index) > 0;
toggle_option("extruder_printable_area", false, i); // disable
@@ -6332,7 +6294,7 @@ void TabPrinter::toggle_options()
vec.resize(0);
vec = {"retract_lift_above", "retract_lift_below", "retract_lift_enforce"};
for (auto el : vec)
toggle_option(el, retraction && (m_config->opt_float("z_hop", variant_index) > 0), i);
toggle_option(el, retraction && (m_config->opt_float("z_hop", i) > 0), i);
// some options only apply when not using firmware retraction
vec.resize(0);
@@ -6385,7 +6347,7 @@ void TabPrinter::toggle_options()
toggle_option("long_retractions_when_cut", !use_firmware_retraction && m_config->opt_int("enable_long_retraction_when_cut"), i);
toggle_line("retraction_distances_when_cut", m_config->opt_bool("long_retractions_when_cut", variant_index), i);
toggle_option("travel_slope", m_config->opt_enum("z_hop_types", variant_index) != ZHopType::zhtNormal, i);
toggle_option("travel_slope", m_config->opt_enum("z_hop_types", i) != ZHopType::zhtNormal, i);
}
if (m_active_page->title() == L("Motion ability")) {
@@ -6459,16 +6421,12 @@ void TabPrinter::on_value_change(const std::string& opt_key, const boost::any& v
return;
const int pos = opt_key.find("#");
// Orca: fields of the single Extruder page keep index 0 but edit the selected extruder.
const int data_idx = pos > 0 ? extruder_page_data_index(opt_key) : -1;
if (pos > 0) {
std::string temp_str = opt_key;
boost::erase_head(temp_str, pos + 1);
int orig_opt_idx = static_cast<size_t>(atoi(temp_str.c_str()));
int opt_idx = orig_opt_idx >= 0 ? orig_opt_idx : 0;
if (data_idx >= 0)
opt_idx = data_idx;
std::string opt_key_pure = opt_key;
boost::erase_tail(opt_key_pure, opt_key_pure.size() - pos);
@@ -6503,12 +6461,7 @@ void TabPrinter::on_value_change(const std::string& opt_key, const boost::any& v
}
}
// Orca: report Extruder page changes as "key#<extruder>", as the former "Extruder N" pages did,
// so per-extruder handling in Tab::on_value_change() sees the extruder that was edited.
if (data_idx >= 0)
Tab::on_value_change(opt_key.substr(0, pos) + "#" + std::to_string(get_current_active_extruder()), value);
else
Tab::on_value_change(opt_key, value);
Tab::on_value_change(opt_key, value);
}
void TabPrinter::update()
@@ -7440,7 +7393,12 @@ bool Tab::tree_sel_change_delayed(wxCommandEvent& event)
// update_undo_buttons();
this->OnActivate();
m_parent->set_active_tab(this);
update_variant_sizer_visibility();
if (m_variant_sizer) {
wxWindow *variant_ctrl = m_extruder_switch ? (wxWindow *) m_extruder_switch : m_variant_combo;
m_main_sizer->Show(m_variant_sizer, variant_ctrl->IsThisEnabled() && !m_active_page->m_opt_id_map.empty() && !m_active_page->title().StartsWith("Extruder "));
if (m_extruder_sync) m_extruder_sync->Show(variant_ctrl->IsShown());
GetParent()->Layout();
}
m_page_view->Thaw();
return false;
@@ -7451,7 +7409,12 @@ bool Tab::tree_sel_change_delayed(wxCommandEvent& event)
return false;
m_active_page = page;
update_variant_sizer_visibility();
if (m_variant_sizer) {
wxWindow *variant_ctrl = m_extruder_switch ? (wxWindow *) m_extruder_switch : m_variant_combo;
m_main_sizer->Show(m_variant_sizer, variant_ctrl->IsThisEnabled() && !m_active_page->m_opt_id_map.empty() && !m_active_page->title().StartsWith("Extruder"));
if (m_extruder_sync) m_extruder_sync->Show(variant_ctrl->IsShown());
GetParent()->Layout();
}
auto throw_if_canceled = std::function<void()>([this](){
#ifdef WIN32
@@ -8277,11 +8240,9 @@ void Tab::update_extruder_variants(int extruder_id, bool reload)
m_actual_nozzle_volumes.resize(extruder_nums, NozzleVolumeType::nvtStandard);
for (int i = 0; i < extruder_nums; i++) m_actual_nozzle_volumes[i] = (NozzleVolumeType)nozzle_volumes->values[i];
// Orca: when every extruder uses the same variant (e.g. a non-Bambu dual-nozzle printer), the
// switch has no nozzle variants to select and nothing to sync. The printer tab still enables it
// to choose the extruder its Extruder and Motion ability pages edit.
m_extruder_switch_variants = extruder_nums >= 2 && m_preset_bundle->support_different_extruders();
if (m_extruder_switch_variants || (m_type == Preset::TYPE_PRINTER && extruder_nums >= 2)) {
// Orca: a non-Bambu dual-nozzle printer has two extruders but a single variant column, so
// the nozzle switch and sync button have nothing to act on. Only enable with real variants.
if (extruder_nums >= 2 && m_preset_bundle->support_different_extruders()) {
auto options = generate_extruder_options();
m_extruder_switch->SetOptions(options);
@@ -8320,8 +8281,12 @@ void Tab::update_extruder_variants(int extruder_id, bool reload)
if (m_type == Preset::TYPE_PRINT) {
update_pages_with_multi_variant();
}
update_extruder_switch_colors();
update_variant_sizer_visibility();
if (m_variant_sizer) {
wxWindow *variant_ctrl = m_extruder_switch ? (wxWindow *) m_extruder_switch : m_variant_combo;
m_main_sizer->Show(m_variant_sizer, variant_ctrl->IsThisEnabled() && m_active_page && !m_active_page->m_opt_id_map.empty() && !m_active_page->title().StartsWith("Extruder "));
if (m_extruder_sync) m_extruder_sync->Show(variant_ctrl->IsShown());
GetParent()->Layout();
}
}
// The variant switch tags are the narrowest place a volume type is named, so they abbreviate it;
@@ -8396,21 +8361,12 @@ std::vector<wxString> Tab::generate_extruder_options()
return options;
}
// Orca: the printer tab has one tag per extruder, named as its former "Extruder N" pages were.
// parse_extruder_selection() counts a hybrid extruder as two tags; that still lines up because
// only the last extruder can be hybrid.
if (m_type == Preset::TYPE_PRINTER) {
for (int i = 0; i < extruder_nums; ++i)
options.push_back(translate_category(wxString::Format("Extruder %d", i + 1), m_type));
return options;
}
std::string pt = m_preset_bundle->printers.get_edited_preset().get_printer_type(m_preset_bundle);
// Orca: the main/deputy toolhead names describe a Bambu dual-nozzle printer, where extruder 0 is
// the left (deputy) and extruder 1 the right (main) nozzle. Other printers number their tools.
const bool toolhead_names = extruder_nums == 2 && m_preset_bundle->is_bbl_vendor();
// Orca: the main/deputy toolhead names describe a dual-nozzle printer, where extruder 0 is the
// left (deputy) and extruder 1 the right (main) nozzle. From three extruders on the tools are
// interchangeable, so name them by index instead of repeating one side.
for (int i = 0; i < extruder_nums; ++i) {
wxString extruder_name = !toolhead_names ? wxString::Format("T%d", i + 1) :
wxString extruder_name = extruder_nums > 2 ? wxString::Format("T%d", i + 1) :
_L(DevPrinterConfigUtil::get_toolhead_display_name(
pt, (i == 0) ? DEPUTY_EXTRUDER_ID : MAIN_EXTRUDER_ID,
ToolHeadComponent::Nozzle, ToolHeadNameCase::TitleCase, true));
@@ -8427,71 +8383,6 @@ std::vector<wxString> Tab::generate_extruder_options()
return options;
}
Page *TabPrinter::extruder_page() const
{
for (const PageShp &page : m_pages)
if (page->title() == "Extruder")
return page.get();
return nullptr;
}
int TabPrinter::extruder_page_data_index(const std::string &field_id) const
{
if (Page *page = extruder_page())
for (const auto &group : page->m_optgroups)
if (auto it = group->opt_map().find(field_id); it != group->opt_map().end())
return it->second.second;
return -1;
}
int TabPrinter::extruder_variant_index(int extruder)
{
const auto *extruders = m_config->option<ConfigOptionEnumsGeneric>("extruder_type");
const int index = extruder < int(extruders->size()) ?
m_config->get_index_for_extruder(extruder + 1, "printer_extruder_id", ExtruderType(extruders->values[extruder]),
get_actual_nozzle_volume_type(extruder), "printer_extruder_variant") :
-1;
return index < 0 ? extruder : index;
}
void TabPrinter::update_custom_dirty(std::vector<std::string> &dirty_options, std::vector<std::string> &nonsys_options)
{
drop_unchanged_added_entries(dirty_options, *m_config, &m_presets->get_selected_preset());
drop_unchanged_added_entries(nonsys_options, *m_config, m_presets->get_selected_preset_parent());
}
void TabPrinter::sync_extruders_count()
{
if (m_printer_technology != ptFFF)
return;
const auto *nozzle_diameter = m_config->option<ConfigOptionFloats>("nozzle_diameter");
if (nozzle_diameter == nullptr || nozzle_diameter->size() == m_extruders_count)
return;
extruders_count_changed(nozzle_diameter->size());
init_options_list();
update_all_extruder_variants();
}
void TabPrinter::activate_option(const std::string &opt_key, const wxString &category)
{
wxString number;
long n = 0;
const bool numbered = category.StartsWith("Extruder ", &number) && number.ToLong(&n);
if (extruder_page() == nullptr || (!numbered && category != "Extruder")) {
Tab::activate_option(opt_key, category);
return;
}
// Selecting fires the switch's event, which re-targets the page (switch_excluder()).
const int extruder_idx = (n >= 1 && n <= long(m_extruders_count)) ? int(n - 1) : 0;
if (m_extruder_switch && m_extruder_switch->IsThisEnabled() && extruder_idx != get_current_active_extruder())
m_extruder_switch->SetSelection(calculate_selection_index_for_extruder(extruder_idx, get_actual_nozzle_volume_type(extruder_idx)));
// The page's controls are created for index 0.
const auto pos = opt_key.find('#');
Tab::activate_option(pos == std::string::npos ? opt_key : opt_key.substr(0, pos) + "#0", "Extruder");
}
NozzleVolumeType Tab::get_actual_nozzle_volume_type(int extruder_id)
{
int extruder_count = m_preset_bundle->get_printer_extruder_count();
@@ -8568,44 +8459,18 @@ bool Tab::get_extruder_sync_enable_state(int extruder_id)
return false;
}
bool Tab::variant_switch_active() const
{
if (m_extruder_switch)
return m_extruder_switch->IsThisEnabled();
return m_variant_combo && m_variant_combo->IsThisEnabled();
}
void Tab::update_variant_sizer_visibility()
{
if (!m_variant_sizer)
return;
const bool show = variant_switch_active() && m_active_page && !m_active_page->m_opt_id_map.empty();
m_main_sizer->Show(m_variant_sizer, show);
if (m_extruder_sync) {
m_extruder_sync->Show(show);
// Orca: copying between extruders is offered only between nozzle variants, and not on the Extruder page.
m_extruder_sync->Enable(m_extruder_switch_variants && !is_printer_extruder_page(m_active_page) &&
get_extruder_sync_enable_state(get_current_active_extruder()));
}
GetParent()->Layout();
}
void Tab::switch_excluder(int extruder_id, bool reload)
{
Preset & printer_preset = m_preset_bundle->printers.get_edited_preset();
auto nozzle_volumes = m_preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
auto extruders = printer_preset.config.option<ConfigOptionEnumsGeneric>("extruder_type");
// Orca: the printer tab re-targets its pages to the extruder selected on the switch. Resolved before
// the range check below, which keeps the extruder_type read in get_index_for_extruder in range.
if (m_type == Preset::TYPE_PRINTER && extruder_id == -1)
extruder_id = get_current_active_extruder();
if (!m_variant_combo && (extruder_id >= (int)nozzle_volumes->size() || extruder_id >= (int)extruders->size()))
extruder_id = 0;
if (m_extruder_switch) {
int current_extruder = get_current_active_extruder();
bool sync_enable = get_extruder_sync_enable_state(current_extruder);
m_extruder_sync->Enable(m_extruder_switch_variants && sync_enable && !is_printer_extruder_page(m_active_page));
m_extruder_sync->Enable(m_extruder_switch->IsThisEnabled() && sync_enable);
m_extruder_sync->Show();
if (m_type != Preset::TYPE_PRINTER) {
if (extruder_id == -1)
@@ -8632,26 +8497,24 @@ void Tab::switch_excluder(int extruder_id, bool reload)
return;
if (m_extruder_switch) m_extruder_switch->SetClientData(reinterpret_cast<void*>(static_cast<std::uintptr_t>(index)));
if (m_variant_combo) m_variant_combo->SetClientData(reinterpret_cast<void *>(static_cast<std::uintptr_t>(index)));
wxWindow *variant_ctrl = m_extruder_switch ? (wxWindow *) m_extruder_switch : m_variant_combo;
for (auto page : m_pages) {
bool is_extruder = false;
int page_index = index;
if (m_type == Preset::TYPE_PRINTER) {
if (page->title() == "Extruder")
if (page->title().StartsWith("Extruder")) {
int extruder_id2 = std::atoi(page->title().Mid(9).ToUTF8()) - 1;
if (extruder_id >= 0 && extruder_id2 != extruder_id)
continue;
if (extruder_id2 > 0)
index = get_index_for_extruder(extruder_id2);
is_extruder = true;
else if (page->title().StartsWith("Motion ability"))
page_index = get_index_for_extruder(extruder_id == -1 ? 0 : extruder_id, 2);
} else if (page->title().StartsWith("Motion ability")) {
index = get_index_for_extruder(extruder_id == -1 ? 0 : extruder_id, 2);
}
}
page->m_opt_id_map.clear();
for (auto group : page->m_optgroups) {
for (auto &opt : group->opt_map()) {
if (is_extruder && opt.second.second >= 0) {
// Per-variant options use the variant column, the others (nozzle_diameter,
// extruder_offset, ...) are sized by the extruder count and use the extruder.
const int idx = printer_options_with_variant_1.count(opt.second.first) > 0 ? page_index : extruder_id;
const_cast<int &>(opt.second.second) = idx;
page->m_opt_id_map.insert({opt.second.first + "#" + std::to_string(idx), opt.first});
continue;
}
auto iter = std::find(printer_extruder_options.begin(), printer_extruder_options.end(), opt.second.first);
if (iter != printer_extruder_options.end()) {
page->m_opt_id_map.insert({opt.first, opt.first});
@@ -8659,9 +8522,9 @@ void Tab::switch_excluder(int extruder_id, bool reload)
}
if (opt.second.second >= 0) {
const_cast<int &>(opt.second.second) = page_index;
page->m_opt_id_map.insert({opt.second.first + "#" + std::to_string(page_index), opt.first});
group->draw_multi_extruder = variant_switch_active();
const_cast<int &>(opt.second.second) = index;
page->m_opt_id_map.insert({opt.second.first + "#" + std::to_string(index), opt.first});
group->draw_multi_extruder = !is_extruder && variant_ctrl->IsThisEnabled();
}
}
}
+1 -31
View File
@@ -331,10 +331,6 @@ public:
MultiSwitchButton * m_variant_combo = nullptr;
ScalableButton *m_extruder_sync = nullptr;
wxPanel * m_extruder_sync_box = nullptr;
// Orca: whether m_extruder_switch switches nozzle variants (it then offers sync between them).
// The printer tab also enables the switch for printers without variants, to choose the extruder
// its Extruder and Motion ability pages edit.
bool m_extruder_switch_variants = false;
std::vector<NozzleVolumeType> m_actual_nozzle_volumes;
public:
@@ -391,13 +387,6 @@ public:
void update_changed_tree_ui();
void update_undo_buttons();
void update_extruder_switch_colors();
// Whether the variant switch (m_extruder_switch / m_variant_combo) is enabled: on the printer tab for
// any multi-extruder printer, on the other tabs when it switches nozzle variants.
bool variant_switch_active() const;
// Orca: whether `page` is the printer tab's single "Extruder" page, which edits the extruder selected on the switch.
bool is_printer_extruder_page(const Page* page) const { return m_type == Preset::TYPE_PRINTER && page && page->title() == "Extruder"; }
// Shows the variant switch row on pages with options that follow it.
void update_variant_sizer_visibility();
void update_all_extruder_options_status();
void check_extruder_options_status(int index, bool &sys_extruder, bool &modified_extruder, const std::vector<PageShp>& pages_to_check);
@@ -455,7 +444,7 @@ public:
virtual void on_value_change(const std::string& opt_key, const boost::any& value);
void update_wiping_button_visibility();
virtual void activate_option(const std::string& opt_key, const wxString& category);
void activate_option(const std::string& opt_key, const wxString& category);
void apply_searcher();
void cache_config_diff(const std::vector<std::string>& selected_options, const DynamicPrintConfig* config = nullptr);
void apply_config_from_cache();
@@ -721,25 +710,6 @@ public:
void cache_extruder_cnt(const DynamicPrintConfig* config = nullptr);
bool apply_extruder_cnt_from_cache();
void refresh_printer_agent_dropdown() const;
// Orca: a single "Extruder" page for all extruders. Its controls are created once (index 0) and
// switch_excluder() re-targets them to the extruder selected on m_extruder_switch.
Page* extruder_page() const;
// Config index an "Extruder" page field (e.g. "retraction_length#0") currently edits, -1 if not on that page.
int extruder_page_data_index(const std::string& field_id) const;
// Config index of an extruder's per-variant options (Retraction, Z-Hop, ...): its variant column
// for the nozzle selected on the switch, or the extruder index on a printer without variants.
int extruder_variant_index(int extruder);
// After the config was restored (roll back): follow its extruder count, if it differs.
void sync_extruders_count();
// Search jump to "Extruder N" / "key#N": selects extruder N on the switch, then activates the
// page's own field on the "Extruder" page.
void activate_option(const std::string& opt_key, const wxString& category) override;
protected:
// Orca: values of extruders added by raising the extruder count have no saved / system value to
// revert to; the change is shown on "extruders_count", not on each of their parameters.
void update_custom_dirty(std::vector<std::string> &dirty_options, std::vector<std::string> &nonsys_options) override;
};
class TabSLAMaterial : public Tab
+5 -5
View File
@@ -1682,13 +1682,13 @@ int GuideFrame::SaveProfileData()
return 0;
}
void StringReplace(std::string &strBase, std::string strSrc, std::string strDes)
void StringReplace(string &strBase, string strSrc, string strDes)
{
std::string::size_type pos = 0;
std::string::size_type srcLen = strSrc.size();
std::string::size_type desLen = strDes.size();
string::size_type pos = 0;
string::size_type srcLen = strSrc.size();
string::size_type desLen = strDes.size();
pos = strBase.find(strSrc, pos);
while ((pos != std::string::npos)) {
while ((pos != string::npos)) {
strBase.replace(pos, srcLen, strDes);
pos = strBase.find(strSrc, (pos + desLen));
}
+1 -1
View File
@@ -1052,7 +1052,7 @@ void AMSControl::UpdateAms(const std::string &series_name,
/*update humidity popup*/
if (m_percent_humidity_dry_popup->IsShown())
{
std::string target_id = m_percent_humidity_dry_popup->get_owner_ams_id();
string target_id = m_percent_humidity_dry_popup->get_owner_ams_id();
for (const auto& the_info : ams_info)
{
if (target_id == the_info.ams_id)
+2 -2
View File
@@ -63,7 +63,7 @@ protected:
std::string m_dev_id;
std::vector<std::vector<std::string>> m_item_ids{ {}, {} };
std::vector<std::pair<std::string, std::string>> pair_id;
std::vector<std::pair<string, string>> pair_id;
int m_total_ext_count = 1;
AMSextruder *m_extruder{nullptr};
@@ -181,7 +181,7 @@ public:
std::tuple<bool, bool> isFilaSwitchReady();
void show_switcher_status(bool show);
void UpdatePassRoad(std::string ams_id, AMSPassRoadType type, AMSPassRoadSTEP step);
void UpdatePassRoad(string ams_id, AMSPassRoadType type, AMSPassRoadSTEP step);
void CreateAms();
void CreateAmsDoubleNozzle(const std::string &series_name, const std::string& printer_type);
void CreateAmsSingleNozzle(const std::string &series_name, const std::string &printer_type);
+3 -3
View File
@@ -634,7 +634,7 @@ void AMSextruderImage::doRender(wxDC &dc)
}
AMSextruderImage::AMSextruderImage(wxWindow *parent, wxWindowID id, std::string file_name, const wxSize& size, const wxPoint &pos)
AMSextruderImage::AMSextruderImage(wxWindow *parent, wxWindowID id, string file_name, const wxSize& size, const wxPoint &pos)
{
wxWindow::Create(parent, id, pos, size);
SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE));
@@ -823,7 +823,7 @@ void SwitcherImage::doRender(wxDC &dc)
Layout();
}
SwitcherImage::SwitcherImage(wxWindow *parent, wxWindowID id, std::string file_name, const wxSize& size, const wxPoint &pos)
SwitcherImage::SwitcherImage(wxWindow *parent, wxWindowID id, string file_name, const wxSize& size, const wxPoint &pos)
{
wxWindow::Create(parent, id, pos, size);
SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE));
@@ -899,7 +899,7 @@ void AMSextruder::OnAmsLoading(bool load, int nozzle_id, wxColour col /*= AMS_CO
}
/*return true if something is updated*/
bool AMSextruder::updateNozzleNum(int nozzle_num, const std::string& series_name)
bool AMSextruder::updateNozzleNum(int nozzle_num, const string& series_name)
{
if (m_nozzle_num == nozzle_num && m_series_name == series_name) return false;
m_series_name = series_name;
+6 -6
View File
@@ -393,10 +393,10 @@ public:
bool m_show_state = {false};
wxColour m_colour;
ScalableBitmap m_ams_extruder;
std::string m_file_name;
string m_file_name;
bool m_ams_loading{ false };
void doRender(wxDC &dc);
AMSextruderImage(wxWindow *parent, wxWindowID id, std::string file_name, const wxSize& size, const wxPoint &pos = wxDefaultPosition);
AMSextruderImage(wxWindow *parent, wxWindowID id, string file_name, const wxSize& size, const wxPoint &pos = wxDefaultPosition);
~AMSextruderImage();
};
@@ -444,10 +444,10 @@ public:
bool m_show_state = {false};
wxColour m_colour;
ScalableBitmap m_switcher;
std::string m_file_name;
string m_file_name;
// bool m_ams_loading{ false };
void doRender(wxDC &dc);
SwitcherImage(wxWindow *parent, wxWindowID id, std::string file_name, const wxSize& size, const wxPoint &pos = wxDefaultPosition);
SwitcherImage(wxWindow *parent, wxWindowID id, string file_name, const wxSize& size, const wxPoint &pos = wxDefaultPosition);
~SwitcherImage();
};
@@ -456,7 +456,7 @@ class AMSextruder : public wxWindow
{
private:
int m_nozzle_num = -1;
std::string m_series_name;
string m_series_name;
public:
void TurnOn(wxColour col);
@@ -466,7 +466,7 @@ public:
void msw_rescale();
void has_ams(bool hams) {m_has_vams = hams; Refresh();};
void no_ams_mode(bool mode) {m_none_ams_mode = mode; Refresh();};
bool updateNozzleNum(int nozzle_num, const std::string& series_name = std::string());
bool updateNozzleNum(int nozzle_num, const std::string& series_name = string());
bool m_none_ams_mode{true};
bool m_has_vams{false};
+1 -2
View File
@@ -596,8 +596,7 @@ PrintParams_Legacy BBLNetworkPlugin::as_legacy(PrintParams& param)
}
// Every PrintParams field except the four the 02.08.01 series added
// (task_timelapse_use_internal, extruder_cali_manual_mode, svc_context, slicer_uid) and the
// queue_plate_id 02.08.02 appended.
// (task_timelapse_use_internal, extruder_cali_manual_mode, svc_context, slicer_uid).
PrintParams_0203 BBLNetworkPlugin::as_0203(PrintParams& param)
{
PrintParams_0203 p;
+4 -7
View File
@@ -336,7 +336,6 @@ struct PrintParams {
bool try_emmc_print;
std::string svc_context;
std::string slicer_uid;
std::string queue_plate_id;
};
struct TaskQueryParams
@@ -413,7 +412,7 @@ enum class NetworkAbi {
Unsupported, // no generation in this build can call it - never dispatch through it
Legacy, // 01.10.01: PrintParams_Legacy; send_message/send_message_to_printer take no flag
V0203, // 02.03.00: PrintParams_0203; bind takes no dev_model
Current, // 02.08.04: the layouts and signatures this build declares directly
Current, // 02.08.01: the layouts and signatures this build declares directly
};
struct NetworkLibraryVersion {
@@ -426,12 +425,10 @@ struct NetworkLibraryVersion {
};
// Every row names the generation that can call it, so a series can never be offered without a
// host-side ABI for it. Series with no generation - 02.08.01 (whose PrintParams lacks the
// queue_plate_id that 02.08.02 appended, and whose malformed bind table macOS 27 refuses to
// load), 02.01.01, 02.00.02 and older - must stay out; is_supported_network_version() is the
// gate that keeps them from loading.
// host-side ABI for it. Series with no generation - 02.01.01, 02.00.02 and older - must stay out;
// is_supported_network_version() is the gate that keeps them from loading.
static const NetworkLibraryVersion AVAILABLE_NETWORK_VERSIONS[] = {
{"02.08.04", "02.08.04", nullptr, true, nullptr, NetworkAbi::Current},
{"02.08.01", "02.08.01", nullptr, true, nullptr, NetworkAbi::Current},
{"02.03.00", "02.03.00", nullptr, false,
"An older plug-in series. Features that need newer plug-in support, such as print-failure "
"snapshots in the device error dialog, are unavailable.", NetworkAbi::V0203},
+3
View File
@@ -7,6 +7,9 @@
#include "nlohmann/json.hpp"
using namespace std;
class json_diff
{
private:
+25 -6
View File
@@ -346,8 +346,20 @@ std::vector<std::string> PluginAuditManager::default_denied_path_keywords()
// must never be able to reach a secret, a certificate, or a configuration file just because
// it happens to live inside an otherwise-allowed root (e.g. the bundled TLS client cert at
// resources_dir()/cert/..., which would become reachable the moment resources_dir() is
// granted as a read-only allowed root).
return {"secret", "cert", "conf"};
// granted as a read-only allowed root). Match as whole path components, not substrings, so
// imports such as numpy/__config__.py and stdlib configparser.py remain usable.
return {"secret", "secrets", "cert", "certs", "certificate", "certificates", "conf", "config"};
}
static bool has_denied_config_extension(std::string name)
{
const size_t stream_pos = name.find(':');
if (stream_pos != std::string::npos)
name.erase(stream_pos);
const boost::filesystem::path path(name);
const std::string extension = path.extension().string();
return extension == ".conf" || extension == ".ini";
}
bool PluginAuditManager::is_denied_path_keyword(const boost::filesystem::path& candidate) const
@@ -372,7 +384,7 @@ bool PluginAuditManager::is_denied_path_keyword(const boost::filesystem::path& c
continue;
std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) { return std::tolower(c); });
for (const auto& keyword : m_denied_path_keywords) {
if (name.find(keyword) != std::string::npos)
if (name == keyword || (keyword == "conf" && has_denied_config_extension(name)))
return true;
}
}
@@ -796,7 +808,8 @@ bool persist_permission(const std::string& plugin_key,
int report_denied(PluginAuditManager& mgr,
const std::string& event_name,
const AuditDecision& decision)
const AuditDecision& decision,
const std::string& target = {})
{
AuditViolation violation;
violation.plugin_key = mgr.current_plugin();
@@ -804,7 +817,13 @@ int report_denied(PluginAuditManager& mgr,
violation.reason = decision.reason;
mgr.report_violation(violation);
PyErr_SetString(PyExc_PermissionError, "Plugin attempted an audited operation without permission");
std::string message = "Plugin attempted audited operation \"" + event_name + "\" without permission";
if (!decision.reason.empty())
message += ": " + decision.reason;
if (!target.empty())
message += ": " + target;
PyErr_SetString(PyExc_PermissionError, message.c_str());
return -1;
}
@@ -916,7 +935,7 @@ int PluginAuditManager::audit_hook(const char* event, PyObject* args, void* user
if (fs_category) {
for (const auto& target : targets) {
if (mgr->is_denied_path(boost::filesystem::path(target)))
return PluginAuditDetail::report_denied(*mgr, event_name, {false, "denied path"});
return PluginAuditDetail::report_denied(*mgr, event_name, {false, "denied path"}, target);
}
}
+8 -11
View File
@@ -4,7 +4,6 @@
// Via pybind11 so this file requests the same python3xx.lib as everything else.
#include <boost/filesystem/path.hpp>
#include <pybind11/conduit/wrap_include_python_h.h>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
@@ -103,22 +102,20 @@ public:
bool is_denied_filename(const boost::filesystem::path& candidate) const;
// --- denied-path-keyword registry ---
// Keywords that categorically deny a path if ANY of its components (directory or file
// name), not just the base name, contains one case-insensitively -- e.g. a "secrets"
// subfolder, a "certificates" folder, or a "conf"/"config" file anywhere the plugin can
// otherwise reach, including inside an allowed root. This is intentionally broader and
// fuzzier than the exact-name is_denied_filename registry: it exists to categorically rule
// out whole classes of sensitive paths (secrets, certificates, config) rather than name
// specific known files, at the cost of over-blocking an unrelated name that happens to
// contain the keyword -- the fail-safe direction, same rationale as is_denied_filename.
// Keywords that categorically deny a path if ANY component matches one case-insensitively --
// e.g. a "secrets" subfolder, a "certificates" folder, a "conf"/"config" directory, or a
// .conf/.ini file anywhere the plugin can otherwise reach, including inside an allowed root.
// This is broader than the exact-name is_denied_filename registry, but it is not a substring
// match: importable modules such as numpy/__config__.py, configparser.py, sysconfig.py, or
// user folders such as "Conference" and "Concert" are unrelated names and must stay promptable.
void add_denied_path_keyword(const std::string& keyword);
// The list install_hook() seeds into the keyword registry. Exposed so tests seed the exact
// same set without a live interpreter.
static std::vector<std::string> default_denied_path_keywords();
// True when any component of candidate's (canonicalized) path contains a registered
// keyword, case-insensitively.
// True when any component of candidate's (canonicalized) path matches a registered keyword,
// case-insensitively. A registered "conf" keyword also blocks .conf/.ini file components.
bool is_denied_path_keyword(const boost::filesystem::path& candidate) const;
// is_denied_filename(candidate) || is_denied_path_keyword(candidate). Convenience for
+5 -43
View File
@@ -28,7 +28,6 @@
#include <wx/app.h>
#include <wx/defs.h>
#include <wx/thread.h>
#include <wx/timer.h>
#include <wx/toplevel.h>
#include <wx/event.h>
#include <wx/progdlg.h>
@@ -416,44 +415,6 @@ struct UiDockPanelHandle
int id{0};
};
// Polls until the plater is shown on screen, then runs the callback with it (null when the app
// is closing instead) and deletes itself. A plugin loaded at startup opens its panes from
// on_load, before the main window exists, and a pane added before that window is laid out is
// sized against the unsized frame and keeps that width (AuiMgr::track_docked_size).
class PlaterShownWaiter : public wxTimer
{
public:
explicit PlaterShownWaiter(std::function<void(GUI::Plater*)> fn) : m_fn(std::move(fn)) {}
// True once the callback ran.
bool try_run()
{
const bool closing = GUI::wxGetApp().is_closing();
GUI::Plater* plater = closing ? nullptr : GUI::wxGetApp().plater();
if (!closing && (plater == nullptr || !plater->IsShownOnScreen()))
return false;
Stop();
m_fn(plater);
// Off the timer callback's stack: wxGTK's timeout callback still reads the timer after Notify().
GUI::wxGetApp().CallAfter([this]() { delete this; });
return true;
}
void Notify() override { try_run(); }
private:
std::function<void(GUI::Plater*)> m_fn;
};
void run_when_plater_shown(std::function<void(GUI::Plater*)> fn)
{
GUI::wxGetApp().CallAfter([fn = std::move(fn)]() mutable {
auto* waiter = new PlaterShownWaiter(std::move(fn));
if (!waiter->try_run())
waiter->Start(100);
});
}
py::object ui_create_dock_panel(const std::string& html, const std::string& title, int width, int height,
py::object on_message, py::object on_close, const std::string& dock)
{
@@ -473,13 +434,14 @@ py::object ui_create_dock_panel(const std::string& html, const std::string& titl
const int new_id = UiRegistry::instance().reserve_id();
UiRegistry::instance().bind(new_id, nullptr, plugin_key);
run_when_plater_shown([new_id, plugin_key, html, title, dock, w, h,
msg_adapter = std::move(msg_adapter),
close_holder = std::move(close_holder)](GUI::Plater* plater) mutable {
GUI::wxGetApp().CallAfter([new_id, plugin_key, html, title, dock, w, h,
msg_adapter = std::move(msg_adapter),
close_holder = std::move(close_holder)]() mutable {
if (!UiRegistry::instance().is_open(new_id))
return;
if (plater == nullptr) {
GUI::Plater* plater = GUI::wxGetApp().plater();
if (plater == nullptr || GUI::wxGetApp().is_closing()) {
UiRegistry::instance().remove(new_id);
return;
}
-104
View File
@@ -538,110 +538,6 @@ SCENARIO("update_diff_values_to_child_config keeps a child's values on variants
}
}
SCENARIO("update_non_diff_values_to_base_config keeps a project's changed values on variants it does not list",
"[Config][Variant]") {
std::set<std::string> no_keys;
auto variants = [](std::initializer_list<std::string> names) { return new Slic3r::ConfigOptionStrings(names); };
GIVEN("A filament base with three variants") {
Slic3r::DynamicPrintConfig base;
base.set_key_value("filament_extruder_variant",
variants({"Direct Drive Standard", "Bowden Standard", "Direct Drive High Flow"}));
base.set_deserialize_strict("nozzle_temperature", "220,220,220");
WHEN("the project was saved when the base had only its first variant") {
Slic3r::DynamicPrintConfig project;
project.set_key_value("filament_extruder_variant", variants({"Direct Drive Standard"}));
project.set_deserialize_strict("nozzle_temperature", "199");
AND_WHEN("the project lists the value as changed") {
project.update_non_diff_values_to_base_config(base, project.keys(), {"nozzle_temperature"}, "", "filament_extruder_variant",
Slic3r::filament_options_with_variant, no_keys);
THEN("the project's value applies to every variant") {
REQUIRE(project.opt_serialize("nozzle_temperature") == "199,199,199");
}
}
AND_WHEN("the project does not list the value as changed") {
project.update_non_diff_values_to_base_config(base, project.keys(), {}, "", "filament_extruder_variant",
Slic3r::filament_options_with_variant, no_keys);
THEN("the base's values replace it") {
REQUIRE(project.opt_serialize("nozzle_temperature") == "220,220,220");
}
}
}
WHEN("the project lists every variant, in another order") {
Slic3r::DynamicPrintConfig project;
project.set_key_value("filament_extruder_variant",
variants({"Bowden Standard", "Direct Drive High Flow", "Direct Drive Standard"}));
project.set_deserialize_strict("nozzle_temperature", "190,205,199");
project.update_non_diff_values_to_base_config(base, project.keys(), {"nozzle_temperature"}, "", "filament_extruder_variant",
Slic3r::filament_options_with_variant, no_keys);
THEN("each variant keeps its own value") {
REQUIRE(project.opt_serialize("nozzle_temperature") == "199,190,205");
}
}
WHEN("the project lists no variants") {
Slic3r::DynamicPrintConfig project;
project.set_deserialize_strict("nozzle_temperature", "199");
project.update_non_diff_values_to_base_config(base, project.keys(), {"nozzle_temperature"}, "", "filament_extruder_variant",
Slic3r::filament_options_with_variant, no_keys);
THEN("the project's value applies to every variant") {
REQUIRE(project.opt_serialize("nozzle_temperature") == "199,199,199");
}
}
}
GIVEN("A two-extruder printer base with two variants per extruder") {
Slic3r::DynamicPrintConfig base;
base.set_key_value("printer_extruder_variant",
variants({"Direct Drive Standard", "Direct Drive High Flow", "Direct Drive Standard", "Direct Drive High Flow"}));
base.set_key_value("printer_extruder_id", new Slic3r::ConfigOptionInts({1, 1, 2, 2}));
base.set_deserialize_strict("retraction_length", "0.8,0.8,0.8,0.8");
WHEN("the project lists only the Standard variant of each extruder") {
Slic3r::DynamicPrintConfig project;
project.set_key_value("printer_extruder_variant", variants({"Direct Drive Standard", "Direct Drive Standard"}));
project.set_key_value("printer_extruder_id", new Slic3r::ConfigOptionInts({1, 2}));
project.set_deserialize_strict("retraction_length", "1.1,2.2");
project.update_non_diff_values_to_base_config(base, project.keys(), {"retraction_length"}, "printer_extruder_id", "printer_extruder_variant",
Slic3r::printer_options_with_variant_1,
Slic3r::printer_options_with_variant_2);
THEN("each extruder's High Flow variant takes that extruder's value") {
REQUIRE(project.opt_serialize("retraction_length") == "1.1,1.1,2.2,2.2");
}
}
WHEN("the project lists only the Standard variant of each extruder, and the variant lists as changed") {
Slic3r::DynamicPrintConfig project;
project.set_key_value("printer_extruder_variant", variants({"Direct Drive Standard", "Direct Drive Standard"}));
project.set_key_value("printer_extruder_id", new Slic3r::ConfigOptionInts({1, 2}));
project.set_deserialize_strict("machine_max_speed_x", "300,100,400,150");
base.set_deserialize_strict("machine_max_speed_x", "500,200,500,200,500,200,500,200");
project.update_non_diff_values_to_base_config(base, project.keys(),
{"machine_max_speed_x", "printer_extruder_id", "printer_extruder_variant"},
"printer_extruder_id", "printer_extruder_variant",
Slic3r::printer_options_with_variant_1,
Slic3r::printer_options_with_variant_2);
THEN("the variant lists are the base's") {
REQUIRE(project.opt_serialize("printer_extruder_variant") == base.opt_serialize("printer_extruder_variant"));
REQUIRE(project.opt_serialize("printer_extruder_id") == "1,1,2,2");
}
THEN("each extruder's High Flow variant takes that extruder's pair of limits") {
REQUIRE(project.opt_serialize("machine_max_speed_x") == "300,100,300,100,400,150,400,150");
}
}
WHEN("the project lists no variants") {
Slic3r::DynamicPrintConfig project;
project.set_deserialize_strict("retraction_length", "1.1");
project.update_non_diff_values_to_base_config(base, project.keys(), {"retraction_length"}, "printer_extruder_id", "printer_extruder_variant",
Slic3r::printer_options_with_variant_1,
Slic3r::printer_options_with_variant_2);
THEN("only the first extruder's variants take the project's value") {
REQUIRE(project.opt_serialize("retraction_length") == "1.1,1.1,0.8,0.8");
}
}
}
}
// SCENARIO("DynamicPrintConfig JSON serialization", "[Config]") {
// WHEN("DynamicPrintConfig is serialized and deserialized") {
// auto now = std::chrono::high_resolution_clock::now();
@@ -799,67 +799,3 @@ TEST_CASE("A per-variant filament option read with a single value gives it to ev
config.load_from_ini_string("pressure_advance = 0.021", ForwardCompatibilitySubstitutionRule::Disable);
REQUIRE(config.option<ConfigOptionFloats>("pressure_advance")->values == std::vector<double>({0.021, 0.021, 0.021}));
}
// Machine limits (printer_options_with_variant_2) hold a (normal, silent) pair per printer variant, so the
// printer Tab's Motion ability page can edit each extruder's own limits.
TEST_CASE("set_num_extruders gives every printer variant its own pair of machine limits", "[Config]")
{
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
auto speed_x = [&config]() { return config.option<ConfigOptionFloats>("machine_max_speed_x")->values; };
SECTION("a new extruder's pair is padded with the first value, like the other variant keys") {
config.option<ConfigOptionFloats>("machine_max_speed_x")->values = {500., 200.};
config.set_num_extruders(3);
REQUIRE(config.option<ConfigOptionStrings>("printer_extruder_variant")->size() == 3);
REQUIRE(speed_x() == std::vector<double>({500., 200., 500., 500., 500., 500.}));
}
SECTION("per-extruder pairs are kept, and removing an extruder removes its pair") {
config.option<ConfigOptionFloats>("machine_max_speed_x")->values = {500., 200., 400., 150., 300., 100.};
config.set_num_extruders(3);
REQUIRE(speed_x() == std::vector<double>({500., 200., 400., 150., 300., 100.}));
config.set_num_extruders(2);
REQUIRE(speed_x() == std::vector<double>({500., 200., 400., 150.}));
}
SECTION("a printer with nozzle variants gets a pair per variant") {
// 2 extruders x 2 variants each = 4 variants
config.option<ConfigOptionStrings>("extruder_variant_list", true)->values = {"Direct Drive Standard,Direct Drive High Flow",
"Direct Drive Standard,Direct Drive High Flow"};
const std::vector<double> per_variant = {500., 200., 510., 210., 520., 220., 530., 230.};
config.option<ConfigOptionFloats>("machine_max_speed_x")->values = per_variant;
config.set_num_extruders(2);
REQUIRE(speed_x() == per_variant);
config.option<ConfigOptionFloats>("machine_max_speed_x")->values = {500., 200.};
config.set_num_extruders(2);
REQUIRE(speed_x() == std::vector<double>({500., 200., 500., 500., 500., 500., 500., 500.}));
}
}
// The device drying options hold several values per filament, as many as each filament preset gives.
TEST_CASE("The device drying options are rebuilt as each filament's values in slot order", "[Config]")
{
DynamicPrintConfig two_values, one_value, no_value;
two_values.option<ConfigOptionStrings>("filament_dev_ams_drying_ams_limitations", true)->values = {"1", "0"};
two_values.option<ConfigOptionFloats>("filament_dev_ams_drying_temperature", true)->values = {45., 45., 55., 55.};
one_value.option<ConfigOptionStrings>("filament_dev_ams_drying_ams_limitations", true)->values = {"1"};
one_value.option<ConfigOptionFloats>("filament_dev_ams_drying_temperature", true)->values = {65., 65., 75., 75.};
// values a project stored for three other filaments
DynamicPrintConfig config;
config.option<ConfigOptionStrings>("filament_dev_ams_drying_ams_limitations", true)->values = {"0", "0", "0"};
config.option<ConfigOptionFloats>("filament_dev_chamber_drying_time", true)->values = {12., 8., 12.};
set_filament_dev_options(config, {&two_values, &one_value, &two_values});
REQUIRE(config.option<ConfigOptionStrings>("filament_dev_ams_drying_ams_limitations")->values ==
std::vector<std::string>({"1", "0", "1", "1", "0"}));
REQUIRE(config.option<ConfigOptionFloats>("filament_dev_ams_drying_temperature")->values ==
std::vector<double>({45., 45., 55., 55., 65., 65., 75., 75., 45., 45., 55., 55.}));
// an option no filament defines keeps the stored values
REQUIRE(config.option<ConfigOptionFloats>("filament_dev_chamber_drying_time")->values == std::vector<double>({12., 8., 12.}));
// a filament without the option takes the option's default
set_filament_dev_options(config, {&two_values, &no_value});
REQUIRE(config.option<ConfigOptionStrings>("filament_dev_ams_drying_ams_limitations")->values == std::vector<std::string>({"1", "0", ""}));
}
@@ -6228,9 +6228,8 @@ TEST_CASE("A per-variant project value maps onto its base preset's variant layou
base_finder(&base, calls));
CHECK(config.option<ConfigOptionStrings>("print_extruder_variant")->values ==
std::vector<std::string>{"Direct Drive Standard", "Direct Drive High Flow"});
// The listed key keeps the project's Standard value, and High Flow, which the project does not
// list, takes it too, as a user preset's value does.
check_double_vector(config.option<ConfigOptionFloats>("outer_wall_speed")->values, {100., 100.});
// The listed key keeps the project's Standard value and takes High Flow from the base.
check_double_vector(config.option<ConfigOptionFloats>("outer_wall_speed")->values, {100., 300.});
check_double_vector(config.option<ConfigOptionFloats>("inner_wall_speed")->values, {250., 350.});
}
+29 -36
View File
@@ -78,34 +78,31 @@ TEST_CASE("Series and managed classification", "[NetworkVersions]")
TEST_CASE_METHOD(PluginFolderFixture, "Managed builds fold into the series; customs are surfaced", "[NetworkVersions]")
{
add_plugin("02.08.04.60"); // managed, same series -> folded into the 02.08.04 row
add_plugin("02.08.01.55"); // managed, same series -> folded into the 02.08.01 row
add_plugin("02.09.00.10"); // managed, unknown series -> not listed
add_plugin("02.08.01.55"); // managed, series this build no longer has an ABI for -> not listed
add_plugin("02.03.00.62"); // managed, older whitelisted series -> folded into 02.03.00
add_plugin("02.01.01.52"); // managed, series with no ABI in this build -> not listed
add_plugin("02.08.04_custom"); // custom, whitelisted series -> listed under it
add_plugin("02.08.04.52-dev"); // custom (dash-suffixed), whitelisted series -> listed
add_plugin("02.08.01_custom"); // custom, whitelisted series -> listed under it
add_plugin("02.08.01.52-dev"); // custom (dash-suffixed), whitelisted series -> listed
auto versions = get_all_available_versions();
// The specific managed build never gets its own row - the series represents it.
REQUIRE(count_version(versions, "02.08.04.60") == 0);
REQUIRE(count_version(versions, "02.08.04") == 1);
REQUIRE(count_version(versions, "02.09.00.10") == 0);
REQUIRE(count_version(versions, "02.08.01.55") == 0);
REQUIRE(count_version(versions, "02.08.01") == 0);
REQUIRE(count_version(versions, "02.08.01") == 1);
REQUIRE(count_version(versions, "02.09.00.10") == 0);
REQUIRE(count_version(versions, "02.03.00.62") == 0);
REQUIRE(count_version(versions, "02.03.00") == 1);
REQUIRE(count_version(versions, "02.01.01.52") == 0);
// Custom-named builds are distinct files kept under their own name.
REQUIRE(count_version(versions, "02.08.04_custom") == 1);
REQUIRE(count_version(versions, "02.08.04.52-dev") == 1);
REQUIRE(count_version(versions, "02.08.01_custom") == 1);
REQUIRE(count_version(versions, "02.08.01.52-dev") == 1);
// Newest series first, its customs nested under it (suffix sort: "" < ".52-dev" < "_custom"),
// then older series, legacy last.
REQUIRE(versions[0].version == "02.08.04");
REQUIRE(versions[1].version == "02.08.04.52-dev");
REQUIRE(versions[2].version == "02.08.04_custom");
REQUIRE(versions[0].version == "02.08.01");
REQUIRE(versions[1].version == "02.08.01.52-dev");
REQUIRE(versions[2].version == "02.08.01_custom");
REQUIRE(versions[3].version == "02.03.00");
REQUIRE(versions.back().version == BAMBU_NETWORK_AGENT_VERSION_LEGACY);
@@ -114,9 +111,9 @@ TEST_CASE_METHOD(PluginFolderFixture, "Managed builds fold into the series; cust
REQUIRE_FALSE(versions[3].is_latest);
// Customs sort/render nested under their series (non-empty suffix, base = the series).
REQUIRE(versions[1].base_version == "02.08.04");
REQUIRE(versions[1].base_version == "02.08.01");
REQUIRE_FALSE(versions[1].suffix.empty());
REQUIRE(versions[2].base_version == "02.08.04");
REQUIRE(versions[2].base_version == "02.08.01");
REQUIRE_FALSE(versions[2].suffix.empty());
// "(Latest)" is the series row, never a nested custom build.
@@ -126,20 +123,20 @@ TEST_CASE_METHOD(PluginFolderFixture, "Managed builds fold into the series; cust
REQUIRE_FALSE(versions[2].is_latest);
// The stored default that drives download and update-check decisions is now the series.
REQUIRE(std::string(get_latest_network_version()) == "02.08.04");
REQUIRE(std::string(get_latest_network_version()) == "02.08.01");
}
TEST_CASE_METHOD(PluginFolderFixture, "Only the loaded series is marked installed", "[NetworkVersions]")
{
add_plugin("02.08.04.60");
add_plugin("02.08.04_custom");
add_plugin("02.08.01.55");
add_plugin("02.08.01_custom");
// The loaded plug-in reports its full build (02.08.04.60); the series row is what gets marked.
// The loaded plug-in reports its full build (02.08.01.55); the series row is what gets marked.
{
auto versions = get_all_available_versions("02.08.04.60");
auto versions = get_all_available_versions("02.08.01.55");
int marked = 0;
for (const auto& info : versions)
if (info.is_loaded) { ++marked; REQUIRE(info.version == "02.08.04"); }
if (info.is_loaded) { ++marked; REQUIRE(info.version == "02.08.01"); }
REQUIRE(marked == 1);
}
@@ -155,10 +152,10 @@ TEST_CASE_METHOD(PluginFolderFixture, "Only the loaded series is marked installe
// A loaded custom build matches its own row, never the bare series.
{
auto versions = get_all_available_versions("02.08.04_custom");
auto versions = get_all_available_versions("02.08.01_custom");
int marked = 0;
for (const auto& info : versions)
if (info.is_loaded) { ++marked; REQUIRE(info.version == "02.08.04_custom"); }
if (info.is_loaded) { ++marked; REQUIRE(info.version == "02.08.01_custom"); }
REQUIRE(marked == 1);
}
@@ -170,11 +167,11 @@ TEST_CASE_METHOD(PluginFolderFixture, "Only the loaded series is marked installe
TEST_CASE("Only whitelisted series pass the load gate", "[NetworkVersions]")
{
// Each whitelisted series, its builds, and custom-named builds of that series.
REQUIRE(is_supported_network_version("02.08.04"));
REQUIRE(is_supported_network_version("02.08.04.52"));
REQUIRE(is_supported_network_version("02.08.04.60"));
REQUIRE(is_supported_network_version("02.08.04_custom"));
REQUIRE(is_supported_network_version("02.08.04.52-dev"));
REQUIRE(is_supported_network_version("02.08.01"));
REQUIRE(is_supported_network_version("02.08.01.52"));
REQUIRE(is_supported_network_version("02.08.01.55"));
REQUIRE(is_supported_network_version("02.08.01_custom"));
REQUIRE(is_supported_network_version("02.08.01.52-dev"));
REQUIRE(is_supported_network_version("02.03.00"));
REQUIRE(is_supported_network_version("02.03.00.62"));
REQUIRE(is_supported_network_version("02.03.00.70"));
@@ -182,9 +179,6 @@ TEST_CASE("Only whitelisted series pass the load gate", "[NetworkVersions]")
REQUIRE(is_supported_network_version(BAMBU_NETWORK_AGENT_VERSION_LEGACY));
// Series whitelisted by previous Orca releases that no generation here can call.
REQUIRE_FALSE(is_supported_network_version("02.08.01"));
REQUIRE_FALSE(is_supported_network_version("02.08.01.55"));
REQUIRE_FALSE(is_supported_network_version("02.08.01_custom"));
REQUIRE_FALSE(is_supported_network_version("02.01.01.52"));
REQUIRE_FALSE(is_supported_network_version("02.00.02.50"));
@@ -204,9 +198,9 @@ TEST_CASE("Each version resolves to the ABI generation that can call it", "[Netw
{
// The generation is keyed on the series, so every build of a series - including the
// custom-named ones - resolves to the same one.
CHECK(network_plugin_abi("02.08.04") == NetworkAbi::Current);
CHECK(network_plugin_abi("02.08.04.60") == NetworkAbi::Current);
CHECK(network_plugin_abi("02.08.04.52-dev") == NetworkAbi::Current);
CHECK(network_plugin_abi("02.08.01") == NetworkAbi::Current);
CHECK(network_plugin_abi("02.08.01.55") == NetworkAbi::Current);
CHECK(network_plugin_abi("02.08.01.52-dev") == NetworkAbi::Current);
CHECK(network_plugin_abi("02.03.00") == NetworkAbi::V0203);
CHECK(network_plugin_abi("02.03.00.62") == NetworkAbi::V0203);
CHECK(network_plugin_abi("02.03.00_custom") == NetworkAbi::V0203);
@@ -214,7 +208,6 @@ TEST_CASE("Each version resolves to the ABI generation that can call it", "[Netw
// Anything the load gate rejects must dispatch through nothing at all, rather than
// defaulting to a layout it does not share.
CHECK(network_plugin_abi("02.08.01.55") == NetworkAbi::Unsupported);
CHECK(network_plugin_abi("02.01.01.52") == NetworkAbi::Unsupported);
CHECK(network_plugin_abi("02.00.02.50") == NetworkAbi::Unsupported);
CHECK(network_plugin_abi("02.09.00.10") == NetworkAbi::Unsupported);
@@ -241,7 +234,7 @@ TEST_CASE_METHOD(PluginFolderFixture, "Legacy series never adopts discovered bui
// With nothing else on disk, the series holds "(Latest)" even though its library is
// not installed.
for (const auto& info : versions) {
if (info.version == "02.08.04") {
if (info.version == "02.08.01") {
REQUIRE(info.is_latest);
REQUIRE_FALSE(info.is_loaded);
}
+12 -3
View File
@@ -222,18 +222,19 @@ TEST_CASE("Plugin audit denies secret/certificate/config-like paths by keyword",
CHECK(mgr.is_denied_path_keyword(fs::path("/resources/certificates/ca.pem")));
}
SECTION("a 'conf'/'config' directory or file component is denied")
SECTION("a 'conf'/'config' directory or config file component is denied")
{
CHECK(mgr.is_denied_path_keyword(fs::path("/plugin/conf/settings.json")));
CHECK(mgr.is_denied_path_keyword(fs::path("/plugin/config/settings.json")));
CHECK(mgr.is_denied_path_keyword(fs::path("/plugin/plugin.conf")));
CHECK(mgr.is_denied_path_keyword(fs::path("/plugin/plugin.ini")));
}
SECTION("matching is case-insensitive")
{
CHECK(mgr.is_denied_path_keyword(fs::path("/plugin/SECRETS/token.txt")));
CHECK(mgr.is_denied_path_keyword(fs::path("/resources/CertBundle/ca.pem")));
CHECK(mgr.is_denied_path_keyword(fs::path("/plugin/CONFIG.JSON")));
CHECK(mgr.is_denied_path_keyword(fs::path("/resources/Certificates/ca.pem")));
CHECK(mgr.is_denied_path_keyword(fs::path("/plugin/PLUGIN.CONF")));
}
SECTION("matching is not limited to the base name -- any ancestor component counts")
@@ -245,6 +246,14 @@ TEST_CASE("Plugin audit denies secret/certificate/config-like paths by keyword",
{
CHECK_FALSE(mgr.is_denied_path_keyword(fs::path("/plugin/output/model.gcode")));
CHECK_FALSE(mgr.is_denied_path_keyword(fs::path("/plugin/storage/state.json")));
CHECK_FALSE(mgr.is_denied_path_keyword(fs::path("/python/packages/cp312/numpy/__config__.py")));
CHECK_FALSE(mgr.is_denied_path_keyword(fs::path("/python/packages/cp312/numpy/_core/_ufunc_config.py")));
CHECK_FALSE(mgr.is_denied_path_keyword(fs::path("/python/Lib/configparser.py")));
CHECK_FALSE(mgr.is_denied_path_keyword(fs::path("/python/Lib/sysconfig.py")));
CHECK_FALSE(mgr.is_denied_path_keyword(fs::path("/python/Lib/logging/config.py")));
CHECK_FALSE(mgr.is_denied_path_keyword(fs::path("/python/packages/cp312/certifi/cacert.pem")));
CHECK_FALSE(mgr.is_denied_path_keyword(fs::path("/users/Conference/output.txt")));
CHECK_FALSE(mgr.is_denied_path_keyword(fs::path("/users/Concert/output.txt")));
}
SECTION("an empty path is not denied")