Compare commits

...

41 Commits

Author SHA1 Message Date
ExPikaPaka
2f67e46047 fix(codegen): drop grpcio-tools, stop committing generated code
The codegen only ever needed a protoc binary, but every entry point installed
grpcio-tools to get one. That drags in the grpcio C extension, which has no
Windows/ARM64 wheel and falls back to building from source there, so the ARM64
job died with "Failed building wheel for grpcio" -> "protoc not found".

tools/codegen_toolchain.py resolves the toolchain instead: protoc from $PROTOC,
PATH, a cache, grpc_tools when already installed, or a pinned checksum-verified
protoc release unpacked into .codegen-tools/; protobuf and pyyaml from the
calling interpreter or a cached virtualenv it re-execs into (distro Pythons
refuse `pip install` under PEP 668). All four build scripts and all three CI
jobs are now just `python tools/run_codegen.py`, with no pip lines around it.

tools/config_metadata_pb2.py was the one generated file checked into git. The
orca.* option extensions are now read out of the descriptor set, which already
carries config_metadata.proto via --include_imports, so nothing is generated
into the tree -- and the protobuf>=6.33.5,<7 CI pin goes away with it, since it
only existed to satisfy gencode's hard ValidateProtobufRuntimeVersion check.
Generated C++ verified byte-identical under upb and the pure-Python protobuf
runtime (what win/arm64 installs), and under both grpc_tools' and standalone
protoc.

Also fixed:
- build_release_macos.sh still passed -DPython3_EXECUTABLE=<codegen venv>,
  pointing the bundled *embed* interpreter at the codegen environment -- the
  same confusion fae4b124 fixed on the CMake side.
- Tab.cpp #includes TabLayout_generated.cpp but had no dependency on
  codegen_config, so an incremental build after a .proto edit could compile it
  while the file was being rewritten. libslic3r already had this guard.
- ConfigCodegen.cmake now probes with `codegen_toolchain.py --check` (which
  never downloads or installs), prefers a host interpreter over the embed one,
  and lets a fresh clone generate at configure time instead of erroring out.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 12:53:05 +02:00
ExPikaPaka
fae4b1241b fix(codegen): don't run build-time codegen with the embed Python (fixes CI build)
main forces Python3_EXECUTABLE to the bundled *embed* interpreter (for the
in-app Python plugin runtime). ConfigCodegen.cmake used that same interpreter to
regenerate the config sources at build time, but the embed Python has no protoc
/ protobuf / pyyaml (and for cross-compiled targets isn't even the host arch),
so ninja's "Re-generating config C++ from changed .proto files" step failed with
"protoc not found" on every platform — even though the workflow's dedicated
codegen step had already generated the files.

Probe whether the interpreter can actually run the codegen (protobuf importable
AND a protoc available, standalone or via grpc_tools). Only wire up the
auto-regenerating custom command when it can; otherwise use the already-generated
files as-is (with a no-op codegen_config target) and only error if they are
missing. Adds ORCA_CODEGEN_PYTHON to let a build point at a tools-capable
interpreter independent of the embed one.

Generated files remain gitignored; the CI "Install codegen tools and generate
config sources" step still produces them before the build.
2026-07-28 10:17:59 +02:00
ExPikaPaka
5a5c25b8d1 ci(windows): fix config codegen on Windows ARM64 (drop grpcio-tools)
The Windows build's "Install codegen tools" step ran `pip install grpcio-tools`,
whose grpcio C-extension has no Windows/ARM64 wheel for current Python and fails
to build from source on windows-11-arm, so protoc was unavailable and
run_codegen aborted at the compile step.

The codegen only needs a protoc binary + the protobuf runtime + pyyaml. Install
those directly on Windows instead: pip install protobuf (>=6.33.5, matching the
committed config_metadata_pb2.py runtime check) + pyyaml, and download a
standalone protoc (win64; runs under x64 emulation on arm64). run_codegen
prefers a standalone protoc on PATH, so grpcio-tools is no longer needed on
Windows. Linux/macOS steps keep grpcio-tools (wheels available there).

Verified locally: run_codegen with a protobuf-only venv (no grpcio-tools) +
standalone protoc 28.3 -> Lint passed (712 fields), Validation PASSED.
2026-07-28 09:00:25 +02:00
ExPikaPaka
571819bfb2 Merge origin/main into feature/protobuf_config_and_dynamic_ui
Resolve the 4 proto-refactored conflicts (Preset.cpp, Print.cpp,
PrintConfig.cpp, Tab.cpp) by keeping the branch's generated-include
versions; auto-merged non-conflict changes from main are preserved.

Reconcile main's new settings into the proto schema. main added 52 new
active init_fff_params settings not present in the proto; ported them all
(type/label/tooltip/default/enum/preset) into print/filament/printer.proto
so the config registers, profiles load, and the GUI does not crash on
missing defs. Added GuiType.plugin_picker to config_metadata.proto and
regenerated config_metadata_pb2.py.

Codegen: run_codegen validate PASSED (712 fields). UI layout (layout.yaml
placement) for the 52 new settings is a follow-up; they are registered and
serialized but not yet placed in GUI tabs.
2026-07-28 08:01:22 +02:00
ExPikaPaka
d47b57af8a strip UTF-8 BOM from PrintConfig.cpp, Print.cpp, Tab.cpp
The Linux CI build fails at the encoding-check step:
  "Source file is valid UTF-8 but contains a BOM mark"
These three files picked up a UTF-8 BOM (EF BB BF) during Windows-side
merges/edits. Removed the BOM (first 3 bytes only); file contents and line
endings are otherwise unchanged.
2026-07-10 08:27:58 +02:00
ExPikaPaka
5f15ead5ee Merge branch 'main' into feature/protobuf_config_and_dynamic_ui 2026-07-10 08:02:45 +02:00
ExPikaPaka
9679cc5b81 fix(protobuf): port 7 new settings from main merge (fixes GUI startup crash)
The merge of newer main brought three features (Top Surface Expansion #14296,
Anisotropic surfaces + Separated Infills #11682, Toolchange ordering #13582)
whose manual code (ConfigManipulation.cpp / Tab.cpp) came in, but whose
settings were never ported to the proto schema. ConfigManipulation::
toggle_print_fff_options then dereferenced options with no ConfigOptionDef
(opt_float("top_surface_expansion"), opt_bool("anisotropic_surfaces")),
crashing the GUI at startup (ACCESS_VIOLATION).

Add proto fields (ported from main, incl. defaults/enums/invalidation/UI):
- top_surface_expansion, top_surface_expansion_margin,
  top_surface_expansion_direction (enum), center_of_surface_pattern (enum),
  anisotropic_surfaces, separated_infills  -> Strength page
- toolchange_ordering (enum) -> Multimaterial page

Verified: run_codegen validate PASSED (660 fields); Release build clean;
GUI now starts and runs past toggle_print_fff_options (no crash log).
2026-07-09 23:27:07 +02:00
ExPikaPaka
08bfb37bb6 Merge branch 'feature/protobuf_config_and_dynamic_ui' of https://github.com/OrcaSlicer/OrcaSlicer into feature/protobuf_config_and_dynamic_ui 2026-07-09 22:51:33 +02:00
ExPikaPaka
be9322fd6e Merge branch 'main' into feature/protobuf_config_and_dynamic_ui 2026-07-09 09:00:21 +02:00
ExPikaPaka
9e7c41d130 Merge branch 'main' into feature/protobuf_config_and_dynamic_ui 2026-07-09 09:00:21 +02:00
ExPikaPaka
4583516e4a fix(protobuf): close config migration gaps (orphaned settings, startup crash)
The proto extraction had dropped several settings that still had struct
members and were used by the engine, and had resurrected two commented-out
ones. This closes those gaps so the generated config matches main.

Fixes startup crash `UnknownOptionException: outer_wall_filament_id`:
- Add proto defs (ported from main) for the 6 struct-backed per-region
  filament-id keys the engine reads and handle_legacy resolves into:
  outer_wall/inner_wall/internal_solid/sparse_infill/top_surface/
  bottom_surface_filament_id. Registered + serialized, but intentionally no
  tab UI (the coarse wall_filament/sparse_infill_filament/solid_infill_filament
  settings provide the UI). Without a def these threw at profile load.

Restore user settings dropped from the proto (def + preset + UI, from main):
- bridge_line_width, relative_bridge_angle, lightning_overhang_angle,
  lightning_prune_angle, lightning_straightening_angle (print.proto)
- initial_layer_fan_speed (filament.proto)

Remove settings the bootstrap resurrected from commented-out code (absent in
main; commented-out struct members): filament_extruder_id (coInts),
spaghetti_detector. The separate custom-gcode filament_extruder_id placeholder
var is untouched.

Add missing printer virtual_preset_keys so vendor machine profiles are not
stripped on load: use_3mf, support_parallel_printheads,
parallel_printheads_count, parallel_printheads_bed_exclude_areas.

Verified: run_codegen validate PASSED (653 fields); libslic3r builds;
OrcaSlicer_profile_validator over all bundled profiles now exits 0 with zero
errors (previously crashed / stripped keys).
2026-07-09 08:38:08 +02:00
ExPikaPaka
bb919a7171 fix(protobuf): close config migration gaps (orphaned settings, startup crash)
The proto extraction had dropped several settings that still had struct
members and were used by the engine, and had resurrected two commented-out
ones. This closes those gaps so the generated config matches main.

Fixes startup crash `UnknownOptionException: outer_wall_filament_id`:
- Add proto defs (ported from main) for the 6 struct-backed per-region
  filament-id keys the engine reads and handle_legacy resolves into:
  outer_wall/inner_wall/internal_solid/sparse_infill/top_surface/
  bottom_surface_filament_id. Registered + serialized, but intentionally no
  tab UI (the coarse wall_filament/sparse_infill_filament/solid_infill_filament
  settings provide the UI). Without a def these threw at profile load.

Restore user settings dropped from the proto (def + preset + UI, from main):
- bridge_line_width, relative_bridge_angle, lightning_overhang_angle,
  lightning_prune_angle, lightning_straightening_angle (print.proto)
- initial_layer_fan_speed (filament.proto)

Remove settings the bootstrap resurrected from commented-out code (absent in
main; commented-out struct members): filament_extruder_id (coInts),
spaghetti_detector. The separate custom-gcode filament_extruder_id placeholder
var is untouched.

Add missing printer virtual_preset_keys so vendor machine profiles are not
stripped on load: use_3mf, support_parallel_printheads,
parallel_printheads_count, parallel_printheads_bed_exclude_areas.

Verified: run_codegen validate PASSED (653 fields); libslic3r builds;
OrcaSlicer_profile_validator over all bundled profiles now exits 0 with zero
errors (previously crashed / stripped keys).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 08:38:08 +02:00
ExPikaPaka
1c576873fc Merge remote-tracking branch 'origin/main' into feature/protobuf_config_and_dynamic_ui
Reconcile main's config changes with the protobuf codegen:
- New settings ported to proto schema (already present) and verified in
  generated PrintConfigDef/Preset_options/TabLayout + PrintConfig.hpp:
  small_support_perimeter_speed, small_support_perimeter_threshold,
  top_layer_direction, bottom_layer_direction, hole_to_polyhole_max_edges
- Ported main's label/tooltip updates for adaptive_pressure_advance_overhangs
  and adaptive_pressure_advance_bridges into filament.proto (were dropped in
  the conflict resolution) and regenerated.
- Kept main's non-generated logic (Preset.cpp nullable filament override
  force-emit).

Codegen validated (python tools/run_codegen.py --validate-only): PASSED.
2026-07-08 10:31:10 +02:00
ExPikaPaka
b1d1fb7dfc Merge remote-tracking branch 'origin/main' into feature/protobuf_config_and_dynamic_ui
Reconcile main's config changes with the protobuf codegen:
- New settings ported to proto schema (already present) and verified in
  generated PrintConfigDef/Preset_options/TabLayout + PrintConfig.hpp:
  small_support_perimeter_speed, small_support_perimeter_threshold,
  top_layer_direction, bottom_layer_direction, hole_to_polyhole_max_edges
- Ported main's label/tooltip updates for adaptive_pressure_advance_overhangs
  and adaptive_pressure_advance_bridges into filament.proto (were dropped in
  the conflict resolution) and regenerated.
- Kept main's non-generated logic (Preset.cpp nullable filament override
  force-emit).

Codegen validated (python tools/run_codegen.py --validate-only): PASSED.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 10:31:10 +02:00
ExPikaPaka
8be6b40e7f Merge branch 'main' into feature/protobuf_config_and_dynamic_ui 2026-07-03 08:38:15 +02:00
ExPikaPaka
cd6223ffaf Make typo verification more robust 2026-06-18 08:48:42 +02:00
ExPikaPaka
0458925f85 Install proto before flatpack when there is internet. Add missing include that caused fail only on Unix 2026-06-04 17:41:40 +02:00
ExPikaPaka
7c34e089e4 Try to fix mac build again
Ahh, I never compiled any program on Mac, i thought it will behave the same was as Linux,
but there are some diferences of course..
2026-06-04 14:37:03 +02:00
ExPikaPaka
d314e9c09a Fix build for Mac 2026-06-04 14:22:04 +02:00
ExPikaPaka
7fa650e410 Fix build script as it was not working on some platforms 2026-06-04 12:28:25 +02:00
ExPikaPaka
1c1cee7784 Add missing fix for BOM file encoding 2026-06-04 12:27:43 +02:00
ExPikaPaka
1d7da51991 Fix encoding and build script 2026-06-04 12:13:10 +02:00
ExPikaPaka
3be63d4369 Use venv for python on Linux and macOS 2026-06-04 11:52:05 +02:00
ExPikaPaka
99a0dd8556 Fix BOM mark 2026-06-04 11:41:24 +02:00
ExPikaPaka
fcd3a66af4 Merge branch 'feature/protobuf_config_and_dynamic_ui' of https://github.com/OrcaSlicer/OrcaSlicer into feature/protobuf_config_and_dynamic_ui 2026-06-04 09:09:32 +02:00
ExPikaPaka
972da86fbc Fix incorrect path at codegen config 2026-06-04 09:08:27 +02:00
ExPikaPaka
8cb357ec06 Merge branch 'main' into feature/protobuf_config_and_dynamic_ui 2026-06-04 09:00:36 +02:00
ExPikaPaka
a29fac5de8 Update printer section in automatic layout 2026-06-04 08:41:43 +02:00
ExPikaPaka
14097382d8 Adds custom hooks that are called cause they need special code and can't be implemented purely via protobuf definition 2026-06-04 08:40:54 +02:00
ExPikaPaka
3db76d7f89 Extend code generators to properly handle new data types 2026-06-04 08:40:20 +02:00
ExPikaPaka
c47fc4529e Wire in generated files 2026-06-04 08:40:00 +02:00
ExPikaPaka
b823994feb Add cmake config to properly do incremental build 2026-06-04 08:38:50 +02:00
ExPikaPaka
403766b1b6 Add .gitignore entry to ignore generated code 2026-06-04 08:38:24 +02:00
ExPikaPaka
6e84139d60 Configure CI/CD build to properly build OrcaSlicer with Protobuf and codegen 2026-06-04 08:37:32 +02:00
ExPikaPaka
a78ef9ce1c Fix proto files after merging them from ~15 files to 3 2026-06-04 08:36:51 +02:00
ExPikaPaka
064e10c069 Remove outdated files 2026-06-04 08:36:28 +02:00
Mykola Nahirnyi
87ceeaa0aa Wires in generated files 2026-05-27 10:02:24 +03:00
Mykola Nahirnyi
35d4bae778 Add codegen pipeline 2026-05-27 09:57:24 +03:00
Mykola Nahirnyi
2eb1b8ddd6 Add CMake integration and design doc 2026-05-27 09:54:25 +03:00
Mykola Nahirnyi
5475e0aebe Add generated C++ files from proto schema 2026-05-27 09:53:55 +03:00
Mykola Nahirnyi
04b7ae9219 Add PrintConfig proto schema and UI layout 2026-05-27 09:50:53 +03:00
29 changed files with 14280 additions and 8803 deletions

View File

@@ -282,6 +282,10 @@ jobs:
sed -i "/name: OrcaSlicer/{n;s|buildsystem: simple|buildsystem: simple\n build-options:\n env:\n git_commit_hash: \"$git_commit_hash\"|}" \
scripts/flatpak/com.orcaslicer.OrcaSlicer.yml
shell: bash
- name: Generate config sources
# Generated on the host: the flatpak build itself runs offline.
run: python3 tools/run_codegen.py
shell: bash
- uses: flatpak/flatpak-github-actions/flatpak-builder@master
with:
bundle: OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak

View File

@@ -57,6 +57,19 @@ jobs:
useLocalCache: true # <--= Use the local cache (default is 'false').
useCloudCache: true
# run_codegen.py resolves its own toolchain (a pinned protoc plus protobuf/pyyaml in a
# cached virtualenv), so nothing has to be pip-installed around it. That is what makes it
# work on windows-11-arm, where `pip install grpcio-tools` has no wheel and fails building
# the grpcio C extension from source.
- name: Generate config sources
if: runner.os == 'Windows'
run: python tools/run_codegen.py
shell: pwsh
- name: Generate config sources
if: runner.os != 'Windows'
run: python3 tools/run_codegen.py
shell: bash
- name: Install CMake 3.31.x (Windows ARM64)
# windows-11-arm ships CMake 4.x, which removed pre-3.5 policy
# compatibility AND has incomplete ASM_ARMASM linker modules

5
.gitignore vendored
View File

@@ -46,6 +46,11 @@ test.js
internal_docs/
*.flatpak
/flatpak-repo/
# Config codegen: descriptor set, generated C++ and the downloaded protoc /
# bootstrap virtualenv. All of it is produced by tools/run_codegen.py.
config.desc
src/slic3r/GUI/generated/
.codegen-tools/
# Python bytecode
__pycache__/
*.pyc

View File

@@ -1082,6 +1082,12 @@ function(orcaslicer_copy_dlls target config postfix output_dlls)
endfunction()
# Config codegen — generates src/slic3r/GUI/generated/*.cpp from src/PrintConfigs/*.proto.
# Must run before compiling libslic3r (PrintConfig.cpp #includes the generated files).
# The toolchain (protoc, protobuf, pyyaml) is resolved by tools/run_codegen.py itself;
# set PROTOC=<path> to use an installed protoc instead of the pinned download.
include(cmake/modules/ConfigCodegen.cmake)
# libslic3r, OrcaSlicer GUI and the OrcaSlicer executable.
add_subdirectory(deps_src)
add_subdirectory(src)

View File

@@ -556,6 +556,11 @@ if [[ -n "${BUILD_ORCA}" ]] || [[ -n "${BUILD_TESTS}" ]] ; then
BUILD_ARGS+=(-DORCA_UPDATER_SIG_KEY="${ORCA_UPDATER_SIG_KEY}")
fi
echo "Generating config sources from proto..."
# Resolves protoc and its Python packages itself; nothing is installed into the
# system interpreter (distro Pythons refuse that under PEP 668 anyway).
python3 tools/run_codegen.py || { echo "ERROR: config codegen failed"; exit 1; }
print_and_run cmake -S . -B $BUILD_DIR "${CMAKE_C_CXX_COMPILER_CLANG[@]}" "${CMAKE_LLD_LINKER_ARGS[@]}" "${CMAKE_CCACHE_ARGS[@]}" -G "Ninja Multi-Config" \
-DSLIC3R_PCH=${SLIC3R_PRECOMPILED_HEADERS} \
-DORCA_TOOLS=ON \

View File

@@ -240,6 +240,11 @@ function verify_python_runtime() {
}
function build_slicer() {
echo "Generating config sources from proto..."
# Resolves protoc and its Python packages itself (into .codegen-tools/), so nothing
# is installed into the system interpreter.
python3 tools/run_codegen.py || { echo "ERROR: config codegen failed"; exit 1; }
# iterate over two architectures: x86_64 and arm64
for _ARCH in x86_64 arm64; do
# if ARCH is universal or equal to _ARCH

View File

@@ -145,6 +145,16 @@ if "%1"=="deps" goto :done
:slicer
echo "building Orca Slicer..."
cd %WP%
echo "generating config sources from proto..."
REM run_codegen.py resolves protoc and its python packages itself (grpcio-tools has
REM no wheel on ARM64 and fails to build there).
python tools/run_codegen.py
if errorlevel 1 (
echo "ERROR: config codegen failed"
exit /b 1
)
mkdir %build_dir%
cd %build_dir%

View File

@@ -66,6 +66,16 @@ if "%1"=="deps" exit /b 0
:slicer
echo "building Orca Slicer..."
cd %WP%
echo "generating config sources from proto..."
REM run_codegen.py resolves protoc and its python packages itself (grpcio-tools has
REM no wheel on ARM64 and fails to build there).
python tools/run_codegen.py
if errorlevel 1 (
echo "ERROR: config codegen failed"
exit /b 1
)
mkdir %build_dir%
cd %build_dir%

View File

@@ -0,0 +1,144 @@
# OrcaSlicer Config Codegen CMake Module
#
# Generates C++ source files from protobuf schema definitions.
# Generated files live in src/slic3r/GUI/generated/ and are gitignored.
# Run 'python tools/run_codegen.py' to regenerate; it resolves protoc and the Python
# packages it needs itself (see tools/codegen_toolchain.py).
#
# Targets:
# codegen_config - Custom target to regenerate C++ from .proto files
# validate_config - Custom target to validate generated vs original
#
# Usage in parent CMakeLists.txt:
# include(cmake/modules/ConfigCodegen.cmake)
find_program(PROTOC_EXECUTABLE protoc)
find_package(Python3 COMPONENTS Interpreter QUIET)
set(_generated_marker "${CMAKE_SOURCE_DIR}/src/slic3r/GUI/generated/PrintConfigDef_generated.cpp")
# Decide which interpreter can actually run the codegen.
#
# The main CMakeLists forces Python3_EXECUTABLE to the *bundled embed* interpreter (used for
# the in-app Python plugin runtime). That interpreter has neither protoc nor the protobuf /
# pyyaml packages, and for cross-compiled targets it may not even be the host architecture — so
# it cannot run tools/run_codegen.py. Prefer a host interpreter, which tools/run_codegen.py can
# bootstrap the toolchain into.
#
# ORCA_CODEGEN_PYTHON lets a build explicitly point at the interpreter to use.
if(NOT ORCA_CODEGEN_PYTHON)
find_program(_orca_host_python NAMES python3 python)
if(_orca_host_python)
set(ORCA_CODEGEN_PYTHON "${_orca_host_python}")
else()
set(ORCA_CODEGEN_PYTHON "${Python3_EXECUTABLE}")
endif()
endif()
# --check answers "can this interpreter regenerate right now?" (protobuf + pyyaml importable
# and a protoc already resolvable). It never downloads or installs, so wiring up the build-time
# regeneration below never turns a build into a network operation.
set(_codegen_usable FALSE)
if(ORCA_CODEGEN_PYTHON)
execute_process(
COMMAND ${ORCA_CODEGEN_PYTHON} "${CMAKE_SOURCE_DIR}/tools/codegen_toolchain.py" --check
RESULT_VARIABLE _codegen_probe
OUTPUT_QUIET ERROR_QUIET
)
if(_codegen_probe EQUAL 0)
set(_codegen_usable TRUE)
endif()
endif()
# If generated files are missing (fresh clone), run the codegen now at configure time so a plain
# cmake configure + build works without a separate pre-build step. Unlike the build-time
# regeneration above this is allowed to fetch the toolchain — there is nothing to build without it.
if(NOT EXISTS "${_generated_marker}")
set(_codegen_result 1)
if(ORCA_CODEGEN_PYTHON)
message(STATUS "Config codegen: generated files missing — running codegen now...")
execute_process(
COMMAND ${ORCA_CODEGEN_PYTHON} "${CMAKE_SOURCE_DIR}/tools/run_codegen.py" --no-validate
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
RESULT_VARIABLE _codegen_result
)
endif()
if(NOT _codegen_result EQUAL 0)
message(FATAL_ERROR
"Config codegen: generated files are missing and could not be generated.\n"
"Run it manually with a host Python:\n"
" python tools/run_codegen.py\n"
"or pass -DORCA_CODEGEN_PYTHON=<python>. Offline builds can point at an installed\n"
"protoc with PROTOC=<path>.")
endif()
message(STATUS "Config codegen: generated files created successfully")
endif()
set(CONFIG_PROTO_DIR "${CMAKE_SOURCE_DIR}/src/PrintConfigs")
set(CONFIG_CODEGEN_DIR "${CMAKE_SOURCE_DIR}/src/slic3r/GUI/generated")
set(CONFIG_LAYOUT_YAML "${CMAKE_SOURCE_DIR}/src/PrintConfigs/layout.yaml")
set(CONFIG_DESC_FILE "${CMAKE_BINARY_DIR}/config.desc")
set(CODEGEN_TOOL "${CMAKE_SOURCE_DIR}/tools/config_codegen.py")
set(VALIDATE_TOOL "${CMAKE_SOURCE_DIR}/tools/validate_codegen.py")
set(RUN_CODEGEN_TOOL "${CMAKE_SOURCE_DIR}/tools/run_codegen.py")
# Generated output files (TabLayout_generated.cpp is also generated from layout.yaml)
set(CONFIG_GENERATED_SOURCES
"${CONFIG_CODEGEN_DIR}/PrintConfigDef_generated.cpp"
"${CONFIG_CODEGEN_DIR}/Preset_options_generated.cpp"
"${CONFIG_CODEGEN_DIR}/Invalidation_generated.cpp"
"${CONFIG_CODEGEN_DIR}/OptionKeys_generated.cpp"
"${CONFIG_CODEGEN_DIR}/TabLayout_generated.cpp"
)
set(CONFIG_GENERATED_SOURCES "${CONFIG_GENERATED_SOURCES}" CACHE INTERNAL "Generated config cpp files")
# Collect all .proto source files (flat in src/PrintConfigs/, excluding config_metadata.proto)
file(GLOB CONFIG_PROTO_FILES
"${CONFIG_PROTO_DIR}/filament.proto"
"${CONFIG_PROTO_DIR}/print.proto"
"${CONFIG_PROTO_DIR}/printer.proto"
)
set(CONFIG_PROTO_FILES
"${CONFIG_PROTO_DIR}/config_metadata.proto"
${CONFIG_PROTO_FILES}
)
if(_codegen_usable)
# Single command: run_codegen.py resolves protoc itself.
# Proto files → generated .cpp files. Runs automatically when any .proto changes.
add_custom_command(
OUTPUT ${CONFIG_GENERATED_SOURCES}
COMMAND ${ORCA_CODEGEN_PYTHON} ${RUN_CODEGEN_TOOL} --no-validate
DEPENDS ${CONFIG_PROTO_FILES} ${CONFIG_LAYOUT_YAML} ${CODEGEN_TOOL}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Re-generating config C++ from changed .proto files"
VERBATIM
)
# codegen_config is part of ALL — runs before every build, checks if protos changed.
add_custom_target(codegen_config ALL
DEPENDS ${CONFIG_GENERATED_SOURCES}
COMMENT "Config codegen up to date"
)
# Validation target: cmake --build . --target validate_config
add_custom_target(validate_config
COMMAND ${ORCA_CODEGEN_PYTHON} ${VALIDATE_TOOL}
DEPENDS ${CONFIG_GENERATED_SOURCES}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMENT "Validating generated config code against PrintConfig.cpp"
VERBATIM
)
message(STATUS "Config codegen: enabled — proto changes auto-regenerate on next build")
else()
# No usable codegen toolchain in this interpreter (e.g. the bundled embed Python in CI).
# The generated files already exist (checked/produced above); use them as-is and provide a
# no-op codegen_config target so dependents that reference it still resolve.
add_custom_target(codegen_config ALL
COMMENT "Config codegen: using pre-generated files (no codegen toolchain in this interpreter)")
add_custom_target(validate_config
COMMENT "Config codegen: validation skipped (no codegen toolchain in this interpreter)")
message(STATUS "Config codegen: no codegen toolchain in '${ORCA_CODEGEN_PYTHON}' — using pre-generated files")
endif()

View File

@@ -0,0 +1,495 @@
# PrintConfig Codegen — Design Document
## 1. Problem Statement
Every config setting in OrcaSlicer (e.g. `travel_speed`, `wipe_distance`) is independently maintained as string literals across ~12 locations in the codebase with zero compile-time validation linking them.
A single setting like `wipe_distance` appears in:
| # | Location | What's duplicated |
|---|----------|-------------------|
| 1 | `PrintConfig.cpp` `init_fff_params()` | Key, type, label, tooltip, default, constraints |
| 2 | `PrintConfig.hpp` struct members | Type + member name (must match key string) |
| 3 | `Preset.cpp` option lists | Key string in serialization lists |
| 4 | `PrintConfig.cpp` extruder/filament lists | Key string in 4 sub-lists |
| 5 | `PrintConfig.cpp` variant option sets | Key string in variant sets |
| 6 | `Print.cpp` invalidation chains | `opt_key == "..."` checks |
| 7 | `Tab.cpp` GUI layout | `append_single_option_line("key")` |
| 8 | GUI files (`Field.cpp`, `OptionsGroup.cpp`) | `opt_key == "..."` special-case handling |
| 9 | `PrintConfig.cpp` `handle_legacy()` | Old-to-new key name mapping |
| 10 | `PrintConfig.cpp` `new_def` G-code placeholders | Re-declared type, label, tooltip |
| 11 | `resources/profiles/*.json` | Key strings as JSON keys |
### Consequences
- Adding a new setting requires editing ~12 files manually
- A typo in any one location causes a silent bug (no compile-time validation)
- Print providers cannot add/customize settings without forking the C++ codebase
- No cross-language tooling (Python scripts, web editors) can consume the schema
- No build-time validation of profile JSONs against the canonical option list
---
## 2. Goals
- **Single source of truth** for all setting definitions
- **Compile-time safety** against key mismatches across the codebase
- **Adding a new setting = editing 1 file** (instead of ~12)
- **Enable print providers** to customize settings (defaults, constraints, visibility) without C++ changes
- **Cross-language API generation** (Python, TypeScript, JSON Schema)
- **Build-time validation** of profile JSONs
- **Hidden mode** — setting exists in config/serialization but is not shown in UI
- **Disabled mode** — setting shown in UI but greyed out / non-editable
- **Automated UI layout** — new settings with GUI annotations appear in UI without manual `Tab.cpp` edits
### Non-goals
- Runtime performance changes (slicing engine untouched)
- Changing the `.3mf` wire format (cereal/JSON serialization preserved)
---
## 3. Current Architecture
### 3.1 Type System
`Config.hpp` defines ~15 `ConfigOptionType` variants:
```cpp
coFloat, coInt, coBool, coString, coPercent, coFloatOrPercent,
coPoint, coPoint3, coEnum,
coFloats, coInts, coBools, coStrings, coPercents, coFloatsOrPercents,
coPoints, coEnums
```
Each has a corresponding C++ class (`ConfigOptionFloat`, `ConfigOptionBools`, etc.) with virtual `serialize()`/`deserialize()` methods:
```cpp
class ConfigOption {
virtual ConfigOptionType type() const = 0;
virtual std::string serialize() const = 0;
virtual bool deserialize(const std::string &str, bool append = false) = 0;
virtual ConfigOption* clone() const = 0;
// ...
};
class ConfigOptionFloat : public ConfigOptionSingle<double> {
ConfigOptionType type() const override { return coFloat; }
std::string serialize() const override { /* double -> string */ }
bool deserialize(const std::string &str, bool append) override { /* string -> double */ }
};
```
### 3.2 Definition Layer
`ConfigOptionDef` holds all metadata for one setting:
```
opt_key, type, nullable, default_value,
label, full_label, category, tooltip, sidetext,
mode (Simple/Advanced/Develop),
min, max, max_literal, ratio_over,
gui_type, multiline, full_width, height,
enum_values, enum_labels, enum_keys_map,
aliases, shortcut
```
All ~500 settings are registered in `PrintConfigDef::init_fff_params()` (~6000 lines) into the global `print_config_def` singleton. Each registration block:
```cpp
def = this->add("bridge_flow", coFloat); // register key + type
def->label = L("Bridge flow ratio"); // UI label
def->category = L("Quality"); // tab category
def->tooltip = L("..."); // tooltip
def->min = 0; // constraint
def->max = 2.0; // constraint
def->mode = comAdvanced; // visibility mode
def->set_default_value(new ConfigOptionFloat(1)); // default
```
### 3.3 Storage Layer
Two parallel systems:
**StaticPrintConfig** — compiled-in struct fields via `PRINT_CONFIG_CLASS_DEFINE` macro. Name-to-byte-offset cache. Used in the slicing engine for direct member access (performance-critical).
**DynamicPrintConfig**`std::map<string, ConfigOptionUniquePtr>`. Used in GUI and for diff/apply operations.
Class hierarchy:
```
FullPrintConfig
├── PrintObjectConfig (~120 fields)
├── PrintRegionConfig (~80 fields)
└── PrintConfig
├── MachineEnvelopeConfig (~25 fields)
└── GCodeConfig (~80 fields)
```
### 3.4 Serialization
- **JSON presets**: `ConfigBase::save_to_json()` / `load_from_json()` — iterates option keys, calls `opt->serialize()` to string, writes JSON key-value pairs
- **Binary .3mf**: cereal archives via `load_option_from_archive()` / `save_option_to_archive()`
- Both formats use the same string keys as identifiers
### 3.5 Invalidation
`Print::invalidate_state_by_config_options()` contains large `opt_key == "..."` chains that classify each changed option key into pipeline steps to invalidate:
```
posSlice, posPerimeters, posInfill, posSupportMaterial,
psGCodeExport, psSkirtBrim, psWipeTower
```
### 3.6 GUI Binding
- `Tab.cpp` builds UI via `append_single_option_line("key_name")` — looks up `ConfigOptionDef` from `print_config_def`, auto-creates the appropriate widget
- `ConfigManipulation.cpp` contains `toggle_print_fff_options()` — imperative logic that reads config values and toggles field visibility
## 4. Proposed Solution
### 4.1 Architecture
Protobuf as schema + codegen, NOT a runtime replacement.
```
┌─────────────────────┐ ┌──────────────────────────────┐
│ src/PrintConfigs/ │ codegen │ PrintConfigDef_generated.cpp │ done
│ *.proto │ ──────────────> │ Preset_options_generated.cpp │ done
│ layout.yaml │ │ Invalidation_generated.cpp │ done
│ │ │ OptionKeys_generated.cpp │ done
└─────────────────────┘ │ PrintConfig_generated.hpp │ future
│ TabLayout_generated.cpp │ future
└──────────────────────────────┘
```
### 4.2 Proto Schema Design
#### 4.2.1 Custom Field Options
`src/PrintConfigs/config_metadata.proto` defines custom extensions covering all `ConfigOptionDef` metadata:
```protobuf
syntax = "proto3";
import "google/protobuf/descriptor.proto";
package orca;
enum ConfigMode {
MODE_SIMPLE = 0;
MODE_ADVANCED = 1;
MODE_DEVELOP = 2;
}
enum PresetType {
PRESET_PRINT = 0;
PRESET_FILAMENT = 1;
PRESET_PRINTER = 2;
}
enum InvalidationStep {
STEP_GCODE_EXPORT = 0;
STEP_SKIRT_BRIM = 1;
STEP_WIPE_TOWER = 2;
STEP_SLICE = 3;
STEP_PERIMETERS = 4;
STEP_INFILL = 5;
STEP_SUPPORT = 6;
STEP_NONE = 7;
}
enum OptionListMembership {
LIST_NONE = 0;
LIST_EXTRUDER_OPTION_KEYS = 1;
LIST_FILAMENT_OPTION_KEYS = 2;
LIST_VARIANT_OPTION_KEYS = 3;
}
extend google.protobuf.FieldOptions {
// Display metadata
string label = 50001;
string full_label = 50002;
string tooltip = 50003;
string category = 50004;
string sidetext = 50005;
// Numeric constraints
double min_value = 50006;
double max_value = 50007;
double max_literal = 50008;
// UI behavior
ConfigMode mode = 50009;
string ratio_over = 50010;
bool multiline = 50013;
bool full_width = 50014;
int32 height = 50015;
// Classification
PresetType preset = 50011;
repeated InvalidationStep invalidates = 50012;
repeated OptionListMembership list_membership = 50018;
// Migration
string legacy_name = 50016;
// Nullable support (for ConfigOptionFloatsNullable, etc.)
bool is_nullable = 50017;
// GUI type override (e.g. "i_enum_open", "color", "f_enum_open")
string gui_type = 50019;
string gui_flags = 50020;
// Enum metadata
string enum_keys_map_ref = 50021;
bool no_cli = 50022;
bool readonly = 50023;
// C++ codegen hints
string co_type_hint = 50024;
// Default value — constructor args only (e.g. "1.0", "5000.0, 5000.0")
// Codegen reconstructs full C++ from co_type + this value
string default_value = 50025;
bool has_default = 50028; // proto3 can't distinguish empty string from unset
// Enum values and labels
repeated string enum_value_entries = 50026;
repeated string enum_label_entries = 50027;
}
extend google.protobuf.MessageOptions {
// Virtual preset keys: keys that belong to this preset type in Preset.cpp
// option lists but have no ConfigOptionDef entry (printer identity fields,
// host/connectivity settings, filament retraction overrides, compatibility
// flags, cross-preset keys). The codegen emits these directly into the
// s_Preset_*_options array alongside the field-derived keys.
// To add a virtual key: add one option line here and re-run codegen.
repeated string virtual_preset_keys = 60001;
}
```
#### 4.2.2 Setting Files
Settings are split into three `.proto` files by preset type. Each setting becomes a proto field with annotations:
| File | Contents |
|------|----------|
| `src/PrintConfigs/print.proto` | ~477 print/process settings |
| `src/PrintConfigs/filament.proto` | ~103 filament settings |
| `src/PrintConfigs/printer.proto` | ~42 printer settings |
Each file also carries message-level `virtual_preset_keys` declarations (see §5.2.3).
Example field:
```protobuf
float travel_speed = 42 [
(label) = "Travel",
(tooltip) = "Speed of travel which is faster and without extrusion.",
(sidetext) = "mm/s",
(min_value) = 1,
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINT,
(has_default) = true,
(default_value) = "200",
(invalidates) = STEP_GCODE_EXPORT
];
```
#### 4.2.3 Virtual Preset Keys
The `s_Preset_*_options` vectors in `Preset.cpp` need to include keys beyond those with `ConfigOptionDef` entries — for example, printer identity fields (`printer_technology`, `printable_area`), connectivity settings (`host_type`, `print_host`), filament retraction overrides (`filament_retraction_length`, `filament_z_hop`, …), and cross-preset keys that belong to multiple preset types.
These are declared directly in the `.proto` message body using the `virtual_preset_keys` message option:
```protobuf
message PrinterSettings {
// Virtual keys (not in PrintConfigDef)
option (virtual_preset_keys) = "printer_technology";
option (virtual_preset_keys) = "printable_area";
option (virtual_preset_keys) = "host_type";
option (virtual_preset_keys) = "print_host";
// ... etc
// Cross-preset keys (defined in print.proto, also saved in printer presets)
option (virtual_preset_keys) = "single_extruder_multi_material";
option (virtual_preset_keys) = "wipe_tower_type";
// ... etc
float extruder_clearance_height_to_rod = 1 [ ... ];
// ...
}
```
The codegen reads these and merges them (deduplicated, sorted) with the field-derived keys into the generated `s_Preset_printer_options` vector. No hand-written extender struct in `Preset.cpp` is needed.
#### 4.2.4 Type Mapping
| C++ Type | Proto Representation | Notes |
|---|---|---|
| `ConfigOptionFloat` | `float field = N` | |
| `ConfigOptionInt` | `int32 field = N` | |
| `ConfigOptionBool` | `bool field = N` | |
| `ConfigOptionString` | `string field = N` | |
| `ConfigOptionFloats` | `repeated float field = N` | Per-extruder vectors |
| `ConfigOptionInts` | `repeated int32 field = N` | |
| `ConfigOptionBools` | `repeated bool field = N` | |
| `ConfigOptionStrings` | `repeated string field = N` | |
| `ConfigOptionPercent` | `float field = N` | `(co_type_hint) = "coPercent"` |
| `ConfigOptionPercents` | `repeated float field = N` | `(co_type_hint) = "coPercents"` |
| `ConfigOptionFloatOrPercent` | `FloatOrPercent field = N` | Custom wrapper message |
| `ConfigOptionEnum<T>` | `int32 field = N` | `(co_type_hint) = "coEnum"` + `(enum_keys_map_ref)` |
| `ConfigOptionPoint` | `Point2D field = N` | Custom wrapper message |
| `ConfigOptionFloatsNullable` | `repeated float field = N` | `(is_nullable) = true` |
#### 4.2.5 UI Layout File
`src/PrintConfigs/layout.yaml` declares the UI tab/page/group structure used by `Tab.cpp`. It lists field names in display order under their respective groups. The codegen will eventually use this to generate `TabLayout_generated.cpp` (future phase).
### 4.3 Code Generator Outputs
| Output | Replaces | Status |
|---|---|---|
| `PrintConfigDef_generated.cpp` | `init_fff_params()` body (~6000 lines) | Done |
| `Preset_options_generated.cpp` | `s_Preset_*_options` string vectors | Done |
| `Invalidation_generated.cpp` | `opt_key ==` chains in `Print.cpp` | Done |
| `OptionKeys_generated.cpp` | Extruder/filament key lists | Done |
| `PrintConfig_generated.hpp` | `PRINT_CONFIG_CLASS_DEFINE` macro blocks | Future |
| `TabLayout_generated.cpp` | `append_single_option_line()` calls in `Tab.cpp` | Future |
### 4.4 CMake Integration
```cmake
add_custom_command(
OUTPUT ${GENERATED_SOURCES}
COMMAND ${ORCA_CODEGEN_PYTHON} tools/run_codegen.py --no-validate
DEPENDS src/PrintConfigs/*.proto src/PrintConfigs/layout.yaml tools/config_codegen.py
)
```
Generated files are **not** checked into the repo — `src/slic3r/GUI/generated/` and `config.desc` are gitignored, and every build produces them. Each build script and CI job runs `tools/run_codegen.py` before configuring; a fresh clone that goes straight to `cmake` gets them generated at configure time.
`tools/run_codegen.py` resolves its own toolchain (`tools/codegen_toolchain.py`), so no caller has to install anything:
- **protoc** — `$PROTOC`, then `PATH`, then a cached copy, then a pinned checksum-verified release downloaded into `.codegen-tools/` (also gitignored)
- **protobuf + pyyaml** — the calling interpreter if it has them, otherwise a virtualenv under `.codegen-tools/` that the script re-execs into
Set `PROTOC=<path>` to build offline or against a distro protoc.
### 4.5 Provider Customization
Providers ship an overlay file alongside their existing JSON profiles:
```yaml
# resources/profiles/Creality/settings_overlay.yaml
overrides:
travel_speed:
max_value: 600
default: 300
travel_speed_z:
mode: hidden # not relevant for this printer
firmware_retraction:
mode: disabled # shown but locked — firmware handles this
custom_options:
- key: creality_vibration_compensation
type: bool
label: "Vibration Compensation"
default: true
category: "Quality"
mode: advanced
gui_page: "Quality"
gui_group: "Other"
```
Custom options get field numbers > 1000 to avoid conflicts.
---
## 5. What Changes vs. What Stays
### Changes (generated from proto)
| Artifact | Current | After | Status |
|---|---|---|---|
| `init_fff_params()` body (~6000 lines) | Hand-written C++ | `#include` of generated file | Done |
| `s_Preset_*_options` lists | Hand-written string vectors | Generated from `(preset)` + `virtual_preset_keys` | Done |
| `invalidate_state_by_config_options()` | Hand-written `opt_key ==` chains | Generated map lookup | Done |
| Extruder/filament key lists | Hand-written string vectors | Generated from `(list_membership)` | Done |
| `PRINT_CONFIG_CLASS_DEFINE` blocks in `.hpp` | Hand-written macros | Generated from `.proto` | Future |
| `Tab.cpp` `append_single_option_line()` layout | Hand-written per-setting calls | Generated from `layout.yaml` + `(tab_*)` annotations | Future |
### Stays manual (NOT generated)
| Component | Reason |
|---|---|
| Conditional visibility (`toggle_print_fff_options`) | Complex runtime logic depending on config values; cannot be declaratively expressed |
| Custom GUI rendering (`Field.cpp`, `OptionsGroup.cpp`) | Case-specific widget behavior (color pickers, special enums) |
| `handle_legacy()` | Migration logic; partially automatable via `(legacy_name)` but complex transforms stay manual |
| Enum C++ maps (top of `PrintConfig.cpp`) | Could eventually generate from proto enums |
---
## 6. Developer Workflow
### Adding a new setting
1. Add a field to the appropriate `.proto` file (`print.proto`, `filament.proto`, or `printer.proto`) with all relevant annotations
2. Run `python tools/run_codegen.py`
3. Commit the `.proto` change — the generated files are gitignored build output, never committed
### Adding a virtual preset key
Virtual keys are preset option keys that have no `ConfigOptionDef` (printer identity fields, connectivity settings, etc.) or that exist in one preset type's proto but also need to appear in another preset's options list.
1. Add `option (virtual_preset_keys) = "key_name";` in the appropriate `.proto` message body
2. Run `python tools/run_codegen.py`
### Running the codegen pipeline manually
```bash
# Full pipeline: compile protos → generate C++ → validate
python tools/run_codegen.py
# Validate only (check generated files are up to date)
python tools/run_codegen.py --validate-only
# Inject invalidation/list-membership annotations from Print.cpp / PrintConfig.cpp
python tools/annotate_protos.py [--dry-run]
```
---
## 7. File Layout
```
src/PrintConfigs/
├── config_metadata.proto # Custom field/message option extensions
├── layout.yaml # UI tab/page/group structure (Tab.cpp layout)
├── print.proto # ~477 print/process settings
├── filament.proto # ~103 filament settings
└── printer.proto # ~42 printer/machine settings
tools/
├── run_codegen.py # Full pipeline script — the entry point everything calls
├── codegen_toolchain.py # Resolves protoc / protobuf / pyyaml
├── config_codegen.py # Proto descriptor → C++ codegen
├── config_metadata.py # Reads the orca.* option extensions from the descriptor set
└── validate_codegen.py # Generated vs original validation
src/slic3r/GUI/generated/ # gitignored — regenerated by every build
├── PrintConfigDef_generated.cpp # init_fff_params() body — #included by PrintConfig.cpp
├── Preset_options_generated.cpp # s_Preset_*_options — #included by Preset.cpp
├── Invalidation_generated.cpp # s_print_steps_map + s_object_steps_map — #included by Print.cpp
├── OptionKeys_generated.cpp # s_extruder_option_keys, s_filament_option_keys
└── TabLayout_generated.cpp # Tab page/group layout from layout.yaml
.codegen-tools/ # gitignored — downloaded protoc + bootstrap virtualenv
cmake/modules/
└── ConfigCodegen.cmake # CMake integration (build-time regeneration)
docs/
└── PrintConfig_Codegen_Design.md # This design document
```

View File

@@ -393,6 +393,9 @@ modules:
- type: dir
path: ../../localization
dest: localization
- type: dir
path: ../../tools
dest: tools
- type: file
path: ../../CMakeLists.txt

View File

@@ -0,0 +1,174 @@
// OrcaSlicer Print Config - Custom Field Options
// This file defines the metadata annotations used on all config setting fields.
// These annotations are read by the codegen tool to produce:
// - PrintConfigDef_generated.cpp (init_fff_params replacement)
// - PrintConfig_generated.hpp (struct definitions)
// - Preset_options_generated.cpp (preset option lists)
// - Invalidation_generated.cpp (invalidation map)
// - OptionKeys_generated.cpp (extruder/filament/variant key lists)
syntax = "proto3";
import "google/protobuf/descriptor.proto";
package orca;
// --- Enums for annotations ---
enum ConfigMode {
MODE_SIMPLE = 0;
MODE_ADVANCED = 1;
MODE_DEVELOP = 2;
MODE_EXPERT = 3;
}
enum PresetType {
PRESET_PRINT = 0;
PRESET_FILAMENT = 1;
PRESET_PRINTER = 2;
}
enum InvalidationStep {
STEP_GCODE_EXPORT = 0;
STEP_SKIRT_BRIM = 1;
STEP_WIPE_TOWER = 2;
STEP_SLICE = 3;
STEP_PERIMETERS = 4;
STEP_INFILL = 5;
STEP_SUPPORT = 6;
STEP_NONE = 7;
}
enum OptionListMembership {
LIST_NONE = 0;
LIST_EXTRUDER_OPTION_KEYS = 1;
LIST_FILAMENT_OPTION_KEYS = 2;
LIST_VARIANT_OPTION_KEYS = 3;
}
// C++ co_type override values, used when the proto wire type (float/int32) is
// ambiguous about the real ConfigOption class. Each value name is the coXXX
// identifier the codegen emits, and must have a matching entry in
// hint_class_map (config_codegen.py). Making this an enum lets protoc reject a
// typo'd hint (e.g. coFloar) at compile time instead of silently mis-typing a
// setting. To add a new override: add a value here AND its hint_class_map entry.
enum CoTypeHint {
CO_TYPE_HINT_UNSET = 0;
coPercent = 1;
coPercents = 2;
coEnum = 3;
coEnums = 4;
}
// Mirrors ConfigOptionDef::GUIType in src/libslic3r/Config.hpp. The codegen
// emits ConfigOptionDef::GUIType::<name>, so each value name must match a C++
// enumerator there. As an enum, a typo'd gui_type fails at protoc time.
enum GuiType {
GUI_TYPE_UNSET = 0;
i_enum_open = 1;
f_enum_open = 2;
color = 3;
select_open = 4;
slider = 5;
legend = 6;
one_string = 7;
plugin_picker = 8;
}
// --- Custom field options ---
extend google.protobuf.FieldOptions {
// Display metadata
string label = 50001;
string full_label = 50002;
string tooltip = 50003;
string category = 50004;
string sidetext = 50005;
// Numeric constraints
double min_value = 50006;
double max_value = 50007;
double max_literal = 50008;
// UI behavior
ConfigMode mode = 50009;
string ratio_over = 50010;
bool multiline = 50013;
bool full_width = 50014;
int32 height = 50015;
// Classification
PresetType preset = 50011;
repeated InvalidationStep invalidates = 50012;
repeated OptionListMembership list_membership = 50018;
// Migration
string legacy_name = 50016;
// Nullable support (for ConfigOptionFloatsNullable, etc.)
bool is_nullable = 50017;
// GUI type override (e.g. i_enum_open, color, f_enum_open)
GuiType gui_type = 50019;
string gui_flags = 50020;
// Enum metadata (key map reference for C++ enum binding)
string enum_keys_map_ref = 50021;
// Whether this option should not appear in CLI
bool no_cli = 50022;
// ConfigOptionDef::readonly
bool readonly = 50023;
// Override the auto-detected co_type (e.g. coPercent, coEnum)
// Used when proto type (float, int32) is ambiguous
CoTypeHint co_type_hint = 50024;
// Default value — constructor args only (e.g. "1.0", "5000.0, 5000.0")
// Codegen reconstructs full C++ from co_type + this value
string default_value = 50025;
// Whether a default value is present (needed because proto3 can't
// distinguish "set to empty string" from "not set")
bool has_default = 50028;
// Enum values (string keys for coEnum options)
repeated string enum_value_entries = 50026;
// Enum labels (display names for enum values)
repeated string enum_label_entries = 50027;
// UI layout: where this option appears in Tab.cpp
// tab_type = "Print" | "Filament" | "Printer"
// tab_page = page title as shown in the UI (e.g. "Quality")
// tab_optgroup = optgroup title within that page (e.g. "Layer height")
string tab_type = 50029;
string tab_page = 50030;
string tab_optgroup = 50031;
}
// --- Message-level options ---
extend google.protobuf.MessageOptions {
// Virtual keys: preset option keys that belong to this preset type but have
// no ConfigOptionDef entry (printer metadata, host settings, compatibility
// flags, filament retraction overrides, cross-preset keys, etc.).
// The codegen emits these directly into s_Preset_*_options alongside the
// field-derived keys, so no hand-written extender is needed in Preset.cpp.
repeated string virtual_preset_keys = 60001;
}
// --- Wrapper messages for complex types ---
// Represents ConfigOptionFloatOrPercent
message FloatOrPercent {
double value = 1;
bool percent = 2;
}
// Represents ConfigOptionPoint (Vec2d)
message Point2D {
double x = 1;
double y = 2;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,687 @@
tabs:
- name: TabPrint
pages:
- name: "Quality"
icon: "custom-gcode_quality"
groups:
- name: "Layer height"
fields:
- layer_height
- initial_layer_print_height
- name: "Line width"
fields:
- line_width
- initial_layer_line_width
- outer_wall_line_width
- inner_wall_line_width
- top_surface_line_width
- sparse_infill_line_width
- internal_solid_infill_line_width
- bridge_line_width: quality_settings_line_width#bridge
- support_line_width
- name: "Seam"
fields:
- seam_position
- staggered_inner_seams
- seam_gap
- seam_slope_type
- seam_slope_conditional
- scarf_angle_threshold
- scarf_overhang_threshold
- scarf_joint_speed
- seam_slope_start_height
- seam_slope_entire_loop
- seam_slope_min_length
- seam_slope_steps
- scarf_joint_flow_ratio
- seam_slope_inner_walls
- role_based_wipe_speed
- wipe_speed
- wipe_on_loops
- wipe_before_external_loop
- name: "Precision"
fields:
- slice_closing_radius
- resolution
- enable_arc_fitting
- xy_hole_compensation
- xy_contour_compensation
- elefant_foot_compensation
- elefant_foot_layers_density
- elefant_foot_compensation_layers
- precise_outer_wall
- precise_z_height
- hole_to_polyhole
- hole_to_polyhole_threshold
- hole_to_polyhole_twisted
- hole_to_polyhole_max_edges
- name: "Ironing"
fields:
- ironing_type
- ironing_pattern
- ironing_flow
- ironing_spacing
- ironing_inset
- ironing_angle
- ironing_angle_fixed
- name: "Wall generator"
fields:
- wall_generator
- wall_transition_angle
- wall_transition_filter_deviation
- wall_transition_length
- wall_distribution_count
- initial_layer_min_bead_width
- min_bead_width
- min_feature_size
- min_length_factor
- wall_maximum_resolution
- wall_maximum_deviation
- name: "Walls and surfaces"
fields:
- wall_sequence
- is_infill_first
- wall_direction
- print_flow_ratio
- top_solid_infill_flow_ratio
- bottom_solid_infill_flow_ratio
- set_other_flow_ratios
- first_layer_flow_ratio
- outer_wall_flow_ratio
- inner_wall_flow_ratio
- overhang_flow_ratio
- sparse_infill_flow_ratio
- internal_solid_infill_flow_ratio
- gap_fill_flow_ratio
- support_flow_ratio
- support_interface_flow_ratio
- only_one_wall_first_layer
- only_one_wall_top
- min_width_top_surface
- reduce_crossing_wall
- max_travel_detour_distance
- small_area_infill_flow_compensation
- small_area_infill_flow_compensation_model
- name: "Bridging"
fields:
- bridge_flow
- internal_bridge_flow
- bridge_density
- internal_bridge_density
- thick_bridges
- thick_internal_bridges
- enable_extra_bridge_layer
- dont_filter_internal_bridges
- counterbore_hole_bridging
- name: "Overhangs"
fields:
- detect_overhang_wall
- make_overhang_printable
- make_overhang_printable_angle
- make_overhang_printable_hole_size
- extra_perimeters_on_overhangs
- overhang_reverse
- overhang_reverse_internal_only
- overhang_reverse_threshold
- name: "Strength"
icon: "custom-gcode_strength"
groups:
- name: "Walls"
fields:
- wall_loops
- alternate_extra_wall
- detect_thin_wall
- name: "Top/bottom shells"
fields:
- top_shell_layers
- top_shell_thickness
- top_surface_density
- top_surface_pattern
- top_layer_direction
- top_surface_expansion: strength_settings_top_bottom_shells#surface-expansion
- top_surface_expansion_margin: strength_settings_top_bottom_shells#surface-expansion-margin
- top_surface_expansion_direction: strength_settings_top_bottom_shells#surface-expansion-direction
- bottom_shell_layers
- bottom_shell_thickness
- bottom_surface_density
- bottom_surface_pattern
- bottom_layer_direction
- center_of_surface_pattern: strength_settings_top_bottom_shells#center-surface-pattern-on
- anisotropic_surfaces: strength_settings_top_bottom_shells#anisotropic-surfaces
- top_bottom_infill_wall_overlap
- name: "Infill"
fields:
- sparse_infill_density
- fill_multiline
- sparse_infill_pattern
- infill_direction
- sparse_infill_rotate_template
- skin_infill_density
- skeleton_infill_density
- infill_lock_depth
- skin_infill_depth
- skin_infill_line_width
- skeleton_infill_line_width
- symmetric_infill_y_axis
- infill_shift_step
- lateral_lattice_angle_1
- lateral_lattice_angle_2
- infill_overhang_angle
- infill_anchor_max
- infill_anchor
- internal_solid_infill_pattern
- solid_infill_direction
- solid_infill_rotate_template
- gap_fill_target
- filter_out_gap_fill
- separated_infills: strength_settings_infill#separated-infills
- infill_wall_overlap
- lightning_overhang_angle: strength_settings_patterns#lightning
- lightning_prune_angle: strength_settings_patterns#lightning
- lightning_straightening_angle: strength_settings_patterns#lightning
- name: "Advanced"
fields:
- align_infill_direction_to_model
- extra_solid_infills
- bridge_angle
- internal_bridge_angle
- relative_bridge_angle: strength_settings_advanced#relative-bridge-angle
- minimum_sparse_infill_area
- infill_combination
- infill_combination_max_layer_height
- detect_narrow_internal_solid_infill
- ensure_vertical_shell_thickness
- name: "Speed"
icon: "custom-gcode_speed"
groups:
- name: "First layer speed"
fields:
- initial_layer_speed
- initial_layer_infill_speed
- initial_layer_travel_speed
- slow_down_layers
- name: "Other layers speed"
fields:
- outer_wall_speed
- inner_wall_speed
- small_perimeter_speed
- small_perimeter_threshold
- sparse_infill_speed
- internal_solid_infill_speed
- top_surface_speed
- gap_infill_speed
- ironing_speed
- support_speed
- support_interface_speed
- small_support_perimeter_speed
- small_support_perimeter_threshold
- name: "Overhang speed"
fields:
- enable_overhang_speed
- slowdown_for_curled_perimeters
- [overhang_1_4_speed, overhang_2_4_speed, overhang_3_4_speed, overhang_4_4_speed]
- [bridge_speed, internal_bridge_speed]
- name: "Travel speed"
fields:
- travel_speed
- name: "Acceleration"
fields:
- default_acceleration
- outer_wall_acceleration
- inner_wall_acceleration
- bridge_acceleration
- sparse_infill_acceleration
- internal_solid_infill_acceleration
- initial_layer_acceleration
- initial_layer_travel_acceleration
- top_surface_acceleration
- travel_acceleration
- accel_to_decel_enable
- accel_to_decel_factor
- name: "Jerk(XY)"
fields:
- default_junction_deviation
- default_jerk
- outer_wall_jerk
- inner_wall_jerk
- infill_jerk
- top_surface_jerk
- initial_layer_jerk
- initial_layer_travel_jerk
- travel_jerk
- name: "Advanced"
fields:
- max_volumetric_extrusion_rate_slope
- max_volumetric_extrusion_rate_slope_segment_length
- extrusion_rate_smoothing_external_perimeter_only
- name: "Support"
icon: "custom-gcode_support"
groups:
- name: "Support"
fields:
- enable_support
- support_type
- support_style
- support_threshold_angle
- support_threshold_overlap
- raft_first_layer_density
- raft_first_layer_expansion
- support_on_build_plate_only
- support_critical_regions_only
- support_remove_small_overhang
- name: "Raft"
fields:
- raft_layers
- raft_contact_distance
- name: "Support filament"
fields:
- support_filament
- support_interface_filament
- support_interface_not_for_body
- name: "Support ironing"
fields:
- support_ironing
- support_ironing_pattern
- support_ironing_flow
- support_ironing_spacing
- name: "Advanced"
fields:
- support_top_z_distance
- support_bottom_z_distance
- tree_support_wall_count
- support_base_pattern
- support_base_pattern_spacing
- support_angle
- support_interface_top_layers
- support_interface_bottom_layers
- support_interface_pattern
- support_interface_spacing
- support_bottom_interface_spacing
- support_expansion
- support_object_xy_distance
- support_object_first_layer_gap
- bridge_no_support
- max_bridge_length
- independent_support_layer_height
- name: "Tree supports"
fields:
- tree_support_tip_diameter
- tree_support_branch_distance
- tree_support_branch_distance_organic
- tree_support_top_rate
- tree_support_branch_diameter
- tree_support_branch_diameter_organic
- tree_support_branch_diameter_angle
- tree_support_branch_angle
- tree_support_branch_angle_organic
- tree_support_angle_slow
- tree_support_auto_brim
- tree_support_brim_width
- name: "Multimaterial"
icon: "custom-gcode_multi_material"
groups:
- name: "Prime tower"
fields:
- enable_prime_tower
- prime_tower_skip_points
- enable_tower_interface_features
- enable_tower_interface_cooldown_during_tower
- prime_tower_enable_framework
- prime_tower_width
- prime_volume
- prime_tower_brim_width
- prime_tower_infill_gap
- wipe_tower_rotation_angle
- wipe_tower_bridging
- wipe_tower_extra_spacing
- wipe_tower_extra_flow
- wipe_tower_max_purge_speed
- wipe_tower_wall_type
- wipe_tower_cone_angle
- wipe_tower_extra_rib_length
- wipe_tower_rib_width
- wipe_tower_fillet_wall
- wipe_tower_no_sparse_layers
- single_extruder_multi_material_priming
- name: "Filament for Features"
fields:
- wall_filament
- sparse_infill_filament
- solid_infill_filament
- wipe_tower_filament
- name: "Ooze prevention"
fields:
- ooze_prevention
- standby_temperature_delta
- preheat_time
- preheat_steps
- name: "Flush options"
fields:
- flush_into_infill
- flush_into_objects
- flush_into_support
- name: "Advanced"
fields:
- interlocking_beam
- toolchange_ordering: multimaterial_settings_advanced#toolchange-ordering
- interface_shells
- mmu_segmented_region_max_width
- mmu_segmented_region_interlocking_depth
- interlocking_beam_width
- interlocking_orientation
- interlocking_beam_layer_count
- interlocking_depth
- interlocking_boundary_avoidance
- name: "Others"
icon: "custom-gcode_other"
groups:
- name: "Skirt"
fields:
- skirt_loops
- skirt_type
- min_skirt_length
- skirt_distance
- skirt_start_angle
- skirt_speed
- skirt_height
- draft_shield
- single_loop_draft_shield
- name: "Brim"
fields:
- brim_type
- brim_width
- brim_object_gap
- brim_flow_ratio
- brim_use_efc_outline
- combine_brims
- brim_ears_max_angle
- brim_ears_detection_length
- name: "Special mode"
fields:
- slicing_mode
- print_sequence
- print_order
- spiral_mode
- spiral_mode_smooth
- spiral_mode_max_xy_smoothing
- spiral_starting_flow_ratio
- spiral_finishing_flow_ratio
- timelapse_type
- enable_wrapping_detection
- name: "Fuzzy Skin"
fields:
- fuzzy_skin
- fuzzy_skin_mode
- fuzzy_skin_noise_type
- fuzzy_skin_point_distance
- fuzzy_skin_thickness
- fuzzy_skin_scale
- fuzzy_skin_octaves
- fuzzy_skin_persistence
- fuzzy_skin_first_layer
- name: "G-code output"
fields:
- reduce_infill_retraction
- gcode_add_line_number
- gcode_comments
- gcode_label_objects
- exclude_object
- filename_format
- name: "Change extrusion role G-code" # HOOK
fields:
- process_change_extrusion_role_gcode
- name: "Post-processing Scripts"
fields:
- post_process
- name: "Notes"
fields:
- notes
- name: TabFilament
pages:
- name: "Filament"
icon: "custom-gcode_filament"
groups:
- name: "Basic information" # HOOK
fields:
- filament_type
- filament_vendor
- filament_soluble
- filament_is_support
- filament_change_length
- required_nozzle_HRC
- default_filament_colour
- filament_diameter
- filament_adhesiveness_category
- filament_density
- filament_shrink
- filament_shrinkage_compensation_z
- filament_cost
- temperature_vitrification
- idle_temperature
- [nozzle_temperature_range_low, nozzle_temperature_range_high]
- name: "Flow ratio and Pressure Advance"
fields:
- pellet_flow_coefficient
- filament_flow_ratio
- enable_pressure_advance
- pressure_advance
- adaptive_pressure_advance
- adaptive_pressure_advance_overhangs
- adaptive_pressure_advance_bridges
- adaptive_pressure_advance_model
- name: "Print chamber temperature"
fields:
- activate_chamber_temp_control
- chamber_temperature
- name: "Print temperature"
fields:
- [nozzle_temperature_initial_layer, nozzle_temperature]
- name: "Bed temperature"
fields:
- [supertack_plate_temp_initial_layer, supertack_plate_temp]
- [cool_plate_temp_initial_layer, cool_plate_temp]
- [textured_cool_plate_temp_initial_layer, textured_cool_plate_temp]
- [eng_plate_temp_initial_layer, eng_plate_temp]
- [hot_plate_temp_initial_layer, hot_plate_temp]
- [textured_plate_temp_initial_layer, textured_plate_temp]
- name: "Volumetric speed limitation"
fields:
- filament_adaptive_volumetric_speed
- filament_max_volumetric_speed
- name: "Cooling"
icon: "custom-gcode_cooling_fan"
groups:
- name: "Cooling for specific layer"
fields:
- close_fan_the_first_x_layers
- full_fan_speed_layer
- initial_layer_fan_speed: material_cooling#first-layer-fan-speed
- name: "Part cooling fan"
fields:
- [fan_min_speed, fan_cooling_layer_time]
- [fan_max_speed, slow_down_layer_time]
- reduce_fan_stop_start_freq
- slow_down_for_layer_cooling
- dont_slow_down_outer_wall
- slow_down_min_speed
- enable_overhang_bridge_fan
- overhang_fan_threshold
- overhang_fan_speed
- internal_bridge_fan_speed
- support_material_interface_fan_speed
- ironing_fan_speed
- name: "Auxiliary part cooling fan"
fields:
- additional_cooling_fan_speed
- name: "Exhaust fan"
fields:
- activate_air_filtration
- [activate_air_filtration_during_print, during_print_exhaust_fan_speed]
- [activate_air_filtration_on_completion, complete_print_exhaust_fan_speed]
- name: "Advanced"
icon: "custom-gcode_advanced"
groups:
- name: "Filament start G-code" # HOOK
fields:
- filament_start_gcode
- name: "Change extrusion role G-code" # HOOK
fields:
- filament_change_extrusion_role_gcode
- name: "Filament end G-code" # HOOK
fields:
- filament_end_gcode
- name: "Multimaterial"
icon: "custom-gcode_multi_material"
groups:
- name: "Wipe tower parameters"
fields:
- filament_minimal_purge_on_wipe_tower
- filament_tower_interface_pre_extrusion_dist
- filament_tower_interface_pre_extrusion_length
- filament_tower_ironing_area
- filament_tower_interface_purge_volume
- filament_tower_interface_print_temp
- name: "Multi Filament"
fields:
- long_retractions_when_ec
- retraction_distances_when_ec
- name: "Tool change parameters with single extruder MM printers"
fields:
- filament_loading_speed_start
- filament_loading_speed
- filament_unloading_speed_start
- filament_unloading_speed
- filament_toolchange_delay
- filament_cooling_moves
- filament_cooling_initial_speed
- filament_cooling_final_speed
- filament_stamping_loading_speed
- filament_stamping_distance
- filament_ramming_parameters # HOOK
- name: "Tool change parameters with multi extruder MM printers"
fields:
- filament_multitool_ramming
- filament_multitool_ramming_volume
- filament_multitool_ramming_flow
- name: "Dependencies"
icon: "advanced"
groups:
- name: "Compatible printers"
fields:
- compatible_printers # HOOK
- compatible_printers_condition
- name: "Compatible process profiles"
fields:
- compatible_prints # HOOK
- compatible_prints_condition
- name: "Notes"
icon: "custom-gcode_note"
groups:
- name: "Notes"
fields:
- filament_notes
- name: TabPrinter
pages:
- name: "Basic information"
icon: "custom-gcode_object-info"
groups:
- name: "Printable space"
icon: "param_printable_space"
hook: true
- name: "Advanced"
icon: "param_advanced"
hook: true
- name: "Cooling Fan"
icon: "param_cooling_fan"
hook: true
- name: "Extruder Clearance"
icon: "param_extruder_clearance"
fields:
- extruder_clearance_radius: printer_basic_information_extruder_clearance#radius
- extruder_clearance_height_to_rod: printer_basic_information_extruder_clearance#height-to-rod
- extruder_clearance_height_to_lid: printer_basic_information_extruder_clearance#height-to-lid
- name: "Adaptive bed mesh"
icon: "param_adaptive_mesh"
fields:
- bed_mesh_min: printer_basic_information_adaptive_bed_mesh#bed-mesh
- bed_mesh_max: printer_basic_information_adaptive_bed_mesh#bed-mesh
- bed_mesh_probe_distance: printer_basic_information_adaptive_bed_mesh#probe-point-distance
- adaptive_bed_mesh_margin: printer_basic_information_adaptive_bed_mesh#mesh-margin
- name: "Accessory"
icon: "param_accessory"
fields:
- nozzle_type: printer_basic_information_accessory#nozzle-type
- nozzle_hrc: printer_basic_information_accessory#nozzle-hrc
- auxiliary_fan: printer_basic_information_accessory#auxiliary-part-cooling-fan
- support_chamber_temp_control: printer_basic_information_accessory#support-controlling-chamber-temperature
- support_air_filtration: printer_basic_information_accessory#support-air-filtration
- name: "Machine G-code"
icon: "custom-gcode_gcode"
groups:
- name: "File header G-code"
icon: "param_gcode"
gcode: true
fields:
- file_start_gcode: ""
- name: "Machine start G-code"
icon: "param_gcode"
gcode: true
fields:
- machine_start_gcode: printer_machine_gcode#machine-start-g-code
- name: "Machine end G-code"
icon: "param_gcode"
gcode: true
fields:
- machine_end_gcode: printer_machine_gcode#machine-end-g-code
- name: "Printing by object G-code"
icon: "param_gcode"
gcode: true
fields:
- printing_by_object_gcode: printer_machine_gcode#between-object-g-code
- name: "Before layer change G-code"
icon: "param_gcode"
gcode: true
fields:
- before_layer_change_gcode: printer_machine_gcode#before-layer-change-g-code
- name: "Layer change G-code"
icon: "param_gcode"
gcode: true
fields:
- layer_change_gcode: printer_machine_gcode#after-layer-change-g-code
- name: "Timelapse G-code"
icon: "param_gcode"
gcode: true
fields:
- time_lapse_gcode: printer_machine_gcode#time-lapse-g-code
- name: "Clumping Detection G-code"
icon: "param_gcode"
gcode: true
fields:
- wrapping_detection_gcode: printer_machine_gcode#clumping-detection-g-code
- name: "Change filament G-code"
icon: "param_gcode"
gcode: true
fields:
- change_filament_gcode: printer_machine_gcode#change-filament-g-code
- name: "Change extrusion role G-code"
icon: "param_gcode"
gcode: true
fields:
- change_extrusion_role_gcode: printer_machine_gcode#change-extrusion-role-g-code
- name: "Pause G-code"
icon: "param_gcode"
gcode: true
fields:
- machine_pause_gcode: printer_machine_gcode#pause-g-code
- name: "Template Custom G-code"
icon: "param_gcode"
gcode: true
fields:
- template_custom_gcode: printer_machine_gcode#template-custom-g-code
- name: "Notes"
icon: "custom-gcode_note"
groups:
- name: "Notes"
icon: "note"
fields:
- printer_notes: ""

7502
src/PrintConfigs/print.proto Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,967 @@
// OrcaSlicer - PrinterSettings
// Edit this file and re-run: python tools/run_codegen.py
syntax = "proto3";
import "config_metadata.proto";
package orca;
message PrinterSettings {
// ── Virtual keys: not in PrintConfigDef, but required in printer presets ──
// Printer identity / bed shape (handled by Preset/PrinterConfig directly)
option (virtual_preset_keys) = "bed_custom_model";
option (virtual_preset_keys) = "bed_custom_texture";
option (virtual_preset_keys) = "bed_exclude_area";
option (virtual_preset_keys) = "bbl_use_printhost";
option (virtual_preset_keys) = "default_print_profile";
option (virtual_preset_keys) = "extruder_printable_area";
option (virtual_preset_keys) = "extruder_variant_list";
option (virtual_preset_keys) = "grab_length";
option (virtual_preset_keys) = "head_wrap_detect_zone";
option (virtual_preset_keys) = "inherits";
option (virtual_preset_keys) = "physical_extruder_map";
option (virtual_preset_keys) = "printable_area";
option (virtual_preset_keys) = "printable_height";
option (virtual_preset_keys) = "extruder_printable_height";
option (virtual_preset_keys) = "printer_agent";
option (virtual_preset_keys) = "printer_extruder_id";
option (virtual_preset_keys) = "printer_extruder_variant";
option (virtual_preset_keys) = "printer_model";
option (virtual_preset_keys) = "printer_technology";
option (virtual_preset_keys) = "printer_variant";
option (virtual_preset_keys) = "silent_mode";
option (virtual_preset_keys) = "support_object_skip_flush";
// Print-host / connectivity
option (virtual_preset_keys) = "host_type";
option (virtual_preset_keys) = "print_host";
option (virtual_preset_keys) = "print_host_webui";
option (virtual_preset_keys) = "printhost_apikey";
option (virtual_preset_keys) = "printhost_authorization_type";
option (virtual_preset_keys) = "printhost_cafile";
option (virtual_preset_keys) = "printhost_port";
option (virtual_preset_keys) = "printhost_password";
option (virtual_preset_keys) = "printhost_ssl_ignore_revoke";
option (virtual_preset_keys) = "printhost_user";
// Cross-preset: defined in print.proto but also saved in printer presets
option (virtual_preset_keys) = "bed_temperature_formula";
option (virtual_preset_keys) = "cooling_tube_length";
option (virtual_preset_keys) = "cooling_tube_retraction";
option (virtual_preset_keys) = "default_bed_type";
option (virtual_preset_keys) = "default_nozzle_volume_type";
option (virtual_preset_keys) = "emit_machine_limits_to_gcode";
option (virtual_preset_keys) = "enable_filament_ramming";
option (virtual_preset_keys) = "enable_long_retraction_when_cut";
option (virtual_preset_keys) = "extra_loading_move";
option (virtual_preset_keys) = "extruder_type";
option (virtual_preset_keys) = "high_current_on_filament_swap";
option (virtual_preset_keys) = "long_retractions_when_cut";
option (virtual_preset_keys) = "machine_load_filament_time";
option (virtual_preset_keys) = "machine_tool_change_time";
option (virtual_preset_keys) = "machine_unload_filament_time";
option (virtual_preset_keys) = "manual_filament_change";
option (virtual_preset_keys) = "master_extruder_id";
option (virtual_preset_keys) = "nozzle_flush_dataset";
option (virtual_preset_keys) = "nozzle_height";
option (virtual_preset_keys) = "nozzle_volume";
option (virtual_preset_keys) = "parking_pos_retraction";
option (virtual_preset_keys) = "preferred_orientation";
option (virtual_preset_keys) = "purge_in_prime_tower";
option (virtual_preset_keys) = "retract_lift_enforce";
option (virtual_preset_keys) = "retraction_distances_when_cut";
option (virtual_preset_keys) = "single_extruder_multi_material";
option (virtual_preset_keys) = "thumbnails_format";
option (virtual_preset_keys) = "tool_change_on_wipe_tower";
option (virtual_preset_keys) = "travel_slope";
option (virtual_preset_keys) = "upward_compatible_machine";
option (virtual_preset_keys) = "wipe_tower_type";
option (virtual_preset_keys) = "wrapping_detection_layers";
option (virtual_preset_keys) = "wrapping_exclude_area";
option (virtual_preset_keys) = "z_hop_types";
// Printer keys with hand-written defs in init_common_params (not proto fields);
// declared here so they land in s_Preset_printer_options and vendor machine
// profiles that set them are not stripped on load.
option (virtual_preset_keys) = "use_3mf";
option (virtual_preset_keys) = "support_parallel_printheads";
option (virtual_preset_keys) = "parallel_printheads_count";
option (virtual_preset_keys) = "parallel_printheads_bed_exclude_areas";
float extruder_clearance_height_to_rod = 1 [
(label) = "Height to rod",
(tooltip) = "Distance of the nozzle tip to the lower rod. Used for collision avoidance in by-object printing.",
(category) = "Printer/Basic information",
(sidetext) = "mm",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Extruder Clearance",
(min_value) = 0,
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "40",
(invalidates) = STEP_GCODE_EXPORT
];
float extruder_clearance_height_to_lid = 2 [
(label) = "Height to lid",
(tooltip) = "Distance of the nozzle tip to the lid. Used for collision avoidance in by-object printing.",
(category) = "Printer/Basic information",
(sidetext) = "mm",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Extruder Clearance",
(min_value) = 0,
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "120",
(invalidates) = STEP_GCODE_EXPORT
];
float extruder_clearance_radius = 3 [
(label) = "Radius",
(tooltip) = "Clearance radius around extruder. Used for collision avoidance in by-object printing.",
(category) = "Printer/Basic information",
(sidetext) = "mm",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Extruder Clearance",
(min_value) = 0,
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "40",
(invalidates) = STEP_GCODE_EXPORT
];
Point2D bed_mesh_min = 4 [
(label) = "Bed mesh min",
(tooltip) = "This option sets the min point for the allowed bed mesh area. Due to the probe's XY offset, most printers are unable to probe the entire bed. To ensure the probe point does not go outside the bed area, the minimum and maximum points of the bed mesh should be set appropriately. OrcaSlicer ensures that adaptive_bed_mesh_min/adaptive_bed_mesh_max values do not exceed these min/max points. This information can usually be obtained from your printer manufacturer. The default setting is (-99999, -99999), which means there are no limits, thus allowing probing across the entire bed.",
(category) = "Printer/Basic information",
(sidetext) = "mm",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Adaptive bed mesh",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "Vec2d(-99999, -99999)"
];
Point2D bed_mesh_max = 5 [
(label) = "Bed mesh max",
(tooltip) = "This option sets the max point for the allowed bed mesh area. Due to the probe's XY offset, most printers are unable to probe the entire bed. To ensure the probe point does not go outside the bed area, the minimum and maximum points of the bed mesh should be set appropriately. OrcaSlicer ensures that adaptive_bed_mesh_min/adaptive_bed_mesh_max values do not exceed these min/max points. This information can usually be obtained from your printer manufacturer. The default setting is (99999, 99999), which means there are no limits, thus allowing probing across the entire bed.",
(category) = "Printer/Basic information",
(sidetext) = "mm",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Adaptive bed mesh",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "Vec2d(99999, 99999)"
];
Point2D bed_mesh_probe_distance = 6 [
(label) = "Probe point distance",
(tooltip) = "This option sets the preferred distance between probe points (grid size) for the X and Y directions, with the default being 50mm for both X and Y.",
(category) = "Printer/Basic information",
(sidetext) = "mm",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Adaptive bed mesh",
(min_value) = 0,
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "Vec2d(50, 50)"
];
float adaptive_bed_mesh_margin = 7 [
(label) = "Mesh margin",
(tooltip) = "This option determines the additional distance by which the adaptive bed mesh area should be expanded in the XY directions.",
(category) = "Printer/Basic information",
(sidetext) = "mm",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Adaptive bed mesh",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "0"
];
bool scan_first_layer = 8 [
(label) = "Scan first layer",
(tooltip) = "Enable this to enable the camera on printer to check the quality of first layer.",
(category) = "Printer/Basic information",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Advanced",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "false"
];
int32 enable_power_loss_recovery = 9 [
(label) = "Power Loss Recovery",
(tooltip) = "Choose how to control power loss recovery. When set to Printer configuration, the slicer will not emit power loss recovery G-code and will leave the printer's configuration unchanged. Applicable to Bambu Lab or Marlin 2 firmware based printers.",
(category) = "Printer/Basic information",
(enum_keys_map_ref) = "ConfigOptionEnum<PowerLossRecoveryMode>::get_enum_values()",
(co_type_hint) = coEnum,
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Advanced",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "PowerLossRecoveryMode::PrinterConfiguration",
(enum_value_entries) = "printer_configuration",
(enum_value_entries) = "enable",
(enum_value_entries) = "disable",
(enum_label_entries) = "Printer configuration",
(enum_label_entries) = "Enable",
(enum_label_entries) = "Disable"
];
repeated int32 nozzle_type = 10 [
(label) = "Nozzle type",
(tooltip) = "The metallic material of nozzle. This determines the abrasive resistance of nozzle, and what kind of filament can be printed.",
(category) = "Printer/Basic information",
(enum_keys_map_ref) = "ConfigOptionEnum<NozzleType>::get_enum_values()",
(co_type_hint) = coEnums,
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Accessory",
(mode) = MODE_ADVANCED,
(is_nullable) = true,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "ntUndefine",
(enum_value_entries) = "undefine",
(enum_value_entries) = "hardened_steel",
(enum_value_entries) = "stainless_steel",
(enum_value_entries) = "tungsten_carbide",
(enum_value_entries) = "brass",
(enum_label_entries) = "Undefine",
(enum_label_entries) = "Hardened steel",
(enum_label_entries) = "Stainless steel",
(enum_label_entries) = "Tungsten carbide",
(enum_label_entries) = "Brass",
(list_membership) = LIST_EXTRUDER_OPTION_KEYS
];
int32 nozzle_hrc = 11 [
(label) = "Nozzle HRC",
(tooltip) = "The nozzle's hardness. Zero means no checking for nozzle's hardness during slicing.",
(category) = "Printer/Basic information",
(sidetext) = "HRC",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Accessory",
(min_value) = 0,
(max_value) = 500,
(mode) = MODE_DEVELOP,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "0",
(invalidates) = STEP_GCODE_EXPORT
];
int32 printer_structure = 12 [
(label) = "Printer structure",
(tooltip) = "The physical arrangement and components of a printing device.",
(category) = "Printer/Basic information",
(enum_keys_map_ref) = "ConfigOptionEnum<PrinterStructure>::get_enum_values()",
(co_type_hint) = coEnum,
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Advanced",
(mode) = MODE_DEVELOP,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "psUndefine",
(enum_value_entries) = "undefine",
(enum_value_entries) = "corexy",
(enum_value_entries) = "i3",
(enum_value_entries) = "hbot",
(enum_value_entries) = "delta",
(enum_label_entries) = "Undefine",
(enum_label_entries) = "CoreXY",
(enum_label_entries) = "I3",
(enum_label_entries) = "Hbot",
(enum_label_entries) = "Delta"
];
Point2D best_object_pos = 13 [
(label) = "Best object position",
(tooltip) = "Best auto arranging position in range [0,1] w.r.t. bed shape.",
(category) = "Printer/Basic information",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Printable space",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "Vec2d(0.5, 0.5)"
];
bool auxiliary_fan = 14 [
(label) = "Auxiliary part cooling fan",
(tooltip) = "Enable this option if machine has auxiliary part cooling fan. G-code command: M106 P2 S(0-255).",
(category) = "Printer/Basic information",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Accessory",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "false"
];
float fan_speedup_time = 15 [
(tooltip) = "Start the fan this number of seconds earlier than its target start time (you can use fractional seconds). It assumes infinite acceleration for this time estimation, and will only take into account G1 and G0 moves (arc fitting is unsupported).\\nIt won't move fan commands from custom G-code (they act as a sort of 'barrier').\\nIt won't move fan commands into the start G-code if the 'only custom start G-code' is activated.\\nUse 0 to deactivate.",
(category) = "Printer/Basic information",
(sidetext) = "s",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Cooling Fan",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "0",
(invalidates) = STEP_GCODE_EXPORT
];
bool fan_speedup_overhangs = 16 [
(label) = "Only overhangs",
(tooltip) = "Will only take into account the delay for the cooling of overhangs.",
(category) = "Printer/Basic information",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Cooling Fan",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "true",
(invalidates) = STEP_GCODE_EXPORT
];
float fan_kickstart = 17 [
(label) = "Fan kick-start time",
(tooltip) = "Emit a max fan speed command for this amount of seconds before reducing to target speed to kick-start the cooling fan.\\nThis is useful for fans where a low PWM/power may be insufficient to get the fan started spinning from a stop, or to get the fan up to speed faster.\\nSet to 0 to deactivate.",
(category) = "Printer/Basic information",
(sidetext) = "s",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Cooling Fan",
(min_value) = 0,
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "0",
(invalidates) = STEP_GCODE_EXPORT
];
int32 part_cooling_fan_min_pwm = 18 [
(label) = "Minimum non-zero part cooling fan speed",
(tooltip) = "Some part-cooling fans cannot start spinning when commanded below a certain PWM duty cycle. When set above 0, any non-zero part-cooling fan command will be raised to at least this percentage so the fan reliably starts. A fan command of 0 (fan off) is always honoured exactly. This clamp is applied after every other fan calculation (first-layer ramp, layer-time interpolation, overhang/bridge/support-interface/ironing overrides), so scaling still operates within the range [this value, 100%].\\nIf your firmware already disables the fan below a threshold (for example Klipper's [fan] off_below: 0.10 shuts the fan off whenever the commanded duty cycle is below 10%), this option and the firmware threshold should ideally be set to the same value. Matching them (e.g. off_below: 0.10 in Klipper and 10% here) guarantees the slicer never emits a non-zero value that the firmware would silently drop, and the fan never receives a value below the one you know it can actually spool at.\\nSet to 0 to deactivate.",
(category) = "Printer/Basic information",
(sidetext) = "%",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Cooling Fan",
(min_value) = 0,
(max_value) = 100,
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "0",
(invalidates) = STEP_GCODE_EXPORT
];
float time_cost = 19 [
(label) = "Time cost",
(tooltip) = "The printer cost per hour.",
(category) = "Printer/Basic information",
(sidetext) = "money/h",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Advanced",
(min_value) = 0,
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "0"
];
bool support_chamber_temp_control = 20 [
(label) = "Support control chamber temperature",
(tooltip) = "This option is enabled if machine support controlling chamber temperature\\nG-code command: M141 S(0-255)",
(category) = "Printer/Basic information",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Accessory",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "true"
];
bool support_air_filtration = 21 [
(label) = "Support air filtration",
(tooltip) = "Enable this if printer support air filtration\\nG-code command: M106 P3 S(0-255)",
(category) = "Printer/Basic information",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Accessory",
(mode) = MODE_DEVELOP,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "true"
];
int32 gcode_flavor = 22 [
(label) = "G-code flavor",
(tooltip) = "What kind of G-code the printer is compatible with.",
(category) = "Printer/Basic information",
(enum_keys_map_ref) = "ConfigOptionEnum<GCodeFlavor>::get_enum_values()",
(co_type_hint) = coEnum,
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Advanced",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "gcfMarlinLegacy",
(enum_value_entries) = "marlin",
(enum_value_entries) = "klipper",
(enum_value_entries) = "reprapfirmware",
(enum_value_entries) = "repetier",
(enum_value_entries) = "marlin2",
(enum_value_entries) = "reprap",
(enum_value_entries) = "teacup",
(enum_value_entries) = "makerware",
(enum_value_entries) = "sailfish",
(enum_value_entries) = "mach3",
(enum_value_entries) = "machinekit",
(enum_value_entries) = "smoothie",
(enum_value_entries) = "no-extrusion",
(enum_label_entries) = "Marlin(legacy)",
(enum_label_entries) = "Klipper",
(enum_label_entries) = "RepRapFirmware",
(enum_label_entries) = "Repetier",
(enum_label_entries) = "Marlin 2",
(enum_label_entries) = "RepRap/Sprinter",
(enum_label_entries) = "Teacup",
(enum_label_entries) = "MakerWare (MakerBot)",
(enum_label_entries) = "Sailfish (MakerBot)",
(enum_label_entries) = "Mach3/LinuxCNC",
(enum_label_entries) = "Machinekit",
(enum_label_entries) = "Smoothie",
(enum_label_entries) = "No extrusion",
(invalidates) = STEP_SKIRT_BRIM,
(invalidates) = STEP_WIPE_TOWER
];
bool pellet_modded_printer = 23 [
(label) = "Pellet Modded Printer",
(tooltip) = "Enable this option if your printer uses pellets instead of filaments.",
(category) = "Printer/Basic information",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Advanced",
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "false"
];
bool support_multi_bed_types = 24 [
(label) = "Support multi bed types",
(tooltip) = "Enable this option if you want to use multiple bed types.",
(category) = "Printer/Basic information",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Printable space",
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "false",
(invalidates) = STEP_SKIRT_BRIM,
(invalidates) = STEP_WIPE_TOWER
];
bool use_firmware_retraction = 25 [
(label) = "Use firmware retraction",
(tooltip) = "This experimental setting uses G10 and G11 commands to have the firmware handle the retraction. This is only supported in recent Marlin.",
(category) = "Printer/Basic information",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Advanced",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "false",
(invalidates) = STEP_GCODE_EXPORT
];
bool disable_m73 = 26 [
(label) = "Disable set remaining print time",
(tooltip) = "Disable generating of the M73: Set remaining print time in the final G-code.",
(category) = "Printer/Basic information",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Advanced",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "false",
(invalidates) = STEP_GCODE_EXPORT
];
float z_offset = 27 [
(label) = "Z offset",
(tooltip) = "This value will be added (or subtracted) from all the Z coordinates in the output G-code. It is used to compensate for bad Z endstop position: for example, if your endstop zero actually leaves the nozzle 0.3mm far from the print bed, set this to -0.3 (or fix your endstop).",
(category) = "Printer/Basic information",
(sidetext) = "mm",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Printable space",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "0",
(invalidates) = STEP_SKIRT_BRIM,
(invalidates) = STEP_WIPE_TOWER
];
string thumbnails = 28 [
(label) = "G-code thumbnails",
(tooltip) = "Picture sizes to be stored into a .gcode and .sl1 / .sl1s files, in the following format: \\\"XxY, XxY, ...\\\"",
(category) = "Printer/Basic information",
(gui_type) = one_string,
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Advanced",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "\"48x48/PNG,300x300/PNG\"",
(invalidates) = STEP_GCODE_EXPORT
];
bool use_relative_e_distances = 29 [
(label) = "Use relative E distances",
(tooltip) = "Relative extrusion is recommended when using \\\"label_objects\\\" option. Some extruders work better with this option unchecked (absolute extrusion mode). Wipe tower is only compatible with relative mode. It is recommended on most printers. Default is checked.",
(category) = "Printer/Basic information",
(tab_type) = "Printer",
(tab_page) = "Basic information",
(tab_optgroup) = "Advanced",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "true",
(invalidates) = STEP_GCODE_EXPORT
];
string before_layer_change_gcode = 30 [
(label) = "Before layer change G-code",
(tooltip) = "This G-code is inserted at every layer change before the Z lift.",
(category) = "Printer/Machine G-code",
(tab_type) = "Printer",
(tab_page) = "Machine G-code",
(tab_optgroup) = "Before layer change G-code",
(height) = 5,
(mode) = MODE_ADVANCED,
(multiline) = true,
(full_width) = true,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "",
(invalidates) = STEP_GCODE_EXPORT
];
string machine_end_gcode = 31 [
(label) = "End G-code",
(tooltip) = "End G-code when finishing the entire print.",
(category) = "Printer/Machine G-code",
(tab_type) = "Printer",
(tab_page) = "Machine G-code",
(tab_optgroup) = "Machine end G-code",
(height) = 12,
(mode) = MODE_ADVANCED,
(multiline) = true,
(full_width) = true,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "\"M104 S0 ; turn off temperature\nG28 X0 ; home X axis\nM84 ; disable motors\n\"",
(invalidates) = STEP_GCODE_EXPORT
];
string printing_by_object_gcode = 32 [
(label) = "Between Object G-code",
(tooltip) = "Insert G-code between objects. This parameter will only come into effect when you print your models object by object.",
(category) = "Printer/Machine G-code",
(tab_type) = "Printer",
(tab_page) = "Machine G-code",
(tab_optgroup) = "Printing by object G-code",
(height) = 12,
(mode) = MODE_ADVANCED,
(multiline) = true,
(full_width) = true,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "",
(invalidates) = STEP_GCODE_EXPORT
];
string layer_change_gcode = 33 [
(label) = "Layer change G-code",
(tooltip) = "This G-code is inserted at every layer change after the Z lift.",
(category) = "Printer/Machine G-code",
(tab_type) = "Printer",
(tab_page) = "Machine G-code",
(tab_optgroup) = "Layer change G-code",
(height) = 5,
(mode) = MODE_ADVANCED,
(multiline) = true,
(full_width) = true,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "",
(invalidates) = STEP_GCODE_EXPORT
];
string time_lapse_gcode = 34 [
(label) = "Timelapse G-code",
(category) = "Printer/Machine G-code",
(tab_type) = "Printer",
(tab_page) = "Machine G-code",
(tab_optgroup) = "Timelapse G-code",
(height) = 5,
(mode) = MODE_ADVANCED,
(multiline) = true,
(full_width) = true,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "",
(invalidates) = STEP_GCODE_EXPORT
];
string wrapping_detection_gcode = 35 [
(label) = "Clumping detection G-code",
(category) = "Printer/Machine G-code",
(tab_type) = "Printer",
(tab_page) = "Machine G-code",
(tab_optgroup) = "Clumping Detection G-code",
(height) = 5,
(mode) = MODE_ADVANCED,
(multiline) = true,
(full_width) = true,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "\"\"",
(invalidates) = STEP_GCODE_EXPORT
];
string machine_pause_gcode = 36 [
(label) = "Pause G-code",
(tooltip) = "This G-code will be used as a code for the pause print. Users can insert pause G-code in the G-code viewer.",
(category) = "Printer/Machine G-code",
(tab_type) = "Printer",
(tab_page) = "Machine G-code",
(tab_optgroup) = "Pause G-code",
(height) = 12,
(mode) = MODE_ADVANCED,
(multiline) = true,
(full_width) = true,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = ""
];
string template_custom_gcode = 37 [
(label) = "Custom G-code",
(tooltip) = "This G-code will be used as a custom code.",
(category) = "Printer/Machine G-code",
(tab_type) = "Printer",
(tab_page) = "Machine G-code",
(tab_optgroup) = "Template Custom G-code",
(height) = 12,
(mode) = MODE_ADVANCED,
(multiline) = true,
(full_width) = true,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = ""
];
string file_start_gcode = 38 [
(label) = "File header G-code",
(tooltip) = "G-code written at the very top of the output file, before any other content. Useful for adding metadata that printer firmware reads from the first lines of the file (e.g. estimated print time, filament usage). Supports placeholders like {print_time_sec} and {used_filament_length}.",
(category) = "Printer/Machine G-code",
(tab_type) = "Printer",
(tab_page) = "Machine G-code",
(tab_optgroup) = "File header G-code",
(height) = 8,
(mode) = MODE_ADVANCED,
(multiline) = true,
(full_width) = true,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "\"\""
];
string machine_start_gcode = 39 [
(label) = "Start G-code",
(tooltip) = "Start G-code when starting the entire print.",
(category) = "Printer/Machine G-code",
(tab_type) = "Printer",
(tab_page) = "Machine G-code",
(tab_optgroup) = "Machine start G-code",
(height) = 12,
(mode) = MODE_ADVANCED,
(multiline) = true,
(full_width) = true,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "\"G28 ; home all axes\nG1 Z5 F5000 ; lift nozzle\n\"",
(invalidates) = STEP_GCODE_EXPORT
];
string change_filament_gcode = 40 [
(label) = "Change filament G-code",
(tooltip) = "This G-code is inserted when filament is changed, including T commands to trigger tool change.",
(category) = "Printer/Machine G-code",
(tab_type) = "Printer",
(tab_page) = "Machine G-code",
(tab_optgroup) = "Change filament G-code",
(height) = 5,
(mode) = MODE_ADVANCED,
(multiline) = true,
(full_width) = true,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "",
(invalidates) = STEP_GCODE_EXPORT
];
string change_extrusion_role_gcode = 41 [
(label) = "Change extrusion role G-code",
(tooltip) = "This G-code is inserted when the extrusion role is changed.",
(category) = "Printer/Machine G-code",
(tab_type) = "Printer",
(tab_page) = "Machine G-code",
(tab_optgroup) = "Change extrusion role G-code",
(height) = 5,
(mode) = MODE_ADVANCED,
(multiline) = true,
(full_width) = true,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = ""
];
string printer_notes = 42 [
(label) = "Printer notes",
(tooltip) = "You can put your notes regarding the printer here.",
(category) = "Printer/Notes",
(tab_type) = "Printer",
(tab_page) = "Notes",
(tab_optgroup) = "Notes",
(height) = 13,
(mode) = MODE_ADVANCED,
(multiline) = true,
(full_width) = true,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "",
(invalidates) = STEP_GCODE_EXPORT
];
bool cooling_filter_enabled = 43 [
(label) = "Use cooling filter",
(tooltip) = "Enable this if printer support cooling filter",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "false"
];
repeated float deretract_speed_extruder_change = 44 [
(label) = "Deretraction speed (extruder change)",
(tooltip) = "Speed for reloading filament into the nozzle when switching extruder.",
(sidetext) = "mm/s",
(is_nullable) = true,
(mode) = MODE_DEVELOP,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "0."
];
bool enable_pre_heating = 45 [
(label) = "enable_pre_heating",
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "false"
];
repeated int32 extruder_max_nozzle_count = 46 [
(label) = "extruder_max_nozzle_count",
(is_nullable) = true,
(mode) = MODE_DEVELOP,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "1"
];
repeated int32 extruder_nozzle_count = 47 [
(label) = "extruder nozzle count",
(tooltip) = "extruder nozzle count",
(mode) = MODE_DEVELOP,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "1"
];
repeated string extruder_nozzle_stats = 48 [
(label) = "Extruder nozzle stats",
(tooltip) = "Physical nozzle counts per extruder, keyed by nozzle volume type.",
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = ""
];
repeated int32 extruder_nozzle_volume_type = 49 [
(label) = "Extruder nozzle volume type",
(tooltip) = "Nozzle volume type per physical nozzle of an extruder.",
(co_type_hint) = coEnums,
(enum_keys_map_ref) = "ConfigOptionEnum<NozzleVolumeType>::get_enum_values()",
(mode) = MODE_DEVELOP,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "NozzleVolumeType::nvtStandard",
(enum_value_entries) = "Standard",
(enum_value_entries) = "High Flow",
(enum_value_entries) = "TPU High Flow",
(enum_label_entries) = "Standard",
(enum_label_entries) = "High Flow",
(enum_label_entries) = "TPU High Flow"
];
int32 fan_direction = 50 [
(label) = "Fan direction",
(tooltip) = "Cooling fan direction of the printer",
(co_type_hint) = coEnum,
(enum_keys_map_ref) = "ConfigOptionEnum<FanDirection>::get_enum_values()",
(mode) = MODE_DEVELOP,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "fdUndefine",
(enum_value_entries) = "undefine",
(enum_value_entries) = "left",
(enum_value_entries) = "right",
(enum_value_entries) = "both",
(enum_label_entries) = "Undefined",
(enum_label_entries) = "Left",
(enum_label_entries) = "Right",
(enum_label_entries) = "Both"
];
bool farthest_point_timelapse = 51 [
(label) = "Farthest point timelapse",
(tooltip) = "When enabled, the timelapse snapshot is taken at the farthest point from camera instead of traveling to the wipe tower or excess chute. Only effective in traditional timelapse mode on non-I3 printers.",
(mode) = MODE_SIMPLE,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "false"
];
bool group_algo_with_time = 52 [
(label) = "group_algo_with_time",
(mode) = MODE_DEVELOP,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "false"
];
bool handle_hotend_as_extruder = 53 [
(label) = "handle_hotend_as_extruder",
(mode) = MODE_DEVELOP,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "false"
];
repeated float hotend_cooling_rate = 54 [
(label) = "hotend_cooling_rate",
(is_nullable) = true,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "2"
];
repeated float hotend_heating_rate = 55 [
(label) = "hotend_heating_rate",
(is_nullable) = true,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "2"
];
float machine_hotend_change_time = 56 [
(label) = "Hotend change time",
(tooltip) = "Time to change hotend.",
(sidetext) = "s",
(min_value) = 0,
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "0.0"
];
float machine_prepare_compensation_time = 57 [
(label) = "machine_prepare_compensation_time",
(mode) = MODE_DEVELOP,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "260"
];
bool support_cooling_filter = 58 [
(label) = "support_cooling_filter",
(mode) = MODE_ADVANCED,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "false"
];
bool support_fast_purge_mode = 59 [
(label) = "Support fast purge mode",
(tooltip) = "Whether this printer supports fast purge mode with optimized temperature and multiplier.",
(mode) = MODE_DEVELOP,
(preset) = PRESET_PRINTER,
(has_default) = true,
(default_value) = "false"
];
}

View File

@@ -493,6 +493,21 @@ add_library(libslic3r STATIC ${lisbslic3r_sources}
${OpenVDBUtils_SOURCES})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${lisbslic3r_sources})
# Ensure codegen runs before compiling libslic3r (PrintConfig.cpp, Preset.cpp, Print.cpp
# all #include generated files — MSVC tracks the #include deps automatically after first build,
# but this dependency ensures the generated files exist and are up-to-date before compilation).
if(TARGET codegen_config)
add_dependencies(libslic3r codegen_config)
# Tell cmake that the three source files that #include generated code depend on them,
# so an incremental build recompiles them when protos change.
set_source_files_properties(
"${CMAKE_CURRENT_SOURCE_DIR}/PrintConfig.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Preset.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Print.cpp"
PROPERTIES OBJECT_DEPENDS "${CONFIG_GENERATED_SOURCES}"
)
endif()
if (SLIC3R_STATIC)
set(CGAL_Boost_USE_STATIC_LIBS ON CACHE BOOL "" FORCE)
endif ()

View File

@@ -1002,388 +1002,8 @@ bool Preset::has_cali_lines(PresetBundle* preset_bundle)
return false;
}
static std::vector<std::string> s_Preset_print_options{
"layer_height",
"initial_layer_print_height",
"wall_loops",
"alternate_extra_wall",
"slice_closing_radius",
"spiral_mode",
"spiral_mode_smooth",
"spiral_mode_max_xy_smoothing",
"spiral_starting_flow_ratio",
"spiral_finishing_flow_ratio",
"slicing_mode",
"top_shell_layers",
"top_shell_thickness",
"top_surface_density",
"bottom_surface_density",
"bottom_shell_layers",
"bottom_shell_thickness",
"extra_perimeters_on_overhangs",
"ensure_vertical_shell_thickness",
"reduce_crossing_wall",
"detect_thin_wall",
"detect_overhang_wall",
"overhang_reverse",
"overhang_reverse_threshold",
"overhang_reverse_internal_only",
"wall_direction",
"seam_position",
"staggered_inner_seams",
"wall_sequence",
"is_infill_first",
"sparse_infill_density",
"fill_multiline",
"gyroid_optimized",
"sparse_infill_pattern",
"lateral_lattice_angle_1",
"lateral_lattice_angle_2",
"infill_overhang_angle",
"lightning_overhang_angle",
"lightning_prune_angle",
"lightning_straightening_angle",
"top_surface_pattern",
"top_surface_expansion",
"top_surface_expansion_margin",
"top_surface_expansion_direction",
"bottom_surface_pattern",
"top_surface_fill_order",
"bottom_surface_fill_order",
"infill_direction",
"solid_infill_direction",
"top_layer_direction",
"bottom_layer_direction",
"counterbore_hole_bridging",
"infill_shift_step",
"sparse_infill_rotate_template",
"solid_infill_rotate_template",
"symmetric_infill_y_axis",
"skeleton_infill_density",
"infill_lock_depth",
"skin_infill_depth",
"skin_infill_density",
"align_infill_direction_to_model",
"extra_solid_infills",
"center_of_surface_pattern",
"separated_infills",
"minimum_sparse_infill_area",
"reduce_infill_retraction",
"internal_solid_infill_pattern",
"gap_fill_target",
"ironing_type",
"ironing_pattern",
"ironing_flow",
"ironing_speed",
"ironing_spacing",
"ironing_angle",
"ironing_angle_fixed",
"ironing_inset",
"support_ironing",
"support_ironing_pattern",
"support_ironing_flow",
"support_ironing_spacing",
"max_travel_detour_distance",
"fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_noise_type", "fuzzy_skin_mode", "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence", "fuzzy_skin_ripples_per_layer", "fuzzy_skin_ripple_offset", "fuzzy_skin_layers_between_ripple_offset",
"max_volumetric_extrusion_rate_slope", "max_volumetric_extrusion_rate_slope_segment_length","extrusion_rate_smoothing_external_perimeter_only",
"inner_wall_speed", "outer_wall_speed", "sparse_infill_speed", "internal_solid_infill_speed",
"top_surface_speed", "support_speed", "support_object_xy_distance", "support_object_first_layer_gap", "support_interface_speed",
"bridge_speed", "internal_bridge_speed", "gap_infill_speed", "travel_speed", "travel_speed_z", "initial_layer_speed",
"outer_wall_acceleration", "initial_layer_acceleration", "top_surface_acceleration", "default_acceleration", "skirt_type", "skirt_loops", "skirt_speed","min_skirt_length", "skirt_distance", "skirt_start_angle", "skirt_height","single_loop_draft_shield", "draft_shield",
"brim_width", "brim_object_gap", "brim_flow_ratio", "brim_use_efc_outline", "combine_brims", "brim_type", "brim_ears_max_angle", "brim_ears_detection_length", "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap","enforce_support_layers",
"raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion",
"support_base_pattern", "support_base_pattern_spacing", "support_expansion", "support_style",
// BBS
"print_extruder_id",
"print_extruder_variant",
"independent_support_layer_height",
"support_angle",
"support_interface_top_layers",
"support_interface_bottom_layers",
"support_interface_pattern",
"support_interface_spacing",
"support_interface_loop_pattern",
"support_top_z_distance",
"support_on_build_plate_only",
"support_critical_regions_only",
"bridge_no_support",
"thick_bridges",
"thick_internal_bridges",
"dont_filter_internal_bridges",
"enable_extra_bridge_layer",
"max_bridge_length",
"print_sequence",
"print_order",
"support_remove_small_overhang",
"filename_format",
"outer_wall_filament_id",
"inner_wall_filament_id",
"support_bottom_z_distance",
"sparse_infill_filament_id",
"internal_solid_filament_id",
"top_surface_filament_id",
"bottom_surface_filament_id",
"support_filament",
"support_interface_filament",
"support_interface_not_for_body",
"ooze_prevention",
"standby_temperature_delta",
"preheat_time",
"preheat_steps",
"interface_shells",
"line_width",
"initial_layer_line_width",
"inner_wall_line_width",
"outer_wall_line_width",
"sparse_infill_line_width",
"internal_solid_infill_line_width",
"skin_infill_line_width",
"skeleton_infill_line_width",
"top_surface_line_width",
"support_line_width",
"infill_wall_overlap",
"top_bottom_infill_wall_overlap",
"bridge_flow",
"bridge_line_width",
"internal_bridge_flow",
"elefant_foot_compensation",
"elefant_foot_compensation_layers",
"elefant_foot_layers_density",
"xy_contour_compensation",
"xy_hole_compensation",
"resolution",
"enable_prime_tower",
"prime_tower_enable_framework",
"prime_tower_width",
"prime_tower_brim_width",
"prime_tower_skip_points",
"prime_volume",
"prime_tower_infill_gap",
"prime_tower_flat_ironing",
"enable_tower_interface_features",
"enable_tower_interface_cooldown_during_tower",
"wipe_tower_no_sparse_layers",
"compatible_printers",
"compatible_printers_condition",
"inherits",
"flush_into_infill",
"flush_into_objects",
"flush_into_support",
"tree_support_branch_angle",
"tree_support_angle_slow",
"tree_support_wall_count",
"tree_support_top_rate",
"tree_support_branch_distance",
"tree_support_tip_diameter",
"tree_support_branch_diameter",
"tree_support_branch_diameter_angle",
"detect_narrow_internal_solid_infill",
"gcode_add_line_number",
"enable_arc_fitting",
"precise_z_height",
"infill_combination",
"infill_combination_max_layer_height", /*"adaptive_layer_height",*/
"support_bottom_interface_spacing",
"enable_overhang_speed",
"slowdown_for_curled_perimeters",
"overhang_1_4_speed",
"overhang_2_4_speed",
"overhang_3_4_speed",
"overhang_4_4_speed",
"initial_layer_infill_speed",
"only_one_wall_top",
"timelapse_type",
"wall_generator",
"wall_transition_length",
"wall_transition_filter_deviation",
"wall_transition_angle",
"wall_distribution_count",
"min_feature_size",
"min_bead_width",
"post_process",
"slicing_pipeline_plugin",
"plugins",
"print_plugin_config_overrides",
"process_change_extrusion_role_gcode",
"min_length_factor",
"wall_maximum_resolution",
"wall_maximum_deviation",
"small_perimeter_speed",
"small_perimeter_threshold",
"small_support_perimeter_speed",
"small_support_perimeter_threshold",
"bridge_angle",
"internal_bridge_angle",
"relative_bridge_angle",
"filter_out_gap_fill",
"travel_acceleration",
"inner_wall_acceleration",
"min_width_top_surface",
"default_jerk",
"outer_wall_jerk",
"inner_wall_jerk",
"infill_jerk",
"top_surface_jerk",
"initial_layer_jerk",
"travel_jerk",
"default_junction_deviation",
"top_solid_infill_flow_ratio",
"bottom_solid_infill_flow_ratio",
"only_one_wall_first_layer",
"print_flow_ratio",
"seam_gap",
"set_other_flow_ratios",
"first_layer_flow_ratio",
"outer_wall_flow_ratio",
"inner_wall_flow_ratio",
"overhang_flow_ratio",
"sparse_infill_flow_ratio",
"internal_solid_infill_flow_ratio",
"gap_fill_flow_ratio",
"support_flow_ratio",
"support_interface_flow_ratio",
"role_based_wipe_speed",
"wipe_speed",
"accel_to_decel_enable",
"accel_to_decel_factor",
"wipe_on_loops",
"wipe_before_external_loop",
"bridge_density",
"internal_bridge_density",
"precise_outer_wall",
"bridge_acceleration",
"sparse_infill_acceleration",
"internal_solid_infill_acceleration",
"tree_support_auto_brim",
"tree_support_brim_width",
"gcode_comments",
"gcode_label_objects",
"initial_layer_travel_speed",
"initial_layer_travel_acceleration",
"initial_layer_travel_jerk",
"exclude_object",
"slow_down_layers",
"infill_anchor",
"infill_anchor_max",
"initial_layer_min_bead_width",
"make_overhang_printable",
"make_overhang_printable_angle",
"make_overhang_printable_hole_size",
"notes",
"wipe_tower_cone_angle",
"wipe_tower_extra_spacing",
"wipe_tower_max_purge_speed",
"wipe_tower_wall_type",
"wipe_tower_extra_rib_length",
"wipe_tower_rib_width",
"wipe_tower_fillet_wall",
"wipe_tower_filament",
"wiping_volumes_extruders",
"wipe_tower_bridging",
"wipe_tower_extra_flow",
"single_extruder_multi_material_priming",
"toolchange_ordering",
"wipe_tower_rotation_angle",
"tree_support_branch_distance_organic",
"tree_support_branch_diameter_organic",
"tree_support_branch_angle_organic",
"hole_to_polyhole",
"hole_to_polyhole_threshold",
"hole_to_polyhole_twisted",
"hole_to_polyhole_max_edges",
"mmu_segmented_region_max_width",
"mmu_segmented_region_interlocking_depth",
"small_area_infill_flow_compensation",
"small_area_infill_flow_compensation_model",
"enable_wrapping_detection",
"seam_slope_type",
"seam_slope_conditional",
"scarf_angle_threshold",
"scarf_joint_speed",
"scarf_joint_flow_ratio",
"seam_slope_start_height",
"seam_slope_entire_loop",
"seam_slope_min_length",
"seam_slope_steps",
"seam_slope_inner_walls",
"scarf_overhang_threshold",
"interlocking_beam",
"interlocking_orientation",
"interlocking_beam_layer_count",
"interlocking_depth",
"interlocking_boundary_avoidance",
"interlocking_beam_width",
"calib_flowrate_topinfill_special_order",
// Z Anti-Aliasing (ZAA)
"zaa_enabled",
"zaa_minimize_perimeter_height",
"zaa_dont_alternate_fill_direction",
"zaa_min_z",
"ironing_expansion",
};
#include "../slic3r/GUI/generated/Preset_options_generated.cpp"
static std::vector<std::string> s_Preset_filament_options {/*"filament_colour", */ "default_filament_colour", "required_nozzle_HRC", "filament_diameter", "pellet_flow_coefficient", "volumetric_speed_coefficients", "filament_type",
"filament_soluble", "filament_is_support", "filament_printable", "filament_extruder_compatibility",
"filament_max_volumetric_speed", "filament_adaptive_volumetric_speed",
"filament_flow_ratio", "filament_density", "filament_adhesiveness_category", "filament_cost", "filament_minimal_purge_on_wipe_tower",
"filament_tower_interface_pre_extrusion_dist", "filament_tower_interface_pre_extrusion_length", "filament_tower_ironing_area", "filament_tower_interface_purge_volume",
"filament_tower_interface_print_temp",
"nozzle_temperature", "nozzle_temperature_initial_layer",
// BBS
"cool_plate_temp", "textured_cool_plate_temp", "eng_plate_temp", "hot_plate_temp", "textured_plate_temp", "cool_plate_temp_initial_layer", "textured_cool_plate_temp_initial_layer", "eng_plate_temp_initial_layer", "hot_plate_temp_initial_layer", "textured_plate_temp_initial_layer", "supertack_plate_temp_initial_layer", "supertack_plate_temp",
// "bed_type",
//BBS:temperature_vitrification
"temperature_vitrification", "reduce_fan_stop_start_freq","dont_slow_down_outer_wall", "slow_down_for_layer_cooling", "fan_min_speed",
"fan_max_speed", "enable_overhang_bridge_fan", "overhang_fan_speed", "overhang_fan_threshold", "close_fan_the_first_x_layers", "close_additional_fan_first_x_layers", "first_x_layer_fan_speed", "full_fan_speed_layer", "initial_layer_fan_speed", "additional_fan_full_speed_layer", "fan_cooling_layer_time", "slow_down_layer_time", "slow_down_min_speed",
"filament_start_gcode", "filament_end_gcode", "filament_change_extrusion_role_gcode",
//exhaust fan control
"activate_air_filtration","activate_air_filtration_during_print","activate_air_filtration_on_completion","during_print_exhaust_fan_speed","complete_print_exhaust_fan_speed",
// Retract overrides
"filament_deretraction_speed",
"filament_retract_after_wipe", // Orca
"filament_retract_before_wipe",
"filament_retract_lift_above",
"filament_retract_lift_below",
"filament_retract_lift_enforce",
"filament_retract_restart_extra",
"filament_retract_when_changing_layer",
"filament_retraction_length",
"filament_retraction_minimum_travel",
"filament_retraction_speed",
"filament_wipe",
"filament_z_hop",
"filament_z_hop_types",
// Profile compatibility
"filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits",
//BBS
"filament_wipe_distance", "additional_cooling_fan_speed",
"nozzle_temperature_range_low", "nozzle_temperature_range_high",
"filament_extruder_variant",
//SoftFever
"enable_pressure_advance", "pressure_advance","adaptive_pressure_advance","adaptive_pressure_advance_model","adaptive_pressure_advance_overhangs", "adaptive_pressure_advance_bridges","chamber_temperature", "filament_shrink","filament_shrinkage_compensation_z", "support_material_interface_fan_speed","internal_bridge_fan_speed", "filament_notes" /*,"filament_seam_gap"*/,
"ironing_fan_speed",
// Filament ironing overrides
"filament_ironing_flow", "filament_ironing_spacing", "filament_ironing_inset", "filament_ironing_speed",
"filament_loading_speed", "filament_loading_speed_start",
"filament_unloading_speed", "filament_unloading_speed_start", "filament_toolchange_delay", "filament_cooling_moves", "filament_stamping_loading_speed", "filament_stamping_distance",
"filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters",
"filament_multitool_ramming", "filament_multitool_ramming_volume", "filament_multitool_ramming_flow", "activate_chamber_temp_control", "chamber_minimal_temperature",
"filament_long_retractions_when_cut","filament_retraction_distances_when_cut", "idle_temperature",
//BBS filament change length while the extruder color
"filament_change_length","filament_flush_volumetric_speed","filament_flush_temp","filament_flush_temp_fast", "filament_cooling_before_tower",
// Multi-nozzle pre-cooling / ramming / nozzle-change (nc) filament overrides
"filament_ramming_volumetric_speed", "filament_ramming_volumetric_speed_nc",
"filament_ramming_travel_time", "filament_ramming_travel_time_nc",
"filament_pre_cooling_temperature", "filament_pre_cooling_temperature_nc",
"filament_preheat_temperature_delta", "filament_retract_length_nc",
"filament_change_length_nc", "filament_prime_volume", "filament_prime_volume_nc",
"long_retractions_when_ec", "retraction_distances_when_ec",
"filament_plugin_config_overrides",
//ams chamber
"filament_dev_ams_drying_ams_limitations", "filament_dev_ams_drying_temperature", "filament_dev_ams_drying_time", "filament_dev_ams_drying_heat_distortion_temperature",
"filament_dev_chamber_drying_bed_temperature", "filament_dev_chamber_drying_time",
"filament_dev_drying_softening_temperature", "filament_dev_drying_cooling_temperature"
};
static std::vector<std::string> s_Preset_machine_limits_options {
"machine_max_acceleration_extruding", "machine_max_acceleration_retracting", "machine_max_acceleration_travel",
@@ -1400,38 +1020,6 @@ static std::vector<std::string> s_Preset_machine_limits_options {
"input_shaping_emit", "input_shaping_type", "input_shaping_freq_x", "input_shaping_freq_y", "input_shaping_damp_x", "input_shaping_damp_y",
};
static std::vector<std::string> s_Preset_printer_options {
"printer_technology",
"printable_area", "extruder_printable_area", "support_parallel_printheads", "parallel_printheads_count", "parallel_printheads_bed_exclude_areas", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "gcode_flavor",
"fan_kickstart", "part_cooling_fan_min_pwm", "fan_speedup_time", "fan_speedup_overhangs",
"single_extruder_multi_material", "manual_filament_change", "file_start_gcode", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "printing_by_object_gcode", "layer_change_gcode", "time_lapse_gcode", "wrapping_detection_gcode", "change_filament_gcode", "change_extrusion_role_gcode",
"printer_model", "printer_variant", "printer_extruder_id", "printer_extruder_variant", "extruder_variant_list", "default_nozzle_volume_type",
"printable_height", "extruder_printable_height", "extruder_clearance_radius", "extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod",
"nozzle_height", "master_extruder_id",
"default_print_profile", "inherits",
"silent_mode",
"scan_first_layer", "enable_power_loss_recovery", "wrapping_detection_layers", "wrapping_exclude_area", "machine_load_filament_time", "machine_unload_filament_time", "machine_tool_change_time", "time_cost", "machine_pause_gcode", "template_custom_gcode",
"nozzle_type", "nozzle_hrc","auxiliary_fan", "fan_direction", "nozzle_volume","upward_compatible_machine", "z_hop_types", "travel_slope", "retract_lift_enforce","support_chamber_temp_control","support_air_filtration","support_cooling_filter","cooling_filter_enabled","printer_structure","farthest_point_timelapse",
"best_object_pos", "head_wrap_detect_zone",
"host_type", "print_host", "printhost_apikey", "flashforge_serial_number", "bbl_use_printhost", "printer_agent",
"print_host_webui",
"printhost_cafile","printhost_port","printhost_authorization_type",
"printhost_user", "printhost_password", "printhost_ssl_ignore_revoke", "thumbnails", "thumbnails_format",
"use_relative_e_distances", "extruder_type", "use_firmware_retraction", "printer_notes",
"grab_length", "support_object_skip_flush", "physical_extruder_map",
"cooling_tube_retraction",
"cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "wipe_tower_type", "purge_in_prime_tower", "enable_filament_ramming", "tool_change_on_wipe_tower",
"z_offset",
"disable_m73", "preferred_orientation", "emit_machine_limits_to_gcode", "pellet_modded_printer", "support_multi_bed_types", "use_3mf", "default_bed_type", "bed_mesh_min","bed_mesh_max","bed_mesh_probe_distance", "adaptive_bed_mesh_margin", "enable_long_retraction_when_cut","long_retractions_when_cut","retraction_distances_when_cut",
"bed_temperature_formula", "nozzle_flush_dataset",
// Multi-nozzle count + pre-heat model printer options
"extruder_max_nozzle_count", "group_algo_with_time", "enable_pre_heating", "hotend_heating_rate", "hotend_cooling_rate",
"machine_hotend_change_time", "machine_prepare_compensation_time",
// Fast-purge printer flag + device/firmware-facing per-variant extruder-change
// deretraction speed (unconsumed by the slicer; carried by H2D/A2L/X2D/P2S machine profiles).
"support_fast_purge_mode", "deretract_speed_extruder_change",
"printer_plugin_config_overrides"
};
static std::vector<std::string> s_Preset_sla_print_options {
"layer_height",

View File

@@ -101,329 +101,23 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
if (opt_keys.empty())
return false;
// Cache the plenty of parameters, which influence the G-code generator only,
// or they are only notes not influencing the generated G-code.
static std::unordered_set<std::string> steps_gcode = {
//BBS
"additional_cooling_fan_speed",
"reduce_crossing_wall",
"max_travel_detour_distance",
"printable_area",
//BBS: add bed_exclude_area
"bed_exclude_area",
"thumbnail_size",
"before_layer_change_gcode",
"enable_pressure_advance",
"pressure_advance",
"enable_overhang_bridge_fan",
"overhang_fan_speed",
"overhang_fan_threshold",
"slow_down_for_layer_cooling",
"default_acceleration",
"deretraction_speed",
"close_fan_the_first_x_layers",
"machine_end_gcode",
"printing_by_object_gcode",
"filament_end_gcode",
"post_process",
// "plugins" is the derived manifest backing the plugin-picker options; on its own it only
// affects G-code export. The specific option (e.g. slicing_pipeline_plugin) drives any re-slice.
"plugins",
"extruder_clearance_height_to_rod",
"extruder_clearance_height_to_lid",
"extruder_clearance_radius",
"nozzle_height",
"extruder_colour",
"extruder_offset",
"filament_flow_ratio",
"reduce_fan_stop_start_freq",
"dont_slow_down_outer_wall",
"fan_cooling_layer_time",
"full_fan_speed_layer",
"initial_layer_fan_speed",
"fan_kickstart",
"part_cooling_fan_min_pwm",
"fan_speedup_overhangs",
"fan_speedup_time",
"filament_colour",
"default_filament_colour",
"filament_diameter",
"volumetric_speed_coefficients",
"filament_density",
"filament_cost",
"filament_notes",
"outer_wall_acceleration",
"inner_wall_acceleration",
"initial_layer_acceleration",
"top_surface_acceleration",
"bridge_acceleration",
"travel_acceleration",
"sparse_infill_acceleration",
"internal_solid_infill_acceleration",
// BBS
"supertack_plate_temp_initial_layer",
"cool_plate_temp_initial_layer",
"textured_cool_plate_temp_initial_layer",
"eng_plate_temp_initial_layer",
"hot_plate_temp_initial_layer",
"textured_plate_temp_initial_layer",
"gcode_add_line_number",
"layer_change_gcode",
"time_lapse_gcode",
"wrapping_detection_gcode",
"fan_min_speed",
"fan_max_speed",
"printable_height",
"slow_down_min_speed",
"max_volumetric_extrusion_rate_slope",
"max_volumetric_extrusion_rate_slope_segment_length",
"extrusion_rate_smoothing_external_perimeter_only",
"reduce_infill_retraction",
"filename_format",
"retraction_minimum_travel",
"retract_before_wipe",
// Orca:
"retract_after_wipe",
"retract_when_changing_layer",
"retraction_length",
"retract_length_toolchange",
"z_hop",
"travel_slope",
"retract_lift_above",
"retract_lift_below",
"retract_lift_enforce",
"retract_restart_extra",
"retract_restart_extra_toolchange",
"retraction_speed",
"use_firmware_retraction",
"slow_down_layer_time",
"standby_temperature_delta",
"preheat_time",
"preheat_steps",
"machine_start_gcode",
"filament_start_gcode",
"change_filament_gcode",
"wipe",
// BBS
"wipe_distance",
"curr_bed_type",
"nozzle_volume",
"nozzle_hrc",
"required_nozzle_HRC",
"upward_compatible_machine",
"is_infill_first",
// Orca
"chamber_temperature",
"chamber_minimal_temperature",
"thumbnails",
"thumbnails_format",
"center_of_surface_pattern",
"separated_infills",
"seam_gap",
"role_based_wipe_speed",
"wipe_speed",
"use_relative_e_distances",
"accel_to_decel_enable",
"accel_to_decel_factor",
"wipe_on_loops",
"gcode_comments",
"gcode_label_objects",
"exclude_object",
"support_material_interface_fan_speed",
"internal_bridge_fan_speed", // ORCA: Add support for separate internal bridge fan speed control
"ironing_fan_speed",
"single_extruder_multi_material_priming",
"activate_air_filtration",
"activate_air_filtration_during_print",
"activate_air_filtration_on_completion",
"during_print_exhaust_fan_speed",
"complete_print_exhaust_fan_speed",
"activate_chamber_temp_control",
"manual_filament_change",
"disable_m73",
"use_firmware_retraction",
"enable_long_retraction_when_cut",
"long_retractions_when_cut",
"retraction_distances_when_cut",
"filament_long_retractions_when_cut",
"filament_retraction_distances_when_cut",
"grab_length",
"bed_temperature_formula",
"filament_notes",
"process_notes",
"printer_notes",
"use_3mf"
};
#include "../slic3r/GUI/generated/Invalidation_generated.cpp"
static std::unordered_set<std::string> steps_ignore;
std::vector<PrintStep> steps;
std::vector<PrintStep> steps;
std::vector<PrintObjectStep> osteps;
bool invalidated = false;
for (const t_config_option_key &opt_key : opt_keys) {
if (steps_gcode.find(opt_key) != steps_gcode.end()) {
// These options only affect G-code export or they are just notes without influence on the generated G-code,
// so there is nothing to invalidate.
steps.emplace_back(psGCodeExport);
} else if (steps_ignore.find(opt_key) != steps_ignore.end()) {
// These steps have no influence on the G-code whatsoever. Just ignore them.
} else if (
opt_key == "skirt_type"
|| opt_key == "skirt_loops"
|| opt_key == "skirt_speed"
|| opt_key == "skirt_height"
|| opt_key == "min_skirt_length"
|| opt_key == "single_loop_draft_shield"
|| opt_key == "draft_shield"
|| opt_key == "skirt_distance"
|| opt_key == "skirt_start_angle"
|| opt_key == "ooze_prevention"
|| opt_key == "wipe_tower_x"
|| opt_key == "wipe_tower_y"
|| opt_key == "wipe_tower_rotation_angle") {
steps.emplace_back(psSkirtBrim);
} else if (
opt_key == "slicing_pipeline_plugin"
|| opt_key == "print_plugin_config_overrides"
|| opt_key == "initial_layer_print_height"
|| opt_key == "nozzle_diameter"
|| opt_key == "filament_shrink"
|| opt_key == "filament_shrinkage_compensation_z"
|| opt_key == "resolution"
|| opt_key == "precise_z_height"
// Spiral Vase forces different kind of slicing than the normal model:
// In Spiral Vase mode, holes are closed and only the largest area contour is kept at each layer.
// Therefore toggling the Spiral Vase on / off requires complete reslicing.
|| opt_key == "spiral_mode") {
osteps.emplace_back(posSlice);
} else if (
opt_key == "print_sequence"
|| opt_key == "filament_type"
|| opt_key == "chamber_temperature"
|| opt_key == "nozzle_temperature_initial_layer"
|| opt_key == "filament_minimal_purge_on_wipe_tower"
|| opt_key == "filament_max_volumetric_speed"
|| opt_key == "filament_adaptive_volumetric_speed"
|| opt_key == "filament_loading_speed"
|| opt_key == "filament_loading_speed_start"
|| opt_key == "filament_unloading_speed"
|| opt_key == "filament_unloading_speed_start"
|| opt_key == "filament_toolchange_delay"
|| opt_key == "filament_cooling_moves"
|| opt_key == "filament_stamping_loading_speed"
|| opt_key == "filament_stamping_distance"
|| opt_key == "filament_cooling_initial_speed"
|| opt_key == "filament_cooling_final_speed"
|| opt_key == "filament_ramming_parameters"
|| opt_key == "filament_multitool_ramming"
|| opt_key == "filament_multitool_ramming_volume"
|| opt_key == "filament_multitool_ramming_flow"
|| opt_key == "filament_max_volumetric_speed"
|| opt_key == "gcode_flavor"
|| opt_key == "single_extruder_multi_material"
|| opt_key == "nozzle_temperature"
// BBS
|| opt_key == "supertack_plate_temp"
|| opt_key == "cool_plate_temp"
|| opt_key == "textured_cool_plate_temp"
|| opt_key == "eng_plate_temp"
|| opt_key == "hot_plate_temp"
|| opt_key == "textured_plate_temp"
|| opt_key == "enable_prime_tower"
|| opt_key == "enable_wrapping_detection"
|| opt_key == "prime_tower_enable_framework"
|| opt_key == "prime_tower_width"
|| opt_key == "prime_tower_brim_width"
|| opt_key == "wipe_tower_type"
|| opt_key == "prime_tower_skip_points"
|| opt_key == "prime_tower_flat_ironing"
|| opt_key == "enable_tower_interface_features"
|| opt_key == "first_layer_print_sequence"
|| opt_key == "other_layers_print_sequence"
|| opt_key == "other_layers_print_sequence_nums"
|| opt_key == "toolchange_ordering"
|| opt_key == "extruder_ams_count"
|| opt_key == "extruder_nozzle_stats"
|| opt_key == "filament_map_mode"
|| opt_key == "filament_map"
|| opt_key == "filament_nozzle_map"
|| opt_key == "filament_volume_map"
|| opt_key == "filament_adhesiveness_category"
|| opt_key == "filament_tower_interface_pre_extrusion_dist"
|| opt_key == "filament_tower_interface_pre_extrusion_length"
|| opt_key == "filament_tower_ironing_area"
|| opt_key == "filament_tower_interface_purge_volume"
|| opt_key == "filament_tower_interface_print_temp"
|| opt_key == "wipe_tower_bridging"
|| opt_key == "wipe_tower_extra_flow"
|| opt_key == "wipe_tower_no_sparse_layers"
|| opt_key == "flush_volumes_matrix"
|| opt_key == "prime_volume"
|| opt_key == "flush_into_infill"
|| opt_key == "flush_into_support"
|| opt_key == "initial_layer_infill_speed"
|| opt_key == "travel_speed"
|| opt_key == "travel_speed_z"
|| opt_key == "initial_layer_speed"
|| opt_key == "initial_layer_travel_speed"
|| opt_key == "initial_layer_travel_acceleration"
|| opt_key == "initial_layer_travel_jerk"
|| opt_key == "slow_down_layers"
|| opt_key == "idle_temperature"
|| opt_key == "wipe_tower_cone_angle"
|| opt_key == "wipe_tower_extra_spacing"
|| opt_key == "wipe_tower_max_purge_speed"
|| opt_key == "wipe_tower_wall_type"
|| opt_key == "wipe_tower_extra_rib_length"
|| opt_key == "wipe_tower_rib_width"
|| opt_key == "wipe_tower_fillet_wall"
|| opt_key == "wipe_tower_filament"
|| opt_key == "wiping_volumes_extruders"
|| opt_key == "enable_filament_ramming"
|| opt_key == "tool_change_on_wipe_tower"
|| opt_key == "purge_in_prime_tower"
|| opt_key == "z_offset"
|| opt_key == "support_multi_bed_types"
) {
steps.emplace_back(psWipeTower);
steps.emplace_back(psSkirtBrim);
} else if (opt_key == "filament_soluble"
|| opt_key == "filament_is_support"
|| opt_key == "filament_printable"
|| opt_key == "filament_change_length"
|| opt_key == "independent_support_layer_height") {
steps.emplace_back(psWipeTower);
// Soluble support interface / non-soluble base interface produces non-soluble interface layers below soluble interface layers.
// Thus switching between soluble / non-soluble interface layer material may require recalculation of supports.
//FIXME Killing supports on any change of "filament_soluble" is rough. We should check for each object whether that is necessary.
osteps.emplace_back(posSupportMaterial);
osteps.emplace_back(posSimplifySupportPath);
} else if (
opt_key == "initial_layer_line_width"
|| opt_key == "min_layer_height"
|| opt_key == "max_layer_height"
//|| opt_key == "resolution"
//BBS: when enable arc fitting, we must re-generate perimeter
|| opt_key == "enable_arc_fitting"
|| opt_key == "print_order"
|| opt_key == "wall_sequence") {
osteps.emplace_back(posPerimeters);
osteps.emplace_back(posEstimateCurledExtrusions);
osteps.emplace_back(posInfill);
osteps.emplace_back(posSupportMaterial);
osteps.emplace_back(posSimplifyPath);
osteps.emplace_back(posSimplifyInfill);
osteps.emplace_back(posSimplifySupportPath);
steps.emplace_back(psSkirtBrim);
}
else if (opt_key == "z_hop_types") {
osteps.emplace_back(posDetectOverhangsForLift);
auto it_ps = s_print_steps_map.find(opt_key);
auto it_os = s_object_steps_map.find(opt_key);
if (it_ps != s_print_steps_map.end() || it_os != s_object_steps_map.end()) {
if (it_ps != s_print_steps_map.end())
steps.insert(steps.end(), it_ps->second.begin(), it_ps->second.end());
if (it_os != s_object_steps_map.end())
osteps.insert(osteps.end(), it_os->second.begin(), it_os->second.end());
} else {
// for legacy, if we can't handle this option let's invalidate all steps
//FIXME invalidate all steps of all objects as well?
// Unknown option — conservatively invalidate all steps
invalidated |= this->invalidate_all_steps();
// Continue with the other opt_keys to possibly invalidate any object specific steps.
}
}
@@ -756,7 +450,7 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print
#if 0 //do not sort anymore, use the order in object list
auto bed_points = get_bed_shape(print_config);
float bed_width = bed_points[1].x() - bed_points[0].x();
// 如果扩大以后的多边形的距离小于这个值,就需要严格保证从左到右的打印顺序,否则会撞工具头右侧
// 如果扩大以后的多边形的距离小于这个值,就需要严格保证从左到右的打印顺序,否则会撞工具头右侧
float unsafe_dist = scale_(print_config.extruder_clearance_max_radius.value - print_config.extruder_clearance_radius.value);
struct VecHash
{
@@ -790,7 +484,7 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print
auto inter_max = std::min(ly2, ry2);
auto inter_y = inter_max - inter_min;
// 如果y方向的重合超过轮廓的膨胀量说明两个物体在一行应该先打左边的物体即先比较二者的x坐标。
// е¦жћњyжеђзљ„重合超过轮廓的膨胀量,说明两个物дЅењЁдёЂиЎЊпјЊеє”该先打左边的物体,即先比较二者的xеќђж гЂ
// If the overlap in the y direction exceeds the expansion of the contour, it means that the two objects are in a row and the object on the left should be hit first, that is, the x coordinates of the two should be compared first.
if (inter_y > scale_(0.5 * print.config().extruder_clearance_radius.value)) {
if (std::max(rx1 - lx2, lx1 - rx2) < unsafe_dist) {
@@ -806,13 +500,13 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print
}
}
if (l.height > hc1 && r.height < hc1) {
// 当前物体超过了顶盖高度,必须后打
// 当前物体超过了顶盖高度,必须后打
left_right_pair.insert({j, i});
BOOST_LOG_TRIVIAL(debug) << "height>hc1, print_instance " << r.print_instance->model_instance->get_object()->name << "(" << r.arrange_score << ")"
<< " -> " << l.print_instance->model_instance->get_object()->name << "(" << l.arrange_score << ")";
}
else if (l.height > hc2 && l.height > r.height && l.arrange_score<r.arrange_score) {
// 如果当前物体的高度超过滑杆且比r高就给它加一点代价尽量让高的物体后打只有物体高度超过滑杆时才有必要按高度来
// е¦жћњеЅе‰Ќз‰©дЅ“的高度超过ж»жќ†пјЊдё”жЇ”r高,就给它加一з№д»Јд»·пјЊе°Ѕй‡Џи®©й«˜зљ„物дЅеђЋж‰“пјеЏЄжњ‰з‰©дЅ“高度超过ж»жќ†ж—¶ж‰Ќжњ‰еї…要按高度来пј
if (l.arrange_score < r.arrange_score)
l.arrange_score = r.arrange_score + 10;
BOOST_LOG_TRIVIAL(debug) << "height>hc2, print_instance " << inst.print_instance->model_instance->get_object()->name
@@ -822,8 +516,8 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print
}
}
}
// 多做几次代价传播,因为前一次有些值没有更新。
// TODO 更好的办法是建立一颗树,一步到位。不过我暂时没精力搞,先就这样吧
// 多做几次代价传播,因为前一次有些值没有更新。
// TODO 更好的办法是建立一颗树,一步到位。不过我暂时没精力搞,先就这样吧
for (int k=0;k<5;k++)
for (auto p : left_right_pair) {
auto &l = print_instance_with_bounding_box[p(0)];
@@ -891,7 +585,7 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print
for (int k = 0; k < print_instance_count; k++)
{
auto inst = print_instance_with_bounding_box[k].print_instance;
// 只需要考虑喷嘴到滑杆的偏移量,这个比整个工具头的碰撞半径要小得多
// 只需要考虑喷嘴到滑杆的偏移量,这个比整个工具头的碰撞半径要小得多
// Only the offset from the nozzle to the slide bar needs to be considered, which is much smaller than the collision radius of the entire tool head.
auto bbox = print_instance_with_bounding_box[k].bounding_box.inflated(-scale_(0.5 * print.config().extruder_clearance_radius.value + object_skirt_offset));
auto iy1 = bbox.min.y();

File diff suppressed because it is too large Load Diff

View File

@@ -490,6 +490,7 @@ set(SLIC3R_GUI_SOURCES
GUI/TabButton.hpp
GUI/Tab.cpp
GUI/Tab.hpp
GUI/TabLayoutExtra.cpp
GUI/TaskManager.cpp
GUI/TaskManager.hpp
GUI/TextLines.cpp
@@ -830,6 +831,16 @@ else ()
endif ()
target_include_directories(libslic3r_gui PRIVATE Utils ${CMAKE_CURRENT_BINARY_DIR})
# Tab.cpp #includes GUI/generated/TabLayout_generated.cpp, so it must not be compiled
# while the codegen is rewriting it (same contract as libslic3r's generated includes).
if(TARGET codegen_config)
add_dependencies(libslic3r_gui codegen_config)
set_source_files_properties(
"${CMAKE_CURRENT_SOURCE_DIR}/GUI/Tab.cpp"
PROPERTIES OBJECT_DEPENDS "${CONFIG_GENERATED_SOURCES}"
)
endif()
if (WIN32)
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../deps/WebView2/include)
target_link_libraries(libslic3r_gui Advapi32)

File diff suppressed because it is too large Load Diff

View File

@@ -590,6 +590,7 @@ private:
void add_filament_overrides_page();
void update_filament_overrides_page(const DynamicPrintConfig* printers_config);
void build_extra_layout(); // TabLayoutExtra.cpp: toolchange/ramming/dependencies/notes
void update_volumetric_flow_preset_hints();
std::map<std::string, ::CheckBox*> m_overrides_options;
@@ -663,6 +664,11 @@ public:
void extruders_count_changed(size_t extruders_count);
PageShp build_kinematics_page();
void build_unregular_pages(bool from_initial_build = false);
void build_fff_extra_layout(); // TabLayoutExtra.cpp: Basic info page with bed-shape widget
// Hook methods called from TabPrinter_build_basic_info_layout (TabLayout_generated.cpp)
void layout_hook_printable_space(ConfigOptionsGroup* optgroup); // bed shape widget
void layout_hook_advanced(ConfigOptionsGroup* optgroup); // thumbnail m_on_change
void layout_hook_cooling_fan(ConfigOptionsGroup* optgroup); // multi-option line
void on_preset_loaded() override;
void init_options_list() override;
void msw_rescale() override;

View File

@@ -0,0 +1,217 @@
// TabLayoutExtra.cpp
//
// TabFilament::build_extra_layout() - member function implementation.
//
// Supplements TabLayout_generated.cpp with UI sections that require custom
// widget factories (create_line_with_widget) and therefore cannot be
// auto-generated from the proto schema.
//
// Called from TabFilament::build() after TabFilament_build_main_layout():
// 1. Toolchange + ramming parameters sections (single + multi extruder)
// 2. Setting Overrides page (checkbox-driven nullable retraction overrides)
// 3. Dependencies page (compatible_printers and compatible_prints widgets)
// 4. Notes page
#include "Tab.hpp"
#include "GUI_App.hpp" // dots, wxGetApp()
#include "libslic3r/FlushVolCalc.hpp" // g_max_flush_volume (needed by WipeTowerDialog)
#include "WipeTowerDialog.hpp" // RammingDialog
#include "MsgDialog.hpp" // InfoDialog
#include "libslic3r/GCode/Thumbnails.hpp"
#include "format.hpp"
namespace Slic3r { namespace GUI {
void TabFilament::build_extra_layout()
{
constexpr int notes_field_height = 25;
// -- Continue the Multimaterial page ----------------------------------
// TabFilament_build_main_layout() ended after the Multi Filament optgroup.
// We continue on the same page by accessing m_pages.back().
{
PageShp page = m_pages.back();
// Tool change parameters - single extruder MM printers
// (includes filament_ramming_parameters which needs a custom button widget)
{
auto optgroup = page->new_optgroup(L("Tool change parameters with single extruder MM printers"), L"param_toolchange");
optgroup->append_single_option_line("filament_loading_speed_start", "material_multimaterial#loading-speed-at-the-start");
optgroup->append_single_option_line("filament_loading_speed", "material_multimaterial#loading-speed");
optgroup->append_single_option_line("filament_unloading_speed_start", "material_multimaterial#unloading-speed-at-the-start");
optgroup->append_single_option_line("filament_unloading_speed", "material_multimaterial#unloading-speed");
optgroup->append_single_option_line("filament_toolchange_delay", "material_multimaterial#delay-after-unloading");
optgroup->append_single_option_line("filament_cooling_moves", "material_multimaterial#number-of-cooling-moves");
optgroup->append_single_option_line("filament_cooling_initial_speed", "material_multimaterial#speed-of-the-first-cooling-move");
optgroup->append_single_option_line("filament_cooling_final_speed", "material_multimaterial#speed-of-the-last-cooling-move");
optgroup->append_single_option_line("filament_stamping_loading_speed", "material_multimaterial#stamping-loading-speed");
optgroup->append_single_option_line("filament_stamping_distance", "material_multimaterial#stamping-distance");
create_line_with_widget(optgroup.get(), "filament_ramming_parameters",
"material_multimaterial#ramming-parameters",
[this](wxWindow* parent) {
Button* btn = new Button(parent, _(L("Set")) + " " + dots);
btn->SetStyle(ButtonStyle::Regular, ButtonType::Parameter);
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(btn);
btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
RammingDialog dlg(this,
(m_config->option<ConfigOptionStrings>("filament_ramming_parameters"))->get_at(0));
if (dlg.ShowModal() == wxID_OK) {
load_key_value("filament_ramming_parameters", dlg.get_parameters());
update_changed_ui();
}
});
return sizer;
});
}
// Tool change parameters - multi extruder MM printers
{
auto optgroup = page->new_optgroup(L("Tool change parameters with multi extruder MM printers"), L"param_toolchange_multi_extruder");
optgroup->append_single_option_line("filament_multitool_ramming", "material_multimaterial#tool-change-parameters-with-multi-extruder");
optgroup->append_single_option_line("filament_multitool_ramming_volume", "material_multimaterial#multi-tool-ramming-volume");
optgroup->append_single_option_line("filament_multitool_ramming_flow", "material_multimaterial#multi-tool-ramming-flow");
}
}
// -- Setting Overrides page --------------------------------------------
// Checkbox-driven nullable retraction overrides - complex runtime logic,
// cannot be expressed in the proto schema.
add_filament_overrides_page();
// -- Dependencies page -------------------------------------------------
// compatible_printers and compatible_prints require create_line_with_widget
// and must come BEFORE the text condition inputs in each optgroup.
{
auto page = add_options_page(L("Dependencies"), "advanced");
{
auto optgroup = page->new_optgroup(L("Compatible printers"), L"param_dependencies_printers");
create_line_with_widget(optgroup.get(), "compatible_printers", "", [this](wxWindow* parent) {
return compatible_widget_create(parent, m_compatible_printers);
});
Option option = optgroup->get_option("compatible_printers_condition");
option.opt.full_width = true;
optgroup->append_single_option_line(option, "material_dependencies#compatible-printers");
}
{
auto optgroup = page->new_optgroup(L("Compatible process profiles"), L"param_dependencies_presets");
create_line_with_widget(optgroup.get(), "compatible_prints", "", [this](wxWindow* parent) {
return compatible_widget_create(parent, m_compatible_prints);
});
Option option = optgroup->get_option("compatible_prints_condition");
option.opt.full_width = true;
optgroup->append_single_option_line(option, "material_dependencies#compatible-process-profiles");
}
}
// -- Notes page --------------------------------------------------------
{
auto page = add_options_page(L("Notes"), "custom-gcode_note");
auto optgroup = page->new_optgroup(L("Notes"), L"note", 0);
Option option = optgroup->get_option("filament_notes");
option.opt.full_width = true;
option.opt.height = notes_field_height;
optgroup->append_single_option_line(option);
}
}
// -----------------------------------------------------------------------------
// TabPrinter::build_fff_extra_layout()
//
// Builds the "Basic information" page for the Printer/FFF tab.
// Kept here (not generated) because it contains:
// - create_line_with_widget for printable_area (bed shape editor)
// - m_on_change for the thumbnails field (thumbnail format sync logic)
// - append_line for Cooling Fan multi-option line (fan_speedup_time + fan_speedup_overhangs)
//
// Called from TabPrinter::build_fff() before TabPrinter_build_gcode_layout().
// -----------------------------------------------------------------------------
// ── TabPrinter hook methods called by TabPrinter_build_basic_information_layout ──
// These implement the optgroups that cannot be auto-generated from yaml because they
// require custom widget factories, special m_on_change callbacks, or multi-option lines.
void TabPrinter::layout_hook_printable_space(ConfigOptionsGroup* optgroup)
{
// Bed shape widget must be FIRST in the group
create_line_with_widget(optgroup, "printable_area", "custom-svg-and-png-bed-textures_124612", [this](wxWindow* parent) {
return create_bed_shape_widget(parent);
});
Option option = optgroup->get_option("bed_exclude_area");
option.opt.full_width = true;
optgroup->append_single_option_line(option, "printer_basic_information_printable_space#excluded-bed-area");
optgroup->append_single_option_line("printable_height", "printer_basic_information_printable_space#printable-height");
optgroup->append_single_option_line("support_multi_bed_types", "printer_basic_information_printable_space#support-multi-bed-types");
optgroup->append_single_option_line("best_object_pos", "printer_basic_information_printable_space#best-object-position");
optgroup->append_single_option_line("z_offset", "printer_basic_information_printable_space#z-offset");
optgroup->append_single_option_line("preferred_orientation", "printer_basic_information_printable_space#preferred-orientation");
}
void TabPrinter::layout_hook_advanced(ConfigOptionsGroup* optgroup)
{
optgroup->append_single_option_line("printer_structure", "printer_basic_information_advanced#printer-structure");
optgroup->append_single_option_line("gcode_flavor", "printer_basic_information_advanced#g-code-flavor");
optgroup->append_single_option_line("pellet_modded_printer", "printer_basic_information_advanced#pellet-modded-printer");
optgroup->append_single_option_line("bbl_use_printhost", "printer_basic_information_advanced#use-3rd-party-print-host");
optgroup->append_single_option_line("scan_first_layer", "printer_basic_information_advanced#scan-first-layer");
optgroup->append_single_option_line("enable_power_loss_recovery", "printer_basic_information_advanced#power-loss-recovery");
optgroup->append_single_option_line("disable_m73", "printer_basic_information_advanced#disable-set-remaining-print-time");
{
Option option = optgroup->get_option("thumbnails");
option.opt.full_width = true;
optgroup->append_single_option_line(option, "printer_basic_information_advanced#g-code-thumbnails");
}
// Thumbnail format sync — cannot be expressed in proto schema
optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
wxTheApp->CallAfter([this, opt_key, value]() {
if (opt_key == "thumbnails" && m_config->has("thumbnails_format")) {
const std::string val = boost::any_cast<std::string>(value);
if (!value.empty()) {
auto [thumbnails_list, errors] = GCodeThumbnails::make_and_check_thumbnail_list(val);
if (errors != enum_bitmask<ThumbnailError>()) {
std::string error_str = format(_u8L("Invalid value provided for parameter %1%: %2%"), "thumbnails", val);
error_str += GCodeThumbnails::get_error_string(errors);
InfoDialog(parent(), _L("G-code flavor is switched"), from_u8(error_str)).ShowModal();
}
if (!thumbnails_list.empty()) {
GCodeThumbnailsFormat old_format = GCodeThumbnailsFormat(m_config->option("thumbnails_format")->getInt());
GCodeThumbnailsFormat new_format = thumbnails_list.begin()->first;
if (old_format != new_format) {
DynamicPrintConfig new_conf = *m_config;
auto* opt = m_config->option("thumbnails_format")->clone();
opt->setInt(int(new_format));
new_conf.set_key_value("thumbnails_format", opt);
load_config(new_conf);
}
}
}
}
update_dirty();
on_value_change(opt_key, value);
});
};
optgroup->append_single_option_line("use_relative_e_distances", "printer_basic_information_advanced#use-relative-e-distances");
optgroup->append_single_option_line("use_firmware_retraction", "printer_basic_information_advanced#use-firmware-retraction");
optgroup->append_single_option_line("time_cost", "printer_basic_information_advanced#time-cost");
}
void TabPrinter::layout_hook_cooling_fan(ConfigOptionsGroup* optgroup)
{
Line line = Line{ L("Fan speed-up time"), optgroup->get_option("fan_speedup_time").opt.tooltip };
line.label_path = "printer_basic_information_cooling_fan#fan-speed-up-time";
line.append_option(optgroup->get_option("fan_speedup_time"));
line.append_option(optgroup->get_option("fan_speedup_overhangs"));
optgroup->append_line(line);
optgroup->append_single_option_line("fan_kickstart", "printer_basic_information_cooling_fan#fan-kick-start-time");
optgroup->append_single_option_line("part_cooling_fan_min_pwm", "printer_basic_information_cooling_fan#minimum-non-zero-part-cooling-fan-speed");
}
// build_fff_extra_layout is kept for backward compatibility.
// It now delegates to the yaml-generated TabPrinter_build_basic_info_layout
// which calls the hook methods above.
void TabPrinter::build_fff_extra_layout()
{
// Superseded: Tab.cpp now calls TabPrinter_build_basic_info_layout(*this) directly.
// Hook methods below are called by that generated function.
}
} } // namespace Slic3r::GUI

260
tools/codegen_toolchain.py Normal file
View File

@@ -0,0 +1,260 @@
#!/usr/bin/env python3
"""
Toolchain resolution for the config codegen.
The codegen needs exactly three things: a protoc binary, the protobuf Python
runtime and pyyaml. Every entry point used to install `grpcio-tools` to get
protoc, which drags in the grpcio C extension: it has no Windows/ARM64 wheel and
falls back to building from source there, which is what broke the ARM64 build
("Failed building wheel for grpcio" -> "protoc not found"). Nothing in the
codegen uses gRPC.
Resolution order, so callers only ever run `python tools/run_codegen.py`:
protoc $PROTOC -> PATH -> cached download -> grpc_tools (if installed) ->
pinned, checksum-verified protoc release downloaded into
.codegen-tools/ (gitignored)
runtime the current interpreter, else a cached virtualenv under
.codegen-tools/venv that the entry point re-execs into
Set PROTOC=/path/to/protoc (or put protoc on PATH) to build offline.
"""
import hashlib
import importlib.util
import os
import platform
import shutil
import subprocess
import sys
import tempfile
import urllib.request
import zipfile
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
CACHE_DIR = ROOT / ".codegen-tools"
# Pinned so every machine generates with the same compiler, and checksummed
# because we execute what we download. To bump: change the version and refresh
# every hash from https://github.com/protocolbuffers/protobuf/releases/tag/v<ver>
PROTOC_VERSION = "28.3"
PROTOC_ARCHIVE_SHA256 = {
"win64": "ce64f49bdeddef49ce4bd313a8f59bcf92fcf67b5831efbf66170386d2e66948",
"linux-x86_64": "0ad949f04a6a174da83cdcbdb36dee0a4925272a5b6d83f79a6bf9852076d53f",
"linux-aarch_64": "1de522032a8b194002fe35cab86d747848238b5e4de4f99648372079f5b46f9a",
"osx-universal_binary": "52df502b263da20f3311b23b5c6553d10cc25c6ebb85df381d80a2806b6a698b",
}
# pip name -> import name
PYTHON_PACKAGES = {"protobuf": "google.protobuf", "pyyaml": "yaml"}
# Guards against an endless re-exec loop if the virtualenv still can't import.
_BOOTSTRAP_ENV = "ORCA_CODEGEN_BOOTSTRAPPED"
_PROTOC_EXE = "protoc.exe" if os.name == "nt" else "protoc"
def _protoc_dir():
return CACHE_DIR / f"protoc-{PROTOC_VERSION}"
def _archive_key():
"""Release asset for this host, or None if protobuf ships no build for it."""
if sys.platform == "win32":
# There is no win/arm64 release; the x64 build runs under Windows'
# emulation, which is how the ARM64 CI job gets a protoc.
return "win64"
if sys.platform == "darwin":
return "osx-universal_binary"
if sys.platform.startswith("linux"):
machine = platform.machine().lower()
if machine in ("x86_64", "amd64"):
return "linux-x86_64"
if machine in ("aarch64", "arm64"):
return "linux-aarch_64"
return None
def _download_protoc():
"""Fetch and unpack the pinned protoc. Returns the binary path, or None."""
key = _archive_key()
if key is None:
print(f" ERROR: no pinned protoc release for {sys.platform}/{platform.machine()}.")
print(" Install protoc from your package manager and re-run, or set PROTOC=<path>.")
return None
url = (f"https://github.com/protocolbuffers/protobuf/releases/download/"
f"v{PROTOC_VERSION}/protoc-{PROTOC_VERSION}-{key}.zip")
print(f" Downloading protoc {PROTOC_VERSION} ({key})...")
CACHE_DIR.mkdir(parents=True, exist_ok=True)
with tempfile.TemporaryDirectory(dir=CACHE_DIR) as tmp:
archive = Path(tmp) / "protoc.zip"
try:
with urllib.request.urlopen(url, timeout=120) as response:
archive.write_bytes(response.read())
except OSError as exc:
print(f" ERROR: download failed: {exc}")
print(" Install protoc manually and re-run, or set PROTOC=<path>.")
return None
actual = hashlib.sha256(archive.read_bytes()).hexdigest()
expected = PROTOC_ARCHIVE_SHA256[key]
if actual != expected:
print(f" ERROR: protoc archive checksum mismatch for {key} {PROTOC_VERSION}:")
print(f" expected {expected}")
print(f" actual {actual}")
return None
# Unpack the whole archive, not just bin/: protoc resolves the well-known
# imports (google/protobuf/descriptor.proto) from ../include next to it.
staging = Path(tmp) / "unpacked"
with zipfile.ZipFile(archive) as zf:
zf.extractall(staging)
target = _protoc_dir()
if target.exists():
shutil.rmtree(target)
# Move into place only once complete, so an interrupted run never leaves
# a half-extracted toolchain that later runs would happily use.
shutil.move(str(staging), str(target))
binary = target / "bin" / _PROTOC_EXE
if not binary.exists():
print(f" ERROR: protoc archive did not contain bin/{_PROTOC_EXE}")
return None
binary.chmod(binary.stat().st_mode | 0o755)
return binary
def find_protoc(allow_download=True):
"""Return the protoc command as a list, or None if it can't be resolved."""
override = os.environ.get("PROTOC")
if override:
return [override]
on_path = shutil.which("protoc")
if on_path:
return [on_path]
cached = _protoc_dir() / "bin" / _PROTOC_EXE
if cached.exists():
return [str(cached)]
# Honour a pre-existing grpcio-tools install rather than downloading.
if importlib.util.find_spec("grpc_tools") is not None:
return [sys.executable, "-m", "grpc_tools.protoc"]
if allow_download:
binary = _download_protoc()
if binary is not None:
return [str(binary)]
return None
def missing_packages():
"""pip names of the required Python packages this interpreter can't import."""
missing = []
for pip_name, module in PYTHON_PACKAGES.items():
try:
found = importlib.util.find_spec(module) is not None
except (ImportError, ValueError):
found = False
if not found:
missing.append(pip_name)
return missing
def _venv_python():
venv_dir = CACHE_DIR / "venv"
if os.name == "nt":
return venv_dir / "Scripts" / "python.exe"
return venv_dir / "bin" / "python"
def bootstrap_python():
"""The cached virtualenv interpreter, if it exists and has the packages."""
python = _venv_python()
if not python.exists():
return None
probe = subprocess.run([str(python), "-c", "import google.protobuf, yaml"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return python if probe.returncode == 0 else None
def _ensure_venv(missing):
"""Create/reuse .codegen-tools/venv with the required packages installed."""
python = _venv_python()
if not python.exists():
print(f" Creating codegen virtualenv in {python.parent.parent}...")
if subprocess.run([sys.executable, "-m", "venv", str(python.parent.parent)]).returncode != 0 \
or not python.exists():
return None
print(f" Installing {', '.join(missing)} into the codegen virtualenv...")
result = subprocess.run([str(python), "-m", "pip", "install", "--quiet",
"--disable-pip-version-check", *missing])
return python if result.returncode == 0 else None
def ensure_python_runtime():
"""
Guarantee protobuf + pyyaml are importable.
If they aren't, re-run the calling script in a cached virtualenv that has
them and exit with its status. Keeping the packages out of the caller's
interpreter is what lets the build scripts work on distros that refuse
`pip install` into a system Python (PEP 668).
"""
missing = missing_packages()
if not missing:
return
if os.environ.get(_BOOTSTRAP_ENV):
# We are already inside the bootstrapped environment: installing again
# would just fail the same way.
print(f" ERROR: {', '.join(missing)} still missing after bootstrap.")
sys.exit(1)
# Reuse a complete virtualenv as-is: builds call this every time, and pip
# would otherwise hit the network on each one.
python = bootstrap_python() or _ensure_venv(missing)
if python is None:
print(f" ERROR: could not provide {', '.join(missing)}.")
print(f" Install them for this interpreter: {sys.executable} -m pip install "
f"{' '.join(missing)}")
sys.exit(1)
env = dict(os.environ, **{_BOOTSTRAP_ENV: "1"})
sys.exit(subprocess.run([str(python), *sys.argv], env=env).returncode)
def toolchain_ready():
"""
True if the codegen can run without downloading or installing anything --
either from this interpreter or by re-execing into an existing bootstrap
virtualenv. This is what decides whether a build regenerates on proto edits.
"""
if missing_packages() and bootstrap_python() is None:
return False
return find_protoc(allow_download=False) is not None
def main():
# --check is what ConfigCodegen.cmake probes with: it answers whether this
# interpreter can regenerate during a build, and must not download, install
# or create anything while doing so.
if "--check" in sys.argv[1:]:
return 0 if toolchain_ready() else 1
missing = missing_packages()
print(f"python: {sys.executable}")
print(f"packages: {'all present' if not missing else 'missing ' + ', '.join(missing)}")
protoc = find_protoc()
print(f"protoc: {' '.join(protoc) if protoc else 'NOT FOUND'}")
return 0 if protoc else 1
if __name__ == "__main__":
sys.exit(main())

1049
tools/config_codegen.py Normal file

File diff suppressed because it is too large Load Diff

67
tools/config_metadata.py Normal file
View File

@@ -0,0 +1,67 @@
#!/usr/bin/env python3
"""
Access to the orca.* option extensions declared in config_metadata.proto.
The extensions are read straight out of the compiled descriptor set: protoc runs
with --include_imports, so config_metadata.proto travels inside the .desc file
that the codegen already consumes. Registering it in the default descriptor pool
before the descriptor set is parsed is what makes the custom options resolve
instead of landing in unknown fields.
Doing it this way keeps generated code out of git. The alternative -- a checked-in
config_metadata_pb2.py -- also pinned the protobuf runtime to whichever protoc
produced it, because gencode embeds a hard ValidateProtobufRuntimeVersion() check.
"""
from google.protobuf import descriptor_pb2, descriptor_pool
METADATA_PROTO = "config_metadata.proto"
class Metadata:
"""
Stand-in for the generated config_metadata_pb2 module.
Exposes each orca extension as an attribute holding its FieldDescriptor
(usable as `options.Extensions[meta.label]`) and each enum value as an int
constant (`meta.MODE_SIMPLE`, `meta.STEP_SLICE`, ...), matching how the
generated module was used.
"""
def __init__(self, file_descriptor):
for name, extension in file_descriptor.extensions_by_name.items():
setattr(self, name, extension)
for enum in file_descriptor.enum_types_by_name.values():
for value in enum.values:
setattr(self, value.name, value.number)
def load_descriptor_set(path):
"""
Read a protoc descriptor set and return (FileDescriptorSet, Metadata).
The file is parsed twice on purpose: the first pass only locates the embedded
config_metadata.proto so its extensions can be registered, the second one
parses with those extensions known.
"""
with open(path, 'rb') as f:
raw = f.read()
probe = descriptor_pb2.FileDescriptorSet()
probe.ParseFromString(raw)
metadata_file = next((f for f in probe.file if f.name == METADATA_PROTO), None)
if metadata_file is None:
raise RuntimeError(
f"{path} does not contain {METADATA_PROTO} -- protoc must be run with "
"--include_imports")
pool = descriptor_pool.Default()
try:
file_descriptor = pool.FindFileByName(METADATA_PROTO)
except KeyError:
pool.Add(metadata_file)
file_descriptor = pool.FindFileByName(METADATA_PROTO)
descriptor_set = descriptor_pb2.FileDescriptorSet()
descriptor_set.ParseFromString(raw)
return descriptor_set, Metadata(file_descriptor)

106
tools/run_codegen.py Normal file
View File

@@ -0,0 +1,106 @@
#!/usr/bin/env python3
"""
Convenience script: runs the codegen pipeline.
1. Compile .proto -> binary descriptor set (protoc)
2. Generate C++ from descriptors (config_codegen.py)
3. Validate output against original
The toolchain (protoc, protobuf, pyyaml) is resolved by codegen_toolchain.py, so
this script is the single entry point every build script and CI job calls -- no
`pip install` lines needed around it.
Usage:
python tools/run_codegen.py # full pipeline
python tools/run_codegen.py --validate-only # just validate
"""
import argparse
import subprocess
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
import codegen_toolchain # noqa: E402
ROOT = Path(__file__).resolve().parent.parent
PROTO_DIR = ROOT / "src" / "PrintConfigs"
CODEGEN_OUT = ROOT / "src" / "slic3r" / "GUI" / "generated"
DESC_FILE = ROOT / "config.desc"
LAYOUT_YAML = PROTO_DIR / "layout.yaml"
def run(cmd, **kwargs):
print(f" $ {' '.join(str(c) for c in cmd)}")
result = subprocess.run(cmd, **kwargs)
if result.returncode != 0:
print(f" FAILED (exit code {result.returncode})")
return False
return True
def step_compile():
print("\n=== Step 1: Compile .proto -> descriptor set ===")
proto_files = [f for f in PROTO_DIR.glob("*.proto") if not f.name.endswith("_gen.proto") and f.name != "config_metadata.proto"]
if not proto_files:
print(" ERROR: No .proto files found")
return False
protoc = codegen_toolchain.find_protoc()
if protoc is None:
return False
return run(protoc + [
f"--proto_path={PROTO_DIR}",
f"--descriptor_set_out={DESC_FILE}",
"--include_imports",
] + [str(f) for f in proto_files])
def step_generate():
print("\n=== Step 2: Generate C++ from descriptors + layout.yaml ===")
return run([sys.executable, str(ROOT / "tools" / "config_codegen.py"),
str(DESC_FILE), str(CODEGEN_OUT)])
def step_lint():
print("\n=== Lint: proto sanity checks ===")
return run([sys.executable, str(ROOT / "tools" / "config_codegen.py"),
str(DESC_FILE), str(CODEGEN_OUT), "--lint-only"])
def step_validate():
print("\n=== Step 3: Validate ===")
return run([sys.executable, str(ROOT / "tools" / "validate_codegen.py")])
def main():
parser = argparse.ArgumentParser(description="Run OrcaSlicer config codegen pipeline")
parser.add_argument("--validate-only", action="store_true",
help="Only run validation")
parser.add_argument("--no-validate", action="store_true",
help="Skip validation step (used by cmake build)")
args = parser.parse_args()
# Re-execs into a virtualenv with protobuf/pyyaml if this interpreter lacks them.
codegen_toolchain.ensure_python_runtime()
if args.validate_only:
# Compile + lint the protos, then check the generated files against PrintConfig.cpp.
sys.exit(0 if (step_compile() and step_lint() and step_validate()) else 1)
for name, fn in [("Compile", step_compile), ("Generate", step_generate)]:
if not fn():
print(f"\n*** Pipeline FAILED at: {name} ***")
sys.exit(1)
if not args.no_validate:
if not step_validate():
print("\n*** Validate FAILED (run with --no-validate to skip) ***")
sys.exit(1)
print("\n=== Pipeline completed successfully ===")
if __name__ == "__main__":
main()

214
tools/validate_codegen.py Normal file
View File

@@ -0,0 +1,214 @@
#!/usr/bin/env python3
"""
Validates generated PrintConfigDef code against the original PrintConfig.cpp.
Compares setting keys, types, defaults, enum values/labels, and metadata
to ensure the codegen output is a faithful reproduction.
"""
import re
import json
import sys
from pathlib import Path
from collections import OrderedDict
def parse_original_settings(cpp_path):
"""Parse the original init_fff_params() into a dict of key -> properties."""
with open(cpp_path, 'r', encoding='utf-8') as f:
text = f.read()
m = re.search(r'void PrintConfigDef::init_fff_params\(\)(.*?)^\}', text, re.DOTALL | re.MULTILINE)
if not m:
print("ERROR: Could not find init_fff_params()")
sys.exit(1)
body = m.group(1)
settings = OrderedDict()
current_key = None
for line in body.split('\n'):
stripped = line.strip()
# Detect this->add("key", coType)
add_match = re.search(r'this->add(?:_nullable)?\s*\(\s*"([^"]+)"\s*,\s*(co\w+)\s*\)', stripped)
if add_match:
current_key = add_match.group(1)
co_type = add_match.group(2)
# Last definition wins (handles duplicates)
settings[current_key] = {
'co_type': co_type,
'has_default': False,
'enum_values': 0,
'enum_labels': 0,
'has_enum_map': False,
}
continue
if current_key and current_key in settings:
s = settings[current_key]
if 'set_default_value' in stripped:
s['has_default'] = True
if re.search(r'enum_values\.(?:push_back|emplace_back)', stripped):
s['enum_values'] += 1
if re.search(r'enum_labels\.(?:push_back|emplace_back)', stripped):
s['enum_labels'] += 1
if 'enum_keys_map' in stripped and '=' in stripped:
s['has_enum_map'] = True
return settings
def parse_generated_settings(gen_path):
"""Parse the generated PrintConfigDef code into a dict of key -> properties."""
with open(gen_path, 'r', encoding='utf-8') as f:
text = f.read()
settings = OrderedDict()
current_key = None
for line in text.split('\n'):
stripped = line.strip()
add_match = re.search(r'this->add(?:_nullable)?\s*\(\s*"([^"]+)"\s*,\s*(co\w+)\s*\)', stripped)
if add_match:
current_key = add_match.group(1)
co_type = add_match.group(2)
settings[current_key] = {
'co_type': co_type,
'has_default': False,
'enum_values': 0,
'enum_labels': 0,
'has_enum_map': False,
}
continue
if current_key and current_key in settings:
s = settings[current_key]
if 'set_default_value' in stripped:
s['has_default'] = True
if 'enum_values.push_back' in stripped:
s['enum_values'] += 1
if 'enum_labels.push_back' in stripped:
s['enum_labels'] += 1
if 'enum_keys_map' in stripped and '=' in stripped:
s['has_enum_map'] = True
return settings
def main():
root = Path(__file__).resolve().parent.parent
orig_path = root / "src/libslic3r/PrintConfig.cpp"
gen_path = root / "src/slic3r/GUI/generated/PrintConfigDef_generated.cpp"
if not orig_path.exists() or not gen_path.exists():
print("ERROR: Required files not found")
sys.exit(1)
print("Parsing original...")
orig = parse_original_settings(orig_path)
print(f" {len(orig)} settings")
print("Parsing generated...")
gen = parse_generated_settings(gen_path)
print(f" {len(gen)} settings")
# Known exceptions: settings that exist in original but are commented out
# or have runtime-generated enums
known_exceptions = {
'adaptive_layer_height', # Commented out in original
'spaghetti_detector', # Commented out in original
}
# Settings with runtime-generated enum values (loop over MaterialType::all())
runtime_enum_keys = {
'filament_type', # enum_values from runtime loop
}
# Compare
errors = []
warnings = []
# Missing keys
orig_keys = set(orig.keys())
gen_keys = set(gen.keys())
missing = orig_keys - gen_keys
extra = gen_keys - orig_keys
if missing:
real_missing = missing - known_exceptions
if real_missing:
errors.append(f"MISSING from generated ({len(real_missing)}): {sorted(real_missing)}")
noted = missing & known_exceptions
if noted:
warnings.append(f"Known exceptions (commented out in original): {sorted(noted)}")
if extra:
warnings.append(f"EXTRA in generated ({len(extra)}): {sorted(extra)}")
# Compare shared keys
shared = orig_keys & gen_keys
type_mismatches = []
default_mismatches = []
enum_val_mismatches = []
enum_lbl_mismatches = []
enum_map_mismatches = []
for key in sorted(shared):
o = orig[key]
g = gen[key]
if o['co_type'] != g['co_type']:
type_mismatches.append(f" {key}: orig={o['co_type']} gen={g['co_type']}")
if o['has_default'] != g['has_default'] and key not in known_exceptions:
default_mismatches.append(f" {key}: orig={o['has_default']} gen={g['has_default']}")
if o['enum_values'] != g['enum_values'] and key not in runtime_enum_keys:
enum_val_mismatches.append(f" {key}: orig={o['enum_values']} gen={g['enum_values']}")
if o['enum_labels'] != g['enum_labels']:
enum_lbl_mismatches.append(f" {key}: orig={o['enum_labels']} gen={g['enum_labels']}")
if o['has_enum_map'] != g['has_enum_map']:
enum_map_mismatches.append(f" {key}: orig={o['has_enum_map']} gen={g['has_enum_map']}")
# Report
print("\n=== VALIDATION RESULTS ===\n")
if type_mismatches:
errors.append(f"TYPE MISMATCHES ({len(type_mismatches)}):\n" + "\n".join(type_mismatches))
if default_mismatches:
errors.append(f"DEFAULT MISMATCHES ({len(default_mismatches)}):\n" + "\n".join(default_mismatches))
if enum_val_mismatches:
warnings.append(f"ENUM VALUE COUNT MISMATCHES ({len(enum_val_mismatches)}):\n" + "\n".join(enum_val_mismatches))
if enum_lbl_mismatches:
warnings.append(f"ENUM LABEL COUNT MISMATCHES ({len(enum_lbl_mismatches)}):\n" + "\n".join(enum_lbl_mismatches))
if enum_map_mismatches:
warnings.append(f"ENUM MAP MISMATCHES ({len(enum_map_mismatches)}):\n" + "\n".join(enum_map_mismatches))
if warnings:
print("WARNINGS:")
for w in warnings:
print(f" {w}")
print()
if errors:
print("ERRORS:")
for e in errors:
print(f" {e}")
print(f"\nValidation FAILED with {len(errors)} error(s)")
sys.exit(1)
else:
print(f"All {len(shared)} shared settings validated successfully")
if extra:
print(f" ({len(extra)} extra settings from axis expansion)")
print("\nValidation PASSED")
if __name__ == "__main__":
main()