mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-14 20:47:33 +00:00
Compare commits
2 Commits
nightly-bu
...
hanif/cli-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4840901fc | ||
|
|
5f01f21661 |
@@ -587,15 +587,10 @@ if ((NOT MSVC OR IS_CLANG_CL) AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR
|
|||||||
add_compile_options(-Wno-${w})
|
add_compile_options(-Wno-${w})
|
||||||
endforeach ()
|
endforeach ()
|
||||||
|
|
||||||
# GCC is not built in CI, so don't throw errors CI won't catch.
|
# Turn everything else into an error. Dependency headers are exempt because the SYSTEM
|
||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
# include flag (-imsvc on clang-cl, -isystem elsewhere) keeps their diagnostics out,
|
||||||
add_compile_options(-Werror=return-type)
|
# apart from GCC's maybe-uninitialized, demoted below.
|
||||||
else ()
|
add_compile_options(-Werror)
|
||||||
# Turn everything else into an error. Dependency headers are exempt because the
|
|
||||||
# SYSTEM include flag (-imsvc on clang-cl, -isystem elsewhere) keeps their
|
|
||||||
# diagnostics out.
|
|
||||||
add_compile_options(-Werror)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
# Demoted. Remove a name once its category is cleared on every compiler.
|
# Demoted. Remove a name once its category is cleared on every compiler.
|
||||||
set(warnings_demoted)
|
set(warnings_demoted)
|
||||||
@@ -617,6 +612,20 @@ if ((NOT MSVC OR IS_CLANG_CL) AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR
|
|||||||
cast-function-type-mismatch
|
cast-function-type-mismatch
|
||||||
)
|
)
|
||||||
endif ()
|
endif ()
|
||||||
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
|
list(APPEND warnings_demoted
|
||||||
|
# maybe-uninitialized runs after inlining and reports inside boost/variant,
|
||||||
|
# boost/tuple and the bundled clipper header even with -isystem.
|
||||||
|
maybe-uninitialized
|
||||||
|
|
||||||
|
# array-bounds is reported once, where ConfigOptionVector::set_at inlines
|
||||||
|
# into OrcaSlicer.cpp on a branch the preceding type test rules out.
|
||||||
|
array-bounds
|
||||||
|
|
||||||
|
# template-id-cdtor is a GCC 14+ warning in the bundled Clipper2 headers.
|
||||||
|
template-id-cdtor
|
||||||
|
)
|
||||||
|
endif ()
|
||||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
list(APPEND warnings_demoted
|
list(APPEND warnings_demoted
|
||||||
# enum-constexpr-conversion is a Clang warning that defaults to an error,
|
# enum-constexpr-conversion is a Clang warning that defaults to an error,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Snapmaker",
|
"name": "Snapmaker",
|
||||||
"version": "02.04.00.13",
|
"version": "02.04.00.12",
|
||||||
"force_update": "0",
|
"force_update": "0",
|
||||||
"description": "Snapmaker configurations",
|
"description": "Snapmaker configurations",
|
||||||
"machine_model_list": [
|
"machine_model_list": [
|
||||||
|
|||||||
@@ -15,13 +15,13 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"cool_plate_temp": [
|
"cool_plate_temp": [
|
||||||
"100"
|
"105"
|
||||||
],
|
],
|
||||||
"cool_plate_temp_initial_layer": [
|
"cool_plate_temp_initial_layer": [
|
||||||
"100"
|
"105"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
"100"
|
"105"
|
||||||
],
|
],
|
||||||
"eng_plate_temp_initial_layer": [
|
"eng_plate_temp_initial_layer": [
|
||||||
"100"
|
"100"
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
"Polymaker"
|
"Polymaker"
|
||||||
],
|
],
|
||||||
"hot_plate_temp": [
|
"hot_plate_temp": [
|
||||||
"100"
|
"105"
|
||||||
],
|
],
|
||||||
"hot_plate_temp_initial_layer": [
|
"hot_plate_temp_initial_layer": [
|
||||||
"100"
|
"100"
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
"110.8"
|
"110.8"
|
||||||
],
|
],
|
||||||
"textured_plate_temp": [
|
"textured_plate_temp": [
|
||||||
"100"
|
"105"
|
||||||
],
|
],
|
||||||
"textured_plate_temp_initial_layer": [
|
"textured_plate_temp_initial_layer": [
|
||||||
"100"
|
"100"
|
||||||
|
|||||||
@@ -15,16 +15,16 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"cool_plate_temp": [
|
"cool_plate_temp": [
|
||||||
"100"
|
"105"
|
||||||
],
|
],
|
||||||
"cool_plate_temp_initial_layer": [
|
"cool_plate_temp_initial_layer": [
|
||||||
"100"
|
"105"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
"100"
|
"105"
|
||||||
],
|
],
|
||||||
"eng_plate_temp_initial_layer": [
|
"eng_plate_temp_initial_layer": [
|
||||||
"100"
|
"105"
|
||||||
],
|
],
|
||||||
"fan_cooling_layer_time": [
|
"fan_cooling_layer_time": [
|
||||||
"12"
|
"12"
|
||||||
@@ -51,10 +51,10 @@
|
|||||||
"Polymaker"
|
"Polymaker"
|
||||||
],
|
],
|
||||||
"hot_plate_temp": [
|
"hot_plate_temp": [
|
||||||
"100"
|
"105"
|
||||||
],
|
],
|
||||||
"hot_plate_temp_initial_layer": [
|
"hot_plate_temp_initial_layer": [
|
||||||
"100"
|
"105"
|
||||||
],
|
],
|
||||||
"nozzle_temperature": [
|
"nozzle_temperature": [
|
||||||
"300"
|
"300"
|
||||||
@@ -81,10 +81,10 @@
|
|||||||
"110"
|
"110"
|
||||||
],
|
],
|
||||||
"textured_plate_temp": [
|
"textured_plate_temp": [
|
||||||
"100"
|
"105"
|
||||||
],
|
],
|
||||||
"textured_plate_temp_initial_layer": [
|
"textured_plate_temp_initial_layer": [
|
||||||
"100"
|
"105"
|
||||||
],
|
],
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"ABS"
|
"ABS"
|
||||||
|
|||||||
@@ -9,10 +9,10 @@
|
|||||||
""
|
""
|
||||||
],
|
],
|
||||||
"hot_plate_temp": [
|
"hot_plate_temp": [
|
||||||
"100"
|
"110"
|
||||||
],
|
],
|
||||||
"hot_plate_temp_initial_layer": [
|
"hot_plate_temp_initial_layer": [
|
||||||
"100"
|
"105"
|
||||||
],
|
],
|
||||||
"overhang_fan_speed": [
|
"overhang_fan_speed": [
|
||||||
"20"
|
"20"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
""
|
""
|
||||||
],
|
],
|
||||||
"hot_plate_temp": [
|
"hot_plate_temp": [
|
||||||
"100"
|
"110"
|
||||||
],
|
],
|
||||||
"hot_plate_temp_initial_layer": [
|
"hot_plate_temp_initial_layer": [
|
||||||
"100"
|
"100"
|
||||||
|
|||||||
@@ -2010,19 +2010,21 @@ int CLI::run(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto resolve_preset = [&ensure_cli_preset_bundle](const std::string &file, DynamicPrintConfig &config,
|
// One resolver for the whole run, so presets from the same vendor tree share its load.
|
||||||
|
std::unique_ptr<PresetBundle> system_preset_resolver;
|
||||||
|
auto resolve_preset = [&ensure_cli_preset_bundle, &system_preset_resolver](const std::string &file, DynamicPrintConfig &config,
|
||||||
std::string &config_type, const std::string &config_from,
|
std::string &config_type, const std::string &config_from,
|
||||||
bool probe_type, std::string &error) {
|
bool probe_type, std::string &error) {
|
||||||
const auto *inherits = config.option<ConfigOptionString>(BBL_JSON_KEY_INHERITS);
|
const auto *inherits = config.option<ConfigOptionString>(BBL_JSON_KEY_INHERITS);
|
||||||
if (!probe_type && (inherits == nullptr || inherits->value.empty()))
|
if (!probe_type && (inherits == nullptr || inherits->value.empty()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
std::unique_ptr<PresetBundle> source_bundle;
|
|
||||||
PresetBundle *bundle = nullptr;
|
PresetBundle *bundle = nullptr;
|
||||||
bool allow_source_manifest = false;
|
bool allow_source_manifest = false;
|
||||||
if (config_from == "system") {
|
if (config_from == "system") {
|
||||||
source_bundle = std::make_unique<PresetBundle>();
|
if (!system_preset_resolver)
|
||||||
bundle = source_bundle.get();
|
system_preset_resolver = std::make_unique<PresetBundle>();
|
||||||
|
bundle = system_preset_resolver.get();
|
||||||
allow_source_manifest = true;
|
allow_source_manifest = true;
|
||||||
} else {
|
} else {
|
||||||
bundle = ensure_cli_preset_bundle(error);
|
bundle = ensure_cli_preset_bundle(error);
|
||||||
|
|||||||
@@ -1595,25 +1595,6 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc
|
|||||||
return sparse_infill_polylines;
|
return sparse_infill_polylines;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the filament id (1-based) the region is ironed with, or -1 when the
|
|
||||||
// region is not ironed. AllSolid always irons. TopSurfaces and TopmostOnly need
|
|
||||||
// either some top shells or, in spiral mode, more than one bottom shell, and
|
|
||||||
// TopmostOnly additionally needs the layer to be the topmost one.
|
|
||||||
int Layer::choose_ironing_extruder(const PrintRegionConfig &cfg,
|
|
||||||
bool spiral_mode,
|
|
||||||
bool is_topmost_layer)
|
|
||||||
{
|
|
||||||
if (cfg.ironing_type == IroningType::NoIroning)
|
|
||||||
return -1;
|
|
||||||
const bool gate = (cfg.ironing_type == IroningType::AllSolid)
|
|
||||||
|| ((cfg.top_shell_layers > 0 || (spiral_mode && cfg.bottom_shell_layers > 1))
|
|
||||||
&& (cfg.ironing_type == IroningType::TopSurfaces
|
|
||||||
|| (cfg.ironing_type == IroningType::TopmostOnly && is_topmost_layer)));
|
|
||||||
if (!gate)
|
|
||||||
return -1;
|
|
||||||
return cfg.top_surface_filament_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create ironing extrusions over top surfaces.
|
// Create ironing extrusions over top surfaces.
|
||||||
void Layer::make_ironing()
|
void Layer::make_ironing()
|
||||||
{
|
{
|
||||||
@@ -1683,10 +1664,19 @@ void Layer::make_ironing()
|
|||||||
if (! layerm->slices.empty()) {
|
if (! layerm->slices.empty()) {
|
||||||
IroningParams ironing_params;
|
IroningParams ironing_params;
|
||||||
const PrintRegionConfig &config = layerm->region().config();
|
const PrintRegionConfig &config = layerm->region().config();
|
||||||
ironing_params.extruder = Layer::choose_ironing_extruder(
|
if (config.ironing_type != IroningType::NoIroning &&
|
||||||
config,
|
(config.ironing_type == IroningType::AllSolid ||
|
||||||
/*spiral_mode=*/this->object()->print()->config().spiral_mode,
|
((config.top_shell_layers > 0 || (this->object()->print()->config().spiral_mode && config.bottom_shell_layers > 1)) &&
|
||||||
/*is_topmost_layer=*/layerm->layer()->upper_layer == nullptr);
|
(config.ironing_type == IroningType::TopSurfaces ||
|
||||||
|
(config.ironing_type == IroningType::TopmostOnly && layerm->layer()->upper_layer == nullptr))))) {
|
||||||
|
if (config.outer_wall_filament_id == config.top_surface_filament_id || config.wall_loops == 0) {
|
||||||
|
// Iron the whole face.
|
||||||
|
ironing_params.extruder = config.top_surface_filament_id;
|
||||||
|
} else {
|
||||||
|
// Iron just the infill.
|
||||||
|
ironing_params.extruder = config.top_surface_filament_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (ironing_params.extruder != -1) {
|
if (ironing_params.extruder != -1) {
|
||||||
//TODO just_infill is currently not used.
|
//TODO just_infill is currently not used.
|
||||||
ironing_params.just_infill = false;
|
ironing_params.just_infill = false;
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ using LayerPtrs = std::vector<Layer*>;
|
|||||||
class LayerRegion;
|
class LayerRegion;
|
||||||
using LayerRegionPtrs = std::vector<LayerRegion*>;
|
using LayerRegionPtrs = std::vector<LayerRegion*>;
|
||||||
class PrintRegion;
|
class PrintRegion;
|
||||||
class PrintRegionConfig;
|
|
||||||
class PrintObject;
|
class PrintObject;
|
||||||
class Print;
|
class Print;
|
||||||
|
|
||||||
@@ -201,11 +200,6 @@ public:
|
|||||||
FillAdaptive::Octree *support_fill_octree,
|
FillAdaptive::Octree *support_fill_octree,
|
||||||
FillLightning::Generator* lightning_generator) const;
|
FillLightning::Generator* lightning_generator) const;
|
||||||
void make_ironing();
|
void make_ironing();
|
||||||
// Returns the filament id (1-based) the region is ironed with, or -1 when the
|
|
||||||
// region is not ironed.
|
|
||||||
static int choose_ironing_extruder(const PrintRegionConfig &cfg,
|
|
||||||
bool spiral_mode,
|
|
||||||
bool is_topmost_layer);
|
|
||||||
void make_contour_z(const sla::IndexedMesh &mesh);
|
void make_contour_z(const sla::IndexedMesh &mesh);
|
||||||
|
|
||||||
void export_region_slices_to_svg(const char *path) const;
|
void export_region_slices_to_svg(const char *path) const;
|
||||||
|
|||||||
@@ -549,30 +549,11 @@ bool PresetBundle::resolve_preset_config(DynamicPrintConfig &config, Preset::Typ
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PresetBundle library_bundle;
|
const SourceManifestBundles *loaded = load_source_manifest(root_dir, vendor_id, compatibility_rule, error);
|
||||||
const PresetBundle *base_bundle = nullptr;
|
if (loaded == nullptr)
|
||||||
if (vendor_id != ORCA_FILAMENT_LIBRARY &&
|
|
||||||
boost::filesystem::is_regular_file(root_dir / (std::string(ORCA_FILAMENT_LIBRARY) + ".json"))) {
|
|
||||||
library_bundle.m_preserve_vendor_source_paths = true;
|
|
||||||
library_bundle.load_vendor_configs_from_json(root_dir.string(), ORCA_FILAMENT_LIBRARY, LoadSystem,
|
|
||||||
compatibility_rule, nullptr, false);
|
|
||||||
if (library_bundle.error_count() != 0) {
|
|
||||||
error = "OrcaFilamentLibrary contains invalid presets";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
base_bundle = &library_bundle;
|
|
||||||
}
|
|
||||||
|
|
||||||
PresetBundle source_bundle;
|
|
||||||
source_bundle.m_preserve_vendor_source_paths = true;
|
|
||||||
source_bundle.load_vendor_configs_from_json(root_dir.string(), vendor_id, LoadSystem,
|
|
||||||
compatibility_rule, base_bundle, false);
|
|
||||||
if (source_bundle.error_count() != 0) {
|
|
||||||
error = "Vendor bundle contains invalid presets";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
const Preset *resolved = find_loaded(source_bundle);
|
const Preset *resolved = find_loaded(*loaded->vendor);
|
||||||
if (resolved == nullptr) {
|
if (resolved == nullptr) {
|
||||||
if (error.empty())
|
if (error.empty())
|
||||||
error = "Source file is not an instantiated preset in its vendor manifest";
|
error = "Source file is not an instantiated preset in its vendor manifest";
|
||||||
@@ -591,6 +572,39 @@ bool PresetBundle::resolve_preset_config(DynamicPrintConfig &config, Preset::Typ
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PresetBundle::SourceManifestBundles *PresetBundle::load_source_manifest(const boost::filesystem::path &root_dir,
|
||||||
|
const std::string &vendor_id,
|
||||||
|
ForwardCompatibilitySubstitutionRule compatibility_rule,
|
||||||
|
std::string &error)
|
||||||
|
{
|
||||||
|
auto key = std::make_tuple(root_dir.string(), vendor_id, static_cast<int>(compatibility_rule));
|
||||||
|
if (auto it = m_source_manifest_bundles.find(key); it != m_source_manifest_bundles.end())
|
||||||
|
return &it->second;
|
||||||
|
|
||||||
|
SourceManifestBundles loaded;
|
||||||
|
if (vendor_id != ORCA_FILAMENT_LIBRARY &&
|
||||||
|
boost::filesystem::is_regular_file(root_dir / (std::string(ORCA_FILAMENT_LIBRARY) + ".json"))) {
|
||||||
|
loaded.library = std::make_unique<PresetBundle>();
|
||||||
|
loaded.library->m_preserve_vendor_source_paths = true;
|
||||||
|
loaded.library->load_vendor_configs_from_json(root_dir.string(), ORCA_FILAMENT_LIBRARY, LoadSystem,
|
||||||
|
compatibility_rule, nullptr, false);
|
||||||
|
if (loaded.library->error_count() != 0) {
|
||||||
|
error = "OrcaFilamentLibrary contains invalid presets";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loaded.vendor = std::make_unique<PresetBundle>();
|
||||||
|
loaded.vendor->m_preserve_vendor_source_paths = true;
|
||||||
|
loaded.vendor->load_vendor_configs_from_json(root_dir.string(), vendor_id, LoadSystem,
|
||||||
|
compatibility_rule, loaded.library.get(), false);
|
||||||
|
if (loaded.vendor->error_count() != 0) {
|
||||||
|
error = "Vendor bundle contains invalid presets";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &m_source_manifest_bundles.emplace(std::move(key), std::move(loaded)).first->second;
|
||||||
|
}
|
||||||
|
|
||||||
bool PresetBundle::resolve_preset_config_type(DynamicPrintConfig &config, Preset::Type &type,
|
bool PresetBundle::resolve_preset_config_type(DynamicPrintConfig &config, Preset::Type &type,
|
||||||
const std::string &source_file,
|
const std::string &source_file,
|
||||||
ForwardCompatibilitySubstitutionRule compatibility_rule,
|
ForwardCompatibilitySubstitutionRule compatibility_rule,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
|
#include <tuple>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <array>
|
#include <array>
|
||||||
@@ -652,6 +653,19 @@ private:
|
|||||||
bool m_generate_vendor_caches { false };
|
bool m_generate_vendor_caches { false };
|
||||||
bool m_preserve_vendor_source_paths { false };
|
bool m_preserve_vendor_source_paths { false };
|
||||||
|
|
||||||
|
// Vendor trees loaded by resolve_preset_config's manifest path, so every preset
|
||||||
|
// resolved through this bundle shares one load per source root and vendor.
|
||||||
|
struct SourceManifestBundles {
|
||||||
|
std::unique_ptr<PresetBundle> library;
|
||||||
|
std::unique_ptr<PresetBundle> vendor;
|
||||||
|
};
|
||||||
|
std::map<std::tuple<std::string, std::string, int>, SourceManifestBundles> m_source_manifest_bundles;
|
||||||
|
|
||||||
|
const SourceManifestBundles *load_source_manifest(const boost::filesystem::path &root_dir,
|
||||||
|
const std::string &vendor_id,
|
||||||
|
ForwardCompatibilitySubstitutionRule compatibility_rule,
|
||||||
|
std::string &error);
|
||||||
|
|
||||||
// Orca: validation only - flag any printer with two or more compatible
|
// Orca: validation only - flag any printer with two or more compatible
|
||||||
// filament presets sharing one filament_id (ambiguous AMS subtype match).
|
// filament presets sharing one filament_id (ambiguous AMS subtype match).
|
||||||
bool check_duplicate_filament_subtypes() const;
|
bool check_duplicate_filament_subtypes() const;
|
||||||
|
|||||||
@@ -1037,6 +1037,9 @@ size_t PublishSettingsDialog::section_group_for(Section kind)
|
|||||||
section.mixed_tabs = new TabCtrl(section.page, wxID_ANY, wxDefaultPosition, wxDefaultSize, s_tab_style);
|
section.mixed_tabs = new TabCtrl(section.page, wxID_ANY, wxDefaultPosition, wxDefaultSize, s_tab_style);
|
||||||
section.mixed_tabs->SetFont(Label::Body_14);
|
section.mixed_tabs->SetFont(Label::Body_14);
|
||||||
section.mixed_tabs->SetBackgroundColour(GetBackgroundColour());
|
section.mixed_tabs->SetBackgroundColour(GetBackgroundColour());
|
||||||
|
// The mixed tabs carry full swatch compositions: give them a touch more room than the
|
||||||
|
// filament tabs so neighbouring compositions stay distinguishable (must precede AppendItem).
|
||||||
|
section.mixed_tabs->SetItemSpace(FromDIP(3));
|
||||||
page_sizer->Add(section.mixed_tabs, 0, wxEXPAND | wxTOP, FromDIP(2));
|
page_sizer->Add(section.mixed_tabs, 0, wxEXPAND | wxTOP, FromDIP(2));
|
||||||
section.mixed_tabs->Hide();
|
section.mixed_tabs->Hide();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -311,11 +311,8 @@ void Button::render(wxDC& dc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto szContent = textSize;
|
auto szContent = textSize;
|
||||||
// Whether the measured content reserved the text/icon gap. macOS measures an empty label
|
|
||||||
// as 0-high, so the gap is skipped there; the dot must not advance past it in that case.
|
|
||||||
const bool gap_reserved = szContent.y > 0;
|
|
||||||
if (icon.bmp().IsOk()) {
|
if (icon.bmp().IsOk()) {
|
||||||
if (gap_reserved) {
|
if (szContent.y > 0) {
|
||||||
//BBS norrow size between text and icon
|
//BBS norrow size between text and icon
|
||||||
if (vertical)
|
if (vertical)
|
||||||
szContent.y += spacing;
|
szContent.y += spacing;
|
||||||
@@ -360,10 +357,10 @@ void Button::render(wxDC& dc)
|
|||||||
dc.DrawBitmap(icon.bmp(), pt);
|
dc.DrawBitmap(icon.bmp(), pt);
|
||||||
//BBS norrow size between text and icon
|
//BBS norrow size between text and icon
|
||||||
if (vertical) {
|
if (vertical) {
|
||||||
pt.y += szIcon.y + (gap_reserved ? spacing : 0);
|
pt.y += szIcon.y + spacing;
|
||||||
pt.x = rcContent.x;
|
pt.x = rcContent.x;
|
||||||
} else {
|
} else {
|
||||||
pt.x += szIcon.x + (gap_reserved ? spacing : 0);
|
pt.x += szIcon.x + spacing;
|
||||||
pt.y = rcContent.y;
|
pt.y = rcContent.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ int TabCtrl::AppendItem(const wxString& item, int image, int selImage, void* cli
|
|||||||
btns.push_back(btn);
|
btns.push_back(btn);
|
||||||
if (btns.size() > 1)
|
if (btns.size() > 1)
|
||||||
sizer->GetItem(sizer->GetItemCount() - 1)->SetMinSize({0, 0});
|
sizer->GetItem(sizer->GetItemCount() - 1)->SetMinSize({0, 0});
|
||||||
sizer->Add(btn, 0, wxALIGN_CENTER_VERTICAL);
|
sizer->Add(btn, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, item_space);
|
||||||
sizer->AddStretchSpacer(1);
|
sizer->AddStretchSpacer(1);
|
||||||
relayout();
|
relayout();
|
||||||
return btns.size() - 1;
|
return btns.size() - 1;
|
||||||
@@ -256,12 +256,12 @@ void TabCtrl::relayout()
|
|||||||
int item = sel + 1;
|
int item = sel + 1;
|
||||||
int first = 0;
|
int first = 0;
|
||||||
for (int i = 0; i < item; ++i)
|
for (int i = 0; i < item; ++i)
|
||||||
offset += btns[i]->GetMinSize().x;
|
offset += btns[i]->GetMinSize().x + item_space * 2;
|
||||||
if (item < btns.size())
|
if (item < btns.size())
|
||||||
offset += btns[item]->GetMinSize().x;
|
offset += btns[item]->GetMinSize().x + item_space * 2;
|
||||||
int width = GetSize().x;
|
int width = GetSize().x;
|
||||||
for (int i = 0; i < btns.size(); ++i) {
|
for (int i = 0; i < btns.size(); ++i) {
|
||||||
auto size = btns[i]->GetMinSize().x;
|
auto size = btns[i]->GetMinSize().x + item_space * 2;
|
||||||
if (i < sel && offset > width) {
|
if (i < sel && offset > width) {
|
||||||
sizer->Show(i * 2 + 1, false);
|
sizer->Show(i * 2 + 1, false);
|
||||||
sizer->Show(i * 2 + 2, false);
|
sizer->Show(i * 2 + 2, false);
|
||||||
@@ -284,17 +284,26 @@ void TabCtrl::relayout()
|
|||||||
if (item >= btns.size())
|
if (item >= btns.size())
|
||||||
--item;
|
--item;
|
||||||
// Keep spacing 2 ~ 10 TAB_BUTTON_SPACE
|
// Keep spacing 2 ~ 10 TAB_BUTTON_SPACE
|
||||||
int b = GetSize().x - offset - 10 - (item + 1 - first) * 16;
|
int b = GetSize().x - offset - 10 - (item + 1 - first) * item_space * 8;
|
||||||
sizer->GetItem(item * 2 + 2)->SetMinSize({b > 0 ? b : 0, 0});
|
sizer->GetItem(item * 2 + 2)->SetMinSize({b > 0 ? b : 0, 0});
|
||||||
Layout();
|
Layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabCtrl::SetItemSpace(int space)
|
||||||
|
{
|
||||||
|
if (space < 0 || space == item_space)
|
||||||
|
return;
|
||||||
|
item_space = space;
|
||||||
|
relayout();
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
int TabCtrl::GetFullSize() const
|
int TabCtrl::GetFullSize() const
|
||||||
{
|
{
|
||||||
// Mirrors relayout(): a 10px leading spacer plus every button's min width.
|
// Mirrors relayout(): a 10px leading spacer plus every button's min width and spacing.
|
||||||
int width = 10;
|
int width = 10;
|
||||||
for (const Button* btn : btns)
|
for (const Button* btn : btns)
|
||||||
width += btn->GetMinSize().x;
|
width += btn->GetMinSize().x + item_space * 2;
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ class TabCtrl : public StaticBox
|
|||||||
|
|
||||||
int sel = -1;
|
int sel = -1;
|
||||||
wxFont bold;
|
wxFont bold;
|
||||||
|
int item_space = 2; // space around each button, both sides (SetItemSpace)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TabCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0);
|
TabCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0);
|
||||||
@@ -63,6 +64,10 @@ public:
|
|||||||
int GetNextVisible(int item) const;
|
int GetNextVisible(int item) const;
|
||||||
bool IsVisible(unsigned int item) const;
|
bool IsVisible(unsigned int item) const;
|
||||||
|
|
||||||
|
// Extra space around each tab button (in px on both sides). Defaults to the control-wide
|
||||||
|
// standard; call before appending items so every button picks it up.
|
||||||
|
void SetItemSpace(int space);
|
||||||
|
|
||||||
int GetFullSize() const;
|
int GetFullSize() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
#include "libslic3r/Geometry.hpp"
|
#include "libslic3r/Geometry.hpp"
|
||||||
#include "libslic3r/Layer.hpp"
|
#include "libslic3r/Layer.hpp"
|
||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
#include "libslic3r/PrintConfig.hpp"
|
|
||||||
#include "libslic3r/SVG.hpp"
|
#include "libslic3r/SVG.hpp"
|
||||||
#include "libslic3r/libslic3r.h"
|
#include "libslic3r/libslic3r.h"
|
||||||
|
|
||||||
@@ -677,73 +676,6 @@ TEST_CASE("Ironing follows the solid infill rotation template", "[Fill]")
|
|||||||
REQUIRE(compared > int(ironing.size()) / 2);
|
REQUIRE(compared > int(ironing.size()) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
PrintRegionConfig ironing_config(IroningType type,
|
|
||||||
int top_surface_filament_id = 1,
|
|
||||||
int top_shell_layers = 3,
|
|
||||||
int bottom_shell_layers = 1)
|
|
||||||
{
|
|
||||||
PrintRegionConfig cfg;
|
|
||||||
cfg.ironing_type.value = type;
|
|
||||||
cfg.top_surface_filament_id.value = top_surface_filament_id;
|
|
||||||
cfg.top_shell_layers.value = top_shell_layers;
|
|
||||||
cfg.bottom_shell_layers.value = bottom_shell_layers;
|
|
||||||
cfg.outer_wall_filament_id.value = 1;
|
|
||||||
cfg.wall_loops.value = 2;
|
|
||||||
return cfg;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
TEST_CASE("Ironing an all-solid region uses the top surface filament on every layer", "[Fill]")
|
|
||||||
{
|
|
||||||
const PrintRegionConfig cfg = ironing_config(IroningType::AllSolid, /*top_surface_filament_id=*/2);
|
|
||||||
const bool is_topmost_layer = GENERATE(false, true);
|
|
||||||
CAPTURE(is_topmost_layer);
|
|
||||||
REQUIRE(Layer::choose_ironing_extruder(cfg, /*spiral_mode=*/false, is_topmost_layer) == 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Ironing top surfaces uses the top surface filament when the region has top shells", "[Fill]")
|
|
||||||
{
|
|
||||||
const PrintRegionConfig cfg = ironing_config(IroningType::TopSurfaces,
|
|
||||||
/*top_surface_filament_id=*/3,
|
|
||||||
/*top_shell_layers=*/2);
|
|
||||||
REQUIRE(Layer::choose_ironing_extruder(cfg, /*spiral_mode=*/false, /*is_topmost_layer=*/false) == 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Ironing top surfaces without top shells needs spiral mode and more than one bottom shell", "[Fill]")
|
|
||||||
{
|
|
||||||
const PrintRegionConfig one_bottom_shell = ironing_config(IroningType::TopSurfaces,
|
|
||||||
/*top_surface_filament_id=*/1,
|
|
||||||
/*top_shell_layers=*/0,
|
|
||||||
/*bottom_shell_layers=*/1);
|
|
||||||
const PrintRegionConfig two_bottom_shells = ironing_config(IroningType::TopSurfaces,
|
|
||||||
/*top_surface_filament_id=*/1,
|
|
||||||
/*top_shell_layers=*/0,
|
|
||||||
/*bottom_shell_layers=*/2);
|
|
||||||
|
|
||||||
REQUIRE(Layer::choose_ironing_extruder(two_bottom_shells, /*spiral_mode=*/true, /*is_topmost_layer=*/false) == 1);
|
|
||||||
REQUIRE(Layer::choose_ironing_extruder(one_bottom_shell, /*spiral_mode=*/true, /*is_topmost_layer=*/false) == -1);
|
|
||||||
REQUIRE(Layer::choose_ironing_extruder(two_bottom_shells, /*spiral_mode=*/false, /*is_topmost_layer=*/false) == -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Ironing the topmost surface only applies to the topmost layer", "[Fill]")
|
|
||||||
{
|
|
||||||
const PrintRegionConfig cfg = ironing_config(IroningType::TopmostOnly, /*top_surface_filament_id=*/4);
|
|
||||||
REQUIRE(Layer::choose_ironing_extruder(cfg, /*spiral_mode=*/false, /*is_topmost_layer=*/true) == 4);
|
|
||||||
REQUIRE(Layer::choose_ironing_extruder(cfg, /*spiral_mode=*/false, /*is_topmost_layer=*/false) == -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("A region with ironing turned off is never ironed", "[Fill]")
|
|
||||||
{
|
|
||||||
const PrintRegionConfig cfg = ironing_config(IroningType::NoIroning);
|
|
||||||
const bool spiral_mode = GENERATE(false, true);
|
|
||||||
CAPTURE(spiral_mode);
|
|
||||||
REQUIRE(Layer::choose_ironing_extruder(cfg, spiral_mode, /*is_topmost_layer=*/true) == -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Solid infill direction offsets every layer when no template is set", "[Fill]")
|
TEST_CASE("Solid infill direction offsets every layer when no template is set", "[Fill]")
|
||||||
{
|
{
|
||||||
auto angles_for = [](int direction) {
|
auto angles_for = [](int direction) {
|
||||||
|
|||||||
@@ -987,6 +987,137 @@ TEST_CASE("Resolution terminates when no vendor manifest exists", "[Preset][Bund
|
|||||||
CHECK(error == "Preset was not found in the loaded bundle");
|
CHECK(error == "Preset was not found in the loaded bundle");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Manifest-backed resolution reuses the vendor tree it already loaded", "[Preset][Bundle][Regression]")
|
||||||
|
{
|
||||||
|
ScopedTemporaryDir dir;
|
||||||
|
const fs::path process_dir = dir.path() / "Acme" / "process";
|
||||||
|
fs::create_directories(process_dir);
|
||||||
|
std::ofstream((dir.path() / "Acme.json").string())
|
||||||
|
<< R"({"version":"1.0.0","name":"Acme","process_list":[)"
|
||||||
|
<< R"({"name":"fdm_process_common","sub_path":"process/base.json"},)"
|
||||||
|
<< R"({"name":"Acme First","sub_path":"process/first.json"},)"
|
||||||
|
<< R"({"name":"Acme Second","sub_path":"process/second.json"}]})";
|
||||||
|
auto write_base = [&](double travel_speed) {
|
||||||
|
std::ofstream((process_dir / "base.json").string())
|
||||||
|
<< R"({"type":"process","name":"fdm_process_common","from":"system",)"
|
||||||
|
<< R"("instantiation":"false","travel_speed":[")" << travel_speed << R"("]})";
|
||||||
|
};
|
||||||
|
auto write_child = [&](const std::string &file, const std::string &name) {
|
||||||
|
std::ofstream((process_dir / file).string())
|
||||||
|
<< R"({"type":"process","name":")" << name << R"(","from":"system",)"
|
||||||
|
<< R"("instantiation":"true","inherits":"fdm_process_common"})";
|
||||||
|
};
|
||||||
|
write_base(111.0);
|
||||||
|
write_child("first.json", "Acme First");
|
||||||
|
write_child("second.json", "Acme Second");
|
||||||
|
|
||||||
|
auto travel_speed = [&](PresetBundle &bundle, const std::string &file) {
|
||||||
|
DynamicPrintConfig raw;
|
||||||
|
raw.option<ConfigOptionString>(BBL_JSON_KEY_INHERITS, true)->value = "fdm_process_common";
|
||||||
|
std::string error;
|
||||||
|
REQUIRE(bundle.resolve_preset_config(raw, Preset::TYPE_PRINT, (process_dir / file).string(),
|
||||||
|
ForwardCompatibilitySubstitutionRule::EnableSilent, error));
|
||||||
|
return raw.option<ConfigOptionFloats>("travel_speed")->values.front();
|
||||||
|
};
|
||||||
|
|
||||||
|
PresetBundle bundle;
|
||||||
|
CHECK_THAT(travel_speed(bundle, "first.json"), Catch::Matchers::WithinAbs(111.0, 1e-6));
|
||||||
|
|
||||||
|
// Only a reload would see this change.
|
||||||
|
write_base(222.0);
|
||||||
|
CHECK_THAT(travel_speed(bundle, "second.json"), Catch::Matchers::WithinAbs(111.0, 1e-6));
|
||||||
|
|
||||||
|
PresetBundle fresh;
|
||||||
|
CHECK_THAT(travel_speed(fresh, "second.json"), Catch::Matchers::WithinAbs(222.0, 1e-6));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Manifest-backed resolution does not keep a vendor tree that failed to load", "[Preset][Bundle][Regression]")
|
||||||
|
{
|
||||||
|
ScopedTemporaryDir dir;
|
||||||
|
const fs::path child_file = dir.path() / "Acme" / "process" / "child.json";
|
||||||
|
auto write_manifest = [&](const std::string &leading_entry) {
|
||||||
|
std::ofstream((dir.path() / "Acme.json").string())
|
||||||
|
<< R"({"version":"1.0.0","name":"Acme","process_list":[)" << leading_entry
|
||||||
|
<< R"({"name":"Acme Process","sub_path":"process/child.json"}]})";
|
||||||
|
};
|
||||||
|
write_manifest("123,");
|
||||||
|
fs::create_directories(child_file.parent_path());
|
||||||
|
std::ofstream(child_file.string())
|
||||||
|
<< R"({"type":"process","name":"Acme Process","from":"system",)"
|
||||||
|
<< R"("instantiation":"true","layer_height":"0.2"})";
|
||||||
|
|
||||||
|
PresetBundle bundle;
|
||||||
|
auto resolve = [&](std::string &error) {
|
||||||
|
DynamicPrintConfig raw;
|
||||||
|
raw.option<ConfigOptionString>(BBL_JSON_KEY_INHERITS, true)->value = "fdm_process_common";
|
||||||
|
return bundle.resolve_preset_config(raw, Preset::TYPE_PRINT, child_file.string(),
|
||||||
|
ForwardCompatibilitySubstitutionRule::EnableSilent, error);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string error;
|
||||||
|
CHECK_FALSE(resolve(error));
|
||||||
|
CHECK_FALSE(error.empty());
|
||||||
|
|
||||||
|
write_manifest("");
|
||||||
|
error.clear();
|
||||||
|
CHECK(resolve(error));
|
||||||
|
CHECK(error.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Manifest-backed resolution reuses the library base for type-probed files", "[Preset][Bundle][Regression]")
|
||||||
|
{
|
||||||
|
ScopedTemporaryDir dir;
|
||||||
|
const fs::path library_pet = dir.path() / PresetBundle::ORCA_FILAMENT_LIBRARY / "filament" / "pet.json";
|
||||||
|
const fs::path filament_dir = dir.path() / "Acme" / "filament";
|
||||||
|
|
||||||
|
std::ofstream((dir.path() / (std::string(PresetBundle::ORCA_FILAMENT_LIBRARY) + ".json")).string())
|
||||||
|
<< R"({"version":"1.0.0","name":"OrcaFilamentLibrary","filament_list":[)"
|
||||||
|
<< R"({"name":"fdm_filament_pet","sub_path":"filament/pet.json","filament_id":"GFL99"}]})";
|
||||||
|
fs::create_directories(library_pet.parent_path());
|
||||||
|
auto write_library_pet = [&](double density) {
|
||||||
|
std::ofstream(library_pet.string())
|
||||||
|
<< R"({"type":"filament","name":"fdm_filament_pet","from":"system",)"
|
||||||
|
<< R"("filament_id":"GFL99","instantiation":"false",)"
|
||||||
|
<< R"("filament_type":["PETG"],"filament_density":[")" << density << R"("]})";
|
||||||
|
};
|
||||||
|
write_library_pet(1.27);
|
||||||
|
|
||||||
|
std::ofstream((dir.path() / "Acme.json").string())
|
||||||
|
<< R"({"version":"1.0.0","name":"Acme","filament_list":[)"
|
||||||
|
<< R"({"name":"Acme PETG","sub_path":"filament/petg.json","filament_id":"GFA00"},)"
|
||||||
|
<< R"({"name":"Acme PETG Matte","sub_path":"filament/petg_matte.json","filament_id":"GFA01"}]})";
|
||||||
|
fs::create_directories(filament_dir);
|
||||||
|
auto write_child = [&](const std::string &file, const std::string &name, const std::string &filament_id) {
|
||||||
|
std::ofstream((filament_dir / file).string())
|
||||||
|
<< R"({"type":"filament","name":")" << name << R"(","from":"system",)"
|
||||||
|
<< R"("filament_id":")" << filament_id << R"(","instantiation":"true","inherits":"fdm_filament_pet"})";
|
||||||
|
};
|
||||||
|
write_child("petg.json", "Acme PETG", "GFA00");
|
||||||
|
write_child("petg_matte.json", "Acme PETG Matte", "GFA01");
|
||||||
|
|
||||||
|
auto density = [](const DynamicPrintConfig &config) {
|
||||||
|
return config.option<ConfigOptionFloats>("filament_density")->values.front();
|
||||||
|
};
|
||||||
|
|
||||||
|
PresetBundle bundle;
|
||||||
|
DynamicPrintConfig first;
|
||||||
|
first.option<ConfigOptionString>(BBL_JSON_KEY_INHERITS, true)->value = "fdm_filament_pet";
|
||||||
|
std::string error;
|
||||||
|
REQUIRE(bundle.resolve_preset_config(first, Preset::TYPE_FILAMENT, (filament_dir / "petg.json").string(),
|
||||||
|
ForwardCompatibilitySubstitutionRule::EnableSilent, error));
|
||||||
|
CHECK_THAT(density(first), Catch::Matchers::WithinAbs(1.27, 1e-6));
|
||||||
|
|
||||||
|
// Only a reload would see this change.
|
||||||
|
write_library_pet(1.5);
|
||||||
|
|
||||||
|
DynamicPrintConfig second;
|
||||||
|
Preset::Type type = Preset::TYPE_INVALID;
|
||||||
|
REQUIRE(bundle.resolve_preset_config_type(second, type, (filament_dir / "petg_matte.json").string(),
|
||||||
|
ForwardCompatibilitySubstitutionRule::EnableSilent, error));
|
||||||
|
CHECK(type == Preset::TYPE_FILAMENT);
|
||||||
|
CHECK_THAT(density(second), Catch::Matchers::WithinAbs(1.27, 1e-6));
|
||||||
|
}
|
||||||
|
|
||||||
// Orca: a filament in the Orca Filament Library that names its compatible printers has to hide the generic
|
// Orca: a filament in the Orca Filament Library that names its compatible printers has to hide the generic
|
||||||
// library filament sharing its alias, the same way a vendor owned filament does. Otherwise both are compatible
|
// library filament sharing its alias, the same way a vendor owned filament does. Otherwise both are compatible
|
||||||
// with that printer and the plater combo box lists the shared alias twice.
|
// with that printer and the plater combo box lists the shared alias twice.
|
||||||
|
|||||||
Reference in New Issue
Block a user