mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-10 18:56:13 +00:00
Merge main and resolved conflicts
This commit is contained in:
13
.github/workflows/check_profiles.yml
vendored
13
.github/workflows/check_profiles.yml
vendored
@@ -9,6 +9,10 @@ on:
|
|||||||
- release/*
|
- release/*
|
||||||
paths:
|
paths:
|
||||||
- 'resources/profiles/**'
|
- 'resources/profiles/**'
|
||||||
|
# The extra JSON check also validates resources/printers/bambu_filament_ids.json,
|
||||||
|
# and lives in scripts/, so a PR touching only those must still run this workflow.
|
||||||
|
- 'resources/printers/**'
|
||||||
|
- 'scripts/**'
|
||||||
- ".github/workflows/check_profiles.yml"
|
- ".github/workflows/check_profiles.yml"
|
||||||
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -64,13 +68,14 @@ jobs:
|
|||||||
set +e
|
set +e
|
||||||
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -s -l 2 2>&1 | tee ${{ runner.temp }}/validate_slice.log
|
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -s -l 2 2>&1 | tee ${{ runner.temp }}/validate_slice.log
|
||||||
exit ${PIPESTATUS[0]}
|
exit ${PIPESTATUS[0]}
|
||||||
# For now run filament subtype check only for BBL profiles until we fix other vendors' profiles.
|
# All vendors' filament_id collisions were fixed (see scripts/filament_id_snapshot.json),
|
||||||
- name: validate filament subtype check for BBL profiles
|
# so the duplicate-filament-subtype check runs tree-wide.
|
||||||
|
- name: validate filament subtype check
|
||||||
id: validate_filament_subtypes
|
id: validate_filament_subtypes
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: |
|
run: |
|
||||||
set +e
|
set +e
|
||||||
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -l 2 -v BBL -f 2>&1 | tee ${{ runner.temp }}/validate_filament_subtypes.log
|
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -l 2 -f 2>&1 | tee ${{ runner.temp }}/validate_filament_subtypes.log
|
||||||
exit ${PIPESTATUS[0]}
|
exit ${PIPESTATUS[0]}
|
||||||
|
|
||||||
- name: validate custom presets
|
- name: validate custom presets
|
||||||
@@ -217,7 +222,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "${{ steps.validate_filament_subtypes.outcome }}" = "failure" ]; then
|
if [ "${{ steps.validate_filament_subtypes.outcome }}" = "failure" ]; then
|
||||||
echo "### BBL Filament Subtype Validation Failed"
|
echo "### Filament Subtype Validation Failed"
|
||||||
echo ""
|
echo ""
|
||||||
echo '```'
|
echo '```'
|
||||||
head -c 30000 ${{ runner.temp }}/validate_filament_subtypes.log || echo "No output captured"
|
head -c 30000 ${{ runner.temp }}/validate_filament_subtypes.log || echo "No output captured"
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -53,3 +53,4 @@ __pycache__/
|
|||||||
*.pyc
|
*.pyc
|
||||||
*.opc
|
*.opc
|
||||||
/.test/
|
/.test/
|
||||||
|
docs/superpowers/
|
||||||
@@ -25,6 +25,13 @@ ctest --test-dir ./tests/libslic3r # individual suite
|
|||||||
ctest --test-dir ./tests/fff_print
|
ctest --test-dir ./tests/fff_print
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
- Docs live in `docs/`; the high-level design of a subsystem goes in `docs/HLSD/<subsystem>.md`.
|
||||||
|
- Describe the design as it stands — what the subsystem does, why it exists, and the constraints that shape it. Not the route that got there: no phases, task lists, status markers, or "before/after this PR" framing.
|
||||||
|
- Planning and investigation output (brainstorms, superpowers design and plan docs) stays in `docs/superpowers/`, which is gitignored. Never commit it.
|
||||||
|
- Write a doc only when the design is not evident from the code, and when a change invalidates an existing one, update it in the same PR.
|
||||||
|
|
||||||
## Code Style
|
## Code Style
|
||||||
|
|
||||||
- C++17, selective C++20. PascalCase classes, snake_case functions/variables
|
- C++17, selective C++20. PascalCase classes, snake_case functions/variables
|
||||||
|
|||||||
@@ -95,33 +95,6 @@ else ()
|
|||||||
add_compile_definitions("$<$<CONFIG:Release>:WXINSPECTOR_DISABLE>")
|
add_compile_definitions("$<$<CONFIG:Release>:WXINSPECTOR_DISABLE>")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
find_package(Git)
|
|
||||||
if(DEFINED ENV{git_commit_hash} AND NOT "$ENV{git_commit_hash}" STREQUAL "")
|
|
||||||
message(STATUS "Specified git commit hash: $ENV{git_commit_hash}")
|
|
||||||
if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
|
||||||
# Convert the given hash to short hash
|
|
||||||
execute_process(
|
|
||||||
COMMAND ${GIT_EXECUTABLE} rev-parse --short "$ENV{git_commit_hash}"
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
||||||
OUTPUT_VARIABLE GIT_COMMIT_HASH
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
# No .git directory (e.g., Flatpak sandbox) — truncate directly
|
|
||||||
string(SUBSTRING "$ENV{git_commit_hash}" 0 7 GIT_COMMIT_HASH)
|
|
||||||
endif()
|
|
||||||
add_definitions("-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"")
|
|
||||||
elseif(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
|
||||||
# Check current Git commit hash
|
|
||||||
execute_process(
|
|
||||||
COMMAND ${GIT_EXECUTABLE} log -1 --format=%h
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
||||||
OUTPUT_VARIABLE GIT_COMMIT_HASH
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
||||||
)
|
|
||||||
add_definitions("-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(DEFINED ENV{SLIC3R_STATIC})
|
if(DEFINED ENV{SLIC3R_STATIC})
|
||||||
set(SLIC3R_STATIC_INITIAL $ENV{SLIC3R_STATIC})
|
set(SLIC3R_STATIC_INITIAL $ENV{SLIC3R_STATIC})
|
||||||
else()
|
else()
|
||||||
@@ -137,6 +110,7 @@ option(SLIC3R_WARNINGS "Emit compiler warnings for OrcaSlicer sources"
|
|||||||
option(SLIC3R_BUNDLED_WARNINGS "Emit compiler warnings for bundled third-party sources" 0)
|
option(SLIC3R_BUNDLED_WARNINGS "Emit compiler warnings for bundled third-party sources" 0)
|
||||||
option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1)
|
option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1)
|
||||||
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)
|
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)
|
||||||
|
option(SLIC3R_RELATIVE_DEBUG_PATHS "Record a relative compilation directory in debug info (clang-cl)" 0)
|
||||||
option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
|
option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
|
||||||
|
|
||||||
# Python stubgen module
|
# Python stubgen module
|
||||||
@@ -379,11 +353,14 @@ if (MSVC)
|
|||||||
add_compile_options(/Zc:lambda)
|
add_compile_options(/Zc:lambda)
|
||||||
endif ()
|
endif ()
|
||||||
# /bigobj (Increase Number of Sections in .Obj file)
|
# /bigobj (Increase Number of Sections in .Obj file)
|
||||||
|
add_compile_options(-bigobj)
|
||||||
# error C3859: virtual memory range for PCH exceeded; please recompile with a command line option of '-Zm90' or greater
|
# error C3859: virtual memory range for PCH exceeded; please recompile with a command line option of '-Zm90' or greater
|
||||||
# Generate symbols at every build target, even for the release.
|
# Generate symbols at every build target, even for the release.
|
||||||
# -Zm520 fixes error C3859 but forces the compiler to pre-allocate that memory for every translation unit regardless
|
# -Zm520 fixes error C3859 but forces the compiler to pre-allocate that memory for every translation unit regardless
|
||||||
# combining /Zi with /FS frees up a significant amount of memory pressure across all parallel compile jobs and makes /MP faster overall.
|
# combining /Zi with /FS frees up a significant amount of memory pressure across all parallel compile jobs and makes /MP faster overall.
|
||||||
add_compile_options(-bigobj /Zi /FS)
|
if (SLIC3R_MSVC_PDB)
|
||||||
|
add_compile_options(/Zi /FS)
|
||||||
|
endif ()
|
||||||
# Disable STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17.
|
# Disable STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17.
|
||||||
#FIXME Remove this line after eigen library adapts to the new C++17 adaptor rules.
|
#FIXME Remove this line after eigen library adapts to the new C++17 adaptor rules.
|
||||||
add_compile_options(-D_SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING)
|
add_compile_options(-D_SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING)
|
||||||
@@ -401,6 +378,16 @@ if (MSVC)
|
|||||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /LTCG")
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /LTCG")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
# Without this every object names its build directory and two worktrees never
|
||||||
|
# share cache entries. The linker still writes absolute paths into the PDB.
|
||||||
|
if (SLIC3R_RELATIVE_DEBUG_PATHS)
|
||||||
|
if (IS_CLANG_CL)
|
||||||
|
add_compile_options(-ffile-compilation-dir=.)
|
||||||
|
else ()
|
||||||
|
message(WARNING "SLIC3R_RELATIVE_DEBUG_PATHS is only implemented for clang-cl")
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
|
||||||
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "AppleClang" AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER 15)
|
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "AppleClang" AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER 15)
|
||||||
add_compile_definitions(BOOST_NO_CXX98_FUNCTION_BASE _HAS_AUTO_PTR_ETC=0)
|
add_compile_definitions(BOOST_NO_CXX98_FUNCTION_BASE _HAS_AUTO_PTR_ETC=0)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ call :add_section "Build configuration"
|
|||||||
call :add_arg config string "" config "release, debug, relwithdebinfo or minsizerel (default: release)"
|
call :add_arg config string "" config "release, debug, relwithdebinfo or minsizerel (default: release)"
|
||||||
call :add_arg target_arch string "" arch "x64 or arm64 (default: the host architecture)"
|
call :add_arg target_arch string "" arch "x64 or arm64 (default: the host architecture)"
|
||||||
call :add_arg slicer_asan bool a asan "Build the slicer with ASAN enabled"
|
call :add_arg slicer_asan bool a asan "Build the slicer with ASAN enabled"
|
||||||
|
call :add_arg no_pch bool "" no-pch "Build without the precompiled header, implied by --cache"
|
||||||
|
|
||||||
call :add_section "Toolchain"
|
call :add_section "Toolchain"
|
||||||
call :add_arg use_clang_cl bool l clang-cl "Use clang-cl as the compiler"
|
call :add_arg use_clang_cl bool l clang-cl "Use clang-cl as the compiler"
|
||||||
@@ -60,6 +61,7 @@ call :add_arg use_ninja bool x ninja "Use the Ninja Multi-Config generator"
|
|||||||
call :add_arg use_msbuild bool "" msbuild "Use the Visual Studio generator (default)"
|
call :add_arg use_msbuild bool "" msbuild "Use the Visual Studio generator (default)"
|
||||||
call :add_arg vs_version string "" vs "Visual Studio release: 2019, 2022 or 2026 (default: autodetect)"
|
call :add_arg vs_version string "" vs "Visual Studio release: 2019, 2022 or 2026 (default: autodetect)"
|
||||||
call :add_arg clang_path string "" clang-path "Path to clang-cl.exe, requires -x (default: the one from Visual Studio)"
|
call :add_arg clang_path string "" clang-path "Path to clang-cl.exe, requires -x (default: the one from Visual Studio)"
|
||||||
|
call :add_arg cache string "" cache "Compiler cache: ccache, sccache or off, requires -l -x (default: off)"
|
||||||
|
|
||||||
call :add_section "How much gets rebuilt"
|
call :add_section "How much gets rebuilt"
|
||||||
call :add_arg slicer_target string "" slicer-target "Build one slicer target instead of all, e.g. libslic3r"
|
call :add_arg slicer_target string "" slicer-target "Build one slicer target instead of all, e.g. libslic3r"
|
||||||
@@ -391,6 +393,49 @@ if not "%clang_path%" == "" if not "%using_ninja%" == "ON" (
|
|||||||
exit /b 1
|
exit /b 1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set "cache_args="
|
||||||
|
if "%cache%" == "" goto :cache_ready
|
||||||
|
if /I "%cache%" == "off" goto :cache_ready
|
||||||
|
if /I "%cache%" == "ccache" goto :cache_named
|
||||||
|
if /I "%cache%" == "sccache" goto :cache_named
|
||||||
|
echo Unknown --cache value "%cache%". Expected ccache, sccache or off.
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
REM CMake accepts a compiler launcher under any generator but only runs it
|
||||||
|
REM under Makefile and Ninja. ccache also refuses cl.exe because the build
|
||||||
|
REM passes /Zi.
|
||||||
|
:cache_named
|
||||||
|
REM Only a configure records the launcher, so --no-configure needs none.
|
||||||
|
if "%no_configure%" == "ON" goto :cache_ready
|
||||||
|
if "%build_deps%%build_slicer%" == "" goto :cache_ready
|
||||||
|
if not "%using_ninja%" == "ON" goto :cache_needs_clang
|
||||||
|
if not "%use_clang_cl%" == "ON" goto :cache_needs_clang
|
||||||
|
goto :cache_tool
|
||||||
|
|
||||||
|
:cache_needs_clang
|
||||||
|
echo --cache needs clang-cl and Ninja; add -l -x.
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
REM Name a full path, so the recorded launcher does not depend on PATH.
|
||||||
|
:cache_tool
|
||||||
|
set "cache_exe="
|
||||||
|
for /f "tokens=*" %%i in ('where %cache% 2^>nul') do (
|
||||||
|
if not defined cache_exe set "cache_exe=%%i"
|
||||||
|
)
|
||||||
|
if not defined cache_exe (
|
||||||
|
echo %cache% is not on PATH. Install it, or leave --cache off.
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
REM Forward slashes, so CMake does not read a backslash as an escape.
|
||||||
|
set "cache_exe=%cache_exe:\=/%"
|
||||||
|
set "cache_args=-DCMAKE_C_COMPILER_LAUNCHER="%cache_exe%" -DCMAKE_CXX_COMPILER_LAUNCHER="%cache_exe%""
|
||||||
|
REM Neither cache stores a compile that uses a precompiled header. sccache
|
||||||
|
REM refuses /Fp outright. ccache does too unless its sloppiness is loosened,
|
||||||
|
REM and even then most hits fall back to the slower preprocessed mode.
|
||||||
|
set "no_pch=ON"
|
||||||
|
|
||||||
|
:cache_ready
|
||||||
|
|
||||||
REM Ninja prints [123/456] by default, which says nothing about how far
|
REM Ninja prints [123/456] by default, which says nothing about how far
|
||||||
REM along it is or how long is left. %p is a percentage, %w and %W are
|
REM along it is or how long is left. %p is a percentage, %w and %W are
|
||||||
REM elapsed and remaining, but those two arrived in ninja 1.12 and an
|
REM elapsed and remaining, but those two arrived in ninja 1.12 and an
|
||||||
@@ -474,6 +519,8 @@ REM real path rather than one glued onto the repository root.
|
|||||||
for %%p in ("!build_dir!") do set "build_full=%%~fp"
|
for %%p in ("!build_dir!") do set "build_full=%%~fp"
|
||||||
echo Configuration: %build_type%, %arch%
|
echo Configuration: %build_type%, %arch%
|
||||||
if not "%clang_exe%" == "" echo Compiler: %clang_exe%
|
if not "%clang_exe%" == "" echo Compiler: %clang_exe%
|
||||||
|
if "%no_pch%" == "ON" echo Precompiled header: off
|
||||||
|
if not "%cache_args%" == "" echo Compiler cache: %cache_exe%
|
||||||
|
|
||||||
set "SIG_FLAG="
|
set "SIG_FLAG="
|
||||||
if defined ORCA_UPDATER_SIG_KEY set "SIG_FLAG=-DORCA_UPDATER_SIG_KEY=%ORCA_UPDATER_SIG_KEY%"
|
if defined ORCA_UPDATER_SIG_KEY set "SIG_FLAG=-DORCA_UPDATER_SIG_KEY=%ORCA_UPDATER_SIG_KEY%"
|
||||||
@@ -570,6 +617,10 @@ if "%build_deps%" == "ON" (
|
|||||||
%error_check%
|
%error_check%
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not "!cache_args!" == "" (
|
||||||
|
set "deps_args=!deps_args! !cache_args!"
|
||||||
|
)
|
||||||
|
|
||||||
if not "%no_configure%" == "ON" (
|
if not "%no_configure%" == "ON" (
|
||||||
call :print_and_run cmake -S deps -B "!DEP_TREE!" -G "%generator%" %gen_args% -DCMAKE_BUILD_TYPE=%build_type% !deps_args! %ORCA_DEPS_CMAKE_ARGS%
|
call :print_and_run cmake -S deps -B "!DEP_TREE!" -G "%generator%" %gen_args% -DCMAKE_BUILD_TYPE=%build_type% !deps_args! %ORCA_DEPS_CMAKE_ARGS%
|
||||||
%error_check%
|
%error_check%
|
||||||
@@ -641,6 +692,17 @@ if "%build_slicer%" == "ON" (
|
|||||||
set "slicer_args=!slicer_args! -DSLIC3R_ASAN=ON"
|
set "slicer_args=!slicer_args! -DSLIC3R_ASAN=ON"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
REM A later -DSLIC3R_PCH=ON in ORCA_SLICER_CMAKE_ARGS still wins, because
|
||||||
|
REM CMake takes the last definition on the command line.
|
||||||
|
if "%no_pch%" == "ON" (
|
||||||
|
set "slicer_args=!slicer_args! -DSLIC3R_PCH=OFF"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not "!cache_args!" == "" (
|
||||||
|
REM Relative debug paths as well, so another tree can reuse the objects.
|
||||||
|
set "slicer_args=!slicer_args! !cache_args! -DSLIC3R_RELATIVE_DEBUG_PATHS=ON"
|
||||||
|
)
|
||||||
|
|
||||||
REM Configuring against a tree that was never built fails deep inside
|
REM Configuring against a tree that was never built fails deep inside
|
||||||
REM package resolution. Name it here instead. Skipped when -d is about to
|
REM package resolution. Name it here instead. Skipped when -d is about to
|
||||||
REM build it in this same run, and under a dry run, which configures
|
REM build it in this same run, and under a dry run, which configures
|
||||||
@@ -870,17 +932,18 @@ REM get_str_len <string> -> length in %ret%
|
|||||||
echo %script_name% -s --no-configure -j 8 Rebuild quickly while iterating
|
echo %script_name% -s --no-configure -j 8 Rebuild quickly while iterating
|
||||||
echo %script_name% -s --slicer-target glad Compile one target to check the toolchain
|
echo %script_name% -s --slicer-target glad Compile one target to check the toolchain
|
||||||
echo %script_name% -l -x --run-tests Test that toolchain's build, not the default one
|
echo %script_name% -l -x --run-tests Test that toolchain's build, not the default one
|
||||||
|
echo %script_name% -s -l -x --cache ccache Rebuild through a compiler cache
|
||||||
echo.
|
echo.
|
||||||
echo Environment:
|
echo Environment:
|
||||||
echo ORCA_DEPS_CMAKE_ARGS Extra arguments for the deps configure
|
echo ORCA_DEPS_CMAKE_ARGS Extra arguments for the deps configure
|
||||||
echo ORCA_SLICER_CMAKE_ARGS Extra arguments for the slicer configure
|
echo ORCA_SLICER_CMAKE_ARGS Extra arguments for the slicer configure
|
||||||
echo ORCA_UPDATER_SIG_KEY Update signing key baked into the slicer
|
echo ORCA_UPDATER_SIG_KEY Update signing key baked into the slicer
|
||||||
echo git_commit_hash Revision to stamp, so a commit does not rebuild everything
|
echo git_commit_hash Revision to stamp into the build, as CI does
|
||||||
echo NINJA_STATUS Ninja progress format, if you want your own
|
echo NINJA_STATUS Ninja progress format, if you want your own
|
||||||
echo debugscript Set to ON to trace this script
|
echo debugscript Set to ON to trace this script
|
||||||
echo.
|
echo.
|
||||||
echo set ORCA_SLICER_CMAKE_ARGS=-DSLIC3R_PCH=OFF -DSLIC3R_MSVC_PDB=OFF
|
echo set ORCA_SLICER_CMAKE_ARGS=-DSLIC3R_BUILD_SANDBOXES=ON -DSLIC3R_WARNINGS=OFF
|
||||||
echo $env:ORCA_SLICER_CMAKE_ARGS = '-DSLIC3R_PCH=OFF' (PowerShell)
|
echo $env:ORCA_SLICER_CMAKE_ARGS = '-DSLIC3R_BUILD_SANDBOXES=ON' (PowerShell)
|
||||||
echo.
|
echo.
|
||||||
echo --deps-args and --slicer-args cannot carry a value with spaces; use
|
echo --deps-args and --slicer-args cannot carry a value with spaces; use
|
||||||
echo these instead. Neither form supports a value containing an ampersand.
|
echo these instead. Neither form supports a value containing an ampersand.
|
||||||
|
|||||||
16
deps/python3/python3.cmake
vendored
16
deps/python3/python3.cmake
vendored
@@ -15,7 +15,13 @@ if(WIN32)
|
|||||||
# See https://github.com/python/cpython/issues/153438
|
# See https://github.com/python/cpython/issues/153438
|
||||||
# Patch from https://github.com/python/cpython/pull/153608
|
# Patch from https://github.com/python/cpython/pull/153608
|
||||||
# This patch has not been merged to 3.12 yet so we need to apply it manually
|
# This patch has not been merged to 3.12 yet so we need to apply it manually
|
||||||
set(_patch_cmd git init && ${PATCH_CMD} ${CMAKE_CURRENT_LIST_DIR}/01-windows-nuget.patch)
|
#
|
||||||
|
# Without core.autocrlf=false the patched find_python.bat comes out LF and
|
||||||
|
# cmd.exe cannot find its goto labels.
|
||||||
|
set(_patch_cmd git init
|
||||||
|
&& ${GIT_EXECUTABLE} -c core.autocrlf=false apply --verbose
|
||||||
|
--ignore-space-change --whitespace=fix
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/01-windows-nuget.patch)
|
||||||
|
|
||||||
if(MSVC_VERSION EQUAL 1800)
|
if(MSVC_VERSION EQUAL 1800)
|
||||||
set(_python_platform_toolset v120)
|
set(_python_platform_toolset v120)
|
||||||
@@ -53,12 +59,9 @@ if(WIN32)
|
|||||||
set(_python_pcbuild_output_dir win32)
|
set(_python_pcbuild_output_dir win32)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# pybind11 undefines _DEBUG around Python.h so a debug build links the
|
||||||
|
# release python3xx.lib; Py_DEBUG could not load release plugin modules.
|
||||||
set(_python_pcbuild_config Release)
|
set(_python_pcbuild_config Release)
|
||||||
set(_python_layout_debug OFF)
|
|
||||||
if(DEFINED DEP_DEBUG AND DEP_DEBUG)
|
|
||||||
set(_python_pcbuild_config Debug)
|
|
||||||
set(_python_layout_debug ON)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# CPython's PCbuild needs a 64-bit-hosted toolchain: find_msbuild.bat picks the
|
# CPython's PCbuild needs a 64-bit-hosted toolchain: find_msbuild.bat picks the
|
||||||
# 32-bit Bin\MSBuild.exe, whose x86 cl.exe/link.exe run out of address space
|
# 32-bit Bin\MSBuild.exe, whose x86 cl.exe/link.exe run out of address space
|
||||||
@@ -101,7 +104,6 @@ if(WIN32)
|
|||||||
-DPYTHON_BUILD_DIR=<SOURCE_DIR>/PCbuild/${_python_pcbuild_output_dir}
|
-DPYTHON_BUILD_DIR=<SOURCE_DIR>/PCbuild/${_python_pcbuild_output_dir}
|
||||||
-DPYTHON_DEST_DIR=${DESTDIR}/libpython
|
-DPYTHON_DEST_DIR=${DESTDIR}/libpython
|
||||||
-DPYTHON_LAYOUT_ARCH=${_python_layout_arch}
|
-DPYTHON_LAYOUT_ARCH=${_python_layout_arch}
|
||||||
-DPYTHON_DEBUG=${_python_layout_debug}
|
|
||||||
-P ${CMAKE_CURRENT_LIST_DIR}/stage_windows.cmake
|
-P ${CMAKE_CURRENT_LIST_DIR}/stage_windows.cmake
|
||||||
)
|
)
|
||||||
elseif(APPLE)
|
elseif(APPLE)
|
||||||
|
|||||||
20
deps/python3/stage_windows.cmake
vendored
20
deps/python3/stage_windows.cmake
vendored
@@ -9,9 +9,6 @@ foreach(_var PYTHON_SOURCE_DIR PYTHON_BUILD_DIR PYTHON_DEST_DIR PYTHON_LAYOUT_AR
|
|||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
set(_python_exe "${PYTHON_BUILD_DIR}/python.exe")
|
set(_python_exe "${PYTHON_BUILD_DIR}/python.exe")
|
||||||
if(PYTHON_DEBUG)
|
|
||||||
set(_python_exe "${PYTHON_BUILD_DIR}/python_d.exe")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT EXISTS "${_python_exe}")
|
if(NOT EXISTS "${_python_exe}")
|
||||||
message(FATAL_ERROR "Built Python executable not found: ${_python_exe}")
|
message(FATAL_ERROR "Built Python executable not found: ${_python_exe}")
|
||||||
@@ -49,22 +46,11 @@ endif()
|
|||||||
set(_required_files
|
set(_required_files
|
||||||
"${PYTHON_DEST_DIR}/Lib/encodings/__init__.py"
|
"${PYTHON_DEST_DIR}/Lib/encodings/__init__.py"
|
||||||
"${PYTHON_DEST_DIR}/include/Python.h"
|
"${PYTHON_DEST_DIR}/include/Python.h"
|
||||||
|
"${PYTHON_DEST_DIR}/python.exe"
|
||||||
|
"${PYTHON_DEST_DIR}/python${_python_abi}.dll"
|
||||||
|
"${PYTHON_DEST_DIR}/libs/python${_python_abi}.lib"
|
||||||
)
|
)
|
||||||
|
|
||||||
if(PYTHON_DEBUG)
|
|
||||||
list(APPEND _required_files
|
|
||||||
"${PYTHON_DEST_DIR}/python_d.exe"
|
|
||||||
"${PYTHON_DEST_DIR}/python${_python_abi}_d.dll"
|
|
||||||
"${PYTHON_DEST_DIR}/libs/python${_python_abi}_d.lib"
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
list(APPEND _required_files
|
|
||||||
"${PYTHON_DEST_DIR}/python.exe"
|
|
||||||
"${PYTHON_DEST_DIR}/python${_python_abi}.dll"
|
|
||||||
"${PYTHON_DEST_DIR}/libs/python${_python_abi}.lib"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
foreach(_required_file IN LISTS _required_files)
|
foreach(_required_file IN LISTS _required_files)
|
||||||
if(NOT EXISTS "${_required_file}")
|
if(NOT EXISTS "${_required_file}")
|
||||||
message(FATAL_ERROR "Staged Python file missing: ${_required_file}")
|
message(FATAL_ERROR "Staged Python file missing: ${_required_file}")
|
||||||
|
|||||||
508
docs/HLSD/filament_id.md
Normal file
508
docs/HLSD/filament_id.md
Normal file
@@ -0,0 +1,508 @@
|
|||||||
|
# Filament IDs (`filament_id`)
|
||||||
|
|
||||||
|
`filament_id` identifies one **filament product**: one named spool product = one id, shared by
|
||||||
|
all of that product's per-printer / per-nozzle variants, in every profile bundle that ships it.
|
||||||
|
Devices use it to match a physical spool or tray to a filament preset. It is never per-color,
|
||||||
|
per-printer, per-nozzle, or per-preset (per-preset identity is `setting_id`), and it is never
|
||||||
|
per-bundle either — PolyLite PLA carries the same id whether the preset lives in the
|
||||||
|
OrcaFilamentLibrary (OFL), Qidi, or Snapmaker bundle. The granularity is the name on the spool,
|
||||||
|
not the brand behind it: `AAA PLA Lite` and `AAA PLA Pro` are two filaments with two ids, not
|
||||||
|
variants of one.
|
||||||
|
|
||||||
|
**How it is generated:** an id is computed, never invented. `scripts/orca_id_tool.py`
|
||||||
|
mints it as a deterministic hash of the product's identity — the triple
|
||||||
|
`(filament_vendor, filament_type, filament name)`, where the filament name is the preset name
|
||||||
|
with its `@...` variant suffix stripped — producing an 8-character `OF*` code that is the
|
||||||
|
same for that product in every bundle, in every PR, on every machine. For example, Polymaker's
|
||||||
|
PolyLite PLA presets (`PolyLite PLA @base`, `PolyLite PLA@Q2-Series`, …) resolve
|
||||||
|
`filament_vendor` `Polymaker`, `filament_type` `PLA`, and filament name `PolyLite PLA`; hashing
|
||||||
|
`filament_product/Polymaker/PLA/PolyLite PLA` yields `OF5CgdDq`, and that is the id the
|
||||||
|
OrcaFilamentLibrary, OrcaArena, Qidi, and Snapmaker bundles all arrive at independently
|
||||||
|
(derivation details in the Minting section).
|
||||||
|
|
||||||
|
**How it is used:** at runtime the id is the join key between hardware and profiles.
|
||||||
|
When a printer reports what a tray holds (Bambu AMS, Qidi box, Creality CFS,
|
||||||
|
Klipper, Snapmaker), OrcaSlicer matches the reported id against the filament presets
|
||||||
|
compatible with that printer to select the right profile; other features — tray display
|
||||||
|
names, support-material detection, vitrification warnings, multi-nozzle filament grouping —
|
||||||
|
look up material properties by id alone. An id that changes is not forwarded anywhere: a
|
||||||
|
tray or record still holding the old value falls back to matching by material type until the
|
||||||
|
user re-selects the filament, so identity changes are made deliberately and rarely.
|
||||||
|
|
||||||
|
This page is the rule for authoring `filament_id` in system profiles
|
||||||
|
(`resources/profiles/**`). CI enforces everything below; the short version is:
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> **Never write a `filament_id` value by hand.** A new filament gets its id from
|
||||||
|
> `python scripts/orca_id_tool.py --generate`; one already in the tree has one — inherit it.
|
||||||
|
|
||||||
|
## The design, in two pieces
|
||||||
|
|
||||||
|
Because several consumers match **globally by id alone, first hit wins** (see the next
|
||||||
|
section), any two materials sharing one id feed wrong data somewhere — a wrong tray name, a
|
||||||
|
wrong support-material flag, a wrong nozzle grouping — and inside one printer a duplicated id
|
||||||
|
makes AMS spool matching a coin toss. Hand-written ids produce such collisions constantly, so
|
||||||
|
the system is built to make them impossible:
|
||||||
|
|
||||||
|
1. **Deterministic minting.** An id is a pure hash of the product's identity — no registry to
|
||||||
|
maintain, no next-free-number ceremony, no way for two concurrent PRs to race for the same
|
||||||
|
number, and no way to get it wrong by hand, because you never write it by hand.
|
||||||
|
2. **A sanctioned snapshot.** The complete id landscape derived from the tree must equal
|
||||||
|
`scripts/filament_id_snapshot.json` exactly, so every change to ids, claims (which bundles
|
||||||
|
ship which id, and for which filament), or product identity surfaces as a reviewable diff to
|
||||||
|
one file — the maintainer gate.
|
||||||
|
|
||||||
|
## Who consumes the id
|
||||||
|
|
||||||
|
The canonical consumer is tray-to-preset matching: a device reports a tray material id
|
||||||
|
(`tray_info_idx`), and the shared matching pipeline (`PresetBundle::sync_ams_list` and
|
||||||
|
friends) resolves it to a preset. The matcher is printer-scoped and first-match-wins:
|
||||||
|
scanning only compatible root presets — system roots plus user-made custom filaments, which
|
||||||
|
are user roots carrying their own `P*` ids; a preset derived from another resolves through
|
||||||
|
its root and never matches directly — it picks the first one whose `filament_id` equals the
|
||||||
|
tray's. On a miss it falls back by filament type: a system `Generic <type>` preset
|
||||||
|
(matched by name, then by type similarity), else the slot's previous selection, else any compatible system generic or,
|
||||||
|
failing that, any compatible system preset, else the slot is skipped — every fallback
|
||||||
|
selection surfaces a user-visible notice.
|
||||||
|
|
||||||
|
Today only the Bambu AMS integration follows this pattern end to end — the device itself
|
||||||
|
reports the id, `BBLPrinterAgent` translates it out of Bambu's catalog into ours, and the
|
||||||
|
pipeline does all the matching. The other device integrations still synthesize a preset id
|
||||||
|
client-side in their agents (by type, brand, or color lookups against the loaded presets)
|
||||||
|
before the pipeline runs; they are intended to converge on the same pattern, with the
|
||||||
|
device-reported tray material id flowing through the shared matcher.
|
||||||
|
|
||||||
|
| Ecosystem | Where the tray id comes from today |
|
||||||
|
| --- | --- |
|
||||||
|
| Bambu AMS | the device itself (RFID / user tray setting), in Bambu's own `GF*` catalog; `BBLPrinterAgent` rewrites it into our id before the matcher sees it (see [The Bambu catalog map](#the-bambu-catalog-map)) |
|
||||||
|
| Qidi box | composed at runtime as `QD_<series>_<vendor>_<typeidx>` — vendor and type indices from the device's per-slot saved variables, the series digit inferred client-side from the printer model/name. No preset carries a `QD_*` value, so the slot currently resolves by filament type; mapping the composed id onto the filament's minted id belongs in the agent |
|
||||||
|
| Creality CFS | runtime brand/type scoring returns the winning preset's id |
|
||||||
|
| Klipper (AFC / Happy Hare) | runtime lookup by filament type |
|
||||||
|
| Snapmaker | runtime color/vendor/type match |
|
||||||
|
|
||||||
|
Tray-to-preset matching is printer-scoped, but **several consumers match globally by id alone,
|
||||||
|
first hit wins**: tray display names, `filament_is_support`, vitrification warnings, and
|
||||||
|
multi-nozzle filament grouping in the slicing pipeline (`FilamentGroup::try_merge_filaments`
|
||||||
|
merges plate slots sharing one `(filament_id, color)` pair, with matching
|
||||||
|
extruder-printability, onto one nozzle group; the engine is implemented but no grouping path
|
||||||
|
calls it yet).
|
||||||
|
Two *different* materials sharing one id
|
||||||
|
feed wrong data to those consumers even when the presets live in different vendors — so
|
||||||
|
cross-material id sharing is never safe. Within one printer, duplicate ids break AMS matching:
|
||||||
|
the matcher picks whichever preset loads first (it now logs an "Ambiguous AMS filament match"
|
||||||
|
warning, but the pick is still arbitrary) and the tray-edit dialog, which lists one entry per
|
||||||
|
id, hides the second preset entirely. The profile validator's `-f` check
|
||||||
|
(`check_filament_subtypes` → `PresetBundle::check_duplicate_filament_subtypes`) rejects this
|
||||||
|
per printer, and CI runs it tree-wide.
|
||||||
|
|
||||||
|
Two more consumer-side facts worth knowing:
|
||||||
|
|
||||||
|
- The machine-facing dialogs (AMS tray edit, AMS dry control, calibration history, extrusion
|
||||||
|
calibration) offer the filaments a connected printer can use by the same compatibility rule
|
||||||
|
the plater uses (an empty `compatible_printers` means *every* printer). Alias shadowing
|
||||||
|
still applies: a vendor's same-name profile supersedes the library generic. That is what
|
||||||
|
puts Orca Filament Library materials in those lists — deduplicated to one entry per
|
||||||
|
`filament_id` in the AMS and calibration-history dialogs, while extrusion calibration
|
||||||
|
deliberately lists every matching preset by full name.
|
||||||
|
- The id is load-bearing at startup: an instantiated system filament (one marked
|
||||||
|
`"instantiation": "true"` — see the structure rules) that resolves **no**
|
||||||
|
`filament_id` anywhere in its `inherits` chain is a hard load error in the C++ loader
|
||||||
|
(`Can not find filament_id for <name>`) that discards the entire vendor bundle (for the
|
||||||
|
OrcaFilamentLibrary itself the failure is messier: library presets loaded before the
|
||||||
|
failing one survive, and every vendor bundle whose filaments inherit from the library is
|
||||||
|
then discarded for want of a base). CI's structure check catches this before it ships.
|
||||||
|
|
||||||
|
## Do I need a new id? The one-question test
|
||||||
|
|
||||||
|
> **Would a user consider this a different spool product than anything already in the tree?**
|
||||||
|
|
||||||
|
Different polymer, different sub-brand (Basic / Matte / Silk / HF), fiber-filled sibling, or a
|
||||||
|
second selectable diameter → **new filament, new id**. The same spool tuned for another printer
|
||||||
|
or nozzle → **join the existing filament** (keep its base name and inherit it; no id
|
||||||
|
key needed). Tuning a generic material → **join the OrcaFilamentLibrary filament** (inherit
|
||||||
|
`Generic X @System` and keep the `Generic X` base name; no id key needed).
|
||||||
|
|
||||||
|
| Situation | id |
|
||||||
|
| --- | --- |
|
||||||
|
| Per-printer / per-nozzle variant of an existing material | same id (inherit it) |
|
||||||
|
| Sub-brand or product line (PLA vs PLA Matte vs PLA Silk vs PLA HF) | new id each |
|
||||||
|
| Color | never a new id |
|
||||||
|
| Second diameter of the same product (1.75 + 2.85) | sibling filament, new id |
|
||||||
|
| "High-speed" tuned for a *different printer model* | same id (it is a printer variant) |
|
||||||
|
| "High-speed" selectable *alongside* the normal preset on one printer | new name, so a new id (it is a product line) |
|
||||||
|
|
||||||
|
## Structure rules
|
||||||
|
|
||||||
|
1. **Every preset carries the id of its own product, wherever it gets it from.** The id is a
|
||||||
|
function of the preset's own triple (rule 5), and `inherits` carries settings, never
|
||||||
|
identity. So a preset may declare the key itself or inherit it from any ancestor — a
|
||||||
|
`<Filament> @base` root, a real (instantiated) preset of the same filament, an
|
||||||
|
OrcaFilamentLibrary preset — and CI checks one thing: the id it ends up with equals the
|
||||||
|
mint of *its* triple. The usual shape is one `@base` root (`"instantiation": "false"`)
|
||||||
|
declaring the key and the per-printer variants inheriting it; a filament may have several
|
||||||
|
roots — Qidi's PolyLite PLA has four per-series roots (`PolyLite PLA@Q2-Series`,
|
||||||
|
`@Q2C-Series`, `@X-Max 4-Series`, `@X-Plus 5-Series`) — which then all declare the identical
|
||||||
|
id. A branded filament that borrows a generic's settings (`Flashforge ABS Basic @FF C5`
|
||||||
|
inherits `Generic ABS @System`) declares its own id, because its triple is its own.
|
||||||
|
2. **The filament name is the base name**: the preset name with everything from the first
|
||||||
|
(optionally space-preceded) `@` stripped. `MyBrand PLA @Orca 3D Fuse1` and `MyBrand PLA@HS`
|
||||||
|
are both the filament `MyBrand PLA`.
|
||||||
|
3. **Within one filament, variants' `compatible_printers` are pairwise disjoint** — per printer,
|
||||||
|
at most one compatible instantiated preset per id, or AMS matching turns ambiguous. The
|
||||||
|
C++ validator's `-f` check enforces this, tree-wide in CI. Since one product carries one id
|
||||||
|
and cannot be split onto two, this rule is the *only* remedy for such an ambiguity: narrow
|
||||||
|
the `compatible_printers`, or retire the preset that duplicates another.
|
||||||
|
4. **Generics belong to OrcaFilamentLibrary.** A vendor tuning a generic material inherits
|
||||||
|
`Generic X @System`, keeps the `Generic X` base name (that alias is what hides the library
|
||||||
|
preset on your printers, and it is what makes its triple — and so its id — the library's)
|
||||||
|
and sets a non-empty `compatible_printers` — e.g. `Generic PLA @Sovol SV08 MAX` inherits
|
||||||
|
`Generic PLA @System` and lists three Sovol nozzles. Renaming such a preset makes it a
|
||||||
|
different product by rule 5, so it then needs its own id.
|
||||||
|
5. **Ids follow the product identity.** The id is a pure function of the product triple
|
||||||
|
`(filament_vendor, filament_type, filament name)`, so correcting any of them re-mints the id
|
||||||
|
**by design**, applied by `--generate` (preview with `--dry-run`, confine with `--vendor`) and
|
||||||
|
gated by the `--update-snapshot` diff; the exact sequence is in the FAQ. Nothing forwards
|
||||||
|
the old value, so anything outside the tree that stored it — a device tray, a calibration
|
||||||
|
record, a saved project — falls back to matching by filament type until the user re-selects
|
||||||
|
the filament. Re-mint deliberately, and only to fix a genuinely wrong identity.
|
||||||
|
(`renamed_from` still gates preset-*name* compatibility, as before.)
|
||||||
|
|
||||||
|
## Minting — nobody invents ids
|
||||||
|
|
||||||
|
New ids are deterministic, computed exactly like the `setting_id` precedent
|
||||||
|
(the `setting_id` half of `scripts/orca_id_tool.py`):
|
||||||
|
|
||||||
|
```text
|
||||||
|
FILAMENT_ID_NAMESPACE = uuid5(setting-id NAMESPACE, "filament_id")
|
||||||
|
= c4d3ff49-4c32-5534-a3e3-00894157ab97
|
||||||
|
filament_id = "OF" + base62_6( uuid5(FILAMENT_ID_NAMESPACE,
|
||||||
|
"filament_product/<filament_vendor>/<filament_type>/<filament_name>") )
|
||||||
|
```
|
||||||
|
|
||||||
|
`base62_6` is the low 6 base62 digits (alphabet `0-9A-Za-z`) of the UUID taken as a big-endian
|
||||||
|
integer, most-significant digit first; with the `OF` prefix the full id is 8 chars, within the
|
||||||
|
AMS length limit. The triple comes from the root preset's *flattened* config:
|
||||||
|
`<filament_vendor>` is the filament
|
||||||
|
**manufacturer** (`"Polymaker"`, or `"Generic"` for generics — never the printer brand),
|
||||||
|
`<filament_type>` the material type, `<filament_name>` the root's base name; the two config
|
||||||
|
values are inheritable list options and the first element counts.
|
||||||
|
|
||||||
|
Content-addressing on that triple is what makes the whole system converge. The key contains no
|
||||||
|
bundle name, so the same product mints the same id in every bundle — moving a filament into
|
||||||
|
OrcaFilamentLibrary never changes its id, and two vendors independently shipping the same
|
||||||
|
product arrive at the same id without coordinating. `Polymaker/PLA/PolyLite PLA` mints
|
||||||
|
`OF5CgdDq`, and that one id is declared by the OrcaFilamentLibrary, OrcaArena, Qidi, and
|
||||||
|
Snapmaker bundles alike; the OFL generic `Generic/PLA/Generic PLA` mints `OFDSrzZ8`, claimed
|
||||||
|
by 35 bundles — most by independent declarations converging on the same mint, the rest
|
||||||
|
purely through inheritance from the OFL preset.
|
||||||
|
|
||||||
|
Nothing but the triple feeds the mint — not the rest of the tree, not the snapshot, not what
|
||||||
|
another preset of the product happens to carry. Determined triple, determined id: one product
|
||||||
|
carries one id and there is no second acceptable value for it, so any other value on a preset
|
||||||
|
is a mismatch `--check` reports and `--generate` pulls back. Two *different* products whose
|
||||||
|
triples mint the same base62 value would be a collision (a roughly 36-bit id space against a
|
||||||
|
few thousand products); nothing salts past it: `--check` reports it naming both products,
|
||||||
|
`--generate` refuses to write it, and the remedy is a rename so their triples differ. Where
|
||||||
|
two presets of one product would be AMS-ambiguous on a printer, the fix is likewise in the
|
||||||
|
profiles — make their `compatible_printers` disjoint (structure rule 3), retire the redundant
|
||||||
|
preset, or, if they really are different products, give them different names so their triples
|
||||||
|
differ. Never a second id for one triple.
|
||||||
|
|
||||||
|
Workflow for a new filament:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Author the filament with NO filament_id key anywhere.
|
||||||
|
python scripts/orca_id_tool.py --dry-run # 2. preview the ids — writes nothing
|
||||||
|
python scripts/orca_id_tool.py --generate # 3. apply them to the profile file(s)
|
||||||
|
python scripts/orca_id_tool.py --update-snapshot # 4. record the new claims in the snapshot
|
||||||
|
python scripts/orca_id_tool.py --check # 5. validate the filament_id state
|
||||||
|
python scripts/orca_extra_profile_check.py # 6. ...and everything else CI checks
|
||||||
|
# 7. Commit the profile edits together with scripts/filament_id_snapshot.json, for review.
|
||||||
|
```
|
||||||
|
|
||||||
|
`--generate` makes every filament's id equal the mint of its own
|
||||||
|
`(filament_vendor, filament_type, filament name)` triple: it inserts one where an instantiated
|
||||||
|
filament resolves none, and re-derives one that does not match. A preset that *inherits* a
|
||||||
|
mismatching id is the one case left to the author — check 3b names it, and the fix is to inherit
|
||||||
|
a preset of the same filament or to give the preset its own key. A declaration is left alone
|
||||||
|
exactly when it already equals the one id its triple mints, and a collision (check 3d) is
|
||||||
|
reported and left unwritten. The same run assigns
|
||||||
|
`generate_preset_setting_id(vendor, type, name)` to every instantiated filament, process
|
||||||
|
and machine preset of every vendor except BBL, which keeps its authoritative `G*` ids, strips
|
||||||
|
`setting_id` from base profiles, and fixes the misspelled `settings_id` key — dropped, or, for
|
||||||
|
BBL, whose ids have no formula to fall back on, restored under the correct name. It is idempotent and
|
||||||
|
byte-preserving (indentation, BOM, and line endings intact, every edited file re-parsed to fail
|
||||||
|
loudly), and a no-op on a tree that already passes `scripts/orca_extra_profile_check.py` — the
|
||||||
|
check CI runs over both id kinds, of which `--check` is the `filament_id` half.
|
||||||
|
|
||||||
|
- `--filament-id` limits the run to `filament_id`.
|
||||||
|
- `--setting-id` limits the run to `setting_id`. The two exclude each other; pass neither to
|
||||||
|
write both.
|
||||||
|
- `--vendor VENDOR` confines the run to that bundle; repeatable. The id is a function of the
|
||||||
|
triple alone, so a narrowed run writes exactly what a full one would; `--check` reports
|
||||||
|
whatever it left outside.
|
||||||
|
- `--dry-run` reports what `--generate` would do and writes nothing; with no mode of its own it
|
||||||
|
implies `--generate`, so `--dry-run --vendor <Vendor>` previews just that bundle.
|
||||||
|
- `--profiles DIR` points the tooling at a different profile tree (default
|
||||||
|
`resources/profiles`). `--check` and `--update-snapshot` read and write the sanctioned state of
|
||||||
|
the tree they are given, so pointing them elsewhere needs `--snapshot PATH` for that tree too —
|
||||||
|
`scripts/filament_id_snapshot.json` describes `resources/profiles` and no other tree.
|
||||||
|
|
||||||
|
**Identity fixes need no separate mode.** `--generate` re-derives an id that no longer matches its
|
||||||
|
triple exactly the way it fills in a missing one, so a rename or a `filament_vendor` /
|
||||||
|
`filament_type` correction is just: fix the config, run `--generate` (confine it with `--vendor`,
|
||||||
|
preview it with `--dry-run`), then `--update-snapshot` and review the diff.
|
||||||
|
|
||||||
|
If you skip the tooling, CI fails and prints the remedy: the expected id for your filament and
|
||||||
|
the instruction to run `python scripts/orca_id_tool.py --generate`; once the id is minted, the
|
||||||
|
snapshot checks likewise point at `--update-snapshot` and tell you to commit the resulting
|
||||||
|
diff.
|
||||||
|
|
||||||
|
## Reserved namespaces — never mint or hand-write into
|
||||||
|
|
||||||
|
A **reserved namespace** is an id space no system profile may declare, because an external
|
||||||
|
catalog or a device protocol owns the values. None of them has an owning vendor: there is no
|
||||||
|
bundle — not even the one whose printers use the catalog — that may write one into a profile.
|
||||||
|
|
||||||
|
| Space | Status | Rule |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `GF*` | Bambu AMS/RFID catalog | declarable by **nobody**, BBL included: Bambu's own ids live in the generated catalog map, never in a profile |
|
||||||
|
| `QD_*` | Qidi device protocol | declarable by **nobody**, Qidi included: the box composes these ids at runtime and they are not preset ids |
|
||||||
|
| `P` + 7 hex chars (case-insensitive), `"null"` | user-created custom filaments (`CreatePresetsDialog.cpp`) | never appears in system profiles |
|
||||||
|
|
||||||
|
The two device namespaces, in detail:
|
||||||
|
|
||||||
|
- **Bambu (`GF*`).** Bambu's device/RFID/cloud catalog is external and opaque, which is a
|
||||||
|
reason to keep it out of the profiles rather than to let one bundle own it. Every BBL filament
|
||||||
|
mints an `OF` id from its triple like every other vendor's, and the correspondence to Bambu's
|
||||||
|
catalog ids lives in one generated file the app applies at the printer boundary — the next
|
||||||
|
section. Nothing under `resources/profiles/**` carries a `GF*` id today and nothing can be
|
||||||
|
exempted, so a `GF*` id appearing anywhere in the tree is a mistake, whoever wrote it.
|
||||||
|
- **Qidi (`QD_*`).** `QD_*` is a device-*protocol* namespace, not a preset id space: the
|
||||||
|
Qidi box path composes `QD_<series>_<vendor>_<typeidx>` ids at runtime (slot vendor and
|
||||||
|
type indices reported by the device, the series digit inferred client-side from the printer
|
||||||
|
model/name). Qidi presets carry ordinary minted `OF*` ids (generics share the OFL ids), so
|
||||||
|
a composed id matches no preset and the slot falls back to filament type; translating it to
|
||||||
|
the filament's id belongs in `QidiPrinterAgent`. The alternative — treating per-series
|
||||||
|
protocol ids as preset ids — would put one product under five ids (`QIDI PLA Rapido` would
|
||||||
|
be `QD_0_1_1` through `QD_4_1_1`), exactly the fragmentation the mint rule removes.
|
||||||
|
|
||||||
|
## The Bambu catalog map
|
||||||
|
|
||||||
|
Bambu's printers, its AMS and its cloud know only Bambu's own catalog ids. Our profiles carry
|
||||||
|
minted `OF` ids like every other vendor's, so one generated file records the correspondence and
|
||||||
|
the app applies it **only where an id crosses to or from a Bambu printer**.
|
||||||
|
|
||||||
|
**The file** is `resources/printers/bambu_filament_ids.json` — a header plus one row per
|
||||||
|
catalogued product, keyed by our id:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"source": "https://github.com/bambulab/BambuStudio",
|
||||||
|
"bambustudio_commit": "66e405477",
|
||||||
|
"generated": "2026-09-04",
|
||||||
|
"filaments": {
|
||||||
|
"OFhuaUQB": { "bambu_id": "GFB00", "vendor": "Bambu Lab", "type": "ABS", "name": "Bambu ABS" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
It ships in `resources/printers/`, next to `filaments_blacklist.json` — deliberately not in
|
||||||
|
`resources/profiles/`, where the loader reads every top-level `.json` as a vendor index. It
|
||||||
|
holds 100 rows today, one per product BambuStudio ships, and the correspondence is
|
||||||
|
one-to-one in both directions.
|
||||||
|
|
||||||
|
**It is generated, never hand-edited.** `python scripts/update_bambu_filament_ids.py` rebuilds
|
||||||
|
it from **BambuStudio's own shipped BBL bundle** — a sparse shallow clone of upstream `master`,
|
||||||
|
or `--bambustudio-dir <a BambuStudio resources/profiles checkout>`. Our BBL bundle is a fork of
|
||||||
|
Bambu's, tuned and extended independently, so it is not the source of truth for Bambu's ids.
|
||||||
|
A row's key is the id the product's `(filament_vendor, filament_type, filament name)` triple
|
||||||
|
mints — the same id any bundle of ours carries for it, since the id is a function of the triple
|
||||||
|
alone; the row of a product we do not ship sits inert until some bundle claims that triple —
|
||||||
|
`OFdyfQvU` / `GFG03`, "Bambu PETG Matte", is such a row today.
|
||||||
|
|
||||||
|
**Regenerate it in the same commit as every BBL profile sync**, and read the drift report it
|
||||||
|
prints. Two lines, both informational, neither blocking the write:
|
||||||
|
|
||||||
|
```text
|
||||||
|
upstream ships 'Bambu PETG Matte' (Bambu Lab/PETG), we ship nothing with that identity
|
||||||
|
Orca BBL filaments with no row: 135 Orca-only product(s)
|
||||||
|
```
|
||||||
|
|
||||||
|
The first names each upstream product our BBL bundle has no same-identity filament for —
|
||||||
|
sometimes a genuinely missing product, sometimes a name drift a follow-up rename would
|
||||||
|
converge. The second counts our own BBL filaments that matched no row: 135 of 234 today, of
|
||||||
|
which 109 send an `OF` id on the wire and 26 already rode `OF` ids inherited from the
|
||||||
|
OrcaFilamentLibrary. **135 is the number to expect at every regeneration** — 109 was the
|
||||||
|
one-off size of the transition and stopped being computable from the tree once the BBL bundle
|
||||||
|
was re-minted, so do not "fix" the report to print it.
|
||||||
|
|
||||||
|
**Check 6** lives in `check_filament_ids`, so profile CI runs it alongside the other five. It
|
||||||
|
holds the file to its contract: it parses, carries `source` / `bambustudio_commit` /
|
||||||
|
`generated`, keys only `OF`-format ids, maps each Bambu id at most once, and — for every row
|
||||||
|
whose key the tree actually claims — agrees with the tree on that id's `(vendor, type, name)`
|
||||||
|
triple. A row for a product we do not ship is skipped, not an error. The remedy it prints is
|
||||||
|
always the same: regenerate the map and commit the diff for review.
|
||||||
|
|
||||||
|
### The runtime rule: swap on hit
|
||||||
|
|
||||||
|
Outbound, our id with a row becomes Bambu's; inbound, Bambu's id with a row becomes ours.
|
||||||
|
Everything else is forwarded untouched — an `OF` id with no row, a Bambu id for a product we do
|
||||||
|
not ship, a `P`-hex user id, `"null"`, an empty string. Translation is confined to the
|
||||||
|
boundary: nothing between the boundaries ever holds a Bambu id.
|
||||||
|
|
||||||
|
Translating one value is a capability of the printer agent: `IPrinterAgent` declares
|
||||||
|
`to_orca_filament_id` and `from_orca_filament_id` returning their argument, and `BBLPrinterAgent`
|
||||||
|
overrides them with Bambu's map, so an agent whose printers already speak our ids inherits the
|
||||||
|
identity default and translates nothing. `NetworkAgent` forwards both to the live agent, so the
|
||||||
|
comparison sites below reach them through `wxGetApp().getAgent()` and leave an id untranslated
|
||||||
|
while no agent is live. Whole documents are Bambu's business alone:
|
||||||
|
`BBLPrinterAgent::to_orca_payload` and `from_orca_payload` rewrite every string under
|
||||||
|
`tray_info_idx`, `filament_id` or `filamentId` at any depth; text that does not parse, or carries
|
||||||
|
none of those keys, comes back unchanged. The map is loaded once, lazily; a missing or malformed
|
||||||
|
file degrades to identity with a log line rather than failing.
|
||||||
|
|
||||||
|
| Boundary | Where it translates |
|
||||||
|
| --- | --- |
|
||||||
|
| Everything the agent sends | `BBLPrinterAgent::send_message` and `send_message_to_printer`, plus `PrintParams::ams_mapping_info` in `dispatch_start` — the funnel all five `start_*` calls share |
|
||||||
|
| Everything the agent receives | `set_on_message_fn` and `set_on_local_message_fn` wrap their callback, so `MachineObject::parse_json` and everything downstream see our ids only |
|
||||||
|
| 3mf export | `Plater::export_3mf` writes Bambu's ids into `slice_info.config`, gated on `preset_bundle.is_bbl_vendor()` — the printer reads that file and knows only its own catalog, and no other vendor's export is affected. The CLI has its own writer in `OrcaSlicer.cpp`; it does the same, gated on the `printer_model` prefix that already decides `Print::is_BBL_printer()` for that run |
|
||||||
|
| Project ingest | `Plater::priv::load_files` reverse-maps the project's `filament_ids` before the bundle ingests them, so a project saved by an older Orca or by BambuStudio still resolves the same presets |
|
||||||
|
| Prints from the printer's SD card | `SelectMachineDialog::update_print_required_data` reverse-maps each plate's slice-info ids as it adopts the plates, so the AMS mapping dialog pairs them with trays |
|
||||||
|
| Bambu-specific comparisons | `CalibUtils.cpp`, `DeviceManager.cpp`, `DeviceCore/DevFilaSystem.cpp`, `DeviceCore/DevFilaBlackList.cpp`, `SelectMachine.cpp`, `AMSDryControl.cpp`, `AMSMaterialsSetting.cpp`, `PresetComboBoxes.cpp`, `ColorDecomposeSupport.cpp` |
|
||||||
|
|
||||||
|
That last row is the rule to follow when a new Bambu-specific behaviour is added: **translate
|
||||||
|
the value you are about to compare, never the table you compare it against.** The shipped data
|
||||||
|
those sites read is Bambu's and stays verbatim — `white_fila_ids` in
|
||||||
|
`resources/printers/filaments_blacklist.json`, the calibration id lists in
|
||||||
|
`resources/printers/<model>.json`, `fila_id` in
|
||||||
|
`resources/profiles/BBL/filament/filaments_color_codes.json`.
|
||||||
|
|
||||||
|
`tests/slic3rutils/test_bambu_filament_ids.cpp` covers the lookups, the payload rewrite and the
|
||||||
|
Bambu-specific rules. `orcaslicer_discover_tests` registers a Catch2 tag as a CTest **label**,
|
||||||
|
not as part of the test name, so `-R` matches nothing here and the filter is `-L`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ctest --test-dir <build dir>/tests/slic3rutils -L BambuFilamentIds
|
||||||
|
```
|
||||||
|
|
||||||
|
### Three places the map deliberately does not reach
|
||||||
|
|
||||||
|
The map and its lookups live in the GUI library, which libslic3r cannot link against and which a
|
||||||
|
GUI-less build does not link at all. Three consequences are known and documented; none is worth
|
||||||
|
pulling the map down into libslic3r for.
|
||||||
|
|
||||||
|
- **The support display type in `PrintConfig.cpp`.** `DynamicPrintConfig::get_filament_type`
|
||||||
|
picks `PLA-S` / `Sup.PLA` and `PA-S` / `Sup.PA` for a support filament by testing
|
||||||
|
`filament_id` against `GFS00` and `GFS01`, and otherwise falls back on `filament_type` — a
|
||||||
|
fallback that returns those same two pairs for `"PLA"` and `"PA"`. Bambu Support W inherits
|
||||||
|
`fdm_filament_pla` and Bambu Support G inherits `fdm_filament_pa`, so with their `OF` ids the
|
||||||
|
fallback produces exactly what the id branches produced. (The only config that ever carries a
|
||||||
|
singular `filament_id` key is the AMS tray config built in `Plater.cpp`, and that one never
|
||||||
|
reaches this function.) These two lines are the only mention of a Bambu id anywhere in
|
||||||
|
libslic3r, and they need no change.
|
||||||
|
- **Config imports.** `PresetBundle::import_presets` (File ▸ Import ▸ Import Configs, for
|
||||||
|
`.json` / `.zip` / `.orca_filament` / `.orca_printer` / `.orca_bundle`) and
|
||||||
|
`PresetBundle::load_config_file` (the CLI's `--load-settings` of a G-code file with an
|
||||||
|
embedded config) both parse inside libslic3r, out of the GUI's reach, so a Bambu id carried
|
||||||
|
in such a file lands on the imported preset untranslated. The effect is bounded: that preset
|
||||||
|
does not auto-match an AMS tray while the stale id is live, and the id does not survive
|
||||||
|
being saved — `Preset::save` writes a `filament_id` key only for a preset whose `inherits` is
|
||||||
|
empty, and on the next load an inheriting preset takes its parent's id. A known gap, and not
|
||||||
|
a regression: nothing forwarded a stale id before either.
|
||||||
|
- **A build configured without the GUI.** `target_link_libraries(OrcaSlicer libslic3r_gui)` sits
|
||||||
|
inside `if (SLIC3R_GUI)` in `src/CMakeLists.txt`, so the lookups are not linkable when the GUI
|
||||||
|
is off. The CLI's 3mf writer in `src/OrcaSlicer.cpp` therefore guards its translation with
|
||||||
|
`#ifdef SLIC3R_GUI`, and a 3mf that such a build slices for a Bambu printer carries our `OF`
|
||||||
|
ids in `slice_info.config` rather than Bambu's. Every shipped build enables the GUI, so this
|
||||||
|
reaches only a purpose-built GUI-less binary.
|
||||||
|
|
||||||
|
One more thing worth recording before it is rediscovered:
|
||||||
|
`SyncAmsInfoDialog::update_print_required_data` is a structural twin of the SD-card function
|
||||||
|
above and carries no translation. It has no callers today and its plate list is only ever read
|
||||||
|
for `printer_model_id`, so it is not a live gap — but wiring it up without adding the reverse
|
||||||
|
map would silently reproduce the bug.
|
||||||
|
|
||||||
|
## How CI enforces this
|
||||||
|
|
||||||
|
Profile CI (`check_profiles.yml`) runs `check_filament_ids()` tree-wide via
|
||||||
|
`scripts/orca_extra_profile_check.py`. Its ground truth is
|
||||||
|
**`scripts/filament_id_snapshot.json` — the sanctioned state**: the id state derived from the
|
||||||
|
tree must equal the snapshot exactly, in both directions. Any change to the id landscape
|
||||||
|
therefore surfaces as a diff to that file, and **that snapshot diff is what maintainers review
|
||||||
|
and gate in a PR**. Never edit the snapshot by hand — `--update-snapshot` regenerates it
|
||||||
|
deterministically (running it twice changes nothing). The snapshot holds one map, `ids`: each
|
||||||
|
entry is the product the id is minted from (`filament_vendor`, `filament_type`, `name`) and the
|
||||||
|
`filaments` claiming it (`Vendor/Filament`), and it sanctions *state*, never exceptions: no check
|
||||||
|
consults it to excuse a preset from a rule, and there is no grandfather list of any kind.
|
||||||
|
|
||||||
|
The checks, in brief:
|
||||||
|
|
||||||
|
- **Format** — every id occurring in the tree is `OF` + 6 base62 chars. No exceptions: not a
|
||||||
|
snapshot entry, not BBL.
|
||||||
|
- **Snapshot equality** — tree claims == snapshot claims **and** each id's declared triple ==
|
||||||
|
its snapshot entry, both directions: any `filament_vendor`/`filament_type`/name change
|
||||||
|
surfaces as a snapshot diff.
|
||||||
|
- **Identity** — the id is a function of the triple alone. A declared `OF*` id must equal the
|
||||||
|
one id its declarer's own triple mints, with no second acceptable value; the id an
|
||||||
|
instantiated preset *inherits* must equal the mint of *its* own triple, however it inherits
|
||||||
|
it (a root, a real filament, a library preset — structure rule 1); and every instantiated
|
||||||
|
system filament must resolve an effective id at all (recall: an id-less one is a hard load
|
||||||
|
error in C++ that discards the whole vendor bundle); and no two products mint one id (a
|
||||||
|
base62 collision, resolved by renaming one of them). The errors print the expected id.
|
||||||
|
- **Reserved namespaces** — `GF*`, `QD_*`, `P<7-hex>` or `"null"` claimed by any vendor,
|
||||||
|
BBL and Qidi included.
|
||||||
|
- **Triple integrity** — every declarer must resolve a non-empty `filament_vendor` and
|
||||||
|
`filament_type` (generics use `"Generic"`), and all declarers of one filament within a
|
||||||
|
bundle must agree on the triple.
|
||||||
|
- **Bambu catalog map** — `resources/printers/bambu_filament_ids.json` parses, carries its
|
||||||
|
`source` / `bambustudio_commit` / `generated` header, keys only `OF`-format ids, maps each
|
||||||
|
Bambu id at most once, and agrees with the tree on the triple of every row whose key the
|
||||||
|
tree claims. See [The Bambu catalog map](#the-bambu-catalog-map); the remedy is always to
|
||||||
|
regenerate, never to hand-edit.
|
||||||
|
|
||||||
|
A profile that declares a **reserved-namespace** id — `GF*`, `QD_*` or `P<7-hex>`, whatever
|
||||||
|
its vendor — cannot pass the format check, so `--update-snapshot` refuses to sanction it
|
||||||
|
rather than hide the mistake until CI. For a Bambu-cataloged product, the catalog map is where
|
||||||
|
the correspondence belongs. Any other new sharing via a *declared* id is caught by the identity
|
||||||
|
check; sharing through inheritance carries no declaration to check and surfaces only as a new
|
||||||
|
claim in the snapshot diff — which is exactly why that diff is the gate.
|
||||||
|
|
||||||
|
`orca_extra_profile_check.py` separately holds every declared id to the AMS 8-character limit,
|
||||||
|
tree-wide and for every vendor alike, scoped to the presets a vendor's index actually
|
||||||
|
references (a file the index never loads cannot break AMS matching).
|
||||||
|
|
||||||
|
Complementing the Python checks, CI also runs the C++ profile validator with `-f`
|
||||||
|
(`check_filament_subtypes`): it loads the bundle exactly as the app does and flags any printer
|
||||||
|
for which two or more compatible filament presets share one `filament_id` — the runtime-shaped
|
||||||
|
ambiguity check behind structure rule 3.
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
- **A new color of an existing product?** Never a new id — colors are not filaments.
|
||||||
|
- **A second diameter (1.75 mm and 2.85 mm) of the same product?** A sibling filament with its
|
||||||
|
own id: two diameters are separately selectable spool products.
|
||||||
|
- **A high-speed tune of an existing material for another printer model?** Same filament:
|
||||||
|
keep the base name and inherit its root; no id key needed.
|
||||||
|
- **A tuned generic ("our profile for Generic PLA")?** Inherit `Generic PLA @System`, keep the
|
||||||
|
`Generic PLA` base name, set `compatible_printers`; no id key needed.
|
||||||
|
- **A branded filament that borrows a generic's settings?** Fine — inherit `Generic X @System`
|
||||||
|
(or any real filament) for the settings and declare the id of your own filament; run
|
||||||
|
`python scripts/orca_id_tool.py --generate` to mint it. Inheritance never changes the id.
|
||||||
|
- **I need to fix a filament's `filament_vendor` or `filament_type`.** Fix the config, run
|
||||||
|
`--generate --vendor <Vendor>` (preview with `--dry-run`), then `--update-snapshot`, and commit
|
||||||
|
the profile and snapshot diffs together. The id re-derives from the corrected identity, and
|
||||||
|
nothing forwards the old value, so a tray or record still holding it falls back to matching by
|
||||||
|
filament type.
|
||||||
|
- **I need to rename a filament.** Rename the presets (adding `renamed_from`, which keeps the
|
||||||
|
preset *name* resolving), then `--generate --vendor <Vendor>` (preview with `--dry-run`), then
|
||||||
|
`--update-snapshot`. The id follows the new filament name; as with any identity fix, the old id
|
||||||
|
is not forwarded.
|
||||||
|
- **Can I reuse a `QD_*` id for a Qidi profile?** No — nobody can. It is the device protocol's
|
||||||
|
own id space: the box composes those values at runtime and no preset carries one. Author
|
||||||
|
Qidi filaments like any other vendor's.
|
||||||
|
- **CI says my filament needs an id.** Run `python scripts/orca_id_tool.py --generate`, then
|
||||||
|
`--update-snapshot`, and commit both diffs. Do not type an id by hand.
|
||||||
|
|
||||||
|
For general profile authoring, see the profile development guide on the
|
||||||
|
[OrcaSlicer wiki](https://www.orcaslicer.com/wiki).
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
# Move `wxInspectable` into `DPIAware` — Implementation Plan
|
|
||||||
|
|
||||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
||||||
|
|
||||||
**Goal:** Move `wxInspector::wxInspectable` from individual leaf classes into the common `DPIAware<P>` template so every DPIAware widget is automatically inspectable and gets the inspector keyboard shortcut.
|
|
||||||
|
|
||||||
**Architecture:** `DPIAware<P>` gains `wxInspector::wxInspectable` as a second base class and calls `SetupInspectorAccelerator(this)` in its constructor. `DPIDialog` and `MainFrame` drop their now-redundant `wxInspectable` inheritance and `SetupInspectorAccelerator` calls.
|
|
||||||
|
|
||||||
**Tech Stack:** C++17, wxWidgets, wxInspector
|
|
||||||
|
|
||||||
## Global Constraints
|
|
||||||
|
|
||||||
- Build with `D:\VisualStudio\2026\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe`
|
|
||||||
- Use `--config RelWithDebInfo` for all builds
|
|
||||||
- Cross-platform: must compile on Windows, macOS, and Linux
|
|
||||||
- Match existing code style: PascalCase classes, `#pragma once`
|
|
||||||
- Do NOT commit files under `.superpowers/`
|
|
||||||
- Do NOT commit `task.md`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 1: Move `wxInspectable` and `SetupInspectorAccelerator` into `DPIAware<P>`
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `src/slic3r/GUI/GUI_Utils.hpp:92` (DPIAware template — add wxInspectable base + SetupInspectorAccelerator call)
|
|
||||||
- Modify: `src/slic3r/GUI/GUI_Utils.hpp:276` (DPIDialog — drop wxInspectable + SetupInspectorAccelerator)
|
|
||||||
- Modify: `src/slic3r/GUI/MainFrame.hpp:96` (MainFrame — drop wxInspectable)
|
|
||||||
- Modify: `src/slic3r/GUI/MainFrame.cpp:304` (MainFrame constructor — drop SetupInspectorAccelerator)
|
|
||||||
|
|
||||||
**Interfaces:**
|
|
||||||
- Consumes: Nothing (standalone refactor)
|
|
||||||
- Produces: All DPIAware widgets automatically inherit `wxInspector::wxInspectable` and get Ctrl+Shift+I accelerator
|
|
||||||
|
|
||||||
- [ ] **Step 1: Add `wxInspectable` to `DPIAware<P>` and call `SetupInspectorAccelerator`**
|
|
||||||
|
|
||||||
In `src/slic3r/GUI/GUI_Utils.hpp`, line 92, change the base class:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// Before:
|
|
||||||
template<class P> class DPIAware : public P
|
|
||||||
// After:
|
|
||||||
template<class P> class DPIAware : public P, public wxInspector::wxInspectable
|
|
||||||
```
|
|
||||||
|
|
||||||
In the constructor body of `DPIAware<P>`, after `this->CenterOnParent();` (currently line 110), add:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
SetupInspectorAccelerator(this);
|
|
||||||
```
|
|
||||||
|
|
||||||
(`<wx/inspector/inspector.h>` is already included at line 23.)
|
|
||||||
|
|
||||||
- [ ] **Step 2: Remove redundant `wxInspectable` and `SetupInspectorAccelerator` from `DPIDialog`**
|
|
||||||
|
|
||||||
In `src/slic3r/GUI/GUI_Utils.hpp`, line 276, change:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// Before:
|
|
||||||
class DPIDialog : public DPIAware<wxDialog>, public wxInspector::wxInspectable
|
|
||||||
// After:
|
|
||||||
class DPIDialog : public DPIAware<wxDialog>
|
|
||||||
```
|
|
||||||
|
|
||||||
In the `DPIDialog` constructor body, remove the `SetupInspectorAccelerator(this);` line (currently line 286). The rest of the constructor stays.
|
|
||||||
|
|
||||||
- [ ] **Step 3: Remove redundant `wxInspectable` from `MainFrame`**
|
|
||||||
|
|
||||||
In `src/slic3r/GUI/MainFrame.hpp`, line 96, change:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// Before:
|
|
||||||
class MainFrame : public DPIFrame, public wxInspector::wxInspectable
|
|
||||||
// After:
|
|
||||||
class MainFrame : public DPIFrame
|
|
||||||
```
|
|
||||||
|
|
||||||
`MainFrame` now gets `wxInspectable` through `DPIFrame` → `DPIAware<wxFrame>`.
|
|
||||||
|
|
||||||
- [ ] **Step 4: Remove redundant `SetupInspectorAccelerator` from `MainFrame` constructor**
|
|
||||||
|
|
||||||
In `src/slic3r/GUI/MainFrame.cpp`, line 304, remove the line:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
SetupInspectorAccelerator(this);
|
|
||||||
```
|
|
||||||
|
|
||||||
It is now called automatically by the `DPIAware<wxFrame>` constructor.
|
|
||||||
|
|
||||||
- [ ] **Step 5: Build to verify compilation**
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
$cmakePath = "D:\VisualStudio\2026\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe"
|
|
||||||
& $cmakePath --build . --config RelWithDebInfo --target ALL_BUILD -- -m
|
|
||||||
```
|
|
||||||
|
|
||||||
Expected: Build succeeds with zero new errors or warnings.
|
|
||||||
|
|
||||||
- [ ] **Step 6: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add src/slic3r/GUI/GUI_Utils.hpp src/slic3r/GUI/MainFrame.hpp src/slic3r/GUI/MainFrame.cpp
|
|
||||||
git commit -m "refactor: move wxInspectable and SetupInspectorAccelerator into DPIAware
|
|
||||||
|
|
||||||
DPIAware<P> now inherits wxInspector::wxInspectable and calls
|
|
||||||
SetupInspectorAccelerator in its constructor, making all DPIAware
|
|
||||||
widgets automatically appear in the inspector tree with the
|
|
||||||
Ctrl+Shift+I shortcut. Remove redundant wxInspectable inheritance
|
|
||||||
and SetupInspectorAccelerator calls from DPIDialog and MainFrame.
|
|
||||||
|
|
||||||
Co-Authored-By: Claude <noreply@anthropic.com>"
|
|
||||||
```
|
|
||||||
@@ -1,753 +0,0 @@
|
|||||||
# wxInspector Plugins for OrcaSlicer — Implementation Plan
|
|
||||||
|
|
||||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
||||||
|
|
||||||
**Goal:** Build two wxInspector plugins (DPIAware + CustomWidgets) that expose OrcaSlicer custom control properties in the inspector's property grid.
|
|
||||||
|
|
||||||
**Architecture:** Two plugins in a shared folder under `src/slic3r/Utils/wxInspectorPlugins/`. DPIAwarePlugin uses `dynamic_cast<DPIFrame*>/<DPIDialog*>` for detection; CustomWidgetsPlugin uses per-type `dynamic_cast`. Both registered as static singletons via a single inline function in `Registration.hpp`, called from `MainFrame` constructor.
|
|
||||||
|
|
||||||
**Tech Stack:** C++17, wxWidgets, wxInspector plugin API (`wx/inspector/plugin.h`, `wx/inspector/inspector.h`), OrcaSlicer custom widget headers
|
|
||||||
|
|
||||||
## Global Constraints
|
|
||||||
|
|
||||||
- Plugins placed under `src/slic3r/Utils/wxInspectorPlugins/`
|
|
||||||
- Build with `D:\VisualStudio\2026\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe`
|
|
||||||
- Minimal source changes: only trivial (one-line) getters/setters added to existing classes
|
|
||||||
- Cross-platform: must compile on Windows, macOS, and Linux
|
|
||||||
- Match existing code style: PascalCase classes, snake_case functions, `#pragma once`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 1: Add getters/setters to existing Orca widget headers
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `src/slic3r/GUI/GUI_Utils.hpp` (DPIAware template — add 4 methods)
|
|
||||||
- Modify: `src/slic3r/GUI/Widgets/Button.hpp` (add 3 getters)
|
|
||||||
- Modify: `src/slic3r/GUI/Widgets/CheckBox.hpp` (add 1 getter)
|
|
||||||
- Modify: `src/slic3r/GUI/Widgets/TextInput.hpp` (add 1 getter)
|
|
||||||
- Modify: `src/slic3r/GUI/Widgets/LabeledStaticBox.hpp` (add 4 getter declarations)
|
|
||||||
- Modify: `src/slic3r/GUI/Widgets/LabeledStaticBox.cpp` (add 4 getter implementations)
|
|
||||||
|
|
||||||
**Interfaces:**
|
|
||||||
- Consumes: Nothing (prerequisite for all other tasks)
|
|
||||||
- Produces:
|
|
||||||
- `DPIAware<P>::set_scale_factor(float)`, `DPIAware<P>::set_prev_scale_factor(float)`, `DPIAware<P>::set_em_unit(int)`, `DPIAware<P>::force_rescale() const`
|
|
||||||
- `Button::GetStyle()`, `Button::GetType()`, `Button::IsSelected()`
|
|
||||||
- `CheckBox::IsHalfChecked()`
|
|
||||||
- `TextInput::GetCornerRadius()`
|
|
||||||
- `LabeledStaticBox::GetCornerRadius()`, `LabeledStaticBox::GetBorderWidth()`, `LabeledStaticBox::GetBorderColor()`, `LabeledStaticBox::GetScale()`
|
|
||||||
|
|
||||||
- [ ] **Step 1: Add DPIAware setters/getter in GUI_Utils.hpp**
|
|
||||||
|
|
||||||
After line 184 (`float prev_scale_factor() const { return m_prev_scale_factor; }`), add:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void set_scale_factor(float v) { m_scale_factor = v; }
|
|
||||||
void set_prev_scale_factor(float v) { m_prev_scale_factor = v; }
|
|
||||||
void set_em_unit(int v) { m_em_unit = v; }
|
|
||||||
bool force_rescale() const { return m_force_rescale; }
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 2: Add Button getters in Button.hpp**
|
|
||||||
|
|
||||||
After line 79 (`void SetSelected(bool selected = true) { m_selected = selected; }`), add:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
ButtonStyle GetStyle() const { return m_style; }
|
|
||||||
ButtonType GetType() const { return m_type; }
|
|
||||||
bool IsSelected() const { return m_selected; }
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 3: Add CheckBox getter in CheckBox.hpp**
|
|
||||||
|
|
||||||
After line 16 (`void SetHalfChecked(bool value = true);`), add:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
bool IsHalfChecked() const { return m_half_checked; }
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 4: Add TextInput getter in TextInput.hpp**
|
|
||||||
|
|
||||||
After line 44 (`void SetCornerRadius(double radius);`), add:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
int GetCornerRadius() const { return static_cast<int>(radius); }
|
|
||||||
```
|
|
||||||
|
|
||||||
(Note: `radius` is inherited from `StaticBox` which has it as a protected `double` member.)
|
|
||||||
|
|
||||||
- [ ] **Step 5: Add LabeledStaticBox getter declarations in LabeledStaticBox.hpp**
|
|
||||||
|
|
||||||
After line 46 (`bool Enable(bool enable) override;`), add:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
int GetCornerRadius() const { return m_radius; }
|
|
||||||
int GetBorderWidth() const { return m_border_width; }
|
|
||||||
StateColor GetBorderColor() const { return border_color; }
|
|
||||||
float GetScale() const { return m_scale; }
|
|
||||||
```
|
|
||||||
|
|
||||||
(Note: all of `m_radius`, `m_border_width`, `border_color`, `m_scale` are protected members, accessible to inline methods.)
|
|
||||||
|
|
||||||
- [ ] **Step 6: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add src/slic3r/GUI/GUI_Utils.hpp src/slic3r/GUI/Widgets/Button.hpp src/slic3r/GUI/Widgets/CheckBox.hpp src/slic3r/GUI/Widgets/TextInput.hpp src/slic3r/GUI/Widgets/LabeledStaticBox.hpp
|
|
||||||
git commit -m "feat: add getters/setters for wxInspector plugin access
|
|
||||||
|
|
||||||
Add minimal public accessors to DPIAware (set_scale_factor,
|
|
||||||
set_prev_scale_factor, set_em_unit, force_rescale), Button
|
|
||||||
(GetStyle, GetType, IsSelected), CheckBox (IsHalfChecked),
|
|
||||||
TextInput (GetCornerRadius), and LabeledStaticBox
|
|
||||||
(GetCornerRadius, GetBorderWidth, GetBorderColor, GetScale)."
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 2: Create Registration helper header
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Create: `src/slic3r/Utils/wxInspectorPlugins/Registration.hpp`
|
|
||||||
|
|
||||||
**Interfaces:**
|
|
||||||
- Consumes: Nothing (forward-declares plugin classes)
|
|
||||||
- Produces: `RegisterOrcaInspectorPlugins()`
|
|
||||||
|
|
||||||
- [ ] **Step 1: Create directory**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mkdir -p src/slic3r/Utils/wxInspectorPlugins
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 2: Write Registration.hpp**
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace wxInspector {
|
|
||||||
class wxInspectorPlugin;
|
|
||||||
void RegisterPlugin(wxInspectorPlugin* plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward declare our plugins
|
|
||||||
class DPIAwarePlugin;
|
|
||||||
class CustomWidgetsPlugin;
|
|
||||||
|
|
||||||
inline void RegisterOrcaInspectorPlugins()
|
|
||||||
{
|
|
||||||
static DPIAwarePlugin dpiaware;
|
|
||||||
static CustomWidgetsPlugin customWidgets;
|
|
||||||
wxInspector::RegisterPlugin(&dpiaware);
|
|
||||||
wxInspector::RegisterPlugin(&customWidgets);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 3: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add src/slic3r/Utils/wxInspectorPlugins/Registration.hpp
|
|
||||||
git commit -m "feat: add wxInspector plugin registration helper
|
|
||||||
|
|
||||||
Add RegisterOrcaInspectorPlugins() inline function that creates
|
|
||||||
and registers the DPIAwarePlugin and CustomWidgetsPlugin as
|
|
||||||
static instances (matching wxInspector's built-in pattern)."
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 3: Create DPIAwarePlugin
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Create: `src/slic3r/Utils/wxInspectorPlugins/DPIAwarePlugin.hpp`
|
|
||||||
- Create: `src/slic3r/Utils/wxInspectorPlugins/DPIAwarePlugin.cpp`
|
|
||||||
|
|
||||||
**Interfaces:**
|
|
||||||
- Consumes: Task 1 (DPIAware getters/setters), Task 2 (registration pattern)
|
|
||||||
- Produces: `class DPIAwarePlugin : public wxInspector::wxInspectorPlugin`
|
|
||||||
|
|
||||||
- [ ] **Step 1: Write DPIAwarePlugin.hpp**
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <wx/inspector/plugin.h>
|
|
||||||
|
|
||||||
class DPIAwarePlugin : public wxInspector::wxInspectorPlugin
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
wxString GetName() const override;
|
|
||||||
|
|
||||||
bool CanProvideProperties(wxClassInfo* info) override;
|
|
||||||
|
|
||||||
wxVector<wxInspector::PropertyDef> GetProperties(
|
|
||||||
wxInspector::InspectableObject& obj) override;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 2: Write DPIAwarePlugin.cpp**
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include "DPIAwarePlugin.hpp"
|
|
||||||
|
|
||||||
#include "slic3r/GUI/GUI_Utils.hpp" // DPIFrame, DPIDialog, DPIAware<P>
|
|
||||||
|
|
||||||
#include <wx/window.h>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void addDPIProps(T* dpi, wxVector<wxInspector::PropertyDef>& props)
|
|
||||||
{
|
|
||||||
using namespace wxInspector;
|
|
||||||
|
|
||||||
props.push_back({"Scale Factor", "DPI Scaling", PropertyType::String,
|
|
||||||
wxString::Format("%.2f", dpi->scale_factor()), false, {},
|
|
||||||
[dpi]() { return wxString::Format("%.2f", dpi->scale_factor()); },
|
|
||||||
[dpi](const wxString& v) {
|
|
||||||
double val;
|
|
||||||
if (wxSscanf(v, "%lf", &val) != 1) return false;
|
|
||||||
dpi->set_scale_factor((float) val);
|
|
||||||
return true;
|
|
||||||
}});
|
|
||||||
|
|
||||||
props.push_back({"Prev Scale Factor", "DPI Scaling", PropertyType::String,
|
|
||||||
wxString::Format("%.2f", dpi->prev_scale_factor()), false, {},
|
|
||||||
[dpi]() { return wxString::Format("%.2f", dpi->prev_scale_factor()); },
|
|
||||||
[dpi](const wxString& v) {
|
|
||||||
double val;
|
|
||||||
if (wxSscanf(v, "%lf", &val) != 1) return false;
|
|
||||||
dpi->set_prev_scale_factor((float) val);
|
|
||||||
return true;
|
|
||||||
}});
|
|
||||||
|
|
||||||
props.push_back({"EM Unit", "DPI Scaling", PropertyType::Integer,
|
|
||||||
wxString::Format("%d", dpi->em_unit()), false, {},
|
|
||||||
[dpi]() { return wxString::Format("%d", dpi->em_unit()); },
|
|
||||||
[dpi](const wxString& v) {
|
|
||||||
long val;
|
|
||||||
if (!v.ToLong(&val)) return false;
|
|
||||||
dpi->set_em_unit((int) val);
|
|
||||||
return true;
|
|
||||||
}});
|
|
||||||
|
|
||||||
props.push_back({"Normal Font", "DPI Scaling", PropertyType::ReadOnly,
|
|
||||||
dpi->normal_font().GetNativeFontInfoDesc(), true, {},
|
|
||||||
[dpi]() { return dpi->normal_font().GetNativeFontInfoDesc(); },
|
|
||||||
nullptr});
|
|
||||||
|
|
||||||
props.push_back({"Force Rescale", "DPI Scaling", PropertyType::Boolean,
|
|
||||||
dpi->force_rescale() ? "true" : "false", true, {},
|
|
||||||
[dpi]() { return dpi->force_rescale() ? "true" : "false"; },
|
|
||||||
nullptr});
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
wxString DPIAwarePlugin::GetName() const
|
|
||||||
{
|
|
||||||
return "OrcaDPIAware";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DPIAwarePlugin::CanProvideProperties(wxClassInfo* info)
|
|
||||||
{
|
|
||||||
return info->IsKindOf(CLASSINFO(wxWindow));
|
|
||||||
}
|
|
||||||
|
|
||||||
wxVector<wxInspector::PropertyDef> DPIAwarePlugin::GetProperties(
|
|
||||||
wxInspector::InspectableObject& obj)
|
|
||||||
{
|
|
||||||
wxVector<wxInspector::PropertyDef> props;
|
|
||||||
wxWindow* win = obj.AsWindow();
|
|
||||||
if (!win) return props;
|
|
||||||
|
|
||||||
if (auto* frame = dynamic_cast<DPIFrame*>(win)) {
|
|
||||||
addDPIProps(frame, props);
|
|
||||||
} else if (auto* dlg = dynamic_cast<DPIDialog*>(win)) {
|
|
||||||
addDPIProps(dlg, props);
|
|
||||||
}
|
|
||||||
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 3: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add src/slic3r/Utils/wxInspectorPlugins/DPIAwarePlugin.hpp src/slic3r/Utils/wxInspectorPlugins/DPIAwarePlugin.cpp
|
|
||||||
git commit -m "feat: add DPIAware wxInspector plugin
|
|
||||||
|
|
||||||
Exposes DPI scaling properties (scale_factor, prev_scale_factor,
|
|
||||||
em_unit, normal_font, force_rescale) on DPIFrame and DPIDialog
|
|
||||||
widgets. Uses dynamic_cast for detection and a template helper
|
|
||||||
to capture the correct static type for lambda accessors."
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 4: Create CustomWidgetsPlugin
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Create: `src/slic3r/Utils/wxInspectorPlugins/CustomWidgetsPlugin.hpp`
|
|
||||||
- Create: `src/slic3r/Utils/wxInspectorPlugins/CustomWidgetsPlugin.cpp`
|
|
||||||
|
|
||||||
**Interfaces:**
|
|
||||||
- Consumes: Task 1 (all widget getters), Task 2 (registration pattern)
|
|
||||||
- Produces: `class CustomWidgetsPlugin : public wxInspector::wxInspectorPlugin`
|
|
||||||
|
|
||||||
- [ ] **Step 1: Write CustomWidgetsPlugin.hpp**
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <wx/inspector/plugin.h>
|
|
||||||
|
|
||||||
class CustomWidgetsPlugin : public wxInspector::wxInspectorPlugin
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
wxString GetName() const override;
|
|
||||||
|
|
||||||
bool CanProvideProperties(wxClassInfo* info) override;
|
|
||||||
|
|
||||||
wxVector<wxInspector::PropertyDef> GetProperties(
|
|
||||||
wxInspector::InspectableObject& obj) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void addButtonProps(class Button* btn,
|
|
||||||
wxVector<wxInspector::PropertyDef>& props);
|
|
||||||
void addCheckBoxProps(class CheckBox* cb,
|
|
||||||
wxVector<wxInspector::PropertyDef>& props);
|
|
||||||
void addTextInputProps(class TextInput* ti,
|
|
||||||
wxVector<wxInspector::PropertyDef>& props);
|
|
||||||
void addSwitchButtonProps(class SwitchButton* sb,
|
|
||||||
wxVector<wxInspector::PropertyDef>& props);
|
|
||||||
void addProgressBarProps(class ProgressBar* pb,
|
|
||||||
wxVector<wxInspector::PropertyDef>& props);
|
|
||||||
void addLabelProps(class Label* lbl,
|
|
||||||
wxVector<wxInspector::PropertyDef>& props);
|
|
||||||
void addLabeledStaticBoxProps(class LabeledStaticBox* lsb,
|
|
||||||
wxVector<wxInspector::PropertyDef>& props);
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 2: Write CustomWidgetsPlugin.cpp — includes and GetName/CanProvideProperties**
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include "CustomWidgetsPlugin.hpp"
|
|
||||||
|
|
||||||
#include "slic3r/GUI/Widgets/Button.hpp"
|
|
||||||
#include "slic3r/GUI/Widgets/CheckBox.hpp"
|
|
||||||
#include "slic3r/GUI/Widgets/TextInput.hpp"
|
|
||||||
#include "slic3r/GUI/Widgets/SwitchButton.hpp"
|
|
||||||
#include "slic3r/GUI/Widgets/ProgressBar.hpp"
|
|
||||||
#include "slic3r/GUI/Widgets/Label.hpp"
|
|
||||||
#include "slic3r/GUI/Widgets/LabeledStaticBox.hpp"
|
|
||||||
|
|
||||||
#include <wx/window.h>
|
|
||||||
#include <wx/tglbtn.h>
|
|
||||||
|
|
||||||
wxString CustomWidgetsPlugin::GetName() const
|
|
||||||
{
|
|
||||||
return "OrcaCustomWidgets";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CustomWidgetsPlugin::CanProvideProperties(wxClassInfo* info)
|
|
||||||
{
|
|
||||||
return info->IsKindOf(CLASSINFO(wxWindow));
|
|
||||||
}
|
|
||||||
|
|
||||||
wxVector<wxInspector::PropertyDef> CustomWidgetsPlugin::GetProperties(
|
|
||||||
wxInspector::InspectableObject& obj)
|
|
||||||
{
|
|
||||||
wxVector<wxInspector::PropertyDef> props;
|
|
||||||
wxWindow* win = obj.AsWindow();
|
|
||||||
if (!win) return props;
|
|
||||||
|
|
||||||
if (auto* btn = dynamic_cast<Button*>(win))
|
|
||||||
addButtonProps(btn, props);
|
|
||||||
if (auto* cb = dynamic_cast<CheckBox*>(win))
|
|
||||||
addCheckBoxProps(cb, props);
|
|
||||||
if (auto* ti = dynamic_cast<TextInput*>(win))
|
|
||||||
addTextInputProps(ti, props);
|
|
||||||
if (auto* sb = dynamic_cast<SwitchButton*>(win))
|
|
||||||
addSwitchButtonProps(sb, props);
|
|
||||||
if (auto* pb = dynamic_cast<ProgressBar*>(win))
|
|
||||||
addProgressBarProps(pb, props);
|
|
||||||
if (auto* lbl = dynamic_cast<Label*>(win))
|
|
||||||
addLabelProps(lbl, props);
|
|
||||||
if (auto* lsb = dynamic_cast<LabeledStaticBox*>(win))
|
|
||||||
addLabeledStaticBoxProps(lsb, props);
|
|
||||||
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 3: Write CustomWidgetsPlugin.cpp — addButtonProps**
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void CustomWidgetsPlugin::addButtonProps(Button* btn,
|
|
||||||
wxVector<wxInspector::PropertyDef>& props)
|
|
||||||
{
|
|
||||||
using namespace wxInspector;
|
|
||||||
|
|
||||||
wxVector<wxString> styleChoices;
|
|
||||||
styleChoices.push_back("Regular");
|
|
||||||
styleChoices.push_back("Confirm");
|
|
||||||
styleChoices.push_back("Alert");
|
|
||||||
styleChoices.push_back("Disabled");
|
|
||||||
|
|
||||||
auto styleToStr = [](ButtonStyle s) -> wxString {
|
|
||||||
switch (s) {
|
|
||||||
case ButtonStyle::Regular: return "Regular";
|
|
||||||
case ButtonStyle::Confirm: return "Confirm";
|
|
||||||
case ButtonStyle::Alert: return "Alert";
|
|
||||||
case ButtonStyle::Disabled: return "Disabled";
|
|
||||||
}
|
|
||||||
return "Regular";
|
|
||||||
};
|
|
||||||
|
|
||||||
props.push_back({"Button Style", "Orca Button", PropertyType::Choice,
|
|
||||||
styleToStr(btn->GetStyle()), false, styleChoices,
|
|
||||||
[btn, styleToStr]() { return styleToStr(btn->GetStyle()); },
|
|
||||||
[btn](const wxString& v) {
|
|
||||||
ButtonStyle s = ButtonStyle::Regular;
|
|
||||||
if (v == "Confirm") s = ButtonStyle::Confirm;
|
|
||||||
else if (v == "Alert") s = ButtonStyle::Alert;
|
|
||||||
else if (v == "Disabled") s = ButtonStyle::Disabled;
|
|
||||||
btn->SetStyle(s, btn->GetType());
|
|
||||||
return true;
|
|
||||||
}});
|
|
||||||
|
|
||||||
wxVector<wxString> typeChoices;
|
|
||||||
typeChoices.push_back("Compact");
|
|
||||||
typeChoices.push_back("Window");
|
|
||||||
typeChoices.push_back("Choice");
|
|
||||||
typeChoices.push_back("Parameter");
|
|
||||||
typeChoices.push_back("Icon");
|
|
||||||
typeChoices.push_back("Expanded");
|
|
||||||
|
|
||||||
auto typeToStr = [](ButtonType t) -> wxString {
|
|
||||||
switch (t) {
|
|
||||||
case ButtonType::Compact: return "Compact";
|
|
||||||
case ButtonType::Window: return "Window";
|
|
||||||
case ButtonType::Choice: return "Choice";
|
|
||||||
case ButtonType::Parameter: return "Parameter";
|
|
||||||
case ButtonType::Icon: return "Icon";
|
|
||||||
case ButtonType::Expanded: return "Expanded";
|
|
||||||
}
|
|
||||||
return "Compact";
|
|
||||||
};
|
|
||||||
|
|
||||||
props.push_back({"Button Type", "Orca Button", PropertyType::Choice,
|
|
||||||
typeToStr(btn->GetType()), false, typeChoices,
|
|
||||||
[btn, typeToStr]() { return typeToStr(btn->GetType()); },
|
|
||||||
[btn](const wxString& v) {
|
|
||||||
ButtonType t = ButtonType::Compact;
|
|
||||||
if (v == "Window") t = ButtonType::Window;
|
|
||||||
else if (v == "Choice") t = ButtonType::Choice;
|
|
||||||
else if (v == "Parameter") t = ButtonType::Parameter;
|
|
||||||
else if (v == "Icon") t = ButtonType::Icon;
|
|
||||||
else if (v == "Expanded") t = ButtonType::Expanded;
|
|
||||||
btn->SetStyle(btn->GetStyle(), t);
|
|
||||||
return true;
|
|
||||||
}});
|
|
||||||
|
|
||||||
props.push_back({"Selected", "Orca Button", PropertyType::Boolean,
|
|
||||||
btn->IsSelected() ? "true" : "false", false, {},
|
|
||||||
[btn]() { return btn->IsSelected() ? "true" : "false"; },
|
|
||||||
[btn](const wxString& v) {
|
|
||||||
btn->SetSelected(v == "true");
|
|
||||||
btn->Refresh();
|
|
||||||
return true;
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 4: Write CustomWidgetsPlugin.cpp — addCheckBoxProps**
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void CustomWidgetsPlugin::addCheckBoxProps(CheckBox* cb,
|
|
||||||
wxVector<wxInspector::PropertyDef>& props)
|
|
||||||
{
|
|
||||||
using namespace wxInspector;
|
|
||||||
|
|
||||||
props.push_back({"Half Checked", "Orca CheckBox", PropertyType::Boolean,
|
|
||||||
cb->IsHalfChecked() ? "true" : "false", false, {},
|
|
||||||
[cb]() { return cb->IsHalfChecked() ? "true" : "false"; },
|
|
||||||
[cb](const wxString& v) {
|
|
||||||
cb->SetHalfChecked(v == "true");
|
|
||||||
return true;
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 5: Write CustomWidgetsPlugin.cpp — addTextInputProps**
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void CustomWidgetsPlugin::addTextInputProps(TextInput* ti,
|
|
||||||
wxVector<wxInspector::PropertyDef>& props)
|
|
||||||
{
|
|
||||||
using namespace wxInspector;
|
|
||||||
|
|
||||||
props.push_back({"Label", "Orca TextInput", PropertyType::String,
|
|
||||||
ti->GetLabel(), false, {},
|
|
||||||
[ti]() { return ti->GetLabel(); },
|
|
||||||
[ti](const wxString& v) { ti->SetLabel(v); return true; }});
|
|
||||||
|
|
||||||
props.push_back({"Text Value", "Orca TextInput", PropertyType::String,
|
|
||||||
ti->GetTextCtrl()->GetValue(), false, {},
|
|
||||||
[ti]() { return ti->GetTextCtrl()->GetValue(); },
|
|
||||||
[ti](const wxString& v) { ti->GetTextCtrl()->SetValue(v); return true; }});
|
|
||||||
|
|
||||||
props.push_back({"Corner Radius", "Orca TextInput", PropertyType::Integer,
|
|
||||||
wxString::Format("%d", ti->GetCornerRadius()), false, {},
|
|
||||||
[ti]() { return wxString::Format("%d", ti->GetCornerRadius()); },
|
|
||||||
[ti](const wxString& v) {
|
|
||||||
long val;
|
|
||||||
if (!v.ToLong(&val)) return false;
|
|
||||||
ti->SetCornerRadius((double) val);
|
|
||||||
ti->Refresh();
|
|
||||||
return true;
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 6: Write CustomWidgetsPlugin.cpp — addSwitchButtonProps**
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void CustomWidgetsPlugin::addSwitchButtonProps(SwitchButton* sb,
|
|
||||||
wxVector<wxInspector::PropertyDef>& props)
|
|
||||||
{
|
|
||||||
using namespace wxInspector;
|
|
||||||
|
|
||||||
props.push_back({"Value", "Orca SwitchButton", PropertyType::Boolean,
|
|
||||||
sb->GetValue() ? "true" : "false", false, {},
|
|
||||||
[sb]() { return sb->GetValue() ? "true" : "false"; },
|
|
||||||
[sb](const wxString& v) {
|
|
||||||
sb->SetValue(v == "true");
|
|
||||||
return true;
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
(Note: `GetValue()` and `SetValue()` are inherited from `wxBitmapToggleButton` → `wxToggleButton`.)
|
|
||||||
|
|
||||||
- [ ] **Step 7: Write CustomWidgetsPlugin.cpp — addProgressBarProps**
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void CustomWidgetsPlugin::addProgressBarProps(ProgressBar* pb,
|
|
||||||
wxVector<wxInspector::PropertyDef>& props)
|
|
||||||
{
|
|
||||||
using namespace wxInspector;
|
|
||||||
|
|
||||||
props.push_back({"Proportion", "Orca ProgressBar", PropertyType::String,
|
|
||||||
wxString::Format("%.2f", pb->m_proportion), false, {},
|
|
||||||
[pb]() { return wxString::Format("%.2f", pb->m_proportion); },
|
|
||||||
[pb](const wxString& v) {
|
|
||||||
double val;
|
|
||||||
if (wxSscanf(v, "%lf", &val) != 1) return false;
|
|
||||||
pb->m_proportion = val;
|
|
||||||
pb->Refresh();
|
|
||||||
return true;
|
|
||||||
}});
|
|
||||||
|
|
||||||
props.push_back({"Show Number", "Orca ProgressBar", PropertyType::Boolean,
|
|
||||||
pb->m_shownumber ? "true" : "false", false, {},
|
|
||||||
[pb]() { return pb->m_shownumber ? "true" : "false"; },
|
|
||||||
[pb](const wxString& v) {
|
|
||||||
pb->m_shownumber = (v == "true");
|
|
||||||
pb->Refresh();
|
|
||||||
return true;
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
(Note: `m_proportion` and `m_shownumber` are public members on `ProgressBar`.)
|
|
||||||
|
|
||||||
- [ ] **Step 8: Write CustomWidgetsPlugin.cpp — addLabelProps**
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void CustomWidgetsPlugin::addLabelProps(Label* lbl,
|
|
||||||
wxVector<wxInspector::PropertyDef>& props)
|
|
||||||
{
|
|
||||||
using namespace wxInspector;
|
|
||||||
|
|
||||||
bool isHyperlink = (lbl->GetWindowStyleFlag() & 0x0020) != 0; // LB_HYPERLINK
|
|
||||||
|
|
||||||
props.push_back({"Is Hyperlink", "Orca Label", PropertyType::Boolean,
|
|
||||||
isHyperlink ? "true" : "false", true, {},
|
|
||||||
[lbl]() {
|
|
||||||
return (lbl->GetWindowStyleFlag() & 0x0020) ? "true" : "false";
|
|
||||||
},
|
|
||||||
nullptr});
|
|
||||||
|
|
||||||
props.push_back({"Font Point Size", "Orca Label", PropertyType::ReadOnly,
|
|
||||||
wxString::Format("%d", lbl->GetFont().GetPointSize()), true, {},
|
|
||||||
[lbl]() {
|
|
||||||
return wxString::Format("%d", lbl->GetFont().GetPointSize());
|
|
||||||
},
|
|
||||||
nullptr});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 9: Write CustomWidgetsPlugin.cpp — addLabeledStaticBoxProps**
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void CustomWidgetsPlugin::addLabeledStaticBoxProps(LabeledStaticBox* lsb,
|
|
||||||
wxVector<wxInspector::PropertyDef>& props)
|
|
||||||
{
|
|
||||||
using namespace wxInspector;
|
|
||||||
|
|
||||||
props.push_back({"Corner Radius", "LabeledStaticBox", PropertyType::Integer,
|
|
||||||
wxString::Format("%d", lsb->GetCornerRadius()), false, {},
|
|
||||||
[lsb]() { return wxString::Format("%d", lsb->GetCornerRadius()); },
|
|
||||||
[lsb](const wxString& v) {
|
|
||||||
long val;
|
|
||||||
if (!v.ToLong(&val)) return false;
|
|
||||||
lsb->SetCornerRadius((int) val);
|
|
||||||
return true;
|
|
||||||
}});
|
|
||||||
|
|
||||||
props.push_back({"Border Width", "LabeledStaticBox", PropertyType::Integer,
|
|
||||||
wxString::Format("%d", lsb->GetBorderWidth()), false, {},
|
|
||||||
[lsb]() { return wxString::Format("%d", lsb->GetBorderWidth()); },
|
|
||||||
[lsb](const wxString& v) {
|
|
||||||
long val;
|
|
||||||
if (!v.ToLong(&val)) return false;
|
|
||||||
lsb->SetBorderWidth((int) val);
|
|
||||||
return true;
|
|
||||||
}});
|
|
||||||
|
|
||||||
// Border Color: display as hex string
|
|
||||||
wxColour bc = lsb->GetBorderColor().colorForStates(0);
|
|
||||||
props.push_back({"Border Color", "LabeledStaticBox", PropertyType::String,
|
|
||||||
bc.GetAsString(wxC2S_HTML_SYNTAX), false, {},
|
|
||||||
[lsb]() {
|
|
||||||
return lsb->GetBorderColor()
|
|
||||||
.colorForStates(0)
|
|
||||||
.GetAsString(wxC2S_HTML_SYNTAX);
|
|
||||||
},
|
|
||||||
[lsb](const wxString& v) {
|
|
||||||
wxColour c(v);
|
|
||||||
if (!c.IsOk()) return false;
|
|
||||||
lsb->SetBorderColor(StateColor(c));
|
|
||||||
return true;
|
|
||||||
}});
|
|
||||||
|
|
||||||
props.push_back({"Scale", "LabeledStaticBox", PropertyType::ReadOnly,
|
|
||||||
wxString::Format("%.2f", lsb->GetScale()), true, {},
|
|
||||||
[lsb]() { return wxString::Format("%.2f", lsb->GetScale()); },
|
|
||||||
nullptr});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 10: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add src/slic3r/Utils/wxInspectorPlugins/CustomWidgetsPlugin.hpp src/slic3r/Utils/wxInspectorPlugins/CustomWidgetsPlugin.cpp
|
|
||||||
git commit -m "feat: add OrcaCustomWidgets wxInspector plugin
|
|
||||||
|
|
||||||
Exposes Orca-specific properties on 7 widget types:
|
|
||||||
- Button: Style, Type, Selected
|
|
||||||
- CheckBox: Half Checked
|
|
||||||
- TextInput: Label, Text Value, Corner Radius
|
|
||||||
- SwitchButton: Value
|
|
||||||
- ProgressBar: Proportion, Show Number
|
|
||||||
- Label: Is Hyperlink, Font Point Size
|
|
||||||
- LabeledStaticBox: Corner Radius, Border Width, Border Color, Scale
|
|
||||||
|
|
||||||
Each widget type uses dynamic_cast for safe detection."
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 5: Wire plugins into MainFrame and CMakeLists
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `src/slic3r/GUI/MainFrame.cpp` (add include + registration call)
|
|
||||||
- Modify: `src/slic3r/CMakeLists.txt` (add 4 source files)
|
|
||||||
|
|
||||||
**Interfaces:**
|
|
||||||
- Consumes: Tasks 1-4 (all plugins and registration helper)
|
|
||||||
- Produces: Registered plugins available at runtime, buildable project
|
|
||||||
|
|
||||||
- [ ] **Step 1: Add include in MainFrame.cpp**
|
|
||||||
|
|
||||||
After the existing includes (around line 30, near the other Utils includes), add:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include "slic3r/Utils/wxInspectorPlugins/Registration.hpp"
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 2: Add registration call in MainFrame constructor**
|
|
||||||
|
|
||||||
After `SetupInspectorAccelerator(this);` (currently line ~303), add:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
RegisterOrcaInspectorPlugins();
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 3: Add source files to CMakeLists.txt**
|
|
||||||
|
|
||||||
Find the `SLIC3R_GUI_SOURCES` list in `src/slic3r/CMakeLists.txt`. After the existing `Utils/*.cpp` entries (around line 650-754), add:
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
Utils/wxInspectorPlugins/DPIAwarePlugin.hpp
|
|
||||||
Utils/wxInspectorPlugins/DPIAwarePlugin.cpp
|
|
||||||
Utils/wxInspectorPlugins/CustomWidgetsPlugin.hpp
|
|
||||||
Utils/wxInspectorPlugins/CustomWidgetsPlugin.cpp
|
|
||||||
Utils/wxInspectorPlugins/Registration.hpp
|
|
||||||
```
|
|
||||||
|
|
||||||
(Note: Add all 5 files — 2 .hpp + 2 .cpp + 1 Registration.hpp. wxWidgets cmake needs headers listed too for the resource system.)
|
|
||||||
|
|
||||||
- [ ] **Step 4: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add src/slic3r/GUI/MainFrame.cpp src/slic3r/CMakeLists.txt
|
|
||||||
git commit -m "feat: wire wxInspector plugins into MainFrame and build
|
|
||||||
|
|
||||||
- Call RegisterOrcaInspectorPlugins() after SetupInspectorAccelerator
|
|
||||||
- Add all plugin source files to SLIC3R_GUI_SOURCES"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 6: Build and verify
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- None modified (verification only)
|
|
||||||
|
|
||||||
- [ ] **Step 1: Configure the build**
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
$cmakePath = "D:\VisualStudio\2026\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe"
|
|
||||||
& $cmakePath --build . --config Debug --target ALL_BUILD -- -m
|
|
||||||
```
|
|
||||||
|
|
||||||
Expected: Build succeeds with zero errors and zero warnings from our new files.
|
|
||||||
|
|
||||||
- [ ] **Step 2: Fix any compilation errors**
|
|
||||||
|
|
||||||
If the build fails:
|
|
||||||
- Check that `#include` paths resolve (the `slic3r/GUI/…` relative paths use `src/` as the include root — verify this is set up in CMake via `include_directories`)
|
|
||||||
- Check that `ButtonStyle` and `ButtonType` enums are visible (they're defined in `Button.hpp`)
|
|
||||||
- Check that `StateColor` constructor from `wxColour` is valid (it has `StateColor(wxColour const&)`)
|
|
||||||
- Check that `LabeledStaticBox::GetBorderColor()` returns by value (StateColor copy is fine)
|
|
||||||
- On macOS: static box margin removal call needs `#ifdef __WXOSX__` guard
|
|
||||||
|
|
||||||
- [ ] **Step 3: Launch OrcaSlicer and verify inspector**
|
|
||||||
|
|
||||||
Launch the built OrcaSlicer, press Ctrl+Shift+I to open the inspector:
|
|
||||||
1. Select the MainFrame in the tree — verify "DPI Scaling" category appears with Scale Factor, Prev Scale Factor, EM Unit, Normal Font, Force Rescale
|
|
||||||
2. Select an Orca Button — verify "Orca Button" category appears
|
|
||||||
3. Select an Orca CheckBox — verify "Orca CheckBox" category appears
|
|
||||||
4. Edit a property value (e.g., Scale Factor) — verify the setter applies correctly
|
|
||||||
5. Select a LabeledStaticBox — verify corner radius, border width, border color, scale appear
|
|
||||||
|
|
||||||
- [ ] **Step 5: Commit (if fixes were needed) or mark complete**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git status
|
|
||||||
```
|
|
||||||
|
|
||||||
If clean: verification complete. If changes were made: `git add` and commit with fix message.
|
|
||||||
@@ -1,376 +0,0 @@
|
|||||||
# macOS FFmpeg Media Player Implementation Plan
|
|
||||||
|
|
||||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
||||||
|
|
||||||
**Goal:** Make macOS use the same FFmpeg-based media player (`wxMediaCtrl3` + `AVVideoDecoder`) as Windows/Linux, linking the static FFmpeg libraries from the deps build, and remove the old `wxMediaCtrl2.mm` BambuPlayer-based player.
|
|
||||||
|
|
||||||
**Architecture:** The new player is platform-neutral C++ already used on Linux/Windows. Enabling it on macOS is pure build wiring: compile `wxMediaCtrl3.cpp` + `AVVideoDecoder.cpp` on macOS, drop the `__WXMAC__` alias that redirects `wxMediaCtrl3` to the old `wxMediaCtrl2`, and link static FFmpeg (`libavcodec.a`/`libswscale.a`/`libavutil.a`) from the deps install. The Bambu stream API is dlsym'd at runtime from the network plugin (`libBambuSource.dylib`), which already exports it — no plugin changes needed. Rendering reuses the existing `wxImage` → `DrawBitmap` paint path (same as Linux).
|
|
||||||
|
|
||||||
**Tech Stack:** C++17, wxWidgets, CMake, FFmpeg 7.0.3 (libavcodec/libswscale/libavutil), macOS (Xcode generator), `deps/` ExternalProject build system.
|
|
||||||
|
|
||||||
## Global Constraints
|
|
||||||
|
|
||||||
- Branch: `dev/ffmpeg-player-macos`. Commit after every task.
|
|
||||||
- **Linux and Windows builds must not change** — the FFmpeg deps flag change is guarded by `APPLE`; Linux keeps `--enable-shared`, Windows keeps its prebuilt DLL zips.
|
|
||||||
- Static FFmpeg only on macOS: deps produce `libavcodec.a`/`libswscale.a`/`libavutil.a`; the app links those explicitly — the app binary must have **no** `libav*` dylib references (`otool -L` check).
|
|
||||||
- Follow existing code style: PascalCase classes, snake_case functions, C++17.
|
|
||||||
- No changes to `StatusPanel.cpp`, `MediaPlayCtrl.*`, or the BambuTunnel interface — the app already creates `wxMediaCtrl3` and uses only its public interface.
|
|
||||||
- The player cannot be unit-tested (hardware/plugin-dependent GUI code); verification is build-level, link-level, and manual runtime on a Mac.
|
|
||||||
- `localization/i18n/list.txt` references only `wxMediaCtrl2.cpp` (Win/Linux, stays) — no translation-list changes needed.
|
|
||||||
- Build dirs on the dev machine: main app = `build_arm64/` (Xcode generator, multi-config), deps = `deps/build/arm64/` (Unix Makefiles). App target name: `OrcaSlicer`. Substitute your own configured build dirs where noted.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 1: Enable wxMediaCtrl3 on macOS and link static FFmpeg
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `src/slic3r/GUI/wxMediaCtrl3.h` (lines 18–22: the `#ifdef __WXMAC__` alias branch)
|
|
||||||
- Modify: `src/slic3r/GUI/wxMediaCtrl3.cpp:13` (uncomment the event define)
|
|
||||||
- Modify: `src/slic3r/GUI/wxMediaCtrl2.cpp:101` (remove the event define)
|
|
||||||
- Modify: `src/slic3r/CMakeLists.txt` (APPLE source list ~lines 779–792; FFmpeg link block ~lines 905–910)
|
|
||||||
|
|
||||||
**Interfaces:**
|
|
||||||
- Consumes: nothing new (all classes already exist).
|
|
||||||
- Produces: `wxMediaCtrl3` class compiled on macOS with the same interface as Linux/Windows — `Load(wxURI)`, `Play()`, `Stop()`, `SetIdleImage(wxString)`, `GetState()`, `GetLastError()`, `GetVideoSize()`, event `EVT_MEDIA_CTRL_STAT` defined once in the lib (from `wxMediaCtrl3.cpp`).
|
|
||||||
|
|
||||||
- [ ] **Step 1: Remove the macOS alias in wxMediaCtrl3.h**
|
|
||||||
|
|
||||||
Current (lines 16–23 of `src/slic3r/GUI/wxMediaCtrl3.h`):
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void wxMediaCtrl_OnSize(wxWindow * ctrl, wxSize const & videoSize, int width, int height);
|
|
||||||
|
|
||||||
#ifdef __WXMAC__
|
|
||||||
|
|
||||||
#include "wxMediaCtrl2.h"
|
|
||||||
#define wxMediaCtrl3 wxMediaCtrl2
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define BAMBU_DYNAMIC
|
|
||||||
```
|
|
||||||
|
|
||||||
New:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void wxMediaCtrl_OnSize(wxWindow * ctrl, wxSize const & videoSize, int width, int height);
|
|
||||||
|
|
||||||
#define BAMBU_DYNAMIC
|
|
||||||
```
|
|
||||||
|
|
||||||
Also remove the matching `#endif` that closed the `#else` branch (the one before the final `#endif /* wxMediaCtrl3_h */`), so the file's `#ifndef`/`#endif` guard pair stays balanced.
|
|
||||||
|
|
||||||
- [ ] **Step 2: Move the EVT_MEDIA_CTRL_STAT definition into wxMediaCtrl3.cpp**
|
|
||||||
|
|
||||||
In `src/slic3r/GUI/wxMediaCtrl3.cpp:13`, uncomment:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
//wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
|
|
||||||
```
|
|
||||||
|
|
||||||
becomes:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
|
|
||||||
```
|
|
||||||
|
|
||||||
In `src/slic3r/GUI/wxMediaCtrl2.cpp:101`, delete:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
|
|
||||||
```
|
|
||||||
|
|
||||||
(One definition total in the lib — `MediaPlayCtrl.cpp:59` binds this event on the media ctrl.)
|
|
||||||
|
|
||||||
- [ ] **Step 3: Update the APPLE source list in CMakeLists.txt**
|
|
||||||
|
|
||||||
In `src/slic3r/CMakeLists.txt`, the APPLE branch (currently compiles `wxMediaCtrl2.mm`, which becomes dead on macOS):
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
GUI/wxMediaCtrl2.mm
|
|
||||||
GUI/wxMediaCtrl2.h
|
|
||||||
GUI/wxMediaCtrl3.h
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
becomes:
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
GUI/AVVideoDecoder.cpp
|
|
||||||
GUI/AVVideoDecoder.hpp
|
|
||||||
GUI/wxMediaCtrl3.cpp
|
|
||||||
GUI/wxMediaCtrl3.h
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
(The `else ()` branch — Win/Linux — stays exactly as it is.)
|
|
||||||
|
|
||||||
- [ ] **Step 4: Link static FFmpeg on macOS**
|
|
||||||
|
|
||||||
In `src/slic3r/CMakeLists.txt`, the FFmpeg block (currently `if (NOT APPLE)`):
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
if (NOT APPLE)
|
|
||||||
pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET
|
|
||||||
libavcodec
|
|
||||||
libswscale
|
|
||||||
libavutil
|
|
||||||
)
|
|
||||||
target_link_libraries(libslic3r_gui PkgConfig::LIBAV)
|
|
||||||
endif()
|
|
||||||
```
|
|
||||||
|
|
||||||
becomes:
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
if (APPLE)
|
|
||||||
# Static FFmpeg from the deps install: nothing to bundle into the .app,
|
|
||||||
# no rpath/install_name handling. Order matters: avcodec -> swscale -> avutil.
|
|
||||||
find_library(LIBAVCODEC_LIBRARY NAMES libavcodec.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
|
||||||
find_library(LIBSWSCALE_LIBRARY NAMES libswscale.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
|
||||||
find_library(LIBAVUTIL_LIBRARY NAMES libavutil.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
|
||||||
target_link_libraries(libslic3r_gui ${LIBAVCODEC_LIBRARY} ${LIBSWSCALE_LIBRARY} ${LIBAVUTIL_LIBRARY})
|
|
||||||
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${CMAKE_PREFIX_PATH}/include)
|
|
||||||
else ()
|
|
||||||
pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET
|
|
||||||
libavcodec
|
|
||||||
libswscale
|
|
||||||
libavutil
|
|
||||||
)
|
|
||||||
target_link_libraries(libslic3r_gui PkgConfig::LIBAV)
|
|
||||||
endif()
|
|
||||||
```
|
|
||||||
|
|
||||||
The deps install (`${CMAKE_PREFIX_PATH}/lib`) already contains the three `.a` files from the existing arm64 deps build — no deps rebuild needed for this task.
|
|
||||||
|
|
||||||
- [ ] **Step 5: Reconfigure and build the app**
|
|
||||||
|
|
||||||
Run (Xcode generator; `cmake` re-runs automatically on build):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cmake --build build_arm64 --config RelWithDebInfo --target OrcaSlicer
|
|
||||||
```
|
|
||||||
|
|
||||||
Expected: configure succeeds (no `pkg_check_modules` errors on macOS, `find_library` finds all three `.a` files), compile succeeds (`wxMediaCtrl3.cpp` and `AVVideoDecoder.cpp` compile on macOS without changes), link succeeds.
|
|
||||||
|
|
||||||
If CMake complains that `wxMediaCtrl3.h` is included but not in the source list or similar IDE-only warnings — ignore; headers in the list are cosmetic.
|
|
||||||
|
|
||||||
- [ ] **Step 6: Verify no dynamic FFmpeg dependency**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
otool -L build_arm64/src/RelWithDebInfo/OrcaSlicer.app/Contents/MacOS/OrcaSlicer | grep -i "libav" || echo "OK: no dynamic FFmpeg"
|
|
||||||
```
|
|
||||||
|
|
||||||
Expected: prints `OK: no dynamic FFmpeg` (empty grep output). This is the whole point of static linking — nothing to bundle into the `.app`.
|
|
||||||
|
|
||||||
- [ ] **Step 7: Quick sanity — macOS unit tests still pass**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ctest --test-dir build_arm64/tests/libslic3r --output-on-failure
|
|
||||||
```
|
|
||||||
|
|
||||||
Expected: passes (add `-C RelWithDebInfo` if the multi-config generator requires it). If no tests were built in this build dir, build target `tests` first (`cmake --build build_arm64 --config RelWithDebInfo --target tests`).
|
|
||||||
|
|
||||||
- [ ] **Step 8: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add src/slic3r/CMakeLists.txt src/slic3r/GUI/wxMediaCtrl3.h src/slic3r/GUI/wxMediaCtrl3.cpp src/slic3r/GUI/wxMediaCtrl2.cpp
|
|
||||||
git commit -m "feat: use FFmpeg media player on macOS with static FFmpeg"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 2: Static-only FFmpeg in the macOS deps build
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `deps/FFMPEG/FFMPEG.cmake` (non-MSVC branch, APPLE section and CONFIGURE_COMMAND)
|
|
||||||
|
|
||||||
**Interfaces:**
|
|
||||||
- Consumes: nothing.
|
|
||||||
- Produces: a deps install on macOS containing only `libavcodec.a`, `libswscale.a`, `libavutil.a` (+ headers) — no `libav*` dylibs, so no bundling/rpath machinery is ever needed on macOS. Linux and Windows output are unchanged.
|
|
||||||
|
|
||||||
- [ ] **Step 1: Add the static flag variable**
|
|
||||||
|
|
||||||
In `deps/FFMPEG/FFMPEG.cmake`, inside the non-MSVC `else ()` branch, in the existing `if (APPLE)` block:
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
if (APPLE)
|
|
||||||
set(_minos_cmd
|
|
||||||
"CFLAGS=-mmacosx-version-min=${DEP_OSX_TARGET}"
|
|
||||||
"LDFLAGS=-mmacosx-version-min=${DEP_OSX_TARGET}"
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
add after the `_minos_cmd` set:
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
# Static FFmpeg: nothing to bundle into the .app, no rpath handling.
|
|
||||||
# Shared flags must come AFTER --enable-shared below so they win.
|
|
||||||
set(_link_cmd --enable-static --disable-shared)
|
|
||||||
```
|
|
||||||
|
|
||||||
and add a matching `else ()` after the `if (IS_CROSS_COMPILE) ... endif()` block inside that `if (APPLE)`, so non-Apple Unix keeps shared:
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
else ()
|
|
||||||
set(_link_cmd --enable-shared)
|
|
||||||
endif ()
|
|
||||||
```
|
|
||||||
|
|
||||||
(If the existing `if (IS_CROSS_COMPILE)` block is the last thing inside `if (APPLE)`, the new `else ()` closes the `if (APPLE)` itself.)
|
|
||||||
|
|
||||||
- [ ] **Step 2: Use the variable in CONFIGURE_COMMAND**
|
|
||||||
|
|
||||||
In the `ExternalProject_Add(dep_FFMPEG ...)` configure command:
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
"--prefix=${DESTDIR}"
|
|
||||||
--enable-shared
|
|
||||||
```
|
|
||||||
|
|
||||||
becomes:
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
"--prefix=${DESTDIR}"
|
|
||||||
--enable-shared
|
|
||||||
${_link_cmd}
|
|
||||||
```
|
|
||||||
|
|
||||||
Order matters: `--enable-shared` comes first, then `--enable-static --disable-shared` (APPLE) or `--enable-shared` (Linux) — the last flag wins in FFmpeg configure.
|
|
||||||
|
|
||||||
- [ ] **Step 3: Rebuild the FFmpeg dep (slow — several minutes, run in background)**
|
|
||||||
|
|
||||||
The changed CONFIGURE_COMMAND invalidates the ExternalProject stamp, so this re-configures and rebuilds FFmpeg:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cmake --build deps/build/arm64 --target dep_FFMPEG
|
|
||||||
```
|
|
||||||
|
|
||||||
For a fully clean static-only check (removes the previous shared build tree, which can leave stale `.dylib` files behind in the in-source build):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
rm -rf deps/build/arm64/dep_FFMPEG-prefix
|
|
||||||
cmake --build deps/build/arm64 --target dep_FFMPEG
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 4: Verify the artifacts**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ls deps/build/arm64/dep_FFMPEG-prefix/src/dep_FFMPEG/libavcodec/*.a
|
|
||||||
ls deps/build/arm64/dep_FFMPEG-prefix/src/dep_FFMPEG/libavcodec/*.dylib 2>/dev/null || echo "OK: no dylibs"
|
|
||||||
```
|
|
||||||
|
|
||||||
Expected: `libavcodec.a` present, second command prints `OK: no dylibs`. Check `libavutil` and `libswscale` the same way.
|
|
||||||
|
|
||||||
- [ ] **Step 5: Verify the app still links against the static libs**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cmake --build build_arm64 --config RelWithDebInfo --target OrcaSlicer
|
|
||||||
otool -L build_arm64/src/RelWithDebInfo/OrcaSlicer.app/Contents/MacOS/OrcaSlicer | grep -i "libav" || echo "OK: no dynamic FFmpeg"
|
|
||||||
```
|
|
||||||
|
|
||||||
Expected: build succeeds, `OK: no dynamic FFmpeg`.
|
|
||||||
|
|
||||||
- [ ] **Step 6: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add deps/FFMPEG/FFMPEG.cmake
|
|
||||||
git commit -m "build: build static-only FFmpeg for macOS deps"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 3: Remove the old macOS player
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Delete: `src/slic3r/GUI/wxMediaCtrl2.mm`
|
|
||||||
- Delete: `src/slic3r/GUI/BambuPlayer/BambuPlayer.h` (and the empty `BambuPlayer/` dir)
|
|
||||||
- Modify: `src/slic3r/GUI/wxMediaCtrl2.h` (remove the `#ifdef __WXMAC__` section, lines 22–60)
|
|
||||||
|
|
||||||
**Interfaces:**
|
|
||||||
- Consumes: Task 1 (macOS no longer references `wxMediaCtrl2` — nothing includes `wxMediaCtrl2.h` on macOS anymore; `wxMediaCtrl2` is never instantiated on any platform).
|
|
||||||
- Produces: a clean tree where the old BambuPlayer-based player is gone from macOS. The `BambuPlayer` ObjC class itself remains inside the network plugin (external prebuilt binary) — only the GUI-side consumer is removed.
|
|
||||||
|
|
||||||
- [ ] **Step 1: Delete the old player files**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git rm src/slic3r/GUI/wxMediaCtrl2.mm
|
|
||||||
git rm src/slic3r/GUI/BambuPlayer/BambuPlayer.h
|
|
||||||
rmdir src/slic3r/GUI/BambuPlayer 2>/dev/null || true
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 2: Strip the __WXMAC__ section from wxMediaCtrl2.h**
|
|
||||||
|
|
||||||
In `src/slic3r/GUI/wxMediaCtrl2.h`, remove the entire macOS branch of the `#ifdef __WXMAC__` guard — from `#ifdef __WXMAC__` (line 22) through the closing `};` of the mac class (line 60), and the `#else` marker — leaving only the non-mac `class wxMediaCtrl2 : public wxMediaCtrl { ... };` definition followed by the final `#endif /* wxMediaCtrl2_h */`. The resulting file keeps its `#ifndef`/`#endif` include guard pair balanced.
|
|
||||||
|
|
||||||
The file stays on disk because Win/Linux compile `wxMediaCtrl2.cpp`, which includes it.
|
|
||||||
|
|
||||||
- [ ] **Step 3: Grep for leftover references**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
grep -rn "wxMediaCtrl2.mm\|BambuPlayer/BambuPlayer.h\|BambuPlayer" src/slic3r --include="*.cpp" --include="*.h" --include="*.mm" --include="*.txt"
|
|
||||||
```
|
|
||||||
|
|
||||||
Expected: no hits in `src/slic3r/GUI` (ignore `localization/i18n/list.txt:196`, which lists the Win/Linux `wxMediaCtrl2.cpp` and stays).
|
|
||||||
|
|
||||||
- [ ] **Step 4: Rebuild the app**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cmake --build build_arm64 --config RelWithDebInfo --target OrcaSlicer
|
|
||||||
```
|
|
||||||
|
|
||||||
Expected: configure + compile + link succeed with the deleted files gone.
|
|
||||||
|
|
||||||
- [ ] **Step 5: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add -A src/slic3r/GUI
|
|
||||||
git commit -m "refactor: remove old BambuPlayer-based media player from macOS"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 4: Runtime verification on hardware
|
|
||||||
|
|
||||||
**Files:** none — manual verification.
|
|
||||||
|
|
||||||
**Interfaces:** consumes all prior tasks. Final gate: the new player must actually stream on a Mac.
|
|
||||||
|
|
||||||
- [ ] **Step 1: Launch the freshly built app**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
open build_arm64/src/RelWithDebInfo/OrcaSlicer.app
|
|
||||||
```
|
|
||||||
|
|
||||||
Expected: app launches normally; no crash in the network/device subsystem.
|
|
||||||
|
|
||||||
- [ ] **Step 2: Load the network plugin and open the Device tab**
|
|
||||||
|
|
||||||
Log in / ensure the network plugin (`libBambuSource.dylib`) loads, select a printer, open the Device tab (camera monitoring panel).
|
|
||||||
|
|
||||||
Expected: the camera preview area shows the idle image initially (no crash — this exercises `wxMediaCtrl3::SetIdleImage` and the `wxImage` load path on macOS for the first time).
|
|
||||||
|
|
||||||
- [ ] **Step 3: Start the stream and watch it render**
|
|
||||||
|
|
||||||
Click play / wait for `MediaPlayCtrl` to start the stream.
|
|
||||||
|
|
||||||
Expected: live video renders in the panel. Check the console/log output (`BOOST_LOG` goes to the terminal if run from it, or check the log file):
|
|
||||||
- `stat_log ...` lines appear (the `EVT_MEDIA_CTRL_STAT` path is live — proves the Bambu C API dlsym worked from `libBambuSource.dylib`);
|
|
||||||
- no repeated decode/error messages like `AVVideoDecoder: ...` or `can not find function ...` (proves `StaticBambuLib::get` resolved all Bambu functions);
|
|
||||||
- Stop/Play toggle works; idle image reappears on stop;
|
|
||||||
- window resize keeps aspect ratio (exercises `DoSetSize`/`adjust_frame_size`/`paintEvent`).
|
|
||||||
|
|
||||||
- [ ] **Step 4: Confirm the old player is really gone**
|
|
||||||
|
|
||||||
Expected: nothing in the logs references `BambuPlayer` (the ObjC class is no longer dlsym'd); the video path is entirely `wxMediaCtrl3` + `AVVideoDecoder`.
|
|
||||||
|
|
||||||
If a printer is unavailable, at minimum verify Steps 1–2 (launch + idle image) and note in the PR that live-stream verification needs hardware.
|
|
||||||
|
|
||||||
- [ ] **Step 5: Final review pass**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git log --oneline -6
|
|
||||||
git show --stat HEAD # and each of the three task commits
|
|
||||||
```
|
|
||||||
|
|
||||||
Expected: the last 4 commits are the design doc + the 3 implementation tasks (each task commit touches only its listed files). Review the diff for scope: no Linux/Windows changes beyond the two `EVT_MEDIA_CTRL_STAT` lines in Task 1, no `StatusPanel`/`MediaPlayCtrl` changes.
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
# Move `wxInspectable` into `DPIAware` — Design Spec
|
|
||||||
|
|
||||||
Date: 2026-07-23
|
|
||||||
Branch: `dev/layout-inspector`
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Move the `wxInspector::wxInspectable` base class from individual leaf classes (`DPIDialog`, `MainFrame`) into the common `DPIAware<P>` template. This makes every DPIAware widget automatically visible in the inspector tree without requiring each subclass to opt in.
|
|
||||||
|
|
||||||
## Motivation
|
|
||||||
|
|
||||||
Currently, only `DPIDialog` and `MainFrame` explicitly inherit `wxInspectable`. `DPIFrame` (which `MainFrame` inherits from) does not — `MainFrame` adds it manually. This means:
|
|
||||||
|
|
||||||
- Any `DPIAware<T>` widget that isn't `DPIDialog` or `MainFrame` is invisible in the inspector tree
|
|
||||||
- `DPIFrame` subclasses (`BaseTransparentDPIFrame`, `ImageDPIFrame`, `ModelMallDialog`, `MediaFileFrame`, `SecondaryCheckDialog`, `PrintErrorDialog`, etc.) don't appear
|
|
||||||
- Adding a new DPIAware widget type requires remembering to also inherit `wxInspectable`
|
|
||||||
|
|
||||||
Moving `wxInspectable` to `DPIAware` fixes this for all current and future DPIAware widgets at once.
|
|
||||||
|
|
||||||
## Design
|
|
||||||
|
|
||||||
### Change 1: `GUI_Utils.hpp` — `DPIAware<P>`
|
|
||||||
|
|
||||||
Add `wxInspector::wxInspectable` as a second base class, and call `SetupInspectorAccelerator(this)` in the constructor (after `this->CenterOnParent()`):
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// Before:
|
|
||||||
template<class P> class DPIAware : public P
|
|
||||||
|
|
||||||
// After:
|
|
||||||
template<class P> class DPIAware : public P, public wxInspector::wxInspectable
|
|
||||||
```
|
|
||||||
|
|
||||||
Add in the constructor body (after `this->CenterOnParent()` at line 110):
|
|
||||||
```cpp
|
|
||||||
SetupInspectorAccelerator(this);
|
|
||||||
```
|
|
||||||
|
|
||||||
This gives every `DPIAware<T>` widget both inspectability and the Ctrl+Shift+I keyboard shortcut automatically. `#include <wx/inspector/inspector.h>` is already present in the file.
|
|
||||||
|
|
||||||
### Change 2: `GUI_Utils.hpp` — `DPIDialog`
|
|
||||||
|
|
||||||
Remove the now-redundant `wxInspector::wxInspectable` and the `SetupInspectorAccelerator(this)` call:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// Before:
|
|
||||||
class DPIDialog : public DPIAware<wxDialog>, public wxInspector::wxInspectable
|
|
||||||
// ...
|
|
||||||
SetupInspectorAccelerator(this);
|
|
||||||
|
|
||||||
// After:
|
|
||||||
class DPIDialog : public DPIAware<wxDialog>
|
|
||||||
// (SetupInspectorAccelerator call removed — now done in DPIAware constructor)
|
|
||||||
```
|
|
||||||
|
|
||||||
`DPIDialog` gets `wxInspectable` and the accelerator through `DPIAware<wxDialog>` now.
|
|
||||||
|
|
||||||
### Change 3: `MainFrame.hpp` — `MainFrame`
|
|
||||||
|
|
||||||
Remove the now-redundant `wxInspector::wxInspectable`:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// Before:
|
|
||||||
class MainFrame : public DPIFrame, public wxInspector::wxInspectable
|
|
||||||
|
|
||||||
// After:
|
|
||||||
class MainFrame : public DPIFrame
|
|
||||||
```
|
|
||||||
|
|
||||||
`MainFrame` gets `wxInspectable` through `DPIFrame` → `DPIAware<wxFrame>`.
|
|
||||||
|
|
||||||
### Change 4: `MainFrame.cpp` — `MainFrame` constructor
|
|
||||||
|
|
||||||
Remove the now-redundant `SetupInspectorAccelerator(this)` call (line 304). It will be called automatically by the `DPIAware` constructor.
|
|
||||||
|
|
||||||
## Impact
|
|
||||||
|
|
||||||
| Widget | Before | After |
|
|
||||||
|--------|--------|-------|
|
|
||||||
| `DPIDialog` subclasses (~80) | ✓ inspectable | ✓ inspectable (transitive) |
|
|
||||||
| `MainFrame` | ✓ inspectable | ✓ inspectable (transitive) |
|
|
||||||
| `DPIFrame` subclasses (8 others) | ✗ invisible | ✓ inspectable |
|
|
||||||
| Future `DPIAware<T>` | ✗ invisible | ✓ inspectable |
|
|
||||||
|
|
||||||
## Files Modified
|
|
||||||
|
|
||||||
| File | Change |
|
|
||||||
|------|--------|
|
|
||||||
| `src/slic3r/GUI/GUI_Utils.hpp` | `DPIAware<P>` gains `wxInspector::wxInspectable` + `SetupInspectorAccelerator(this)` call; `DPIDialog` drops redundant `wxInspector::wxInspectable` and `SetupInspectorAccelerator(this)` |
|
|
||||||
| `src/slic3r/GUI/MainFrame.hpp` | `MainFrame` drops redundant `wxInspector::wxInspectable` |
|
|
||||||
| `src/slic3r/GUI/MainFrame.cpp` | Remove redundant `SetupInspectorAccelerator(this)` from MainFrame constructor |
|
|
||||||
|
|
||||||
## Non-Goals
|
|
||||||
|
|
||||||
- The `DPIAwarePlugin` detection logic (`dynamic_cast<DPIFrame*>` / `dynamic_cast<DPIDialog*>`) is unchanged
|
|
||||||
- No new DPI properties — this is purely about tree visibility and accelerator setup
|
|
||||||
|
|
||||||
## Risk Assessment
|
|
||||||
|
|
||||||
- **Multiple inheritance**: `DPIAware<P>` already has a vtable (virtual destructor). Adding `wxInspectable` adds a second base but no additional data members. The `wxInspector::wxInspectable` class is expected to be a lightweight marker interface.
|
|
||||||
- **Build**: No new includes needed; `<wx/inspector/inspector.h>` is already included in `GUI_Utils.hpp`.
|
|
||||||
- **Cross-platform**: The change is standard C++ multiple inheritance — no platform-specific concerns.
|
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
# wxInspector Plugins for OrcaSlicer Custom Controls — Design Spec
|
|
||||||
|
|
||||||
Date: 2026-07-23
|
|
||||||
Branch: `dev/layout-inspector`
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Create wxInspector plugins that expose OrcaSlicer's custom widget properties in the inspector's property grid. Without these plugins, the inspector shows only generic wxWidgets properties — missing all DPI-awareness data, custom styling, and Orca-specific control state.
|
|
||||||
|
|
||||||
## Goals
|
|
||||||
|
|
||||||
1. **DPIAware properties** — Inspect and update `scale_factor`, `prev_scale_factor`, `em_unit`, and `normal_font` on any DPIAware-derived widget
|
|
||||||
2. **Custom widget properties** — Surface Orca-specific properties on `Button`, `CheckBox`, `TextInput`, `SwitchButton`, `ProgressBar`, `Label`, and `LabeledStaticBox`
|
|
||||||
3. **Minimal source changes** — Only add trivial (one-line) getters/setters to existing classes; no architectural refactoring of Orca's widget hierarchy
|
|
||||||
|
|
||||||
## Non-Goals
|
|
||||||
|
|
||||||
- Custom inspector panels or AUI tabs (use the existing property grid and method invoker)
|
|
||||||
- Python-plugin integration (this is C++ wxInspector, not Orca's Python plugin system)
|
|
||||||
- Event logging customization (the built-in event logger already works)
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
### Two Plugins
|
|
||||||
|
|
||||||
| Plugin | Class | Files |
|
|
||||||
|--------|-------|-------|
|
|
||||||
| DPIAware plugin | `DPIAwarePlugin` | `DPIAwarePlugin.hpp`, `DPIAwarePlugin.cpp` |
|
|
||||||
| Custom widgets plugin | `CustomWidgetsPlugin` | `CustomWidgetsPlugin.hpp`, `CustomWidgetsPlugin.cpp` |
|
|
||||||
| Registration helper | inline function | `Registration.hpp` |
|
|
||||||
|
|
||||||
All files live under `src/slic3r/Utils/wxInspectorPlugins/`.
|
|
||||||
|
|
||||||
### Plugin Detection Strategy
|
|
||||||
|
|
||||||
**DPIAware plugin**: Uses `dynamic_cast<DPIFrame*>` and `dynamic_cast<DPIDialog*>` as detection gates. `DPIFrame` = `DPIAware<wxFrame>`, `DPIDialog` = `DPIAware<wxDialog>`. Since these are concrete typedefs, `dynamic_cast` works at runtime. This covers `MainFrame`, `SettingsDialog`, and all 8 calibration dialogs (which inherit `DPIDialog`).
|
|
||||||
|
|
||||||
**Custom widgets plugin**: Gates broadly on `CLASSINFO(wxWindow)`, then uses per-type `dynamic_cast` inside `GetProperties` to check each Orca-specific type. Only matching types append properties.
|
|
||||||
|
|
||||||
### Registration
|
|
||||||
|
|
||||||
A single `RegisterOrcaInspectorPlugins()` inline function in `Registration.hpp` creates both plugins as function-local statics (matching the wxInspector built-in provider pattern) and registers them via `wxInspector::RegisterPlugin()`.
|
|
||||||
|
|
||||||
Called once from `MainFrame::MainFrame()` after `SetupInspectorAccelerator(this)`.
|
|
||||||
|
|
||||||
### Why Separate Plugins?
|
|
||||||
|
|
||||||
- DPIAware is a C++ template concept (not a wxClassInfo-isKindOf check), so it needs its own detection logic
|
|
||||||
- Custom widgets use standard wxClassInfo-based detection, matching the built-in provider pattern
|
|
||||||
- Two focused files are easier to review and maintain than one monolithic plugin
|
|
||||||
- Compile-time failure isolation: if a widget header changes, only one plugin breaks
|
|
||||||
|
|
||||||
## DPIAware Plugin — Property Specification
|
|
||||||
|
|
||||||
### Source Changes (GUI_Utils.hpp)
|
|
||||||
|
|
||||||
Four one-liner methods added to the `DPIAware<P>` template class (public section):
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
float scale_factor() const { return m_scale_factor; } // already exists
|
|
||||||
float prev_scale_factor() const { return m_prev_scale_factor; } // already exists
|
|
||||||
int em_unit() const { return m_em_unit; } // already exists
|
|
||||||
void set_scale_factor(float v) { m_scale_factor = v; } // NEW
|
|
||||||
void set_prev_scale_factor(float v) { m_prev_scale_factor = v; } // NEW
|
|
||||||
void set_em_unit(int v) { m_em_unit = v; } // NEW
|
|
||||||
bool force_rescale() const { return m_force_rescale; } // NEW
|
|
||||||
// m_normal_font getter already exists: normal_font()
|
|
||||||
```
|
|
||||||
|
|
||||||
### Detection
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
bool CanProvideProperties(wxClassInfo* info) override {
|
|
||||||
// Gated in GetProperties via dynamic_cast on the window itself
|
|
||||||
return info->IsKindOf(CLASSINFO(wxWindow));
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
In `GetProperties`:
|
|
||||||
```cpp
|
|
||||||
auto* win = obj.AsWindow();
|
|
||||||
bool isDPI = dynamic_cast<DPIFrame*>(win) || dynamic_cast<DPIDialog*>(win);
|
|
||||||
if (!isDPI) return props;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Property Table (category: "DPI Scaling")
|
|
||||||
|
|
||||||
| Name | Type | Editable | Getter | Setter |
|
|
||||||
|------|------|----------|--------|--------|
|
|
||||||
| Scale Factor | String (float) | Yes | `dpi->scale_factor()` | `dpi->set_scale_factor(v)` |
|
|
||||||
| Prev Scale Factor | String (float) | Yes | `dpi->prev_scale_factor()` | `dpi->set_prev_scale_factor(v)` |
|
|
||||||
| EM Unit | Integer | Yes | `dpi->em_unit()` | `dpi->set_em_unit(v)` |
|
|
||||||
| Normal Font | ReadOnly | No | `dpi->normal_font().GetNativeFontInfoDesc()` | — |
|
|
||||||
| Force Rescale | Boolean (ReadOnly) | No | `dpi->force_rescale()` | — |
|
|
||||||
|
|
||||||
**Note on setters**: The setters simply store values. They do NOT trigger a widget rescale/layout. To see the effect of a changed scale factor, use the inspector's Methods panel to call `Layout()` or resize the window — which triggers the DPI_CHANGED event path naturally.
|
|
||||||
|
|
||||||
## Custom Widgets Plugin — Property Specification
|
|
||||||
|
|
||||||
All properties are appended to the built-in wxWindow properties. Each widget type is independently detected via `dynamic_cast`.
|
|
||||||
|
|
||||||
### Detection gates (in `GetProperties`)
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
auto* win = obj.AsWindow();
|
|
||||||
if (auto* btn = dynamic_cast<Button*>(win)) { addButtonProperties(btn, props); }
|
|
||||||
if (auto* cb = dynamic_cast<CheckBox*>(win)) { addCheckBoxProperties(cb, props); }
|
|
||||||
if (auto* ti = dynamic_cast<TextInput*>(win)) { addTextInputProperties(ti, props); }
|
|
||||||
if (auto* sb = dynamic_cast<SwitchButton*>(win)) { addSwitchButtonProperties(sb, props); }
|
|
||||||
if (auto* pb = dynamic_cast<ProgressBar*>(win)) { addProgressBarProperties(pb, props); }
|
|
||||||
if (auto* lbl = dynamic_cast<Label*>(win)) { addLabelProperties(lbl, props); }
|
|
||||||
if (auto* lsb = dynamic_cast<LabeledStaticBox*>(win)) { addLabeledStaticBoxProperties(lsb, props); }
|
|
||||||
```
|
|
||||||
|
|
||||||
### Orca Button (`Button`) — category: "Orca Button"
|
|
||||||
|
|
||||||
| Name | Type | Editable | Getter | Setter |
|
|
||||||
|------|------|----------|--------|--------|
|
|
||||||
| Button Style | Choice | Yes | enum→string | string→enum |
|
|
||||||
| Button Type | Choice | Yes | enum→string | string→enum |
|
|
||||||
| Selected | Boolean | Yes | `m_selected` (needs getter) | `SetSelected(v)` |
|
|
||||||
| Active Icon | ReadOnly | No | icon name string | — |
|
|
||||||
| Inactive Icon | ReadOnly | No | icon name string | — |
|
|
||||||
|
|
||||||
Choices for Button Style: `Regular`, `Confirm`, `Alert`, `Disabled`
|
|
||||||
Choices for Button Type: `Compact`, `Window`, `Choice`, `Parameter`, `Icon`, `Expanded`
|
|
||||||
|
|
||||||
**Source changes needed**: Button's `m_selected` is private. Add one-liner getter:
|
|
||||||
```cpp
|
|
||||||
bool IsSelected() const { return m_selected; }
|
|
||||||
```
|
|
||||||
|
|
||||||
### Orca CheckBox (`CheckBox`) — category: "Orca CheckBox"
|
|
||||||
|
|
||||||
| Name | Type | Editable | Getter | Setter |
|
|
||||||
|------|------|----------|--------|--------|
|
|
||||||
| Half Checked | Boolean | Yes | `m_half_checked` (needs getter) | `SetHalfChecked(v)` |
|
|
||||||
|
|
||||||
**Source changes needed**: `m_half_checked` is private. Add one-liner getter:
|
|
||||||
```cpp
|
|
||||||
bool IsHalfChecked() const { return m_half_checked; }
|
|
||||||
```
|
|
||||||
|
|
||||||
### Orca TextInput (`TextInput`) — category: "Orca TextInput"
|
|
||||||
|
|
||||||
| Name | Type | Editable | Getter | Setter |
|
|
||||||
|------|------|----------|--------|--------|
|
|
||||||
| Label | String | Yes | `GetLabel()` (inherited from wxWindow) | `SetLabel(v)` (exists) |
|
|
||||||
| Text Value | String | Yes | `GetTextCtrl()->GetValue()` (GetTextCtrl is public) | `GetTextCtrl()->SetValue(v)` |
|
|
||||||
| Corner Radius | Integer | Yes | `GetCornerRadius()` (NEW) | `SetCornerRadius(v)` (exists) |
|
|
||||||
|
|
||||||
**Source changes needed**: Add one getter to `TextInput`:
|
|
||||||
```cpp
|
|
||||||
int GetCornerRadius() const { return static_cast<int>(radius); }
|
|
||||||
```
|
|
||||||
(`radius` is inherited from StaticBox. `SetCornerRadius(double)` already exists. `GetTextCtrl()` is already public.)
|
|
||||||
|
|
||||||
### Orca SwitchButton (`SwitchButton`) — category: "Orca SwitchButton"
|
|
||||||
|
|
||||||
| Name | Type | Editable | Getter | Setter |
|
|
||||||
|------|------|----------|--------|--------|
|
|
||||||
| Value | Boolean | Yes | existing getter | existing setter |
|
|
||||||
|
|
||||||
### Orca ProgressBar (`ProgressBar`) — category: "Orca ProgressBar"
|
|
||||||
|
|
||||||
| Name | Type | Editable | Getter | Setter |
|
|
||||||
|------|------|----------|--------|--------|
|
|
||||||
| Proportion | Float (0-1) | Yes | `pb->m_proportion` (public member) | `pb->m_proportion = v` |
|
|
||||||
| Show Number | Boolean | Yes | `pb->m_shownumber` (public member) | `pb->m_shownumber = v` |
|
|
||||||
|
|
||||||
**No source changes needed**: `m_proportion` and `m_shownumber` are already public members. `SetValue(int)` and `SetProgress(int)` already exist as public methods.
|
|
||||||
|
|
||||||
### Orca Label (`Label`) — category: "Orca Label"
|
|
||||||
|
|
||||||
| Name | Type | Editable | Getter | Setter |
|
|
||||||
|------|------|----------|--------|--------|
|
|
||||||
| Is Hyperlink | Boolean | No | existing flag check | — |
|
|
||||||
| Font Size | ReadOnly | No | `GetFont().GetPointSize()` | — |
|
|
||||||
|
|
||||||
### LabeledStaticBox — category: "LabeledStaticBox"
|
|
||||||
|
|
||||||
| Name | Type | Editable | Getter | Setter |
|
|
||||||
|------|------|----------|--------|--------|
|
|
||||||
| Corner Radius | Integer | Yes | `GetCornerRadius()` (NEW) | `SetCornerRadius(v)` (exists) |
|
|
||||||
| Border Width | Integer | Yes | `GetBorderWidth()` (NEW) | `SetBorderWidth(v)` (exists) |
|
|
||||||
| Border Color | String (hex) | Yes | `GetBorderColor()` (NEW) | `SetBorderColor(v)` (exists) |
|
|
||||||
| Scale | Float (ReadOnly) | No | `m_scale` (protected, needs getter) | — |
|
|
||||||
|
|
||||||
**Source changes needed**: Four one-liner getters added to `LabeledStaticBox`:
|
|
||||||
```cpp
|
|
||||||
int GetCornerRadius() const { return m_radius; }
|
|
||||||
int GetBorderWidth() const { return m_border_width; }
|
|
||||||
StateColor GetBorderColor() const { return border_color; }
|
|
||||||
float GetScale() const { return m_scale; }
|
|
||||||
```
|
|
||||||
|
|
||||||
## Files Modified (Existing Code)
|
|
||||||
|
|
||||||
| File | Changes |
|
|
||||||
|------|---------|
|
|
||||||
| `src/slic3r/GUI/GUI_Utils.hpp` | +4 methods in `DPIAware<P>`: `set_scale_factor()`, `set_prev_scale_factor()`, `set_em_unit()`, `force_rescale()` |
|
|
||||||
| `src/slic3r/GUI/Widgets/LabeledStaticBox.hpp` | +4 getter declarations: `GetCornerRadius()`, `GetBorderWidth()`, `GetBorderColor()`, `GetScale()` |
|
|
||||||
| `src/slic3r/GUI/Widgets/LabeledStaticBox.cpp` | +4 getter implementations |
|
|
||||||
| `src/slic3r/GUI/Widgets/Button.hpp` | +1 getter: `IsSelected()` |
|
|
||||||
| `src/slic3r/GUI/Widgets/CheckBox.hpp` | +1 getter: `IsHalfChecked()` |
|
|
||||||
| `src/slic3r/GUI/Widgets/TextInput.hpp` | +1 getter: `GetCornerRadius()` |
|
|
||||||
| `src/slic3r/GUI/Widgets/ProgressBar.hpp` | None (public members are used directly) |
|
|
||||||
| `src/slic3r/GUI/MainFrame.cpp` | +1 `#include`, +1 call to `RegisterOrcaInspectorPlugins()` |
|
|
||||||
| `src/slic3r/CMakeLists.txt` | +4 entries in `SLIC3R_GUI_SOURCES` (the .cpp plugin files) |
|
|
||||||
|
|
||||||
## Files Created
|
|
||||||
|
|
||||||
```
|
|
||||||
src/slic3r/Utils/wxInspectorPlugins/
|
|
||||||
├── DPIAwarePlugin.hpp
|
|
||||||
├── DPIAwarePlugin.cpp
|
|
||||||
├── CustomWidgetsPlugin.hpp
|
|
||||||
├── CustomWidgetsPlugin.cpp
|
|
||||||
└── Registration.hpp
|
|
||||||
```
|
|
||||||
|
|
||||||
## Build & Linking
|
|
||||||
|
|
||||||
The `wxInspector` dependency is already wired:
|
|
||||||
- `deps/wxInspector/wxInspector.cmake` fetches and builds wxInspector
|
|
||||||
- `src/CMakeLists.txt` lines 92-93 link `wxInspector::wxInspector` into `wxWidgets_LIBRARIES`
|
|
||||||
- The plugin files only need `#include <wx/inspector/plugin.h>` and `#include <wx/inspector/inspector.h>` — both available from the installed dependency
|
|
||||||
|
|
||||||
No new CMake dependencies needed. Only the new source files need listing in `SLIC3R_GUI_SOURCES`.
|
|
||||||
|
|
||||||
## Error Handling & Edge Cases
|
|
||||||
|
|
||||||
- **Stale pointers**: Plugin lambdas capture raw pointers, regenerated on every `GetProperties` call (matching wxInspector's built-in provider pattern). Pointers live only until the next tree selection.
|
|
||||||
- **Widget destruction**: If a widget is destroyed while the inspector is showing its properties, `InspectableObject::IsValid()` returns false and properties are not displayed. The inspector won't show stale data.
|
|
||||||
- **Invalid property values**: Setters use `sscanf` / `ToLong` with validation (matching built-in patterns). Bogus input is rejected — setter returns `false`, property grid shows error state.
|
|
||||||
- **DPI drift**: Setting `scale_factor` without triggering rescale means displayed sizes don't match the new factor. This is acceptable — the inspector is a developer tool; operators know to call `Layout()` after making changes.
|
|
||||||
- **Missing widget type**: If a `dynamic_cast` fails for all types, only built-in wxWindow properties are shown. No crash, no error — just reduced info.
|
|
||||||
|
|
||||||
## Future Work (Out of Scope)
|
|
||||||
|
|
||||||
- **StateColor visualization**: `StateColor` is a multi-value type (maps bitmask states to colors). A full solution would need a custom property editor (e.g., a table showing each state→color pair). Keep it simple for now.
|
|
||||||
- **ScalableBitmap display**: Could show the bitmap as an inline thumbnail. Complex property editor work — deferred.
|
|
||||||
- **More widget types**: `SwitchBoard`, `MultiSwitchButton`, `StepCtrl`, `FanControl`, `DropDown`, `ComboBox`, `AMS*` widgets could all benefit. Add as needed.
|
|
||||||
- **Property refresh on tree selection**: Currently properties are static snapshots. A "refresh" button or auto-poll could keep values current for rapidly-changing widgets (progress bars, etc.). The built-in wxInspector already provides a tree-refresh button.
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
# FFmpeg Media Player for macOS — Design
|
|
||||||
|
|
||||||
Date: 2026-08-14
|
|
||||||
Branch: `dev/ffmpeg-player-macos`
|
|
||||||
|
|
||||||
## Problem
|
|
||||||
|
|
||||||
The branch's new FFmpeg-based media player (`wxMediaCtrl3` + `AVVideoDecoder`) is used on
|
|
||||||
Windows and Linux, but macOS still runs the old player: `wxMediaCtrl2.mm`, an ObjC
|
|
||||||
`BambuPlayer` class dlsym'd from the Bambu network plugin that renders via CALayer.
|
|
||||||
On macOS, `wxMediaCtrl3` is currently aliased to `wxMediaCtrl2` and FFmpeg is not linked
|
|
||||||
into the app at all.
|
|
||||||
|
|
||||||
Goal: make macOS use the same FFmpeg player as Windows/Linux, linking the **static**
|
|
||||||
FFmpeg libraries from the deps build instead of dynamic ones.
|
|
||||||
|
|
||||||
## Current state (verified)
|
|
||||||
|
|
||||||
- New player (Win/Linux): `GUI/wxMediaCtrl3.cpp` + `GUI/AVVideoDecoder.cpp`. Decodes with
|
|
||||||
FFmpeg (libavcodec/libswscale/libavutil), renders frames into `wxImage` (non-Windows) /
|
|
||||||
`wxBitmap` (Windows) drawn in a `paintEvent`, feeds via the `Bambu_*` C API
|
|
||||||
(`BambuTunnel.h`, `BAMBU_DYNAMIC`) dlsym'd from the network plugin through
|
|
||||||
`StaticBambuLib::get()` (`GUI/Printer/PrinterFileSystem.cpp`, compiled on all platforms).
|
|
||||||
- Old player (macOS): `GUI/wxMediaCtrl2.mm` uses the ObjC `BambuPlayer` class found via
|
|
||||||
`dlsym(module, "OBJC_CLASS_$_BambuPlayer")` in `libBambuSource.dylib`.
|
|
||||||
- The macOS network plugin `libBambuSource.dylib` already exports the full Bambu C API
|
|
||||||
(verified with `nm`), so the new player needs zero plugin changes.
|
|
||||||
- FFmpeg linking in `src/slic3r/CMakeLists.txt` is guarded by `if (NOT APPLE)` —
|
|
||||||
macOS currently does not link FFmpeg.
|
|
||||||
- `deps/FFMPEG/FFMPEG.cmake`: non-MSVC branch builds FFmpeg from source with
|
|
||||||
`--enable-shared`. The existing arm64 deps build on the dev machine happened to be
|
|
||||||
configured with both static and shared enabled, so `libavcodec.a` / `libswscale.a` /
|
|
||||||
`libavutil.a` are already present at
|
|
||||||
`deps/build/arm64/OrcaSlicer_dep/usr/local/lib/`.
|
|
||||||
- `EVT_MEDIA_CTRL_STAT` is `wxDEFINE_EVENT`'d in `wxMediaCtrl2.cpp` (Win/Linux) and
|
|
||||||
`wxMediaCtrl2.mm` (macOS); the define in `wxMediaCtrl3.cpp` is commented out.
|
|
||||||
- `wxMediaCtrl2` is never instantiated anywhere on any platform — dead code.
|
|
||||||
- `StatusPanel` already creates `wxMediaCtrl3`; `MediaPlayCtrl` only uses the
|
|
||||||
`wxMediaCtrl3` interface (`Load/Play/Stop/GetState/GetVideoSize/GetLastError/SetIdleImage`),
|
|
||||||
so no UI-side changes are needed.
|
|
||||||
|
|
||||||
## Approach (approved)
|
|
||||||
|
|
||||||
**Reuse the shared player on macOS.** Compile the existing `wxMediaCtrl3.cpp` +
|
|
||||||
`AVVideoDecoder.cpp` on macOS so all three platforms run one implementation.
|
|
||||||
Rendering uses the existing `wxImage` → `DrawBitmap` paint path, identical to Linux.
|
|
||||||
Known trade-off: frames are scaled to the widget's logical (1x) size, so Retina is
|
|
||||||
slightly soft compared to the old CALayer player. Accepted for now; a Retina-aware
|
|
||||||
scaling follow-up is possible later.
|
|
||||||
|
|
||||||
Rejected alternative: a native CGImage/CALayer renderer for macOS — faster and
|
|
||||||
Retina-crisp, but adds a second render implementation to maintain.
|
|
||||||
|
|
||||||
## Changes
|
|
||||||
|
|
||||||
### 1. Enable the FFmpeg player on macOS (source)
|
|
||||||
|
|
||||||
- `GUI/wxMediaCtrl3.h`: remove the `#ifdef __WXMAC__` branch (lines 18–22) that aliases
|
|
||||||
`wxMediaCtrl3` → `wxMediaCtrl2`. macOS then compiles the real `wxMediaCtrl3` class,
|
|
||||||
including the `BAMBU_DYNAMIC` BambuTunnel path used on Linux.
|
|
||||||
- Event symbol fix: move `wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent)` into
|
|
||||||
`wxMediaCtrl3.cpp` (uncomment the existing line) and remove it from
|
|
||||||
`wxMediaCtrl2.cpp`. One definition total in the lib; all three platforms resolve it.
|
|
||||||
|
|
||||||
### 2. Static FFmpeg linking (deps + app)
|
|
||||||
|
|
||||||
- `deps/FFMPEG/FFMPEG.cmake`: in the non-MSVC branch, pass
|
|
||||||
`--disable-shared --enable-static` when `APPLE`. Linux keeps `--enable-shared`;
|
|
||||||
Windows keeps its prebuilt shared DLL zips. Fresh macOS deps builds install only
|
|
||||||
`libavcodec.a` / `libswscale.a` / `libavutil.a` — no dylibs to bundle, no
|
|
||||||
rpath/install_name handling. (The existing local arm64 deps build already contains
|
|
||||||
the `.a` files, so no deps rebuild is strictly needed to try the change locally,
|
|
||||||
but a fresh CI deps build must produce them.)
|
|
||||||
- `src/slic3r/CMakeLists.txt`:
|
|
||||||
- APPLE branch of `SLIC3R_GUI_SOURCES`: add `GUI/wxMediaCtrl3.cpp`,
|
|
||||||
`GUI/wxMediaCtrl3.h`, `GUI/AVVideoDecoder.cpp`, `GUI/AVVideoDecoder.hpp`;
|
|
||||||
remove `GUI/wxMediaCtrl2.mm` and `GUI/wxMediaCtrl2.h` (the `.h` stays on
|
|
||||||
disk for the Win/Linux build of `wxMediaCtrl2.cpp`, but nothing on macOS
|
|
||||||
includes it after this change).
|
|
||||||
- Add an APPLE mirror of the `NOT APPLE` FFmpeg block: `find_library` for
|
|
||||||
`libavcodec.a`, `libswscale.a`, `libavutil.a` under `${CMAKE_PREFIX_PATH}/lib`
|
|
||||||
with `NO_DEFAULT_PATH`, link them (order avcodec → swscale → avutil), and add
|
|
||||||
`${CMAKE_PREFIX_PATH}/include` as a SYSTEM include directory. Deps are built with
|
|
||||||
`--disable-zlib` and no external codecs, so the three static libs link cleanly.
|
|
||||||
|
|
||||||
### 3. Remove the old player
|
|
||||||
|
|
||||||
- Delete `GUI/wxMediaCtrl2.mm` and `GUI/BambuPlayer/BambuPlayer.h` (header used only
|
|
||||||
by the `.mm`; the real `BambuPlayer` lives inside the network plugin).
|
|
||||||
- Remove the now-dead `__WXMAC__` section of `GUI/wxMediaCtrl2.h`.
|
|
||||||
- `wxMediaCtrl2.cpp` (Win/Linux) stays in the build as-is (dead but harmless; out of
|
|
||||||
scope to remove on this branch).
|
|
||||||
|
|
||||||
### 4. Verification
|
|
||||||
|
|
||||||
- Build on macOS: `cmake --build build_arm64` (or `build/arm64`).
|
|
||||||
- Confirm no dynamic FFmpeg dependency: `otool -L` on the app binary shows no `libav*`
|
|
||||||
dylib references.
|
|
||||||
- Runtime: with the network plugin loaded, the Device tab camera preview streams via
|
|
||||||
the FFmpeg player (check the device page / `MediaPlayCtrl`).
|
|
||||||
- macOS `ctest` still passes — static linking means no test-executable `.so` copying
|
|
||||||
hacks (unlike the Linux shared-lib setup).
|
|
||||||
|
|
||||||
## Out of scope
|
|
||||||
|
|
||||||
- Linux (shared libs, AppImage/flatpak bundling) and Windows (prebuilt DLL zips)
|
|
||||||
keep their current FFmpeg setup.
|
|
||||||
- Retina-aware frame scaling / native CGImage rendering (follow-up if visual quality
|
|
||||||
is judged insufficient).
|
|
||||||
- Audio streaming (neither player plays audio in this UI path).
|
|
||||||
1
resources/images/param_spiralinset.svg
Normal file
1
resources/images/param_spiralinset.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12.00,12.00 L12.00,11.96 L12.01,11.92 L12.03,11.89 L12.05,11.85 L12.08,11.82 L12.12,11.80 L12.16,11.78 L12.20,11.76 L12.25,11.75 L12.30,11.75 L12.35,11.75 L12.40,11.77 L12.46,11.79 L12.51,11.81 L12.56,11.85 L12.61,11.89 L12.66,11.94 L12.70,12.00 L12.74,12.06 L12.77,12.14 L12.79,12.21 L12.80,12.29 L12.81,12.38 L12.81,12.47 L12.80,12.56 L12.77,12.65 L12.74,12.74 L12.70,12.83 L12.65,12.92 L12.58,13.01 L12.51,13.09 L12.43,13.17 L12.33,13.24 L12.23,13.30 L12.12,13.36 L12.00,13.40 L11.87,13.43 L11.74,13.46 L11.61,13.46 L11.47,13.46 L11.33,13.45 L11.18,13.41 L11.04,13.37 L10.90,13.31 L10.76,13.24 L10.63,13.15 L10.50,13.05 L10.38,12.93 L10.27,12.81 L10.17,12.67 L10.08,12.51 L10.01,12.35 L9.95,12.18 L9.90,12.00 L9.87,11.81 L9.86,11.62 L9.86,11.43 L9.88,11.23 L9.92,11.03 L9.98,10.83 L10.06,10.64 L10.15,10.45 L10.27,10.27 L10.40,10.09 L10.55,9.93 L10.72,9.78 L10.90,9.64 L11.10,9.52 L11.31,9.41 L11.53,9.32 L11.76,9.25 L12.00,9.20 L12.25,9.17 L12.50,9.17 L12.75,9.18 L13.01,9.22 L13.27,9.29 L13.52,9.37 L13.76,9.48 L14.00,9.62 L14.23,9.77 L14.44,9.95 L14.64,10.15 L14.83,10.37 L15.00,10.60 L15.14,10.86 L15.27,11.12 L15.37,11.41 L15.45,11.70 L15.50,12.00 L15.53,12.31 L15.52,12.62 L15.49,12.94 L15.44,13.25 L15.35,13.56 L15.23,13.87 L15.09,14.16 L14.92,14.45 L14.72,14.72 L14.50,14.98 L14.25,15.22 L13.98,15.44 L13.69,15.63 L13.38,15.80 L13.06,15.94 L12.72,16.06 L12.36,16.15 L12.00,16.20 L11.63,16.22 L11.26,16.21 L10.88,16.17 L10.51,16.09 L10.14,15.98 L9.78,15.84 L9.43,15.66 L9.10,15.46 L8.78,15.22 L8.48,14.95 L8.21,14.65 L7.96,14.33 L7.74,13.99 L7.54,13.62 L7.38,13.24 L7.25,12.84 L7.16,12.42 L7.10,12.00 L7.08,11.57 L7.10,11.14 L7.15,10.70 L7.25,10.27 L7.38,9.85 L7.55,9.43 L7.76,9.03 L8.01,8.65 L8.29,8.29 L8.60,7.95 L8.94,7.64 L9.32,7.35 L9.72,7.10 L10.14,6.88 L10.58,6.70 L11.04,6.56 L11.52,6.46 L12.00,6.40 L12.49,6.38 L12.99,6.41 L13.48,6.48 L13.97,6.59 L14.45,6.75 L14.92,6.95 L15.37,7.19 L15.80,7.47 L16.21,7.79 L16.59,8.15 L16.94,8.54 L17.25,8.97 L17.53,9.42 L17.77,9.90 L17.97,10.40 L18.13,10.92 L18.24,11.45 L18.30,12.00 L18.31,12.55 L18.28,13.11 L18.20,13.66 L18.07,14.21 L17.89,14.74 L17.66,15.27 L17.38,15.77 L17.06,16.25 L16.70,16.70 L16.30,17.12 L15.86,17.51 L15.38,17.86 L14.88,18.17 L14.34,18.43 L13.78,18.65 L13.20,18.82 L12.61,18.93 L12.00,19.00 L11.39,19.01 L10.77,18.97 L10.16,18.87 L9.55,18.72 L8.96,18.52 L8.38,18.26 L7.83,17.96 L7.30,17.60 L6.80,17.20 L6.34,16.75 L5.92,16.26 L5.53,15.73 L5.20,15.17 L4.91,14.58 L4.68,13.96 L4.49,13.32 L4.37,12.67 L4.30,12.00 L4.29,11.33 L4.34,10.65 L4.45,9.98 L4.62,9.31 L4.85,8.66 L5.13,8.03 L5.47,7.43 L5.86,6.85 L6.31,6.31 L6.80,5.80 L7.34,5.34 L7.92,4.93 L8.53,4.56 L9.18,4.25 L9.86,4.00 L10.55,3.80 L11.27,3.67 L12.00,3.60" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/><rect x="1.5" y="1.5" width="21" height="21" rx="2" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
||||||
|
After Width: | Height: | Size: 2.9 KiB |
607
resources/printers/bambu_filament_ids.json
Normal file
607
resources/printers/bambu_filament_ids.json
Normal file
@@ -0,0 +1,607 @@
|
|||||||
|
{
|
||||||
|
"bambustudio_commit": "66e405477",
|
||||||
|
"filaments": {
|
||||||
|
"OF0UJcb6": {
|
||||||
|
"bambu_id": "GFG60",
|
||||||
|
"name": "PolyLite PETG",
|
||||||
|
"type": "PETG",
|
||||||
|
"vendor": "Polymaker"
|
||||||
|
},
|
||||||
|
"OF0wBGNx": {
|
||||||
|
"bambu_id": "GFB51",
|
||||||
|
"name": "Bambu ASA-CF",
|
||||||
|
"type": "ASA-CF",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OF1UNk9P": {
|
||||||
|
"bambu_id": "GFP97",
|
||||||
|
"name": "Generic PP",
|
||||||
|
"type": "PP",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OF2GCW1l": {
|
||||||
|
"bambu_id": "GFSNL08",
|
||||||
|
"name": "SUNLU PETG",
|
||||||
|
"type": "PETG",
|
||||||
|
"vendor": "SUNLU"
|
||||||
|
},
|
||||||
|
"OF2VFe4J": {
|
||||||
|
"bambu_id": "GFN04",
|
||||||
|
"name": "Bambu PAHT-CF",
|
||||||
|
"type": "PA-CF",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OF342jVN": {
|
||||||
|
"bambu_id": "GFA10",
|
||||||
|
"name": "Bambu PLA Tough+",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OF4RvVuU": {
|
||||||
|
"bambu_id": "GFT02",
|
||||||
|
"name": "Bambu PPS-CF",
|
||||||
|
"type": "PPS-CF",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OF54B0S0": {
|
||||||
|
"bambu_id": "GFN06",
|
||||||
|
"name": "Bambu PPA-CF",
|
||||||
|
"type": "PPA-CF",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OF5CgdDq": {
|
||||||
|
"bambu_id": "GFL00",
|
||||||
|
"name": "PolyLite PLA",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Polymaker"
|
||||||
|
},
|
||||||
|
"OF6rdQ6M": {
|
||||||
|
"bambu_id": "GFT98",
|
||||||
|
"name": "Generic PPS-CF",
|
||||||
|
"type": "PPS-CF",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OF74KeQR": {
|
||||||
|
"bambu_id": "GFR98",
|
||||||
|
"name": "Generic PHA",
|
||||||
|
"type": "PHA",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OF7lOgYF": {
|
||||||
|
"bambu_id": "GFG96",
|
||||||
|
"name": "Generic PETG HF",
|
||||||
|
"type": "PETG",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OF8Tlg47": {
|
||||||
|
"bambu_id": "GFN96",
|
||||||
|
"name": "Generic PPA-GF",
|
||||||
|
"type": "PPA-GF",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OF8tPByX": {
|
||||||
|
"bambu_id": "GFN97",
|
||||||
|
"name": "Generic PPA-CF",
|
||||||
|
"type": "PPA-CF",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OF9OlTWH": {
|
||||||
|
"bambu_id": "GFA07",
|
||||||
|
"name": "Bambu PLA Marble",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFAnyRUI": {
|
||||||
|
"bambu_id": "GFS02",
|
||||||
|
"name": "Bambu Support For PLA",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFBSW57R": {
|
||||||
|
"bambu_id": "GFA11",
|
||||||
|
"name": "Bambu PLA Aero",
|
||||||
|
"type": "PLA-AERO",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFBw6eEG": {
|
||||||
|
"bambu_id": "GFL05",
|
||||||
|
"name": "Overture Matte PLA",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Overture"
|
||||||
|
},
|
||||||
|
"OFCD8qiU": {
|
||||||
|
"bambu_id": "GFR99",
|
||||||
|
"name": "Generic EVA",
|
||||||
|
"type": "EVA",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFDGigEI": {
|
||||||
|
"bambu_id": "GFA13",
|
||||||
|
"name": "Bambu PLA Dynamic",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFDSrzZ8": {
|
||||||
|
"bambu_id": "GFL99",
|
||||||
|
"name": "Generic PLA",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFDvXujf": {
|
||||||
|
"bambu_id": "GFS99",
|
||||||
|
"name": "Generic PVA",
|
||||||
|
"type": "PVA",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFDxfPgH": {
|
||||||
|
"bambu_id": "GFA08",
|
||||||
|
"name": "Bambu PLA Sparkle",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFEGNJD4": {
|
||||||
|
"bambu_id": "GFA05",
|
||||||
|
"name": "Bambu PLA Silk",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFEkPBwx": {
|
||||||
|
"bambu_id": "GFA12",
|
||||||
|
"name": "Bambu PLA Glow",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFEswT5W": {
|
||||||
|
"bambu_id": "GFA50",
|
||||||
|
"name": "Bambu PLA-CF",
|
||||||
|
"type": "PLA-CF",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFFNYwWR": {
|
||||||
|
"bambu_id": "GFN03",
|
||||||
|
"name": "Bambu PA-CF",
|
||||||
|
"type": "PA-CF",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFFbSnCD": {
|
||||||
|
"bambu_id": "GFA17",
|
||||||
|
"name": "Bambu PLA Translucent",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFFvzqcd": {
|
||||||
|
"bambu_id": "GFG00",
|
||||||
|
"name": "Bambu PETG Basic",
|
||||||
|
"type": "PETG",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFHWSM21": {
|
||||||
|
"bambu_id": "GFL54",
|
||||||
|
"name": "Fiberon PET-CF",
|
||||||
|
"type": "PET-CF",
|
||||||
|
"vendor": "Polymaker"
|
||||||
|
},
|
||||||
|
"OFHa48An": {
|
||||||
|
"bambu_id": "GFT01",
|
||||||
|
"name": "Bambu PET-CF",
|
||||||
|
"type": "PET-CF",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFHmPYRy": {
|
||||||
|
"bambu_id": "GFSNL04",
|
||||||
|
"name": "SUNLU PLA+ 2.0",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "SUNLU"
|
||||||
|
},
|
||||||
|
"OFIBbYO5": {
|
||||||
|
"bambu_id": "GFU02",
|
||||||
|
"name": "Bambu TPU for AMS",
|
||||||
|
"type": "TPU-AMS",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFIfnzxC": {
|
||||||
|
"bambu_id": "GFS05",
|
||||||
|
"name": "Bambu Support For PLA/PETG",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFKhMPeX": {
|
||||||
|
"bambu_id": "GFC00",
|
||||||
|
"name": "Bambu PC",
|
||||||
|
"type": "PC",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFLJ8S6I": {
|
||||||
|
"bambu_id": "GFSNL07",
|
||||||
|
"name": "SUNLU Wood PLA",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "SUNLU"
|
||||||
|
},
|
||||||
|
"OFLPAxz3": {
|
||||||
|
"bambu_id": "GFB98",
|
||||||
|
"name": "Generic ASA",
|
||||||
|
"type": "ASA",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFLakOUI": {
|
||||||
|
"bambu_id": "GFC99",
|
||||||
|
"name": "Generic PC",
|
||||||
|
"type": "PC",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFMTK0UC": {
|
||||||
|
"bambu_id": "GFS03",
|
||||||
|
"name": "Bambu Support For PA/PET",
|
||||||
|
"type": "PA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFMUWNkp": {
|
||||||
|
"bambu_id": "GFSNL03",
|
||||||
|
"name": "SUNLU PLA+",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "SUNLU"
|
||||||
|
},
|
||||||
|
"OFMjtqTC": {
|
||||||
|
"bambu_id": "GFA16",
|
||||||
|
"name": "Bambu PLA Wood",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFNk8bxk": {
|
||||||
|
"bambu_id": "GFN08",
|
||||||
|
"name": "Bambu PA6-GF",
|
||||||
|
"type": "PA-GF",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFOvv91M": {
|
||||||
|
"bambu_id": "GFB60",
|
||||||
|
"name": "PolyLite ABS",
|
||||||
|
"type": "ABS",
|
||||||
|
"vendor": "Polymaker"
|
||||||
|
},
|
||||||
|
"OFPklMI1": {
|
||||||
|
"bambu_id": "GFP99",
|
||||||
|
"name": "Generic PE",
|
||||||
|
"type": "PE",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFQ3e56w": {
|
||||||
|
"bambu_id": "GFA15",
|
||||||
|
"name": "Bambu PLA Galaxy",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFQHiNJs": {
|
||||||
|
"bambu_id": "GFS01",
|
||||||
|
"name": "Bambu Support G",
|
||||||
|
"type": "PA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFQLcbps": {
|
||||||
|
"bambu_id": "GFN98",
|
||||||
|
"name": "Generic PA-CF",
|
||||||
|
"type": "PA-CF",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFS2tn6G": {
|
||||||
|
"bambu_id": "GFL53",
|
||||||
|
"name": "Fiberon PA612-CF",
|
||||||
|
"type": "PA",
|
||||||
|
"vendor": "Polymaker"
|
||||||
|
},
|
||||||
|
"OFTHDCqA": {
|
||||||
|
"bambu_id": "GFA19",
|
||||||
|
"name": "Bambu PLA Pure",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFTRZ8Y4": {
|
||||||
|
"bambu_id": "GFG50",
|
||||||
|
"name": "Bambu PETG-CF",
|
||||||
|
"type": "PETG-CF",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFUanySo": {
|
||||||
|
"bambu_id": "GFA06",
|
||||||
|
"name": "Bambu PLA Silk+",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFVCkX5w": {
|
||||||
|
"bambu_id": "GFU01",
|
||||||
|
"name": "Bambu TPU 95A",
|
||||||
|
"type": "TPU",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFW29a9R": {
|
||||||
|
"bambu_id": "GFL01",
|
||||||
|
"name": "PolyTerra PLA",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Polymaker"
|
||||||
|
},
|
||||||
|
"OFWbdGsC": {
|
||||||
|
"bambu_id": "GFL98",
|
||||||
|
"name": "Generic PLA-CF",
|
||||||
|
"type": "PLA-CF",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFX0ycRQ": {
|
||||||
|
"bambu_id": "GFL52",
|
||||||
|
"name": "Fiberon PA12-CF",
|
||||||
|
"type": "PA-CF",
|
||||||
|
"vendor": "Polymaker"
|
||||||
|
},
|
||||||
|
"OFXIbw5D": {
|
||||||
|
"bambu_id": "GFA01",
|
||||||
|
"name": "Bambu PLA Matte",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFXkm8q1": {
|
||||||
|
"bambu_id": "GFP96",
|
||||||
|
"name": "Generic PP-CF",
|
||||||
|
"type": "PP-CF",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFXzQ4yL": {
|
||||||
|
"bambu_id": "GFB02",
|
||||||
|
"name": "Bambu ASA-Aero",
|
||||||
|
"type": "ASA-AERO",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFY9muEs": {
|
||||||
|
"bambu_id": "GFB99",
|
||||||
|
"name": "Generic ABS",
|
||||||
|
"type": "ABS",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFYPdQJh": {
|
||||||
|
"bambu_id": "GFG99",
|
||||||
|
"name": "Generic PETG",
|
||||||
|
"type": "PETG",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFaQMgRH": {
|
||||||
|
"bambu_id": "GFA09",
|
||||||
|
"name": "Bambu PLA Tough",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFc3xdm9": {
|
||||||
|
"bambu_id": "GFL04",
|
||||||
|
"name": "Overture PLA",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Overture"
|
||||||
|
},
|
||||||
|
"OFcytyoA": {
|
||||||
|
"bambu_id": "GFL06",
|
||||||
|
"name": "Fiberon PETG-ESD",
|
||||||
|
"type": "PETG",
|
||||||
|
"vendor": "Polymaker"
|
||||||
|
},
|
||||||
|
"OFd0Fv0k": {
|
||||||
|
"bambu_id": "GFP98",
|
||||||
|
"name": "Generic PE-CF",
|
||||||
|
"type": "PE-CF",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFdyfQvU": {
|
||||||
|
"bambu_id": "GFG03",
|
||||||
|
"name": "Bambu PETG Matte",
|
||||||
|
"type": "PETG",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFesA6rF": {
|
||||||
|
"bambu_id": "GFL96",
|
||||||
|
"name": "Generic PLA Silk",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFf6mfQO": {
|
||||||
|
"bambu_id": "GFS06",
|
||||||
|
"name": "Bambu Support for ABS",
|
||||||
|
"type": "ABS",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFfBpSRI": {
|
||||||
|
"bambu_id": "GFB01",
|
||||||
|
"name": "Bambu ASA",
|
||||||
|
"type": "ASA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFg57Nmc": {
|
||||||
|
"bambu_id": "GFC01",
|
||||||
|
"name": "Bambu PC FR",
|
||||||
|
"type": "PC",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFg8ndtj": {
|
||||||
|
"bambu_id": "GFN99",
|
||||||
|
"name": "Generic PA",
|
||||||
|
"type": "PA",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFgbpcy9": {
|
||||||
|
"bambu_id": "GFU99",
|
||||||
|
"name": "Generic TPU",
|
||||||
|
"type": "TPU",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFhuaUQB": {
|
||||||
|
"bambu_id": "GFB00",
|
||||||
|
"name": "Bambu ABS",
|
||||||
|
"type": "ABS",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFk8t9mz": {
|
||||||
|
"bambu_id": "GFL55",
|
||||||
|
"name": "Fiberon PETG-rCF",
|
||||||
|
"type": "PETG-CF",
|
||||||
|
"vendor": "Polymaker"
|
||||||
|
},
|
||||||
|
"OFkOviHk": {
|
||||||
|
"bambu_id": "GFL50",
|
||||||
|
"name": "Fiberon PA6-CF",
|
||||||
|
"type": "PA6-CF",
|
||||||
|
"vendor": "Polymaker"
|
||||||
|
},
|
||||||
|
"OFknl9Iz": {
|
||||||
|
"bambu_id": "GFB50",
|
||||||
|
"name": "Bambu ABS-GF",
|
||||||
|
"type": "ABS-GF",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFlfuj2k": {
|
||||||
|
"bambu_id": "GFU04",
|
||||||
|
"name": "Bambu TPU 85A",
|
||||||
|
"type": "TPU",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFmN2lvw": {
|
||||||
|
"bambu_id": "GFU98",
|
||||||
|
"name": "Generic TPU for AMS",
|
||||||
|
"type": "TPU-AMS",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFmpMwxS": {
|
||||||
|
"bambu_id": "GFL95",
|
||||||
|
"name": "Generic PLA High Speed",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFnfxTvi": {
|
||||||
|
"bambu_id": "GFA18",
|
||||||
|
"name": "Bambu PLA Lite",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFniMuTN": {
|
||||||
|
"bambu_id": "GFN05",
|
||||||
|
"name": "Bambu PA6-CF",
|
||||||
|
"type": "PA6-CF",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFo2UF2C": {
|
||||||
|
"bambu_id": "GFS97",
|
||||||
|
"name": "Generic BVOH",
|
||||||
|
"type": "BVOH",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFoYSJKi": {
|
||||||
|
"bambu_id": "GFG98",
|
||||||
|
"name": "Generic PETG-CF",
|
||||||
|
"type": "PETG-CF",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFoiVqVM": {
|
||||||
|
"bambu_id": "GFA00",
|
||||||
|
"name": "Bambu PLA Basic",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFovEIbw": {
|
||||||
|
"bambu_id": "GFG02",
|
||||||
|
"name": "Bambu PETG HF",
|
||||||
|
"type": "PETG",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFpPGSKG": {
|
||||||
|
"bambu_id": "GFSNL05",
|
||||||
|
"name": "SUNLU Silk PLA+",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "SUNLU"
|
||||||
|
},
|
||||||
|
"OFpW4gdi": {
|
||||||
|
"bambu_id": "GFSNL02",
|
||||||
|
"name": "SUNLU PLA Matte",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "SUNLU"
|
||||||
|
},
|
||||||
|
"OFq9svOz": {
|
||||||
|
"bambu_id": "GFT97",
|
||||||
|
"name": "Generic PPS",
|
||||||
|
"type": "PPS",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFqINlYj": {
|
||||||
|
"bambu_id": "GFL03",
|
||||||
|
"name": "eSUN PLA+",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "eSUN"
|
||||||
|
},
|
||||||
|
"OFrKLeE3": {
|
||||||
|
"bambu_id": "GFA02",
|
||||||
|
"name": "Bambu PLA Metal",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFsFon5l": {
|
||||||
|
"bambu_id": "GFS98",
|
||||||
|
"name": "Generic HIPS",
|
||||||
|
"type": "HIPS",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFsHSVZc": {
|
||||||
|
"bambu_id": "GFS00",
|
||||||
|
"name": "Bambu Support W",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFsijjtH": {
|
||||||
|
"bambu_id": "GFP95",
|
||||||
|
"name": "Generic PP-GF",
|
||||||
|
"type": "PP-GF",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFtkLO6q": {
|
||||||
|
"bambu_id": "GFU03",
|
||||||
|
"name": "Bambu TPU 90A",
|
||||||
|
"type": "TPU",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFu1evlr": {
|
||||||
|
"bambu_id": "GFG97",
|
||||||
|
"name": "Generic PCTG",
|
||||||
|
"type": "PCTG",
|
||||||
|
"vendor": "Generic"
|
||||||
|
},
|
||||||
|
"OFvKUnLh": {
|
||||||
|
"bambu_id": "GFU00",
|
||||||
|
"name": "Bambu TPU 95A HF",
|
||||||
|
"type": "TPU",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFvrXuV7": {
|
||||||
|
"bambu_id": "GFB61",
|
||||||
|
"name": "PolyLite ASA",
|
||||||
|
"type": "ASA",
|
||||||
|
"vendor": "Polymaker"
|
||||||
|
},
|
||||||
|
"OFwPrlCM": {
|
||||||
|
"bambu_id": "GFG01",
|
||||||
|
"name": "Bambu PETG Translucent",
|
||||||
|
"type": "PETG",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
},
|
||||||
|
"OFwaYjL6": {
|
||||||
|
"bambu_id": "GFL51",
|
||||||
|
"name": "Fiberon PA6-GF",
|
||||||
|
"type": "PA-GF",
|
||||||
|
"vendor": "Polymaker"
|
||||||
|
},
|
||||||
|
"OFxUwUeW": {
|
||||||
|
"bambu_id": "GFSNL06",
|
||||||
|
"name": "SUNLU PLA Marble",
|
||||||
|
"type": "PLA",
|
||||||
|
"vendor": "SUNLU"
|
||||||
|
},
|
||||||
|
"OFzyIxba": {
|
||||||
|
"bambu_id": "GFS04",
|
||||||
|
"name": "Bambu PVA",
|
||||||
|
"type": "PVA",
|
||||||
|
"vendor": "Bambu Lab"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"generated": "2026-09-04",
|
||||||
|
"source": "https://github.com/bambulab/BambuStudio"
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Afinia",
|
"name": "Afinia",
|
||||||
"version": "02.04.00.02",
|
"version": "02.04.00.03",
|
||||||
"force_update": "0",
|
"force_update": "0",
|
||||||
"description": "Afinia configurations",
|
"description": "Afinia configurations",
|
||||||
"machine_model_list": [
|
"machine_model_list": [
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"filament_id": "GFB00_01",
|
"filament_id": "OFLfywkp",
|
||||||
"setting_id": "wAJTMxtCY7EoavRi",
|
"setting_id": "wAJTMxtCY7EoavRi",
|
||||||
"name": "Afinia ABS+@HS",
|
"name": "Afinia ABS+@HS",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"filament_id": "GFB00_01",
|
"filament_id": "OFV5wEMe",
|
||||||
"setting_id": "qCDnb2iBaz4hd4vX",
|
"setting_id": "qCDnb2iBaz4hd4vX",
|
||||||
"name": "Afinia ABS@HS",
|
"name": "Afinia ABS@HS",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"filament_id": "GFA00_01",
|
"filament_id": "OF9HCdyQ",
|
||||||
"setting_id": "N3sCgjdjvp6FTtw9",
|
"setting_id": "N3sCgjdjvp6FTtw9",
|
||||||
"name": "Afinia PLA@HS",
|
"name": "Afinia PLA@HS",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"inherits": "fdm_filament_tpu",
|
"inherits": "fdm_filament_tpu",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "zUqTgAEbqTN1EdRl",
|
"setting_id": "zUqTgAEbqTN1EdRl",
|
||||||
"filament_id": "GFU01_01",
|
"filament_id": "OFDJU6R3",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_vendor": [
|
"filament_vendor": [
|
||||||
"Afinia"
|
"Afinia"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"filament_id": "GFB00_01",
|
"filament_id": "OFXi59OX",
|
||||||
"setting_id": "OxIiEYjbhEvSykaQ",
|
"setting_id": "OxIiEYjbhEvSykaQ",
|
||||||
"name": "Afinia Value ABS@HS",
|
"name": "Afinia Value ABS@HS",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"filament_id": "GFA00_01",
|
"filament_id": "OFgHh8ly",
|
||||||
"setting_id": "BASsUdyvElEVJ9AA",
|
"setting_id": "BASsUdyvElEVJ9AA",
|
||||||
"name": "Afinia Value PLA@HS",
|
"name": "Afinia Value PLA@HS",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Anker",
|
"name": "Anker",
|
||||||
"version": "02.04.00.01",
|
"version": "02.04.00.02",
|
||||||
"force_update": "0",
|
"force_update": "0",
|
||||||
"description": "Anker configurations",
|
"description": "Anker configurations",
|
||||||
"machine_model_list": [
|
"machine_model_list": [
|
||||||
@@ -161,172 +161,172 @@
|
|||||||
"sub_path": "filament/fdm_filament_tpu.json"
|
"sub_path": "filament/fdm_filament_tpu.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic ABS @base",
|
"name": "Generic ABS @Anker base",
|
||||||
"sub_path": "filament/Anker Generic ABS @base.json"
|
"sub_path": "filament/Generic ABS @Anker base.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic ASA @base",
|
"name": "Generic ASA @Anker base",
|
||||||
"sub_path": "filament/Anker Generic ASA @base.json"
|
"sub_path": "filament/Generic ASA @Anker base.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PA @base",
|
"name": "Generic PA @Anker base",
|
||||||
"sub_path": "filament/Anker Generic PA @base.json"
|
"sub_path": "filament/Generic PA @Anker base.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PA-CF @base",
|
"name": "Generic PA-CF @Anker base",
|
||||||
"sub_path": "filament/Anker Generic PA-CF @base.json"
|
"sub_path": "filament/Generic PA-CF @Anker base.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PC @base",
|
"name": "Generic PC @Anker base",
|
||||||
"sub_path": "filament/Anker Generic PC @base.json"
|
"sub_path": "filament/Generic PC @Anker base.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PETG @base",
|
"name": "Generic PETG @Anker base",
|
||||||
"sub_path": "filament/Anker Generic PETG @base.json"
|
"sub_path": "filament/Generic PETG @Anker base.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PETG-CF @base",
|
"name": "Generic PETG-CF @Anker base",
|
||||||
"sub_path": "filament/Anker Generic PETG-CF @base.json"
|
"sub_path": "filament/Generic PETG-CF @Anker base.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PLA @base",
|
"name": "Generic PLA @Anker base",
|
||||||
"sub_path": "filament/Anker Generic PLA @base.json"
|
"sub_path": "filament/Generic PLA @Anker base.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PLA Silk @base",
|
"name": "Generic PLA Silk @Anker base",
|
||||||
"sub_path": "filament/Anker Generic PLA Silk @base.json"
|
"sub_path": "filament/Generic PLA Silk @Anker base.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PLA+ @base",
|
"name": "Generic PLA+ @Anker base",
|
||||||
"sub_path": "filament/Anker Generic PLA+ @base.json"
|
"sub_path": "filament/Generic PLA+ @Anker base.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PLA-CF @base",
|
"name": "Generic PLA-CF @Anker base",
|
||||||
"sub_path": "filament/Anker Generic PLA-CF @base.json"
|
"sub_path": "filament/Generic PLA-CF @Anker base.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PVA @base",
|
"name": "Generic PVA @Anker base",
|
||||||
"sub_path": "filament/Anker Generic PVA @base.json"
|
"sub_path": "filament/Generic PVA @Anker base.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic TPU @base",
|
"name": "Generic TPU @Anker base",
|
||||||
"sub_path": "filament/Anker Generic TPU @base.json"
|
"sub_path": "filament/Generic TPU @Anker base.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic ABS",
|
"name": "Generic ABS @Anker",
|
||||||
"sub_path": "filament/Anker Generic ABS.json"
|
"sub_path": "filament/Generic ABS @Anker.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic ABS 0.2 nozzle",
|
"name": "Generic ABS @Anker 0.2 nozzle",
|
||||||
"sub_path": "filament/Anker Generic ABS 0.2 nozzle.json"
|
"sub_path": "filament/Generic ABS @Anker 0.2 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic ABS 0.25 nozzle",
|
"name": "Generic ABS @Anker 0.25 nozzle",
|
||||||
"sub_path": "filament/Anker Generic ABS 0.25 nozzle.json"
|
"sub_path": "filament/Generic ABS @Anker 0.25 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic ASA",
|
"name": "Generic ASA @Anker",
|
||||||
"sub_path": "filament/Anker Generic ASA.json"
|
"sub_path": "filament/Generic ASA @Anker.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic ASA 0.2 nozzle",
|
"name": "Generic ASA @Anker 0.2 nozzle",
|
||||||
"sub_path": "filament/Anker Generic ASA 0.2 nozzle.json"
|
"sub_path": "filament/Generic ASA @Anker 0.2 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic ASA 0.25 nozzle",
|
"name": "Generic ASA @Anker 0.25 nozzle",
|
||||||
"sub_path": "filament/Anker Generic ASA 0.25 nozzle.json"
|
"sub_path": "filament/Generic ASA @Anker 0.25 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PA",
|
"name": "Generic PA @Anker",
|
||||||
"sub_path": "filament/Anker Generic PA.json"
|
"sub_path": "filament/Generic PA @Anker.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PA 0.2 nozzle",
|
"name": "Generic PA @Anker 0.2 nozzle",
|
||||||
"sub_path": "filament/Anker Generic PA 0.2 nozzle.json"
|
"sub_path": "filament/Generic PA @Anker 0.2 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PA 0.25 nozzle",
|
"name": "Generic PA @Anker 0.25 nozzle",
|
||||||
"sub_path": "filament/Anker Generic PA 0.25 nozzle.json"
|
"sub_path": "filament/Generic PA @Anker 0.25 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PA-CF",
|
"name": "Generic PA-CF @Anker",
|
||||||
"sub_path": "filament/Anker Generic PA-CF.json"
|
"sub_path": "filament/Generic PA-CF @Anker.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PC",
|
"name": "Generic PC @Anker",
|
||||||
"sub_path": "filament/Anker Generic PC.json"
|
"sub_path": "filament/Generic PC @Anker.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PC 0.2 nozzle",
|
"name": "Generic PC @Anker 0.2 nozzle",
|
||||||
"sub_path": "filament/Anker Generic PC 0.2 nozzle.json"
|
"sub_path": "filament/Generic PC @Anker 0.2 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PC 0.25 nozzle",
|
"name": "Generic PC @Anker 0.25 nozzle",
|
||||||
"sub_path": "filament/Anker Generic PC 0.25 nozzle.json"
|
"sub_path": "filament/Generic PC @Anker 0.25 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PETG",
|
"name": "Generic PETG @Anker",
|
||||||
"sub_path": "filament/Anker Generic PETG.json"
|
"sub_path": "filament/Generic PETG @Anker.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PETG 0.2 nozzle",
|
"name": "Generic PETG @Anker 0.2 nozzle",
|
||||||
"sub_path": "filament/Anker Generic PETG 0.2 nozzle.json"
|
"sub_path": "filament/Generic PETG @Anker 0.2 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PETG 0.25 nozzle",
|
"name": "Generic PETG @Anker 0.25 nozzle",
|
||||||
"sub_path": "filament/Anker Generic PETG 0.25 nozzle.json"
|
"sub_path": "filament/Generic PETG @Anker 0.25 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PETG-CF",
|
"name": "Generic PETG-CF @Anker",
|
||||||
"sub_path": "filament/Anker Generic PETG-CF.json"
|
"sub_path": "filament/Generic PETG-CF @Anker.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PLA",
|
"name": "Generic PLA @Anker",
|
||||||
"sub_path": "filament/Anker Generic PLA.json"
|
"sub_path": "filament/Generic PLA @Anker.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PLA 0.2 nozzle",
|
"name": "Generic PLA @Anker 0.2 nozzle",
|
||||||
"sub_path": "filament/Anker Generic PLA 0.2 nozzle.json"
|
"sub_path": "filament/Generic PLA @Anker 0.2 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PLA 0.25 nozzle",
|
"name": "Generic PLA @Anker 0.25 nozzle",
|
||||||
"sub_path": "filament/Anker Generic PLA 0.25 nozzle.json"
|
"sub_path": "filament/Generic PLA @Anker 0.25 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PLA Silk",
|
"name": "Generic PLA Silk @Anker",
|
||||||
"sub_path": "filament/Anker Generic PLA Silk.json"
|
"sub_path": "filament/Generic PLA Silk @Anker.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PLA Silk 0.2 nozzle",
|
"name": "Generic PLA Silk @Anker 0.2 nozzle",
|
||||||
"sub_path": "filament/Anker Generic PLA Silk 0.2 nozzle.json"
|
"sub_path": "filament/Generic PLA Silk @Anker 0.2 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PLA Silk 0.25 nozzle",
|
"name": "Generic PLA Silk @Anker 0.25 nozzle",
|
||||||
"sub_path": "filament/Anker Generic PLA Silk 0.25 nozzle.json"
|
"sub_path": "filament/Generic PLA Silk @Anker 0.25 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PLA+",
|
"name": "Generic PLA+ @Anker",
|
||||||
"sub_path": "filament/Anker Generic PLA+.json"
|
"sub_path": "filament/Generic PLA+ @Anker.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PLA+ 0.2 nozzle",
|
"name": "Generic PLA+ @Anker 0.2 nozzle",
|
||||||
"sub_path": "filament/Anker Generic PLA+ 0.2 nozzle.json"
|
"sub_path": "filament/Generic PLA+ @Anker 0.2 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PLA+ 0.25 nozzle",
|
"name": "Generic PLA+ @Anker 0.25 nozzle",
|
||||||
"sub_path": "filament/Anker Generic PLA+ 0.25 nozzle.json"
|
"sub_path": "filament/Generic PLA+ @Anker 0.25 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PLA-CF",
|
"name": "Generic PLA-CF @Anker",
|
||||||
"sub_path": "filament/Anker Generic PLA-CF.json"
|
"sub_path": "filament/Generic PLA-CF @Anker.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic PVA",
|
"name": "Generic PVA @Anker",
|
||||||
"sub_path": "filament/Anker Generic PVA.json"
|
"sub_path": "filament/Generic PVA @Anker.json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Anker Generic TPU",
|
"name": "Generic TPU @Anker",
|
||||||
"sub_path": "filament/Anker Generic TPU.json"
|
"sub_path": "filament/Generic TPU @Anker.json"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"machine_list": [
|
"machine_list": [
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Anker Generic PLA Silk 0.2 nozzle",
|
|
||||||
"inherits": "Anker Generic PLA Silk @base",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "A1l6NiwRrasdV556",
|
|
||||||
"instantiation": "true",
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"2"
|
|
||||||
],
|
|
||||||
"compatible_printers": [
|
|
||||||
"Anker M5 0.2 nozzle",
|
|
||||||
"Anker M5 All-Metal 0.2 nozzle",
|
|
||||||
"Anker M5C 0.2 nozzle"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Anker Generic PLA Silk 0.25 nozzle",
|
|
||||||
"inherits": "Anker Generic PLA Silk @base",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "yzHmKTOtA9JamlNf",
|
|
||||||
"instantiation": "true",
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"compatible_printers": [
|
|
||||||
"Anker M5 0.25 nozzle",
|
|
||||||
"Anker M5 All-Metal 0.25 nozzle",
|
|
||||||
"Anker M5C 0.25 nozzle"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Anker Generic PLA Silk",
|
|
||||||
"inherits": "Anker Generic PLA Silk @base",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "BGttYO9m2rGcnrEG",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Anker M5 0.4 nozzle",
|
|
||||||
"Anker M5 0.6 nozzle",
|
|
||||||
"Anker M5 All-Metal 0.4 nozzle",
|
|
||||||
"Anker M5 All-Metal 0.6 nozzle",
|
|
||||||
"Anker M5C 0.4 nozzle",
|
|
||||||
"Anker M5C 0.6 nozzle"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Anker Generic PLA+ 0.2 nozzle",
|
|
||||||
"inherits": "Anker Generic PLA+ @base",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "6IcMSjyxt0szdUuY",
|
|
||||||
"instantiation": "true",
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"2"
|
|
||||||
],
|
|
||||||
"compatible_printers": [
|
|
||||||
"Anker M5 0.2 nozzle",
|
|
||||||
"Anker M5 All-Metal 0.2 nozzle",
|
|
||||||
"Anker M5C 0.2 nozzle"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Anker Generic PLA+ 0.25 nozzle",
|
|
||||||
"inherits": "Anker Generic PLA+ @base",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "a2Rf07ZUhpTPONN1",
|
|
||||||
"instantiation": "true",
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"compatible_printers": [
|
|
||||||
"Anker M5 0.25 nozzle",
|
|
||||||
"Anker M5 All-Metal 0.25 nozzle",
|
|
||||||
"Anker M5C 0.25 nozzle"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Anker Generic PLA+",
|
|
||||||
"inherits": "Anker Generic PLA+ @base",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "0yQN44WNvLVjQu2b",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Anker M5 0.4 nozzle",
|
|
||||||
"Anker M5 0.6 nozzle",
|
|
||||||
"Anker M5 All-Metal 0.4 nozzle",
|
|
||||||
"Anker M5 All-Metal 0.6 nozzle",
|
|
||||||
"Anker M5C 0.4 nozzle",
|
|
||||||
"Anker M5C 0.6 nozzle"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Anker Generic PLA-CF",
|
|
||||||
"inherits": "Anker Generic PLA-CF @base",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "diNUVM7UcHLnOr9J",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Anker M5 0.4 nozzle",
|
|
||||||
"Anker M5 0.6 nozzle",
|
|
||||||
"Anker M5 All-Metal 0.4 nozzle",
|
|
||||||
"Anker M5 All-Metal 0.6 nozzle",
|
|
||||||
"Anker M5C 0.4 nozzle",
|
|
||||||
"Anker M5C 0.6 nozzle"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Anker Generic PLA",
|
|
||||||
"inherits": "Anker Generic PLA @base",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "qfKC91VAAFZSExhm",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Anker M5 0.4 nozzle",
|
|
||||||
"Anker M5 0.6 nozzle",
|
|
||||||
"Anker M5 All-Metal 0.4 nozzle",
|
|
||||||
"Anker M5 All-Metal 0.6 nozzle",
|
|
||||||
"Anker M5C 0.4 nozzle",
|
|
||||||
"Anker M5C 0.6 nozzle"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Anker Generic PVA",
|
|
||||||
"inherits": "Anker Generic PVA @base",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "GRtdOKUkQfZ5eDH4",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Anker M5 0.4 nozzle",
|
|
||||||
"Anker M5 0.6 nozzle",
|
|
||||||
"Anker M5 All-Metal 0.4 nozzle",
|
|
||||||
"Anker M5 All-Metal 0.6 nozzle",
|
|
||||||
"Anker M5C 0.4 nozzle",
|
|
||||||
"Anker M5C 0.6 nozzle"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Anker Generic TPU",
|
|
||||||
"inherits": "Anker Generic TPU @base",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "YyTaPGGiEyAzmh9A",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Anker M5 0.4 nozzle",
|
|
||||||
"Anker M5 0.6 nozzle",
|
|
||||||
"Anker M5 All-Metal 0.4 nozzle",
|
|
||||||
"Anker M5 All-Metal 0.6 nozzle",
|
|
||||||
"Anker M5C 0.4 nozzle",
|
|
||||||
"Anker M5C 0.6 nozzle"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic ABS 0.2 nozzle",
|
"name": "Generic ABS @Anker 0.2 nozzle",
|
||||||
"inherits": "Anker Generic ABS @base",
|
"inherits": "Generic ABS @Anker base",
|
||||||
|
"renamed_from": "Anker Generic ABS 0.2 nozzle",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "BD5ODYVM90Ig44C5",
|
"setting_id": "iOCt7x95XbWYMe5q",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"2"
|
"2"
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PETG 0.25 nozzle",
|
"name": "Generic ABS @Anker 0.25 nozzle",
|
||||||
"inherits": "Anker Generic PETG @base",
|
"inherits": "Generic ABS @Anker base",
|
||||||
|
"renamed_from": "Anker Generic ABS 0.25 nozzle",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "UgKfPuleh1xnoJLT",
|
"setting_id": "7Q2pr70SpSjK7v7Y",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"3"
|
"3"
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic ABS @base",
|
"name": "Generic ABS @Anker base",
|
||||||
"inherits": "fdm_filament_abs",
|
"inherits": "fdm_filament_abs",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "GFB99",
|
"filament_id": "OFY9muEs",
|
||||||
"instantiation": "false"
|
"instantiation": "false"
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic ASA",
|
"name": "Generic ABS @Anker",
|
||||||
"inherits": "Anker Generic ASA @base",
|
"inherits": "Generic ABS @Anker base",
|
||||||
|
"renamed_from": "Anker Generic ABS",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "QiFoBW5WuDUJGmFZ",
|
"setting_id": "x3IBYtgKBx6Mszzk",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Anker M5 0.4 nozzle",
|
"Anker M5 0.4 nozzle",
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PETG 0.2 nozzle",
|
"name": "Generic ASA @Anker 0.2 nozzle",
|
||||||
"inherits": "Anker Generic PETG @base",
|
"inherits": "Generic ASA @Anker base",
|
||||||
|
"renamed_from": "Anker Generic ASA 0.2 nozzle",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "VItvDP6zmenWXwPO",
|
"setting_id": "lTR8QLbuttyVs5UW",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"2"
|
"2"
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic ABS 0.25 nozzle",
|
"name": "Generic ASA @Anker 0.25 nozzle",
|
||||||
"inherits": "Anker Generic ABS @base",
|
"inherits": "Generic ASA @Anker base",
|
||||||
|
"renamed_from": "Anker Generic ASA 0.25 nozzle",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "WS5wXckNuiQqSVwO",
|
"setting_id": "FU4BiMydEyo7zxq5",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"3"
|
"3"
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic ASA @base",
|
"name": "Generic ASA @Anker base",
|
||||||
"inherits": "fdm_filament_asa",
|
"inherits": "fdm_filament_asa",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "GFB98",
|
"filament_id": "OFLPAxz3",
|
||||||
"instantiation": "false"
|
"instantiation": "false"
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PETG-CF",
|
"name": "Generic ASA @Anker",
|
||||||
"inherits": "Anker Generic PETG-CF @base",
|
"inherits": "Generic ASA @Anker base",
|
||||||
|
"renamed_from": "Anker Generic ASA",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "j8PLF6AZD0R0oVs8",
|
"setting_id": "aDADuxiEKt2dVKOJ",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Anker M5 0.4 nozzle",
|
"Anker M5 0.4 nozzle",
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PA 0.2 nozzle",
|
"name": "Generic PA @Anker 0.2 nozzle",
|
||||||
"inherits": "Anker Generic PA @base",
|
"inherits": "Generic PA @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PA 0.2 nozzle",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "NZB26MSD9WbOeY2S",
|
"setting_id": "tYAT7xnNFD6gY84A",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"2"
|
"2"
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PA 0.25 nozzle",
|
"name": "Generic PA @Anker 0.25 nozzle",
|
||||||
"inherits": "Anker Generic PA @base",
|
"inherits": "Generic PA @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PA 0.25 nozzle",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "Wj7oXTGUxo8lie1B",
|
"setting_id": "Zlv65wLA94PbevRG",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"3"
|
"3"
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PA @base",
|
"name": "Generic PA @Anker base",
|
||||||
"inherits": "fdm_filament_pa",
|
"inherits": "fdm_filament_pa",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "GFN99",
|
"filament_id": "OFg8ndtj",
|
||||||
"instantiation": "false"
|
"instantiation": "false"
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PC",
|
"name": "Generic PA @Anker",
|
||||||
"inherits": "Anker Generic PC @base",
|
"inherits": "Generic PA @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PA",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "xY25QcIsR9pWai3n",
|
"setting_id": "sLWVtBxpAC53eUwo",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Anker M5 All-Metal 0.4 nozzle",
|
"Anker M5 All-Metal 0.4 nozzle",
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PA-CF @base",
|
"name": "Generic PA-CF @Anker base",
|
||||||
"inherits": "fdm_filament_pa",
|
"inherits": "fdm_filament_pa",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "GFN98",
|
"filament_id": "OFQLcbps",
|
||||||
"instantiation": "false",
|
"instantiation": "false",
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PA-CF"
|
"PA-CF"
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PA",
|
"name": "Generic PA-CF @Anker",
|
||||||
"inherits": "Anker Generic PA @base",
|
"inherits": "Generic PA-CF @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PA-CF",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "QbIiX554Yee6vb32",
|
"setting_id": "K4LcpR0zBp5klSpb",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Anker M5 All-Metal 0.4 nozzle",
|
"Anker M5 All-Metal 0.4 nozzle",
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PC 0.2 nozzle",
|
"name": "Generic PC @Anker 0.2 nozzle",
|
||||||
"inherits": "Anker Generic PC @base",
|
"inherits": "Generic PC @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PC 0.2 nozzle",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "GhIOAidtgDkzh9Aj",
|
"setting_id": "2sSOgctcnVh9bGbQ",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"2"
|
"2"
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PC 0.25 nozzle",
|
"name": "Generic PC @Anker 0.25 nozzle",
|
||||||
"inherits": "Anker Generic PC @base",
|
"inherits": "Generic PC @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PC 0.25 nozzle",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "TQm9EPdenyGJMvgP",
|
"setting_id": "h7IRuq5uekjNw4vg",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"3"
|
"3"
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PC @base",
|
"name": "Generic PC @Anker base",
|
||||||
"inherits": "fdm_filament_pc",
|
"inherits": "fdm_filament_pc",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "GFC99",
|
"filament_id": "OFLakOUI",
|
||||||
"instantiation": "false"
|
"instantiation": "false"
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PA-CF",
|
"name": "Generic PC @Anker",
|
||||||
"inherits": "Anker Generic PA-CF @base",
|
"inherits": "Generic PC @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PC",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "qdsEps11ugFHJkn7",
|
"setting_id": "ffufXVvW95sunH1B",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Anker M5 All-Metal 0.4 nozzle",
|
"Anker M5 All-Metal 0.4 nozzle",
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic ASA 0.2 nozzle",
|
"name": "Generic PETG @Anker 0.2 nozzle",
|
||||||
"inherits": "Anker Generic ASA @base",
|
"inherits": "Generic PETG @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PETG 0.2 nozzle",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "G7pzEyyhPFDnae3R",
|
"setting_id": "67ZHuiXPyCP6Tdtr",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"2"
|
"2"
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PLA 0.25 nozzle",
|
"name": "Generic PETG @Anker 0.25 nozzle",
|
||||||
"inherits": "Anker Generic PLA @base",
|
"inherits": "Generic PETG @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PETG 0.25 nozzle",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "uKfcnPWdXxAGB5Ls",
|
"setting_id": "aLuRALDt0Otbd2So",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"3"
|
"3"
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PETG @base",
|
"name": "Generic PETG @Anker base",
|
||||||
"inherits": "fdm_filament_pet",
|
"inherits": "fdm_filament_pet",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "GFG99",
|
"filament_id": "OFYPdQJh",
|
||||||
"instantiation": "false",
|
"instantiation": "false",
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PETG"
|
"PETG"
|
||||||
17
resources/profiles/Anker/filament/Generic PETG @Anker.json
Normal file
17
resources/profiles/Anker/filament/Generic PETG @Anker.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"type": "filament",
|
||||||
|
"name": "Generic PETG @Anker",
|
||||||
|
"inherits": "Generic PETG @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PETG",
|
||||||
|
"from": "system",
|
||||||
|
"setting_id": "hvV0rmnzRHJk9sMz",
|
||||||
|
"instantiation": "true",
|
||||||
|
"compatible_printers": [
|
||||||
|
"Anker M5 0.4 nozzle",
|
||||||
|
"Anker M5 0.6 nozzle",
|
||||||
|
"Anker M5 All-Metal 0.4 nozzle",
|
||||||
|
"Anker M5 All-Metal 0.6 nozzle",
|
||||||
|
"Anker M5C 0.4 nozzle",
|
||||||
|
"Anker M5C 0.6 nozzle"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PETG-CF @base",
|
"name": "Generic PETG-CF @Anker base",
|
||||||
"inherits": "fdm_filament_pet",
|
"inherits": "fdm_filament_pet",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "GFG98",
|
"filament_id": "OFoYSJKi",
|
||||||
"instantiation": "false",
|
"instantiation": "false",
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PETG-CF"
|
"PETG-CF"
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"type": "filament",
|
||||||
|
"name": "Generic PETG-CF @Anker",
|
||||||
|
"inherits": "Generic PETG-CF @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PETG-CF",
|
||||||
|
"from": "system",
|
||||||
|
"setting_id": "vCAuQeQLoXUk28ph",
|
||||||
|
"instantiation": "true",
|
||||||
|
"compatible_printers": [
|
||||||
|
"Anker M5 0.4 nozzle",
|
||||||
|
"Anker M5 0.6 nozzle",
|
||||||
|
"Anker M5 All-Metal 0.4 nozzle",
|
||||||
|
"Anker M5 All-Metal 0.6 nozzle",
|
||||||
|
"Anker M5C 0.4 nozzle",
|
||||||
|
"Anker M5C 0.6 nozzle"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PLA 0.2 nozzle",
|
"name": "Generic PLA @Anker 0.2 nozzle",
|
||||||
"inherits": "Anker Generic PLA @base",
|
"inherits": "Generic PLA @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PLA 0.2 nozzle",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "j6QmCITPJoP7bWHq",
|
"setting_id": "rCvmCzPgi4KA6nmI",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"2"
|
"2"
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic ASA 0.25 nozzle",
|
"name": "Generic PLA @Anker 0.25 nozzle",
|
||||||
"inherits": "Anker Generic ASA @base",
|
"inherits": "Generic PLA @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PLA 0.25 nozzle",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "ErUUDTQ7h1wNHAKT",
|
"setting_id": "C0hNEbEueKrcYojS",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"3"
|
"3"
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PLA @base",
|
"name": "Generic PLA @Anker base",
|
||||||
"inherits": "fdm_filament_pla",
|
"inherits": "fdm_filament_pla",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "GFL99",
|
"filament_id": "OFDSrzZ8",
|
||||||
"instantiation": "false"
|
"instantiation": "false"
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic ABS",
|
"name": "Generic PLA @Anker",
|
||||||
"inherits": "Anker Generic ABS @base",
|
"inherits": "Generic PLA @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PLA",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "axEspGzFJnrnidm4",
|
"setting_id": "GfVhcxRmt6mHSemI",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Anker M5 0.4 nozzle",
|
"Anker M5 0.4 nozzle",
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"type": "filament",
|
||||||
|
"name": "Generic PLA Silk @Anker 0.2 nozzle",
|
||||||
|
"inherits": "Generic PLA Silk @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PLA Silk 0.2 nozzle",
|
||||||
|
"from": "system",
|
||||||
|
"setting_id": "NWGiPWYmLVktDMJt",
|
||||||
|
"instantiation": "true",
|
||||||
|
"filament_max_volumetric_speed": [
|
||||||
|
"2"
|
||||||
|
],
|
||||||
|
"compatible_printers": [
|
||||||
|
"Anker M5 0.2 nozzle",
|
||||||
|
"Anker M5 All-Metal 0.2 nozzle",
|
||||||
|
"Anker M5C 0.2 nozzle"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"type": "filament",
|
||||||
|
"name": "Generic PLA Silk @Anker 0.25 nozzle",
|
||||||
|
"inherits": "Generic PLA Silk @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PLA Silk 0.25 nozzle",
|
||||||
|
"from": "system",
|
||||||
|
"setting_id": "4thKBCnYgDtnAtF5",
|
||||||
|
"instantiation": "true",
|
||||||
|
"filament_max_volumetric_speed": [
|
||||||
|
"3"
|
||||||
|
],
|
||||||
|
"compatible_printers": [
|
||||||
|
"Anker M5 0.25 nozzle",
|
||||||
|
"Anker M5 All-Metal 0.25 nozzle",
|
||||||
|
"Anker M5C 0.25 nozzle"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PLA Silk @base",
|
"name": "Generic PLA Silk @Anker base",
|
||||||
"inherits": "fdm_filament_pla",
|
"inherits": "fdm_filament_pla",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "GFL96",
|
"filament_id": "OFesA6rF",
|
||||||
"instantiation": "false",
|
"instantiation": "false",
|
||||||
"filament_cost": [
|
"filament_cost": [
|
||||||
"20"
|
"20"
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"type": "filament",
|
||||||
|
"name": "Generic PLA Silk @Anker",
|
||||||
|
"inherits": "Generic PLA Silk @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PLA Silk",
|
||||||
|
"from": "system",
|
||||||
|
"setting_id": "URRIeNXIiIPjxbKL",
|
||||||
|
"instantiation": "true",
|
||||||
|
"compatible_printers": [
|
||||||
|
"Anker M5 0.4 nozzle",
|
||||||
|
"Anker M5 0.6 nozzle",
|
||||||
|
"Anker M5 All-Metal 0.4 nozzle",
|
||||||
|
"Anker M5 All-Metal 0.6 nozzle",
|
||||||
|
"Anker M5C 0.4 nozzle",
|
||||||
|
"Anker M5C 0.6 nozzle"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"type": "filament",
|
||||||
|
"name": "Generic PLA+ @Anker 0.2 nozzle",
|
||||||
|
"inherits": "Generic PLA+ @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PLA+ 0.2 nozzle",
|
||||||
|
"from": "system",
|
||||||
|
"setting_id": "5m3xLxdReqLlE2Jp",
|
||||||
|
"instantiation": "true",
|
||||||
|
"filament_max_volumetric_speed": [
|
||||||
|
"2"
|
||||||
|
],
|
||||||
|
"compatible_printers": [
|
||||||
|
"Anker M5 0.2 nozzle",
|
||||||
|
"Anker M5 All-Metal 0.2 nozzle",
|
||||||
|
"Anker M5C 0.2 nozzle"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"type": "filament",
|
||||||
|
"name": "Generic PLA+ @Anker 0.25 nozzle",
|
||||||
|
"inherits": "Generic PLA+ @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PLA+ 0.25 nozzle",
|
||||||
|
"from": "system",
|
||||||
|
"setting_id": "wwkWVDsg6SoeCS0F",
|
||||||
|
"instantiation": "true",
|
||||||
|
"filament_max_volumetric_speed": [
|
||||||
|
"3"
|
||||||
|
],
|
||||||
|
"compatible_printers": [
|
||||||
|
"Anker M5 0.25 nozzle",
|
||||||
|
"Anker M5 All-Metal 0.25 nozzle",
|
||||||
|
"Anker M5C 0.25 nozzle"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PLA+ @base",
|
"name": "Generic PLA+ @Anker base",
|
||||||
"inherits": "fdm_filament_pla",
|
"inherits": "fdm_filament_pla",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "GFL95",
|
"filament_id": "OFEWYR89",
|
||||||
"instantiation": "false",
|
"instantiation": "false",
|
||||||
"filament_cost": [
|
"filament_cost": [
|
||||||
"25"
|
"25"
|
||||||
17
resources/profiles/Anker/filament/Generic PLA+ @Anker.json
Normal file
17
resources/profiles/Anker/filament/Generic PLA+ @Anker.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"type": "filament",
|
||||||
|
"name": "Generic PLA+ @Anker",
|
||||||
|
"inherits": "Generic PLA+ @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PLA+",
|
||||||
|
"from": "system",
|
||||||
|
"setting_id": "MDb4CH02FxbgPNjS",
|
||||||
|
"instantiation": "true",
|
||||||
|
"compatible_printers": [
|
||||||
|
"Anker M5 0.4 nozzle",
|
||||||
|
"Anker M5 0.6 nozzle",
|
||||||
|
"Anker M5 All-Metal 0.4 nozzle",
|
||||||
|
"Anker M5 All-Metal 0.6 nozzle",
|
||||||
|
"Anker M5C 0.4 nozzle",
|
||||||
|
"Anker M5C 0.6 nozzle"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PLA-CF @base",
|
"name": "Generic PLA-CF @Anker base",
|
||||||
"inherits": "fdm_filament_pla",
|
"inherits": "fdm_filament_pla",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "GFL98",
|
"filament_id": "OFWbdGsC",
|
||||||
"instantiation": "false",
|
"instantiation": "false",
|
||||||
"filament_type": [
|
"filament_type": [
|
||||||
"PLA-CF"
|
"PLA-CF"
|
||||||
17
resources/profiles/Anker/filament/Generic PLA-CF @Anker.json
Normal file
17
resources/profiles/Anker/filament/Generic PLA-CF @Anker.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"type": "filament",
|
||||||
|
"name": "Generic PLA-CF @Anker",
|
||||||
|
"inherits": "Generic PLA-CF @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PLA-CF",
|
||||||
|
"from": "system",
|
||||||
|
"setting_id": "5AdjHUxRi8LCU4E9",
|
||||||
|
"instantiation": "true",
|
||||||
|
"compatible_printers": [
|
||||||
|
"Anker M5 0.4 nozzle",
|
||||||
|
"Anker M5 0.6 nozzle",
|
||||||
|
"Anker M5 All-Metal 0.4 nozzle",
|
||||||
|
"Anker M5 All-Metal 0.6 nozzle",
|
||||||
|
"Anker M5C 0.4 nozzle",
|
||||||
|
"Anker M5C 0.6 nozzle"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PVA @base",
|
"name": "Generic PVA @Anker base",
|
||||||
"inherits": "fdm_filament_pva",
|
"inherits": "fdm_filament_pva",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "GFS99",
|
"filament_id": "OFDvXujf",
|
||||||
"instantiation": "false"
|
"instantiation": "false"
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic PETG",
|
"name": "Generic PVA @Anker",
|
||||||
"inherits": "Anker Generic PETG @base",
|
"inherits": "Generic PVA @Anker base",
|
||||||
|
"renamed_from": "Anker Generic PVA",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "FMnK9qOMiqDcGqhd",
|
"setting_id": "HXERDaP3AgzWtmiu",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"compatible_printers": [
|
"compatible_printers": [
|
||||||
"Anker M5 0.4 nozzle",
|
"Anker M5 0.4 nozzle",
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"type": "filament",
|
"type": "filament",
|
||||||
"name": "Anker Generic TPU @base",
|
"name": "Generic TPU @Anker base",
|
||||||
"inherits": "fdm_filament_tpu",
|
"inherits": "fdm_filament_tpu",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"filament_id": "GFU99",
|
"filament_id": "OFgbpcy9",
|
||||||
"instantiation": "false",
|
"instantiation": "false",
|
||||||
"filament_retraction_speed": "90",
|
"filament_retraction_speed": "90",
|
||||||
"filament_deretraction_speed": "50",
|
"filament_deretraction_speed": "50",
|
||||||
17
resources/profiles/Anker/filament/Generic TPU @Anker.json
Normal file
17
resources/profiles/Anker/filament/Generic TPU @Anker.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"type": "filament",
|
||||||
|
"name": "Generic TPU @Anker",
|
||||||
|
"inherits": "Generic TPU @Anker base",
|
||||||
|
"renamed_from": "Anker Generic TPU",
|
||||||
|
"from": "system",
|
||||||
|
"setting_id": "5YigkBBSP2RM1MbK",
|
||||||
|
"instantiation": "true",
|
||||||
|
"compatible_printers": [
|
||||||
|
"Anker M5 0.4 nozzle",
|
||||||
|
"Anker M5 0.6 nozzle",
|
||||||
|
"Anker M5 All-Metal 0.4 nozzle",
|
||||||
|
"Anker M5 All-Metal 0.6 nozzle",
|
||||||
|
"Anker M5C 0.4 nozzle",
|
||||||
|
"Anker M5C 0.6 nozzle"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
"auxiliary_fan": "0",
|
"auxiliary_fan": "0",
|
||||||
"bed_exclude_area": [],
|
"bed_exclude_area": [],
|
||||||
"default_filament_profile": [
|
"default_filament_profile": [
|
||||||
"Anker Generic PLA+"
|
"Generic PLA+ @Anker"
|
||||||
],
|
],
|
||||||
"default_print_profile": "0.10mm Standard 0.2mm nozzle @Anker",
|
"default_print_profile": "0.10mm Standard 0.2mm nozzle @Anker",
|
||||||
"extruder_clearance_height_to_lid": "250",
|
"extruder_clearance_height_to_lid": "250",
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"auxiliary_fan": "0",
|
"auxiliary_fan": "0",
|
||||||
"bed_exclude_area": [],
|
"bed_exclude_area": [],
|
||||||
"default_filament_profile": [
|
"default_filament_profile": [
|
||||||
"Anker Generic PLA+"
|
"Generic PLA+ @Anker"
|
||||||
],
|
],
|
||||||
"default_print_profile": "0.10mm Standard 0.25mm nozzle @Anker",
|
"default_print_profile": "0.10mm Standard 0.25mm nozzle @Anker",
|
||||||
"extruder_clearance_height_to_lid": "250",
|
"extruder_clearance_height_to_lid": "250",
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"auxiliary_fan": "0",
|
"auxiliary_fan": "0",
|
||||||
"bed_exclude_area": [],
|
"bed_exclude_area": [],
|
||||||
"default_filament_profile": [
|
"default_filament_profile": [
|
||||||
"Anker Generic PLA+"
|
"Generic PLA+ @Anker"
|
||||||
],
|
],
|
||||||
"default_print_profile": "0.20mm Standard @Anker",
|
"default_print_profile": "0.20mm Standard @Anker",
|
||||||
"extruder_clearance_height_to_lid": "250",
|
"extruder_clearance_height_to_lid": "250",
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"auxiliary_fan": "0",
|
"auxiliary_fan": "0",
|
||||||
"bed_exclude_area": [],
|
"bed_exclude_area": [],
|
||||||
"default_filament_profile": [
|
"default_filament_profile": [
|
||||||
"Anker Generic PLA+"
|
"Generic PLA+ @Anker"
|
||||||
],
|
],
|
||||||
"default_print_profile": "0.30mm Standard 0.6 nozzle @Anker",
|
"default_print_profile": "0.30mm Standard 0.6 nozzle @Anker",
|
||||||
"extruder_clearance_height_to_lid": "250",
|
"extruder_clearance_height_to_lid": "250",
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"auxiliary_fan": "0",
|
"auxiliary_fan": "0",
|
||||||
"bed_exclude_area": [],
|
"bed_exclude_area": [],
|
||||||
"default_filament_profile": [
|
"default_filament_profile": [
|
||||||
"Anker Generic PLA+"
|
"Generic PLA+ @Anker"
|
||||||
],
|
],
|
||||||
"default_print_profile": "0.10mm Standard 0.2mm nozzle @Anker",
|
"default_print_profile": "0.10mm Standard 0.2mm nozzle @Anker",
|
||||||
"extruder_clearance_height_to_lid": "250",
|
"extruder_clearance_height_to_lid": "250",
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"auxiliary_fan": "0",
|
"auxiliary_fan": "0",
|
||||||
"bed_exclude_area": [],
|
"bed_exclude_area": [],
|
||||||
"default_filament_profile": [
|
"default_filament_profile": [
|
||||||
"Anker Generic PLA+"
|
"Generic PLA+ @Anker"
|
||||||
],
|
],
|
||||||
"default_print_profile": "0.10mm Standard 0.25mm nozzle @Anker",
|
"default_print_profile": "0.10mm Standard 0.25mm nozzle @Anker",
|
||||||
"extruder_clearance_height_to_lid": "250",
|
"extruder_clearance_height_to_lid": "250",
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"auxiliary_fan": "0",
|
"auxiliary_fan": "0",
|
||||||
"bed_exclude_area": [],
|
"bed_exclude_area": [],
|
||||||
"default_filament_profile": [
|
"default_filament_profile": [
|
||||||
"Anker Generic PLA+"
|
"Generic PLA+ @Anker"
|
||||||
],
|
],
|
||||||
"default_print_profile": "0.20mm Standard @Anker",
|
"default_print_profile": "0.20mm Standard @Anker",
|
||||||
"extruder_clearance_height_to_lid": "250",
|
"extruder_clearance_height_to_lid": "250",
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"auxiliary_fan": "0",
|
"auxiliary_fan": "0",
|
||||||
"bed_exclude_area": [],
|
"bed_exclude_area": [],
|
||||||
"default_filament_profile": [
|
"default_filament_profile": [
|
||||||
"Anker Generic PLA+"
|
"Generic PLA+ @Anker"
|
||||||
],
|
],
|
||||||
"default_print_profile": "0.30mm Standard 0.6 nozzle @Anker",
|
"default_print_profile": "0.30mm Standard 0.6 nozzle @Anker",
|
||||||
"extruder_clearance_height_to_lid": "250",
|
"extruder_clearance_height_to_lid": "250",
|
||||||
|
|||||||
@@ -7,5 +7,5 @@
|
|||||||
"family": "Anker",
|
"family": "Anker",
|
||||||
"machine_tech": "FFF",
|
"machine_tech": "FFF",
|
||||||
"model_id": "V8111v2",
|
"model_id": "V8111v2",
|
||||||
"default_materials": "Anker Generic PLA;Anker Generic PLA+;Anker Generic PLA Silk;Anker Generic TPU;Anker Generic PETG"
|
"default_materials": "Generic PLA @Anker;Generic PLA+ @Anker;Generic PLA Silk @Anker;Generic TPU @Anker;Generic PETG @Anker"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,5 +7,5 @@
|
|||||||
"family": "Anker",
|
"family": "Anker",
|
||||||
"machine_tech": "FFF",
|
"machine_tech": "FFF",
|
||||||
"model_id": "V8111",
|
"model_id": "V8111",
|
||||||
"default_materials": "Anker Generic PLA;Anker Generic PLA+;Anker Generic PLA Silk;Anker Generic TPU;Anker Generic PETG"
|
"default_materials": "Generic PLA @Anker;Generic PLA+ @Anker;Generic PLA Silk @Anker;Generic TPU @Anker;Generic PETG @Anker"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"auxiliary_fan": "0",
|
"auxiliary_fan": "0",
|
||||||
"bed_exclude_area": [],
|
"bed_exclude_area": [],
|
||||||
"default_filament_profile": [
|
"default_filament_profile": [
|
||||||
"Anker Generic PLA+"
|
"Generic PLA+ @Anker"
|
||||||
],
|
],
|
||||||
"default_print_profile": "0.10mm Standard 0.2mm nozzle @Anker",
|
"default_print_profile": "0.10mm Standard 0.2mm nozzle @Anker",
|
||||||
"extruder_clearance_height_to_lid": "250",
|
"extruder_clearance_height_to_lid": "250",
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"auxiliary_fan": "0",
|
"auxiliary_fan": "0",
|
||||||
"bed_exclude_area": [],
|
"bed_exclude_area": [],
|
||||||
"default_filament_profile": [
|
"default_filament_profile": [
|
||||||
"Anker Generic PLA+"
|
"Generic PLA+ @Anker"
|
||||||
],
|
],
|
||||||
"default_print_profile": "0.10mm Standard 0.25mm nozzle @Anker",
|
"default_print_profile": "0.10mm Standard 0.25mm nozzle @Anker",
|
||||||
"extruder_clearance_height_to_lid": "250",
|
"extruder_clearance_height_to_lid": "250",
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"auxiliary_fan": "0",
|
"auxiliary_fan": "0",
|
||||||
"bed_exclude_area": [],
|
"bed_exclude_area": [],
|
||||||
"default_filament_profile": [
|
"default_filament_profile": [
|
||||||
"Anker Generic PLA+"
|
"Generic PLA+ @Anker"
|
||||||
],
|
],
|
||||||
"default_print_profile": "0.20mm Standard @Anker",
|
"default_print_profile": "0.20mm Standard @Anker",
|
||||||
"extruder_clearance_height_to_lid": "250",
|
"extruder_clearance_height_to_lid": "250",
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"auxiliary_fan": "0",
|
"auxiliary_fan": "0",
|
||||||
"bed_exclude_area": [],
|
"bed_exclude_area": [],
|
||||||
"default_filament_profile": [
|
"default_filament_profile": [
|
||||||
"Anker Generic PLA+"
|
"Generic PLA+ @Anker"
|
||||||
],
|
],
|
||||||
"default_print_profile": "0.30mm Standard 0.6 nozzle @Anker",
|
"default_print_profile": "0.30mm Standard 0.6 nozzle @Anker",
|
||||||
"extruder_clearance_height_to_lid": "250",
|
"extruder_clearance_height_to_lid": "250",
|
||||||
|
|||||||
@@ -7,5 +7,5 @@
|
|||||||
"family": "Anker",
|
"family": "Anker",
|
||||||
"machine_tech": "FFF",
|
"machine_tech": "FFF",
|
||||||
"model_id": "V81101C3",
|
"model_id": "V81101C3",
|
||||||
"default_materials": "Anker Generic PLA;Anker Generic PLA+;Anker Generic PLA Silk;Anker Generic TPU;Anker Generic PETG"
|
"default_materials": "Generic PLA @Anker;Generic PLA+ @Anker;Generic PLA Silk @Anker;Generic TPU @Anker;Generic PETG @Anker"
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
|||||||
"inherits": "fdm_filament_abs",
|
"inherits": "fdm_filament_abs",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "RDI26qeSRSTe0PDg",
|
"setting_id": "RDI26qeSRSTe0PDg",
|
||||||
"filament_id": "GFB99",
|
"filament_id": "OF223rZv",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_settings_id": [
|
"filament_settings_id": [
|
||||||
"Anycubic ABS @Anycubic Kobra 3 Max 0.4 nozzle"
|
"Anycubic ABS @Anycubic Kobra 3 Max 0.4 nozzle"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"inherits": "fdm_filament_abs",
|
"inherits": "fdm_filament_abs",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "Moc1cylP6mmSQjlb",
|
"setting_id": "Moc1cylP6mmSQjlb",
|
||||||
"filament_id": "GFB99",
|
"filament_id": "OF223rZv",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_settings_id": [
|
"filament_settings_id": [
|
||||||
"Anycubic ABS @Anycubic Kobra 3 Max 0.6 nozzle"
|
"Anycubic ABS @Anycubic Kobra 3 Max 0.6 nozzle"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"inherits": "fdm_filament_abs",
|
"inherits": "fdm_filament_abs",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "2xgfnUKyOUQwYWPa",
|
"setting_id": "2xgfnUKyOUQwYWPa",
|
||||||
"filament_id": "GFB99",
|
"filament_id": "OF223rZv",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_settings_id": [
|
"filament_settings_id": [
|
||||||
"Anycubic ABS @Anycubic Kobra 3 Max 0.8 nozzle"
|
"Anycubic ABS @Anycubic Kobra 3 Max 0.8 nozzle"
|
||||||
|
|||||||
@@ -4,11 +4,14 @@
|
|||||||
"inherits": "fdm_filament_abs",
|
"inherits": "fdm_filament_abs",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "NOiAgxA0BbvLhR1v",
|
"setting_id": "NOiAgxA0BbvLhR1v",
|
||||||
"filament_id": "GFB99",
|
"filament_id": "OF223rZv",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_settings_id": [
|
"filament_settings_id": [
|
||||||
"Anycubic ABS @Anycubic Kobra S1 0.4 nozzle"
|
"Anycubic ABS @Anycubic Kobra S1 0.4 nozzle"
|
||||||
],
|
],
|
||||||
|
"filament_vendor": [
|
||||||
|
"Anycubic"
|
||||||
|
],
|
||||||
"filament_flow_ratio": [
|
"filament_flow_ratio": [
|
||||||
"0.95"
|
"0.95"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"inherits": "fdm_filament_abs",
|
"inherits": "fdm_filament_abs",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "MDWaiSjl89E6Edsn",
|
"setting_id": "MDWaiSjl89E6Edsn",
|
||||||
"filament_id": "GFABS",
|
"filament_id": "OF223rZv",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_settings_id": [
|
"filament_settings_id": [
|
||||||
"Anycubic ABS @Anycubic Kobra S1 Max 0.25 nozzle"
|
"Anycubic ABS @Anycubic Kobra S1 Max 0.25 nozzle"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"inherits": "fdm_filament_abs",
|
"inherits": "fdm_filament_abs",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "wZjVYc7dBDSKRusJ",
|
"setting_id": "wZjVYc7dBDSKRusJ",
|
||||||
"filament_id": "GFABS",
|
"filament_id": "OF223rZv",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_settings_id": [
|
"filament_settings_id": [
|
||||||
"Anycubic ABS @Anycubic Kobra S1 Max 0.4 nozzle"
|
"Anycubic ABS @Anycubic Kobra S1 Max 0.4 nozzle"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"inherits": "fdm_filament_abs",
|
"inherits": "fdm_filament_abs",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "AbB6JtoPRsNgmxyy",
|
"setting_id": "AbB6JtoPRsNgmxyy",
|
||||||
"filament_id": "GFABS",
|
"filament_id": "OF223rZv",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_settings_id": [
|
"filament_settings_id": [
|
||||||
"Anycubic ABS @Anycubic Kobra S1 Max 0.6 nozzle"
|
"Anycubic ABS @Anycubic Kobra S1 Max 0.6 nozzle"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"inherits": "fdm_filament_abs",
|
"inherits": "fdm_filament_abs",
|
||||||
"from": "system",
|
"from": "system",
|
||||||
"setting_id": "exX565xnrLPkYkvu",
|
"setting_id": "exX565xnrLPkYkvu",
|
||||||
"filament_id": "GFABS",
|
"filament_id": "OF223rZv",
|
||||||
"instantiation": "true",
|
"instantiation": "true",
|
||||||
"filament_settings_id": [
|
"filament_settings_id": [
|
||||||
"Anycubic ABS @Anycubic Kobra S1 Max 0.8 nozzle"
|
"Anycubic ABS @Anycubic Kobra S1 Max 0.8 nozzle"
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user