Compare commits

..

40 Commits

Author SHA1 Message Date
ExPikaPaka
0458925f85 Install proto before flatpack when there is internet. Add missing include that caused fail only on Unix 2026-06-04 17:41:40 +02:00
ExPikaPaka
7c34e089e4 Try to fix mac build again
Ahh, I never compiled any program on Mac, i thought it will behave the same was as Linux,
but there are some diferences of course..
2026-06-04 14:37:03 +02:00
ExPikaPaka
d314e9c09a Fix build for Mac 2026-06-04 14:22:04 +02:00
ExPikaPaka
7fa650e410 Fix build script as it was not working on some platforms 2026-06-04 12:28:25 +02:00
ExPikaPaka
1c1cee7784 Add missing fix for BOM file encoding 2026-06-04 12:27:43 +02:00
ExPikaPaka
1d7da51991 Fix encoding and build script 2026-06-04 12:13:10 +02:00
ExPikaPaka
3be63d4369 Use venv for python on Linux and macOS 2026-06-04 11:52:05 +02:00
ExPikaPaka
99a0dd8556 Fix BOM mark 2026-06-04 11:41:24 +02:00
ExPikaPaka
fcd3a66af4 Merge branch 'feature/protobuf_config_and_dynamic_ui' of https://github.com/OrcaSlicer/OrcaSlicer into feature/protobuf_config_and_dynamic_ui 2026-06-04 09:09:32 +02:00
ExPikaPaka
972da86fbc Fix incorrect path at codegen config 2026-06-04 09:08:27 +02:00
ExPikaPaka
8cb357ec06 Merge branch 'main' into feature/protobuf_config_and_dynamic_ui 2026-06-04 09:00:36 +02:00
ExPikaPaka
a29fac5de8 Update printer section in automatic layout 2026-06-04 08:41:43 +02:00
ExPikaPaka
14097382d8 Adds custom hooks that are called cause they need special code and can't be implemented purely via protobuf definition 2026-06-04 08:40:54 +02:00
ExPikaPaka
3db76d7f89 Extend code generators to properly handle new data types 2026-06-04 08:40:20 +02:00
ExPikaPaka
c47fc4529e Wire in generated files 2026-06-04 08:40:00 +02:00
ExPikaPaka
b823994feb Add cmake config to properly do incremental build 2026-06-04 08:38:50 +02:00
ExPikaPaka
403766b1b6 Add .gitignore entry to ignore generated code 2026-06-04 08:38:24 +02:00
ExPikaPaka
6e84139d60 Configure CI/CD build to properly build OrcaSlicer with Protobuf and codegen 2026-06-04 08:37:32 +02:00
ExPikaPaka
a78ef9ce1c Fix proto files after merging them from ~15 files to 3 2026-06-04 08:36:51 +02:00
ExPikaPaka
064e10c069 Remove outdated files 2026-06-04 08:36:28 +02:00
TheLegendTubaGuy
e0a47c61a2 [FIX] Fix Elegoo process profiles (#14020)
* Bump Elegoo profile version to refresh installed bundle

Bumps the Elegoo vendor profile version so installed profile bundles are refreshed from bundled resources after the recent Elegoo profile sync.\n\nThe previous version stayed at 02.04.00.00 after the profile layout changed, so existing installs could keep loading stale system/Elegoo files. That stale bundle can abort during profile loading and cause user presets inheriting from Elegoo machines, such as OrangeStorm Giga and Neptune 3 Max, to report missing parents.\n\nValidation:\n- jq parsed resources/profiles/Elegoo.json\n- verified all Elegoo.json sub_path entries exist\n- git diff --check

* Fix Elegoo process profile manifest
2026-06-04 14:19:10 +08:00
gyarros
a3e479af4e Add FilAr filament vendor (PLA, PLA-mate, PETG) (#13977) 2026-06-04 14:15:28 +08:00
Tobias Gloth
dc5d6b45de add "logfile" option to log diagnostics to file using boost (#13931)
add some logging options

Co-authored-by: SoftFever <softfeverever@gmail.com>
2026-06-04 13:28:51 +08:00
Noisyfox
58a8722a69 Don't show unsupported presets in drop down list (#13959)
* Don't show unsupported presets in drop down list, since it's not useful

* Add option to show unsupported presets

* Explicitly set the default value to `false`

* update filament list without restart on preference change

---------

Co-authored-by: yw4z <ywsyildiz@gmail.com>
2026-06-04 09:02:09 +08:00
Terasit Juntarasombut
dfe4b52822 l10n: Update Thai translation (th) and fix font issues (#14006)
* i18n: complete Thai (th) localization

* feat: fix thi translation

* feat: fix Thai language localization file

* feat: implement ImGuiWrapper with icon/font support and add Thai localization files

* l10n: Update Thai translation and fix font rendering issues

---------

Co-authored-by: SoftFever <softfeverever@gmail.com>
2026-06-04 02:35:47 +08:00
gedanke
9a053f15eb Fix: macOS Print/Export dropdown dismissed before the cursor reaches the menu (#12936) (#13995)
Since the wxWidgets 3.3 upgrade the Slice/Print split-button's transient
popup was dismissed the moment the cursor entered the gap between the
button and the menu, making "Print -> Export" impossible to select.

Anchor the menu flush against the button (with a 2 px overlap) instead of
6 px below it, removing the dead-zone the cursor had to cross.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-04 02:34:18 +08:00
3DPrinterOS SDK
c467990724 Support for 3DPrinterOS cloud integration (#10403) 2026-06-04 02:31:57 +08:00
Ian Bassi
757b6a5c46 Minor desc and wiki redirection fixe (#14011) 2026-06-03 10:58:25 -03:00
Ian Bassi
6f011c9f6a External bridge fix (#12568)
* Internal bridge fix

Co-Authored-By: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>

* Revert expansion increasing

Co-Authored-By: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>

* Recover assert

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update RegionExpansion.cpp

* Update RegionExpansion.cpp

---------

Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-06-03 10:19:04 -03:00
Ian Bassi
ae16c76dd2 Bridge Line Width + Improve bridge density (#11255)
* Base

* Standarized

Co-Authored-By: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>

* Wiki

* Improved descriptions based in RF47 Tests

Co-Authored-By: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>

* Bridge Flow Wiki

* Removed CMATH

Co-Authored-By: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>

* Default to 100

* Revert "TESTING BRIDGE DENSITY"

This reverts commit 8634f802311cd3877b0dd5651029b30b2d4eab60.

Removed desc change

* Minor changes

Co-Authored-By: Noisyfox <timemanager.rick@gmail.com>

* Update LayerRegion.cpp

* Missing ;

Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>

* Restrict bridge line width to nozzle diameter

* Clarification

* Increased both Bridge Densitys to 125

Co-Authored-By: Valerii Bokhan <80919135+valerii-bokhan@users.noreply.github.com>

* Valerii check

Co-Authored-By: Valerii Bokhan <80919135+valerii-bokhan@users.noreply.github.com>

* Fix error handling

* Clarify thick bridges documentation and tooltips

Updated the documentation and tooltips for 'thick_bridges' and 'thick_internal_bridges' to clarify that bridge extrusion uses a line height equal to the nozzle diameter, and to better explain the trade-offs between strength, reliability, and appearance.

* Partially restore bridge_flow description

* Suggestions

---------

Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
Co-authored-by: Noisyfox <timemanager.rick@gmail.com>
Co-authored-by: Valerii Bokhan <80919135+valerii-bokhan@users.noreply.github.com>
2026-06-03 10:16:59 -03:00
Ian Bassi
065540e48f ENH: Relative bridge direction + Align bridge/Ironing angles with model (#12055)
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
2026-06-03 10:12:26 -03:00
Kiss Lorand
1b72dbf6fa Fix inconsistent ordering of support base outline and fill (#11761)
* Preserve support base outline/fill order

Honor no_sort when emitting support toolpaths to keep outline-first order.
Group tree support base paths (including lightning) into per-area no_sort collections to prevent interleaving across islands.
Keep lightning layer lookup side-effect free.

* Tag Orca specific changes

Tag Orca specific changes vs. Bambu using the comment //ORCA: . This helps when reviewing merge commits from upstream Bambu so we don't end up causing regressions when pulling in commits from upstream
2026-06-02 14:39:27 +08:00
Kiss Lorand
ac92125012 Fix counterbore hole bridge (#13956)
Fix counterbore hole partial bridge
2026-06-02 14:34:43 +08:00
Bingo2023
d6a49ace15 Update Bambu Lab X2D 0.4 nozzle.json (#13985)
* Update Bambu Lab X2D 0.4 nozzle.json

corrected mistake from 31.5.2026
" is correct in machine code.

* Update Bambu Lab X2D 0.4 nozzle.json

fixed error with " -> \"

* Merge branch 'main' into patch-2
2026-06-01 22:15:34 +08:00
yw4z
71eebc2332 Merge code base of Setup Guide and Standalone versions of Printer / Filament Selection Dialogs (#13579) 2026-06-01 21:00:42 +08:00
Mykola Nahirnyi
87ceeaa0aa Wires in generated files 2026-05-27 10:02:24 +03:00
Mykola Nahirnyi
35d4bae778 Add codegen pipeline 2026-05-27 09:57:24 +03:00
Mykola Nahirnyi
2eb1b8ddd6 Add CMake integration and design doc 2026-05-27 09:54:25 +03:00
Mykola Nahirnyi
5475e0aebe Add generated C++ files from proto schema 2026-05-27 09:53:55 +03:00
Mykola Nahirnyi
04b7ae9219 Add PrintConfig proto schema and UI layout 2026-05-27 09:50:53 +03:00
199 changed files with 18152 additions and 33388 deletions

View File

@@ -211,6 +211,12 @@ jobs:
sed -i "/name: OrcaSlicer/{n;s|buildsystem: simple|buildsystem: simple\n build-options:\n env:\n git_commit_hash: \"$git_commit_hash\"|}" \
scripts/flatpak/com.orcaslicer.OrcaSlicer.yml
shell: bash
- name: Generate config sources
run: |
python3 -m venv /tmp/codegen_venv
/tmp/codegen_venv/bin/pip install grpcio-tools pyyaml -q
/tmp/codegen_venv/bin/python tools/run_codegen.py
shell: bash
- uses: flatpak/flatpak-github-actions/flatpak-builder@master
with:
bundle: OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak

View File

@@ -50,6 +50,26 @@ jobs:
useLocalCache: true # <--= Use the local cache (default is 'false').
useCloudCache: true
- name: Install codegen tools and generate config sources
run: |
pip install grpcio-tools
python tools/run_codegen.py
if: runner.os == 'Windows'
shell: pwsh
- name: Install codegen tools and generate config sources
run: |
if [ "$(uname)" = "Linux" ]; then
pip3 install grpcio-tools pyyaml
python3 tools/run_codegen.py
else
python3 -m venv /tmp/codegen_venv
/tmp/codegen_venv/bin/pip install grpcio-tools pyyaml -q
/tmp/codegen_venv/bin/python tools/run_codegen.py
fi
if: runner.os != 'Windows'
shell: bash
- name: Get the version and date on Ubuntu and macOS
if: runner.os != 'Windows'
run: |

5
.gitignore vendored
View File

@@ -45,4 +45,7 @@ test.js
.clangd
internal_docs/
*.flatpak
/flatpak-repo/
/flatpak-repo/
config.desc
tools/__pycache__/
src/slic3r/GUI/generated/

View File

@@ -721,7 +721,6 @@ foreach(po_file ${BBL_L10N_PO_FILES})
add_custom_command(
TARGET gettext_merge_po_with_pot PRE_BUILD
COMMAND msgmerge -N -o ${po_file} ${po_file} "${BBL_L18N_DIR}/OrcaSlicer.pot"
DEPENDS ${po_file}
)
endforeach()
add_custom_target(gettext_po_to_mo
@@ -737,7 +736,6 @@ foreach(po_file ${BBL_L10N_PO_FILES})
TARGET gettext_po_to_mo PRE_BUILD
COMMAND msgfmt ARGS --check-format -o ${mo_file} ${po_file}
#COMMAND msgfmt ARGS --check-compatibility -o ${mo_file} ${po_file}
DEPENDS ${po_file}
)
endforeach()
@@ -872,6 +870,11 @@ function(orcaslicer_copy_dlls target config postfix output_dlls)
endfunction()
# Config codegen — generates src/slic3r/GUI/generated/*.cpp from src/PrintConfigs/*.proto.
# Must run before compiling libslic3r (PrintConfig.cpp #includes the generated files).
# Requires: pip install grpcio-tools OR standalone protoc in PATH.
include(cmake/modules/ConfigCodegen.cmake)
# libslic3r, OrcaSlicer GUI and the OrcaSlicer executable.
add_subdirectory(deps_src)
add_subdirectory(src)

View File

@@ -545,6 +545,10 @@ if [[ -n "${BUILD_ORCA}" ]] || [[ -n "${BUILD_TESTS}" ]] ; then
BUILD_ARGS+=(-DORCA_UPDATER_SIG_KEY="${ORCA_UPDATER_SIG_KEY}")
fi
echo "Generating config sources from proto..."
pip install grpcio-tools -q
python3 tools/run_codegen.py || { echo "ERROR: config codegen failed"; exit 1; }
print_and_run cmake -S . -B $BUILD_DIR "${CMAKE_C_CXX_COMPILER_CLANG[@]}" "${CMAKE_LLD_LINKER_ARGS[@]}" "${CMAKE_CCACHE_ARGS[@]}" -G "Ninja Multi-Config" \
-DSLIC3R_PCH=${SLIC3R_PRECOMPILED_HEADERS} \
-DORCA_TOOLS=ON \

View File

@@ -180,6 +180,12 @@ function pack_deps() {
}
function build_slicer() {
echo "Generating config sources from proto..."
python3 -m venv /tmp/codegen_venv
/tmp/codegen_venv/bin/pip install grpcio-tools pyyaml -q
/tmp/codegen_venv/bin/python tools/run_codegen.py || { echo "ERROR: config codegen failed"; exit 1; }
CODEGEN_PYTHON="/tmp/codegen_venv/bin/python3"
# iterate over two architectures: x86_64 and arm64
for _ARCH in x86_64 arm64; do
# if ARCH is universal or equal to _ARCH
@@ -204,6 +210,7 @@ function build_slicer() {
-DCMAKE_OSX_ARCHITECTURES="${_ARCH}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET="${OSX_DEPLOYMENT_TARGET}" \
-DCMAKE_IGNORE_PREFIX_PATH="${CMAKE_IGNORE_PREFIX_PATH}" \
-DPython3_EXECUTABLE="${CODEGEN_PYTHON}" \
${CMAKE_POLICY_COMPAT}
fi
cmake --build . --config "$BUILD_CONFIG" --target "$SLICER_BUILD_TARGET"

View File

@@ -126,6 +126,15 @@ if "%1"=="deps" goto :done
:slicer
echo "building Orca Slicer..."
cd %WP%
echo "generating config sources from proto..."
pip install grpcio-tools -q
python tools/run_codegen.py
if errorlevel 1 (
echo "ERROR: config codegen failed"
exit /b 1
)
mkdir %build_dir%
cd %build_dir%

View File

@@ -57,6 +57,15 @@ if "%1"=="deps" exit /b 0
:slicer
echo "building Orca Slicer..."
cd %WP%
echo "generating config sources from proto..."
pip install grpcio-tools -q
python tools/run_codegen.py
if errorlevel 1 (
echo "ERROR: config codegen failed"
exit /b 1
)
mkdir %build_dir%
cd %build_dir%

View File

@@ -0,0 +1,99 @@
# OrcaSlicer Config Codegen CMake Module
#
# Generates C++ source files from protobuf schema definitions.
# Generated files live in src/slic3r/GUI/generated/ and are gitignored.
# Run 'python tools/run_codegen.py' (requires grpcio-tools or protoc) to regenerate.
#
# Targets:
# codegen_config - Custom target to regenerate C++ from .proto files
# validate_config - Custom target to validate generated vs original
#
# Usage in parent CMakeLists.txt:
# include(cmake/modules/ConfigCodegen.cmake)
find_program(PROTOC_EXECUTABLE protoc)
find_package(Python3 COMPONENTS Interpreter QUIET)
# If generated files are missing (fresh clone), run codegen immediately at configure time.
# This allows cmake configure + build to work without a separate pre-build step.
set(_generated_marker "${CMAKE_SOURCE_DIR}/src/slic3r/GUI/generated/PrintConfigDef_generated.cpp")
if(Python3_EXECUTABLE AND NOT EXISTS "${_generated_marker}")
message(STATUS "Config codegen: generated files missing — running codegen now...")
execute_process(
COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/tools/run_codegen.py" --no-validate
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
RESULT_VARIABLE _codegen_result
)
if(NOT _codegen_result EQUAL 0)
message(FATAL_ERROR "Config codegen failed. Install grpcio-tools: pip install grpcio-tools")
endif()
message(STATUS "Config codegen: generated files created successfully")
elseif(NOT Python3_EXECUTABLE AND NOT EXISTS "${_generated_marker}")
message(FATAL_ERROR "Config codegen: generated files missing and Python3 not found.\n"
"Install Python and grpcio-tools: pip install grpcio-tools\n"
"Then run: python tools/run_codegen.py")
endif()
set(CONFIG_PROTO_DIR "${CMAKE_SOURCE_DIR}/src/PrintConfigs")
set(CONFIG_CODEGEN_DIR "${CMAKE_SOURCE_DIR}/src/slic3r/GUI/generated")
set(CONFIG_LAYOUT_YAML "${CMAKE_SOURCE_DIR}/src/PrintConfigs/layout.yaml")
set(CONFIG_DESC_FILE "${CMAKE_BINARY_DIR}/config.desc")
set(CODEGEN_TOOL "${CMAKE_SOURCE_DIR}/tools/config_codegen.py")
set(VALIDATE_TOOL "${CMAKE_SOURCE_DIR}/tools/validate_codegen.py")
set(RUN_CODEGEN_TOOL "${CMAKE_SOURCE_DIR}/tools/run_codegen.py")
# Generated output files (TabLayout_generated.cpp is also generated from layout.yaml)
set(CONFIG_GENERATED_SOURCES
"${CONFIG_CODEGEN_DIR}/PrintConfigDef_generated.cpp"
"${CONFIG_CODEGEN_DIR}/Preset_options_generated.cpp"
"${CONFIG_CODEGEN_DIR}/Invalidation_generated.cpp"
"${CONFIG_CODEGEN_DIR}/OptionKeys_generated.cpp"
"${CONFIG_CODEGEN_DIR}/TabLayout_generated.cpp"
)
# Collect all .proto source files (flat in src/PrintConfigs/, excluding config_metadata.proto)
file(GLOB CONFIG_PROTO_FILES
"${CONFIG_PROTO_DIR}/filament.proto"
"${CONFIG_PROTO_DIR}/print.proto"
"${CONFIG_PROTO_DIR}/printer.proto"
)
set(CONFIG_PROTO_FILES
"${CONFIG_PROTO_DIR}/config_metadata.proto"
${CONFIG_PROTO_FILES}
)
if(Python3_EXECUTABLE)
# Single command: run_codegen.py handles protoc/grpcio-tools detection internally.
# Proto files → generated .cpp files. Runs automatically when any .proto changes.
add_custom_command(
OUTPUT ${CONFIG_GENERATED_SOURCES}
COMMAND ${Python3_EXECUTABLE} ${RUN_CODEGEN_TOOL} --no-validate
DEPENDS ${CONFIG_PROTO_FILES} ${CONFIG_LAYOUT_YAML} ${CODEGEN_TOOL}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Re-generating config C++ from changed .proto files"
VERBATIM
)
# codegen_config is part of ALL — runs before every build, checks if protos changed.
add_custom_target(codegen_config ALL
DEPENDS ${CONFIG_GENERATED_SOURCES}
COMMENT "Config codegen up to date"
)
# Validation target: cmake --build . --target validate_config
add_custom_target(validate_config
COMMAND ${Python3_EXECUTABLE} ${VALIDATE_TOOL}
DEPENDS ${CONFIG_GENERATED_SOURCES}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMENT "Validating generated config code against PrintConfig.cpp"
VERBATIM
)
# Export for use by subdirectories (libslic3r, etc.)
set(CONFIG_GENERATED_SOURCES "${CONFIG_GENERATED_SOURCES}" CACHE INTERNAL "Generated config cpp files")
message(STATUS "Config codegen: enabled — proto changes auto-regenerate on next build")
else()
message(STATUS "Config codegen: Python3 not found — run: pip install grpcio-tools && python tools/run_codegen.py")
endif()

View File

@@ -1,171 +0,0 @@
# Mixed Filament
Ported from [OrcaSlicer-FullSpectrum](https://github.com/SoftFever/OrcaSlicer-FullSpectrum)
with contributions from Rad, Justin Hayes, Calogero Guagenti, xSil3nt, and ratdoux.
---
## User Guide
### What It Does
Mixed Filament lets a single virtual filament slot alternate between two
physical filaments across layers (or within a layer in Pointillisme mode),
producing blended or gradient-like colours on single-extruder printers.
### Enabling
1. Load a multi-colour (multi-extruder) profile with at least 2 filaments.
2. The **Mixed Filaments** panel appears automatically in the right-hand sidebar
when 2 or more filaments are configured.
3. Each auto-generated row represents one pair of physical filaments.
Toggle a row to enable it; the total filament count grows to include the
virtual slot.
### Sidebar Workflow
- **Add** — creates a custom row for the same pair or a different ratio.
- **Edit** — opens `MixedFilamentConfigPanel` to adjust ratio, pattern,
surface offset (bias), and distribution mode.
- **Delete** — marks the row deleted; existing painted geometry retains its
virtual filament ID until you re-slice or repaint.
Painting with a virtual filament ID behaves the same as painting with a
physical one — use the Multi-Material Painting gizmo and select the virtual
slot from the colour palette.
### Color Match Dialog
Open via the colour swatch on a mixed row. The dialog (`MixedFilamentColorMatchDialog`)
shows a live preview strip of the blended result and lets you adjust ratio
until the preview matches your target colour. The preview accounts for
surface-offset bias when enabled.
### Anti-Banding Options
| Setting | What it does |
|---|---|
| `mixed_filament_advanced_dithering` | Uses an ordered dither pattern instead of simple A-then-B runs. Reduces stripe visibility on some hue pairs. More experimental than the default. |
| `dithering_local_z_mode` | Splits each blended layer into two sub-layers whose heights are proportional to the mix ratio (e.g. 66/33 at 0.12 mm → 0.08 mm + 0.04 mm). Produces the smoothest colour gradients. |
| `dithering_local_z_whole_objects` | Extends Local-Z splitting beyond painted masks to cover the entire object cross-section. Useful when mixed walls surround a painted zone. |
| `dithering_local_z_direct_multicolor` | For rows with 3 or more physical components, allocates Local-Z sub-layers directly across all components with carry-over error correction instead of collapsing to pair cadence. More toolchanges; less banding. |
### Gotchas
- **Single-extruder warning** — Mixed Filament requires a physical toolchange
between the two components. On a true single-nozzle printer this means a
manual filament swap. Verify your printer profile supports `T0`/`T1` before
using mixed slots in a production print.
- **Variable-layer interaction** — If Variable Layer Height is enabled, Local-Z
sub-layer heights are recomputed per interval. The mix ratio is preserved but
the absolute sub-layer heights change with the variable height. Review the
layer preview after applying variable layers.
- **Custom sequence disabled** — OrcaSlicer's "custom toolchange sequence" is
suppressed when mixed filaments are active (`PlateSettingsDialog`). The
virtual-to-physical resolution must control toolchange order; a user-defined
sequence would break it.
- **Stable IDs** — each mixed row carries a `stable_id` (64-bit). If you
reorder or delete rows and then load an older project, the ID remap in
`PresetBundle::update_mixed_filament_id_remap` translates painted geometry
to the correct new virtual slot. Do not rely on the 1-based filament index
as a stable identifier.
---
## Developer Guide
### Core Data Structures
```
src/libslic3r/MixedFilament.hpp — MixedFilament struct, MixedFilamentManager
src/libslic3r/MixedFilament.cpp — serialization, resolve(), auto_generate()
src/libslic3r/LocalZOrderOptimizer.hpp — bucket-ordering helpers for Local-Z
```
The key scalar fields on `MixedFilament`:
- `component_a`, `component_b` — 1-based physical filament indices.
- `ratio_a`, `ratio_b` — layer-alternation cadence numerators.
- `mix_b_percent` — nominal colour mix (used for Local-Z height computation
and the Color Match preview; does not change the cadence).
- `stable_id` — monotonically increasing 64-bit ID assigned at construction.
Never reused. Survives serialization round-trips.
- `distribution_mode` — selects between `Simple`, `SameLayerPointillisme`,
and `GroupedManual`.
### Seam: Adding New Distribution Modes
`MixedFilamentManager::resolve()` in `MixedFilament.cpp` is the single
dispatch point that maps `(virtual_filament_id, num_physical, layer_index)`
to a physical extruder. The current switch covers `Simple` and
`SameLayerPointillisme`. A new mode is added by:
1. Adding a value to the `MixedFilament::DistributionMode` enum in
`MixedFilament.hpp`.
2. Adding a `case` to `MixedFilamentManager::resolve()` in `MixedFilament.cpp`.
3. Serializing the new mode token in `serialize_custom_entries` /
`load_custom_entries` (format is a semicolon-delimited row string; see
existing tokens for the convention).
G-code emission (`src/libslic3r/GCode/`) reads only the physical ID returned
by `resolve()`, so new modes are automatically emitted without further changes.
### Seam: New Toolchange-Cost Heuristics
`LocalZOrderOptimizer` (`src/libslic3r/LocalZOrderOptimizer.hpp`) exposes:
- `order_bucket_extruders(bucket, current, preferred_last)` — reorders a
single-layer bucket to minimise toolchanges given the current active extruder.
- `order_pass_group(group, current_extruder)` — greedy walk across a set of
buckets (one per Local-Z sub-layer) to minimise total transitions.
To add a new heuristic (e.g. cost-based look-ahead), replace or wrap
`order_pass_group`. The caller in `PrintObjectSlice.cpp` passes the result
directly into the sub-layer plan, so the heuristic is fully decoupled from
the plan builder.
### Seam: New Picker Shapes in the Color Map Panel
`MixedFilamentColorMapPanel` (`src/slic3r/GUI/MixedFilamentColorMapPanel.hpp`)
renders a 2-D colour map using a set of geometry "types" (currently strip and
gradient). Each type is a small self-contained rendering path keyed by an enum
value. New shapes are added by:
1. Adding an enum value to `MixedFilamentColorMapPanel::GeometryType`.
2. Implementing the corresponding `Paint*` helper (follow `PaintStrip` as a
template).
3. Wiring the new type into the `switch` in `OnPaint`.
### Persistence (3MF)
The entire mixed-filament state is stored as a single string key
`mixed_filament_definitions` in the project config block (section `[presets]`
in the 3MF metadata).
Round-trip path:
```
MixedFilamentManager::serialize_custom_entries()
called by PresetBundle::sync_mixed_filaments_to_config()
written by bbs_3mf: store_bbs_3mf → config.set("presets", "mixed_filament_definitions", ...)
load_bbs_3mf → config.get("presets", "mixed_filament_definitions")
stored in project_config["mixed_filament_definitions"]
read by PresetBundle::sync_mixed_filaments_from_config()
→ mixed_filaments.auto_generate(colours)
→ mixed_filaments.load_custom_entries(defs, colours)
```
Auto-generated rows are *not* written to the definitions string; they are
rebuilt from the filament colour list. Only `custom == true` rows are stored.
See `tests/fff_print/test_mixed_filament_e2e.cpp` for regression tests
covering this path.
### ID Remap
When filaments are added, removed, or reordered, virtual IDs shift.
`PresetBundle::update_mixed_filament_id_remap(old_mixed, old_count, new_count)`
produces a `remap` vector where `remap[old_virtual_id] = new_virtual_id`.
Painted triangle mesh face data uses these IDs; the remap is applied in
`TriangleSelectorMixed` after any filament list change.

View File

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

View File

@@ -250,7 +250,3 @@ src/slic3r/GUI/RammingChart.cpp
src/slic3r/GUI/StepMeshDialog.cpp
src/slic3r/GUI/FilamentPickerDialog.hpp
src/libslic3r/PresetBundle.cpp
src/slic3r/GUI/MixedFilamentColorMatchDialog.cpp
src/slic3r/GUI/MixedFilamentColorMatchDialog.hpp
src/slic3r/GUI/MixedFilamentConfigPanel.cpp
src/slic3r/GUI/MixedFilamentConfigPanel.hpp

View File

@@ -4,7 +4,19 @@
# Icezaza, 2026.
#
msgid ""
msgstr "Project-Id-Version: Orca Slicer\nReport-Msgid-Bugs-To: \nPOT-Creation-Date: 2026-05-22 02:24+0800\nPO-Revision-Date: 2026-05-28 22:39+0700\nLast-Translator: Icezaza\nLanguage-Team: Thai\nLanguage: th\nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit\nPlural-Forms: nplurals=1; plural=0;\nX-Generator: Codex Thai translation bootstrap"
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-05-22 02:24+0800\n"
"PO-Revision-Date: 2026-05-28 22:39+0700\n"
"Last-Translator: Icezaza\n"
"Language-Team: Thai\n"
"Language: th\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Codex Thai translation bootstrap\n"
msgid "right"
msgstr "ขวา"
@@ -9608,10 +9620,10 @@ msgid "Normal"
msgstr "ปกติ"
msgid "Resonance Compensation"
msgstr "การชดเชยเสียงสะท้อ"
msgstr "การชดเชยการสั่นพ้อ"
msgid "Resonance Avoidance Speed"
msgstr "ความเร็วการหลีกเลี่ยงเสียงสะท้อ"
msgstr "ความเร็วการหลีกเลี่ยงการสั่นพ้อ"
msgid "Frequency"
msgstr "ความถี่"
@@ -9758,7 +9770,7 @@ msgid "Continue"
msgstr "ดำเนินการต่อ"
msgid "Back"
msgstr "ย้อนกลั"
msgstr "ลั"
msgid "Don't warn again for this preset"
msgstr "ไม่ต้องเตือนอีกสำหรับค่าที่กำหนดล่วงหน้านี้"
@@ -9799,7 +9811,7 @@ msgid "Transfer"
msgstr "โอนย้าย"
msgid "Don't save"
msgstr "อย่าบันทึก"
msgstr "ไม่บันทึก"
msgid "Discard"
msgstr "ทิ้ง"
@@ -11852,10 +11864,10 @@ msgid ""
msgstr "สร้างเส้นทางรอบขอบเพิ่มไส้ในเหนือส่วนยื่นสูงชันและพื้นที่ที่ไม่สามารถทอดสมอสะพานได้"
msgid "Reverse on even"
msgstr "ย้อนกลับในคู่"
msgstr "กลับด้านหน้าเลขคู่"
msgid "Overhang reversal"
msgstr "การกลับรายการยื่นออกมา"
msgstr "การกลับด้านส่วนยื่นออกมา"
msgid ""
"Extrude perimeters that have a part over an overhang in the reverse "
@@ -11867,7 +11879,7 @@ msgid ""
msgstr "รีดเส้นรอบวงที่มีส่วนยื่นออกมาในทิศทางย้อนกลับบนชั้นคู่ รูปแบบการสลับนี้สามารถปรับปรุงระยะยื่นที่สูงชันได้อย่างมาก\n\nการตั้งค่านี้ยังช่วยลดการบิดงอของชิ้นส่วนเนื่องจากการลดความเค้นในผนังชิ้นส่วนอีกด้วย"
msgid "Reverse only internal perimeters"
msgstr "ย้อนกลับเฉพาะขอบเขตภายในเท่านั้น"
msgstr "กลับด้านเฉพาะขอบเขตภายในเท่านั้น"
msgid ""
"Apply the reverse perimeters logic only on internal perimeters.\n"
@@ -11902,7 +11914,7 @@ msgid "Sacrificial layer"
msgstr "ชั้นบูชายัญ"
msgid "Reverse threshold"
msgstr "เกณฑ์ย้อนกลับ"
msgstr "เกณฑ์การกลับด้าน"
msgid "Overhang reversal threshold"
msgstr "เกณฑ์การกลับรายการส่วนเกิน"
@@ -14395,25 +14407,25 @@ msgid "Maximum acceleration for travel (M204 T), it only applies to Marlin 2."
msgstr "อัตราเร่งสูงสุดสำหรับการเดินทาง (M204 T) ใช้กับ Marlin 2 เท่านั้น"
msgid "Resonance avoidance"
msgstr "การหลีกเลี่ยงเสียงสะท้อ"
msgstr "การหลีกเลี่ยงการสั่นพ้อ"
msgid ""
"By reducing the speed of the outer wall to avoid the resonance zone of the "
"printer, ringing on the surface of the model are avoided.\n"
"Please turn this option off when testing ringing."
msgstr "โดยการลดความเร็วของผนังด้านนอกเพื่อหลีกเลี่ยงโซนเสียงสะท้อของเครื่องพิมพ์ หลีกเลี่ยงเสียงกริ่งบนพื้นผิวของแบบจำลอง\nโปรดปิดตัวเลือกนี้เมื่อทดสอบเสียงเรียกเข้า"
msgstr "โดยการลดความเร็วของผนังด้านนอกเพื่อหลีกเลี่ยงโซนสั่นพ้อของเครื่องพิมพ์ หลีกเลี่ยงรอยคลื่นบนพื้นผิวของโมเดล\nโปรดปิดตัวเลือกนี้เมื่อทดสอบการสั่นพ้อง"
msgid "Min"
msgstr "นาที"
msgid "Minimum speed of resonance avoidance."
msgstr "ความเร็วขั้นต่ำของการหลีกเลี่ยงเสียงสะท้อ"
msgstr "ความเร็วขั้นต่ำของการหลีกเลี่ยงเสียงการสั่นพ้อ"
msgid "Max"
msgstr "สูงสุด"
msgid "Maximum speed of resonance avoidance."
msgstr "ความเร็วสูงสุดของการหลีกเลี่ยงเสียงสะท้อ"
msgstr "ความเร็วสูงสุดของการหลีกเลี่ยงการสั่นพ้อ"
msgid "Emit input shaping"
msgstr "ปล่อยรูปร่างอินพุต"

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
{
"name": "Elegoo",
"version": "02.04.00.00",
"version": "02.04.00.02",
"force_update": "0",
"description": "Elegoo configurations",
"machine_model_list": [
@@ -286,6 +286,10 @@
"name": "0.40mm Standard @Elegoo Neptune 0.8 nozzle",
"sub_path": "process/EN2SERIES/0.40mm Standard @Elegoo Neptune 0.8 nozzle.json"
},
{
"name": "0.50mm Standard @Elegoo Giga 1.0 nozzle",
"sub_path": "process/EOSGIGA/0.50mm Standard @Elegoo Giga 1.0 nozzle.json"
},
{
"name": "0.50mm Standard @Elegoo N3Max 1.0 nozzle",
"sub_path": "process/EN3SERIES/0.50mm Standard @Elegoo N3Max 1.0 nozzle.json"
@@ -314,6 +318,42 @@
"name": "0.50mm Standard @Elegoo N4Pro 1.0 nozzle",
"sub_path": "process/EN4SERIES/0.50mm Standard @Elegoo N4Pro 1.0 nozzle.json"
},
{
"name": "0.08mm Optimal @Elegoo C 0.2 nozzle",
"sub_path": "process/EC/0.08mm Optimal @Elegoo C 0.2 nozzle.json"
},
{
"name": "0.12mm Draft @Elegoo C 0.2 nozzle",
"sub_path": "process/EC/0.12mm Draft @Elegoo C 0.2 nozzle.json"
},
{
"name": "0.14mm Extra Draft @Elegoo C 0.2 nozzle",
"sub_path": "process/EC/0.14mm Extra Draft @Elegoo C 0.2 nozzle.json"
},
{
"name": "0.08mm Optimal @Elegoo CC 0.2 nozzle",
"sub_path": "process/ECC/0.08mm Optimal @Elegoo CC 0.2 nozzle.json"
},
{
"name": "0.12mm Draft @Elegoo CC 0.2 nozzle",
"sub_path": "process/ECC/0.12mm Draft @Elegoo CC 0.2 nozzle.json"
},
{
"name": "0.14mm Extra Draft @Elegoo CC 0.2 nozzle",
"sub_path": "process/ECC/0.14mm Extra Draft @Elegoo CC 0.2 nozzle.json"
},
{
"name": "0.08mm Optimal @Elegoo CC2 0.2 nozzle",
"sub_path": "process/ECC2/0.08mm Optimal @Elegoo CC2 0.2 nozzle.json"
},
{
"name": "0.12mm Draft @Elegoo CC2 0.2 nozzle",
"sub_path": "process/ECC2/0.12mm Draft @Elegoo CC2 0.2 nozzle.json"
},
{
"name": "0.14mm Extra Draft @Elegoo CC2 0.2 nozzle",
"sub_path": "process/ECC2/0.14mm Extra Draft @Elegoo CC2 0.2 nozzle.json"
},
{
"name": "0.08mm Optimal @Elegoo N3Max 0.2 nozzle",
"sub_path": "process/EN3SERIES/0.08mm Optimal @Elegoo N3Max 0.2 nozzle.json"
@@ -370,6 +410,322 @@
"name": "0.12mm Draft @Elegoo N4Pro 0.2 nozzle",
"sub_path": "process/EN4SERIES/0.12mm Draft @Elegoo N4Pro 0.2 nozzle.json"
},
{
"name": "0.12mm Fine @Elegoo C 0.4 nozzle",
"sub_path": "process/EC/0.12mm Fine @Elegoo C 0.4 nozzle.json"
},
{
"name": "0.16mm Optimal @Elegoo C 0.4 nozzle",
"sub_path": "process/EC/0.16mm Optimal @Elegoo C 0.4 nozzle.json"
},
{
"name": "0.20mm Strength @Elegoo C 0.4 nozzle",
"sub_path": "process/EC/0.20mm Strength @Elegoo C 0.4 nozzle.json"
},
{
"name": "0.24mm Draft @Elegoo C 0.4 nozzle",
"sub_path": "process/EC/0.24mm Draft @Elegoo C 0.4 nozzle.json"
},
{
"name": "0.28mm Extra Draft @Elegoo C 0.4 nozzle",
"sub_path": "process/EC/0.28mm Extra Draft @Elegoo C 0.4 nozzle.json"
},
{
"name": "0.12mm Fine @Elegoo CC 0.4 nozzle",
"sub_path": "process/ECC/0.12mm Fine @Elegoo CC 0.4 nozzle.json"
},
{
"name": "0.16mm Optimal @Elegoo CC 0.4 nozzle",
"sub_path": "process/ECC/0.16mm Optimal @Elegoo CC 0.4 nozzle.json"
},
{
"name": "0.20mm Strength @Elegoo CC 0.4 nozzle",
"sub_path": "process/ECC/0.20mm Strength @Elegoo CC 0.4 nozzle.json"
},
{
"name": "0.24mm Draft @Elegoo CC 0.4 nozzle",
"sub_path": "process/ECC/0.24mm Draft @Elegoo CC 0.4 nozzle.json"
},
{
"name": "0.28mm Extra Draft @Elegoo CC 0.4 nozzle",
"sub_path": "process/ECC/0.28mm Extra Draft @Elegoo CC 0.4 nozzle.json"
},
{
"name": "0.12mm Fine @Elegoo CC2 0.4 nozzle",
"sub_path": "process/ECC2/0.12mm Fine @Elegoo CC2 0.4 nozzle.json"
},
{
"name": "0.16mm Optimal @Elegoo CC2 0.4 nozzle",
"sub_path": "process/ECC2/0.16mm Optimal @Elegoo CC2 0.4 nozzle.json"
},
{
"name": "0.20mm Strength @Elegoo CC2 0.4 nozzle",
"sub_path": "process/ECC2/0.20mm Strength @Elegoo CC2 0.4 nozzle.json"
},
{
"name": "0.24mm Draft @Elegoo CC2 0.4 nozzle",
"sub_path": "process/ECC2/0.24mm Draft @Elegoo CC2 0.4 nozzle.json"
},
{
"name": "0.28mm Extra Draft @Elegoo CC2 0.4 nozzle",
"sub_path": "process/ECC2/0.28mm Extra Draft @Elegoo CC2 0.4 nozzle.json"
},
{
"name": "0.16mm Optimal @Elegoo Giga 0.4 nozzle",
"sub_path": "process/EOSGIGA/0.16mm Optimal @Elegoo Giga 0.4 nozzle.json"
},
{
"name": "0.20mm Strength @Elegoo Giga 0.4 nozzle",
"sub_path": "process/EOSGIGA/0.20mm Strength @Elegoo Giga 0.4 nozzle.json"
},
{
"name": "0.24mm Draft @Elegoo Giga 0.4 nozzle",
"sub_path": "process/EOSGIGA/0.24mm Draft @Elegoo Giga 0.4 nozzle.json"
},
{
"name": "0.28mm Extra Draft @Elegoo Giga 0.4 nozzle",
"sub_path": "process/EOSGIGA/0.28mm Extra Draft @Elegoo Giga 0.4 nozzle.json"
},
{
"name": "0.12mm Fine @Elegoo N3Max 0.4 nozzle",
"sub_path": "process/EN3SERIES/0.12mm Fine @Elegoo N3Max 0.4 nozzle.json"
},
{
"name": "0.16mm Optimal @Elegoo N3Max 0.4 nozzle",
"sub_path": "process/EN3SERIES/0.16mm Optimal @Elegoo N3Max 0.4 nozzle.json"
},
{
"name": "0.20mm Strength @Elegoo N3Max 0.4 nozzle",
"sub_path": "process/EN3SERIES/0.20mm Strength @Elegoo N3Max 0.4 nozzle.json"
},
{
"name": "0.24mm Draft @Elegoo N3Max 0.4 nozzle",
"sub_path": "process/EN3SERIES/0.24mm Draft @Elegoo N3Max 0.4 nozzle.json"
},
{
"name": "0.28mm Extra Draft @Elegoo N3Max 0.4 nozzle",
"sub_path": "process/EN3SERIES/0.28mm Extra Draft @Elegoo N3Max 0.4 nozzle.json"
},
{
"name": "0.12mm Fine @Elegoo N3Plus 0.4 nozzle",
"sub_path": "process/EN3SERIES/0.12mm Fine @Elegoo N3Plus 0.4 nozzle.json"
},
{
"name": "0.16mm Optimal @Elegoo N3Plus 0.4 nozzle",
"sub_path": "process/EN3SERIES/0.16mm Optimal @Elegoo N3Plus 0.4 nozzle.json"
},
{
"name": "0.20mm Strength @Elegoo N3Plus 0.4 nozzle",
"sub_path": "process/EN3SERIES/0.20mm Strength @Elegoo N3Plus 0.4 nozzle.json"
},
{
"name": "0.24mm Draft @Elegoo N3Plus 0.4 nozzle",
"sub_path": "process/EN3SERIES/0.24mm Draft @Elegoo N3Plus 0.4 nozzle.json"
},
{
"name": "0.28mm Extra Draft @Elegoo N3Plus 0.4 nozzle",
"sub_path": "process/EN3SERIES/0.28mm Extra Draft @Elegoo N3Plus 0.4 nozzle.json"
},
{
"name": "0.12mm Fine @Elegoo N3Pro 0.4 nozzle",
"sub_path": "process/EN3SERIES/0.12mm Fine @Elegoo N3Pro 0.4 nozzle.json"
},
{
"name": "0.16mm Optimal @Elegoo N3Pro 0.4 nozzle",
"sub_path": "process/EN3SERIES/0.16mm Optimal @Elegoo N3Pro 0.4 nozzle.json"
},
{
"name": "0.20mm Strength @Elegoo N3Pro 0.4 nozzle",
"sub_path": "process/EN3SERIES/0.20mm Strength @Elegoo N3Pro 0.4 nozzle.json"
},
{
"name": "0.24mm Draft @Elegoo N3Pro 0.4 nozzle",
"sub_path": "process/EN3SERIES/0.24mm Draft @Elegoo N3Pro 0.4 nozzle.json"
},
{
"name": "0.28mm Extra Draft @Elegoo N3Pro 0.4 nozzle",
"sub_path": "process/EN3SERIES/0.28mm Extra Draft @Elegoo N3Pro 0.4 nozzle.json"
},
{
"name": "0.12mm Fine @Elegoo N4 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.12mm Fine @Elegoo N4 0.4 nozzle.json"
},
{
"name": "0.16mm Optimal @Elegoo N4 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.16mm Optimal @Elegoo N4 0.4 nozzle.json"
},
{
"name": "0.20mm Strength @Elegoo N4 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.20mm Strength @Elegoo N4 0.4 nozzle.json"
},
{
"name": "0.24mm Draft @Elegoo N4 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.24mm Draft @Elegoo N4 0.4 nozzle.json"
},
{
"name": "0.28mm Extra Draft @Elegoo N4 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.28mm Extra Draft @Elegoo N4 0.4 nozzle.json"
},
{
"name": "0.12mm Fine @Elegoo N4Max 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.12mm Fine @Elegoo N4Max 0.4 nozzle.json"
},
{
"name": "0.16mm Optimal @Elegoo N4Max 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.16mm Optimal @Elegoo N4Max 0.4 nozzle.json"
},
{
"name": "0.20mm Strength @Elegoo N4Max 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.20mm Strength @Elegoo N4Max 0.4 nozzle.json"
},
{
"name": "0.24mm Draft @Elegoo N4Max 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.24mm Draft @Elegoo N4Max 0.4 nozzle.json"
},
{
"name": "0.28mm Extra Draft @Elegoo N4Max 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.28mm Extra Draft @Elegoo N4Max 0.4 nozzle.json"
},
{
"name": "0.12mm Fine @Elegoo N4Plus 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.12mm Fine @Elegoo N4Plus 0.4 nozzle.json"
},
{
"name": "0.16mm Optimal @Elegoo N4Plus 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.16mm Optimal @Elegoo N4Plus 0.4 nozzle.json"
},
{
"name": "0.20mm Strength @Elegoo N4Plus 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.20mm Strength @Elegoo N4Plus 0.4 nozzle.json"
},
{
"name": "0.24mm Draft @Elegoo N4Plus 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.24mm Draft @Elegoo N4Plus 0.4 nozzle.json"
},
{
"name": "0.28mm Extra Draft @Elegoo N4Plus 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.28mm Extra Draft @Elegoo N4Plus 0.4 nozzle.json"
},
{
"name": "0.12mm Fine @Elegoo N4Pro 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.12mm Fine @Elegoo N4Pro 0.4 nozzle.json"
},
{
"name": "0.16mm Optimal @Elegoo N4Pro 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.16mm Optimal @Elegoo N4Pro 0.4 nozzle.json"
},
{
"name": "0.20mm Strength @Elegoo N4Pro 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.20mm Strength @Elegoo N4Pro 0.4 nozzle.json"
},
{
"name": "0.24mm Draft @Elegoo N4Pro 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.24mm Draft @Elegoo N4Pro 0.4 nozzle.json"
},
{
"name": "0.28mm Extra Draft @Elegoo N4Pro 0.4 nozzle",
"sub_path": "process/EN4SERIES/0.28mm Extra Draft @Elegoo N4Pro 0.4 nozzle.json"
},
{
"name": "0.12mm Fine @Elegoo Neptune 0.4 nozzle",
"sub_path": "process/EN2SERIES/0.12mm Fine @Elegoo Neptune 0.4 nozzle.json"
},
{
"name": "0.16mm Optimal @Elegoo Neptune 0.4 nozzle",
"sub_path": "process/EN2SERIES/0.16mm Optimal @Elegoo Neptune 0.4 nozzle.json"
},
{
"name": "0.20mm Strength @Elegoo Neptune 0.4 nozzle",
"sub_path": "process/EN2SERIES/0.20mm Strength @Elegoo Neptune 0.4 nozzle.json"
},
{
"name": "0.24mm Draft @Elegoo Neptune 0.4 nozzle",
"sub_path": "process/EN2SERIES/0.24mm Draft @Elegoo Neptune 0.4 nozzle.json"
},
{
"name": "0.28mm Extra Draft @Elegoo Neptune 0.4 nozzle",
"sub_path": "process/EN2SERIES/0.28mm Extra Draft @Elegoo Neptune 0.4 nozzle.json"
},
{
"name": "0.18mm Fine @Elegoo C 0.6 nozzle",
"sub_path": "process/EC/0.18mm Fine @Elegoo C 0.6 nozzle.json"
},
{
"name": "0.24mm Optimal @Elegoo C 0.6 nozzle",
"sub_path": "process/EC/0.24mm Optimal @Elegoo C 0.6 nozzle.json"
},
{
"name": "0.30mm Strength @Elegoo C 0.6 nozzle",
"sub_path": "process/EC/0.30mm Strength @Elegoo C 0.6 nozzle.json"
},
{
"name": "0.36mm Draft @Elegoo C 0.6 nozzle",
"sub_path": "process/EC/0.36mm Draft @Elegoo C 0.6 nozzle.json"
},
{
"name": "0.42mm Extra Draft @Elegoo C 0.6 nozzle",
"sub_path": "process/EC/0.42mm Extra Draft @Elegoo C 0.6 nozzle.json"
},
{
"name": "0.18mm Fine @Elegoo CC 0.6 nozzle",
"sub_path": "process/ECC/0.18mm Fine @Elegoo CC 0.6 nozzle.json"
},
{
"name": "0.24mm Optimal @Elegoo CC 0.6 nozzle",
"sub_path": "process/ECC/0.24mm Optimal @Elegoo CC 0.6 nozzle.json"
},
{
"name": "0.30mm Strength @Elegoo CC 0.6 nozzle",
"sub_path": "process/ECC/0.30mm Strength @Elegoo CC 0.6 nozzle.json"
},
{
"name": "0.36mm Draft @Elegoo CC 0.6 nozzle",
"sub_path": "process/ECC/0.36mm Draft @Elegoo CC 0.6 nozzle.json"
},
{
"name": "0.42mm Extra Draft @Elegoo CC 0.6 nozzle",
"sub_path": "process/ECC/0.42mm Extra Draft @Elegoo CC 0.6 nozzle.json"
},
{
"name": "0.18mm Fine @Elegoo CC2 0.6 nozzle",
"sub_path": "process/ECC2/0.18mm Fine @Elegoo CC2 0.6 nozzle.json"
},
{
"name": "0.24mm Optimal @Elegoo CC2 0.6 nozzle",
"sub_path": "process/ECC2/0.24mm Optimal @Elegoo CC2 0.6 nozzle.json"
},
{
"name": "0.30mm Strength @Elegoo CC2 0.6 nozzle",
"sub_path": "process/ECC2/0.30mm Strength @Elegoo CC2 0.6 nozzle.json"
},
{
"name": "0.36mm Draft @Elegoo CC2 0.6 nozzle",
"sub_path": "process/ECC2/0.36mm Draft @Elegoo CC2 0.6 nozzle.json"
},
{
"name": "0.42mm Extra Draft @Elegoo CC2 0.6 nozzle",
"sub_path": "process/ECC2/0.42mm Extra Draft @Elegoo CC2 0.6 nozzle.json"
},
{
"name": "0.18mm Fine @Elegoo Giga 0.6 nozzle",
"sub_path": "process/EOSGIGA/0.18mm Fine @Elegoo Giga 0.6 nozzle.json"
},
{
"name": "0.24mm Optimal @Elegoo Giga 0.6 nozzle",
"sub_path": "process/EOSGIGA/0.24mm Optimal @Elegoo Giga 0.6 nozzle.json"
},
{
"name": "0.30mm Strength @Elegoo Giga 0.6 nozzle",
"sub_path": "process/EOSGIGA/0.30mm Strength @Elegoo Giga 0.6 nozzle.json"
},
{
"name": "0.36mm Draft @Elegoo Giga 0.6 nozzle",
"sub_path": "process/EOSGIGA/0.36mm Draft @Elegoo Giga 0.6 nozzle.json"
},
{
"name": "0.42mm Extra Draft @Elegoo Giga 0.6 nozzle",
"sub_path": "process/EOSGIGA/0.42mm Extra Draft @Elegoo Giga 0.6 nozzle.json"
},
{
"name": "0.24mm Optimal @Elegoo N3Max 0.6 nozzle",
"sub_path": "process/EN3SERIES/0.24mm Optimal @Elegoo N3Max 0.6 nozzle.json"
@@ -454,6 +810,82 @@
"name": "0.42mm Extra Draft @Elegoo N4Pro 0.6 nozzle",
"sub_path": "process/EN4SERIES/0.42mm Extra Draft @Elegoo N4Pro 0.6 nozzle.json"
},
{
"name": "0.24mm Optimal @Elegoo Neptune 0.6 nozzle",
"sub_path": "process/EN2SERIES/0.24mm Optimal @Elegoo Neptune 0.6 nozzle.json"
},
{
"name": "0.36mm Draft @Elegoo Neptune 0.6 nozzle",
"sub_path": "process/EN2SERIES/0.36mm Draft @Elegoo Neptune 0.6 nozzle.json"
},
{
"name": "0.42mm Extra Draft @Elegoo Neptune 0.6 nozzle",
"sub_path": "process/EN2SERIES/0.42mm Extra Draft @Elegoo Neptune 0.6 nozzle.json"
},
{
"name": "0.16mm Extra Fine @Elegoo C 0.8 nozzle",
"sub_path": "process/EC/0.16mm Extra Fine @Elegoo C 0.8 nozzle.json"
},
{
"name": "0.24mm Fine @Elegoo C 0.8 nozzle",
"sub_path": "process/EC/0.24mm Fine @Elegoo C 0.8 nozzle.json"
},
{
"name": "0.32mm Optimal @Elegoo C 0.8 nozzle",
"sub_path": "process/EC/0.32mm Optimal @Elegoo C 0.8 nozzle.json"
},
{
"name": "0.48mm Draft @Elegoo C 0.8 nozzle",
"sub_path": "process/EC/0.48mm Draft @Elegoo C 0.8 nozzle.json"
},
{
"name": "0.16mm Extra Fine @Elegoo CC 0.8 nozzle",
"sub_path": "process/ECC/0.16mm Extra Fine @Elegoo CC 0.8 nozzle.json"
},
{
"name": "0.24mm Fine @Elegoo CC 0.8 nozzle",
"sub_path": "process/ECC/0.24mm Fine @Elegoo CC 0.8 nozzle.json"
},
{
"name": "0.32mm Optimal @Elegoo CC 0.8 nozzle",
"sub_path": "process/ECC/0.32mm Optimal @Elegoo CC 0.8 nozzle.json"
},
{
"name": "0.48mm Draft @Elegoo CC 0.8 nozzle",
"sub_path": "process/ECC/0.48mm Draft @Elegoo CC 0.8 nozzle.json"
},
{
"name": "0.16mm Extra Fine @Elegoo CC2 0.8 nozzle",
"sub_path": "process/ECC2/0.16mm Extra Fine @Elegoo CC2 0.8 nozzle.json"
},
{
"name": "0.24mm Fine @Elegoo CC2 0.8 nozzle",
"sub_path": "process/ECC2/0.24mm Fine @Elegoo CC2 0.8 nozzle.json"
},
{
"name": "0.32mm Optimal @Elegoo CC2 0.8 nozzle",
"sub_path": "process/ECC2/0.32mm Optimal @Elegoo CC2 0.8 nozzle.json"
},
{
"name": "0.48mm Draft @Elegoo CC2 0.8 nozzle",
"sub_path": "process/ECC2/0.48mm Draft @Elegoo CC2 0.8 nozzle.json"
},
{
"name": "0.24mm Fine @Elegoo Giga 0.8 nozzle",
"sub_path": "process/EOSGIGA/0.24mm Fine @Elegoo Giga 0.8 nozzle.json"
},
{
"name": "0.32mm Optimal @Elegoo Giga 0.8 nozzle",
"sub_path": "process/EOSGIGA/0.32mm Optimal @Elegoo Giga 0.8 nozzle.json"
},
{
"name": "0.48mm Draft @Elegoo Giga 0.8 nozzle",
"sub_path": "process/EOSGIGA/0.48mm Draft @Elegoo Giga 0.8 nozzle.json"
},
{
"name": "0.56mm Extra Draft @Elegoo Giga 0.8 nozzle",
"sub_path": "process/EOSGIGA/0.56mm Extra Draft @Elegoo Giga 0.8 nozzle.json"
},
{
"name": "0.24mm Fine @Elegoo N3Max 0.8 nozzle",
"sub_path": "process/EN3SERIES/0.24mm Fine @Elegoo N3Max 0.8 nozzle.json"
@@ -538,6 +970,26 @@
"name": "0.48mm Draft @Elegoo N4Pro 0.8 nozzle",
"sub_path": "process/EN4SERIES/0.48mm Draft @Elegoo N4Pro 0.8 nozzle.json"
},
{
"name": "0.24mm Fine @Elegoo Neptune 0.8 nozzle",
"sub_path": "process/EN2SERIES/0.24mm Fine @Elegoo Neptune 0.8 nozzle.json"
},
{
"name": "0.32mm Optimal @Elegoo Neptune 0.8 nozzle",
"sub_path": "process/EN2SERIES/0.32mm Optimal @Elegoo Neptune 0.8 nozzle.json"
},
{
"name": "0.30mm Fine @Elegoo Giga 1.0 nozzle",
"sub_path": "process/EOSGIGA/0.30mm Fine @Elegoo Giga 1.0 nozzle.json"
},
{
"name": "0.40mm Optimal @Elegoo Giga 1.0 nozzle",
"sub_path": "process/EOSGIGA/0.40mm Optimal @Elegoo Giga 1.0 nozzle.json"
},
{
"name": "0.60mm Draft @Elegoo Giga 1.0 nozzle",
"sub_path": "process/EOSGIGA/0.60mm Draft @Elegoo Giga 1.0 nozzle.json"
},
{
"name": "0.30mm Fine @Elegoo N3Max 1.0 nozzle",
"sub_path": "process/EN3SERIES/0.30mm Fine @Elegoo N3Max 1.0 nozzle.json"

View File

@@ -68,6 +68,258 @@
"name": "fdm_filament_pla",
"sub_path": "filament/base/fdm_filament_pla.json"
},
{
"name": "FilAr PLA @base",
"sub_path": "filament/FilAr/FilAr PLA @base.json"
},
{
"name": "FilAr PLA Bronce",
"sub_path": "filament/FilAr/FilAr PLA Bronce.json"
},
{
"name": "FilAr PLA Gris Plata",
"sub_path": "filament/FilAr/FilAr PLA Gris Plata.json"
},
{
"name": "FilAr PLA Cobre",
"sub_path": "filament/FilAr/FilAr PLA Cobre.json"
},
{
"name": "FilAr PLA Titanio",
"sub_path": "filament/FilAr/FilAr PLA Titanio.json"
},
{
"name": "FilAr PLA Tabaco",
"sub_path": "filament/FilAr/FilAr PLA Tabaco.json"
},
{
"name": "FilAr PLA Cafe con Leche",
"sub_path": "filament/FilAr/FilAr PLA Cafe con Leche.json"
},
{
"name": "FilAr PLA Manteca",
"sub_path": "filament/FilAr/FilAr PLA Manteca.json"
},
{
"name": "FilAr PLA Marron Oxido",
"sub_path": "filament/FilAr/FilAr PLA Marron Oxido.json"
},
{
"name": "FilAr PLA Carpincho",
"sub_path": "filament/FilAr/FilAr PLA Carpincho.json"
},
{
"name": "FilAr PLA Rosa Amaranto",
"sub_path": "filament/FilAr/FilAr PLA Rosa Amaranto.json"
},
{
"name": "FilAr PLA Rosa Flamenco",
"sub_path": "filament/FilAr/FilAr PLA Rosa Flamenco.json"
},
{
"name": "FilAr PLA Piel",
"sub_path": "filament/FilAr/FilAr PLA Piel.json"
},
{
"name": "FilAr PLA Verde FilAr",
"sub_path": "filament/FilAr/FilAr PLA Verde FilAr.json"
},
{
"name": "FilAr PLA Verde Manzana",
"sub_path": "filament/FilAr/FilAr PLA Verde Manzana.json"
},
{
"name": "FilAr PLA Verde Pixel",
"sub_path": "filament/FilAr/FilAr PLA Verde Pixel.json"
},
{
"name": "FilAr PLA Verde Oliva",
"sub_path": "filament/FilAr/FilAr PLA Verde Oliva.json"
},
{
"name": "FilAr PLA Blanco Antartida",
"sub_path": "filament/FilAr/FilAr PLA Blanco Antartida.json"
},
{
"name": "FilAr PLA Blanco Calido",
"sub_path": "filament/FilAr/FilAr PLA Blanco Calido.json"
},
{
"name": "FilAr PLA Negro Azabache",
"sub_path": "filament/FilAr/FilAr PLA Negro Azabache.json"
},
{
"name": "FilAr PLA Naranja Tigre",
"sub_path": "filament/FilAr/FilAr PLA Naranja Tigre.json"
},
{
"name": "FilAr PLA Rojo de Carreras",
"sub_path": "filament/FilAr/FilAr PLA Rojo de Carreras.json"
},
{
"name": "FilAr PLA Amarillo Lirio",
"sub_path": "filament/FilAr/FilAr PLA Amarillo Lirio.json"
},
{
"name": "FilAr PLA Violeta Jacaranda",
"sub_path": "filament/FilAr/FilAr PLA Violeta Jacaranda.json"
},
{
"name": "FilAr PLA Gris Pizarra",
"sub_path": "filament/FilAr/FilAr PLA Gris Pizarra.json"
},
{
"name": "FilAr PLA Gris Ceniza",
"sub_path": "filament/FilAr/FilAr PLA Gris Ceniza.json"
},
{
"name": "FilAr PLA Azul Francia",
"sub_path": "filament/FilAr/FilAr PLA Azul Francia.json"
},
{
"name": "FilAr PLA Celeste Cielo",
"sub_path": "filament/FilAr/FilAr PLA Celeste Cielo.json"
},
{
"name": "FilAr PLA Oro",
"sub_path": "filament/FilAr/FilAr PLA Oro.json"
},
{
"name": "FilAr PLA Dorado",
"sub_path": "filament/FilAr/FilAr PLA Dorado.json"
},
{
"name": "FilAr PLA-mate @base",
"sub_path": "filament/FilAr/FilAr PLA-mate @base.json"
},
{
"name": "FilAr PLA-mate Amarillo",
"sub_path": "filament/FilAr/FilAr PLA-mate Amarillo.json"
},
{
"name": "FilAr PLA-mate Azul",
"sub_path": "filament/FilAr/FilAr PLA-mate Azul.json"
},
{
"name": "FilAr PLA-mate Beige",
"sub_path": "filament/FilAr/FilAr PLA-mate Beige.json"
},
{
"name": "FilAr PLA-mate Blanco",
"sub_path": "filament/FilAr/FilAr PLA-mate Blanco.json"
},
{
"name": "FilAr PLA-mate Bordo",
"sub_path": "filament/FilAr/FilAr PLA-mate Bordo.json"
},
{
"name": "FilAr PLA-mate Celeste Cielo",
"sub_path": "filament/FilAr/FilAr PLA-mate Celeste Cielo.json"
},
{
"name": "FilAr PLA-mate Chocolate",
"sub_path": "filament/FilAr/FilAr PLA-mate Chocolate.json"
},
{
"name": "FilAr PLA-mate Gris",
"sub_path": "filament/FilAr/FilAr PLA-mate Gris.json"
},
{
"name": "FilAr PLA-mate Marron",
"sub_path": "filament/FilAr/FilAr PLA-mate Marron.json"
},
{
"name": "FilAr PLA-mate Naranja",
"sub_path": "filament/FilAr/FilAr PLA-mate Naranja.json"
},
{
"name": "FilAr PLA-mate Negro",
"sub_path": "filament/FilAr/FilAr PLA-mate Negro.json"
},
{
"name": "FilAr PLA-mate Piel",
"sub_path": "filament/FilAr/FilAr PLA-mate Piel.json"
},
{
"name": "FilAr PLA-mate Rojo",
"sub_path": "filament/FilAr/FilAr PLA-mate Rojo.json"
},
{
"name": "FilAr PLA-mate Rosa",
"sub_path": "filament/FilAr/FilAr PLA-mate Rosa.json"
},
{
"name": "FilAr PLA-mate Uva",
"sub_path": "filament/FilAr/FilAr PLA-mate Uva.json"
},
{
"name": "FilAr PLA-mate Verde",
"sub_path": "filament/FilAr/FilAr PLA-mate Verde.json"
},
{
"name": "FilAr PLA-mate Violeta",
"sub_path": "filament/FilAr/FilAr PLA-mate Violeta.json"
},
{
"name": "FilAr PETG @base",
"sub_path": "filament/FilAr/FilAr PETG @base.json"
},
{
"name": "FilAr PETG Amarillo Lima",
"sub_path": "filament/FilAr/FilAr PETG Amarillo Lima.json"
},
{
"name": "FilAr PETG Amarillo Radiante",
"sub_path": "filament/FilAr/FilAr PETG Amarillo Radiante.json"
},
{
"name": "FilAr PETG Azul Boreal",
"sub_path": "filament/FilAr/FilAr PETG Azul Boreal.json"
},
{
"name": "FilAr PETG Azul Francia",
"sub_path": "filament/FilAr/FilAr PETG Azul Francia.json"
},
{
"name": "FilAr PETG Azul Imperial",
"sub_path": "filament/FilAr/FilAr PETG Azul Imperial.json"
},
{
"name": "FilAr PETG Blanco Antartida",
"sub_path": "filament/FilAr/FilAr PETG Blanco Antartida.json"
},
{
"name": "FilAr PETG Cian",
"sub_path": "filament/FilAr/FilAr PETG Cian.json"
},
{
"name": "FilAr PETG Coral",
"sub_path": "filament/FilAr/FilAr PETG Coral.json"
},
{
"name": "FilAr PETG Cristal",
"sub_path": "filament/FilAr/FilAr PETG Cristal.json"
},
{
"name": "FilAr PETG Gris Ceniza",
"sub_path": "filament/FilAr/FilAr PETG Gris Ceniza.json"
},
{
"name": "FilAr PETG Gris Plata",
"sub_path": "filament/FilAr/FilAr PETG Gris Plata.json"
},
{
"name": "FilAr PETG Magenta",
"sub_path": "filament/FilAr/FilAr PETG Magenta.json"
},
{
"name": "FilAr PETG Negro Azabache",
"sub_path": "filament/FilAr/FilAr PETG Negro Azabache.json"
},
{
"name": "FilAr PETG Rojo Carmesi",
"sub_path": "filament/FilAr/FilAr PETG Rojo Carmesi.json"
},
{
"name": "fdm_filament_pp",
"sub_path": "filament/base/fdm_filament_pp.json"

View File

@@ -0,0 +1,53 @@
{
"type": "filament",
"name": "FilAr PETG @base",
"inherits": "fdm_filament_pet",
"from": "system",
"filament_id": "FILARB03",
"instantiation": "false",
"filament_type": [
"PETG"
],
"filament_vendor": [
"FilAr"
],
"filament_diameter": [
"1.75"
],
"filament_density": [
"1.27"
],
"filament_flow_ratio": [
"0.95"
],
"nozzle_temperature": [
"240"
],
"nozzle_temperature_initial_layer": [
"245"
],
"nozzle_temperature_range_low": [
"230"
],
"nozzle_temperature_range_high": [
"250"
],
"hot_plate_temp": [
"78"
],
"hot_plate_temp_initial_layer": [
"78"
],
"textured_plate_temp": [
"78"
],
"textured_plate_temp_initial_layer": [
"78"
],
"fan_min_speed": [
"40"
],
"fan_max_speed": [
"60"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PETG Amarillo Lima",
"inherits": "FilAr PETG @base",
"from": "system",
"filament_id": "FILAR0047",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#C7E03A"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PETG Amarillo Radiante",
"inherits": "FilAr PETG @base",
"from": "system",
"filament_id": "FILAR0048",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#FFD400"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PETG Azul Boreal",
"inherits": "FilAr PETG @base",
"from": "system",
"filament_id": "FILAR0049",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#1B4F9C"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PETG Azul Francia",
"inherits": "FilAr PETG @base",
"from": "system",
"filament_id": "FILAR0050",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#0033A0"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PETG Azul Imperial",
"inherits": "FilAr PETG @base",
"from": "system",
"filament_id": "FILAR0051",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#14306B"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PETG Blanco Antartida",
"inherits": "FilAr PETG @base",
"from": "system",
"filament_id": "FILAR0052",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#F7FAFC"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PETG Cian",
"inherits": "FilAr PETG @base",
"from": "system",
"filament_id": "FILAR0053",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#00B7D4"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PETG Coral",
"inherits": "FilAr PETG @base",
"from": "system",
"filament_id": "FILAR0054",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#FF6F5E"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PETG Cristal",
"inherits": "FilAr PETG @base",
"from": "system",
"filament_id": "FILAR0055",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#E8F0EC"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PETG Gris Ceniza",
"inherits": "FilAr PETG @base",
"from": "system",
"filament_id": "FILAR0056",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#B4B6B1"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PETG Gris Plata",
"inherits": "FilAr PETG @base",
"from": "system",
"filament_id": "FILAR0057",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#8C8686"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PETG Magenta",
"inherits": "FilAr PETG @base",
"from": "system",
"filament_id": "FILAR0058",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#B5174B"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PETG Negro Azabache",
"inherits": "FilAr PETG @base",
"from": "system",
"filament_id": "FILAR0059",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#000000"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PETG Rojo Carmesi",
"inherits": "FilAr PETG @base",
"from": "system",
"filament_id": "FILAR0060",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#8C1020"
]
}

View File

@@ -0,0 +1,47 @@
{
"type": "filament",
"name": "FilAr PLA @base",
"inherits": "fdm_filament_pla",
"from": "system",
"filament_id": "FILARB01",
"instantiation": "false",
"filament_type": [
"PLA"
],
"filament_vendor": [
"FilAr"
],
"filament_diameter": [
"1.75"
],
"filament_density": [
"1.24"
],
"filament_flow_ratio": [
"0.98"
],
"nozzle_temperature": [
"210"
],
"nozzle_temperature_initial_layer": [
"215"
],
"nozzle_temperature_range_low": [
"200"
],
"nozzle_temperature_range_high": [
"220"
],
"hot_plate_temp": [
"60"
],
"hot_plate_temp_initial_layer": [
"60"
],
"textured_plate_temp": [
"60"
],
"textured_plate_temp_initial_layer": [
"60"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Amarillo Lirio",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0022",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#FFD52B"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Azul Francia",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0026",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#0000FF"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Blanco Antartida",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0017",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#F7FAFC"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Blanco Calido",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0018",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#FFF8E7"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Bronce",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0001",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#AD8428"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Cafe con Leche",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0006",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#E0B269"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Carpincho",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0009",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#E8DFC1"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Celeste Cielo",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0027",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#A1EBFF"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Cobre",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0003",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#87421E"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Dorado",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0029",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#A67F00"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Gris Ceniza",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0025",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#B4B6B1"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Gris Pizarra",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0024",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#4B4B4B"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Gris Plata",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0002",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#8C8686"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Manteca",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0007",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#FFF5AB"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Marron Oxido",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0008",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#5E190E"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Naranja Tigre",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0020",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#FC5017"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Negro Azabache",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0019",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#000000"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Oro",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0028",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#FFD700"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Piel",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0012",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#FADDAC"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Rojo de Carreras",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0021",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#FA0F0F"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Rosa Amaranto",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0010",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#FA4164"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Rosa Flamenco",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0011",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#FFC7C2"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Tabaco",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0005",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#7D5429"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Titanio",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0004",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#878681"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Verde FilAr",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0013",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#036D6B"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Verde Manzana",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0014",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#D4FF38"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Verde Oliva",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0016",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#595900"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Verde Pixel",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0015",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#02E32F"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA Violeta Jacaranda",
"inherits": "FilAr PLA @base",
"from": "system",
"filament_id": "FILAR0023",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#9342C9"
]
}

View File

@@ -0,0 +1,47 @@
{
"type": "filament",
"name": "FilAr PLA-mate @base",
"inherits": "fdm_filament_pla",
"from": "system",
"filament_id": "FILARB02",
"instantiation": "false",
"filament_type": [
"PLA"
],
"filament_vendor": [
"FilAr"
],
"filament_diameter": [
"1.75"
],
"filament_density": [
"1.24"
],
"filament_flow_ratio": [
"0.98"
],
"nozzle_temperature": [
"200"
],
"nozzle_temperature_initial_layer": [
"205"
],
"nozzle_temperature_range_low": [
"195"
],
"nozzle_temperature_range_high": [
"210"
],
"hot_plate_temp": [
"60"
],
"hot_plate_temp_initial_layer": [
"60"
],
"textured_plate_temp": [
"60"
],
"textured_plate_temp_initial_layer": [
"60"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Amarillo",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0030",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#E8C547"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Azul",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0031",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#2D5DA8"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Beige",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0032",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#D8C4A0"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Blanco",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0033",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#F2F2EC"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Bordo",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0034",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#6E1A2B"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Celeste Cielo",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0035",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#9DC8E8"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Chocolate",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0036",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#4A2E22"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Gris",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0037",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#7E7E7E"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Marron",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0038",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#6B4226"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Naranja",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0039",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#E0662A"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Negro",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0040",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#1A1A1A"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Piel",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0041",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#E8C9A8"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Rojo",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0042",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#B5302E"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Rosa",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0043",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#E07A9B"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Uva",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0044",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#5B2A6B"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Verde",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0045",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#3A7D44"
]
}

View File

@@ -0,0 +1,14 @@
{
"type": "filament",
"name": "FilAr PLA-mate Violeta",
"inherits": "FilAr PLA-mate @base",
"from": "system",
"filament_id": "FILAR0046",
"instantiation": "true",
"filament_vendor": [
"FilAr"
],
"default_filament_colour": [
"#6B3FA0"
]
}

View File

@@ -1,470 +1 @@
#Content
{
overflow-y:auto;
padding: 0 10px 0 20px; /* ORCA Specify & Reduce horizontal paddings to fit 4 items per row */
height: 100%;
}
.OneVendorBlock {
position: relative;
margin-bottom: 7px;
}
.OneVendorBlock:last-of-type {
margin-bottom: 36px;
}
.BlockBanner
{
position: sticky;
top: 0;
left: 0;
padding: 0px;
border-bottom: 2px solid var(--main-color);
width: 100%;
display: flex;
align-items: center;
z-index: 100;
background-color: var(--bg-color-secondary);
box-sizing: border-box;
}
.BannerBtns
{
display: flex;
white-space: nowrap;
justify-content: space-around;
align-items: center;
text-align: center;
margin-right: 5px; /* ORCA align buttons with end of horizontal separator/line */
margin-left: auto;
}
.BlockBanner a
{
line-height: 30px;
height: 30px;
font-size: 17px;
font-weight: 600;
padding: 0px 10px;
color: var(--fg-color-text);
}
.BlockBanner .modelCount {
margin: 0 15px 0 auto;
font-size: 14px;
line-height: 14px;
height: 15px;
color: var(--fg-color-label);
}
.VendorCheckbox {
transform: scale(1.3);
}
.PrinterArea
{
padding: 7px 0px; /* ORCA Reduce horizontal paddings to fit 4 items per row */
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 7px;
}
.PrinterBlock
{
display: flex;
align-items: center;
text-align: center;
flex-direction: column;
gap:10px;
padding: 15px 10px 10px 10px;
background-color: var(--bg-color-secondary);
position: relative;
border: 1px solid transparent
}
.PrinterBlock:hover {
background-color: var(--focus-bg-item);
border-color:var(--main-color);
}
.PImg {
width:120px; /* ORCA use covers as 120x120px but use source file as 240x240 for better quality on hidpi */
height:120px; /* ORCA fit image to fill frame */
}
.PrinterInfo,
.PrinterInfoMark {
position: absolute;
right: 4px;
top: 4px;
opacity: 0;
border-radius: 11px;
line-height: 19px;
font-size: 14px;
}
.PrinterInfo {
--card-animation-delay: .8s; /* open info with delay on list / compact view to prevent them appear while mouse movements */
--card-info-height: fit-content;
left: 4px;
width: auto;
z-index: 9998;
height: var(--card-info-height);
border-color: var(--border-color);
background: var(--bg-color);
padding: 10px;
text-align: left;
color: var(--fg-color-text);
pointer-events: none;
}
#Content[layout="2"] .PrinterInfo {
--card-animation-delay: .3s;
--card-info-height: 116px;
}
.PrinterInfo .title {font-weight: 700}
.PrinterInfo .value {font-weight: 400}
.PrinterInfoMark:hover + .PrinterInfo {
animation: infoCard 0s forwards var(--card-animation-delay);
}
@keyframes infoCard {100% {
opacity: 1;
box-shadow: 0 5px 10px rgba(0,0,0,.2);
}}
.PrinterInfoMark {
width: 20px;
height: 20px;
background: var(--main-color);
border: 1px solid var(--main-color);
z-index: 9999;
color: #FFF;
text-align: center;
}
.PrinterBlock:hover .PrinterInfoMark {
opacity: 1;
}
.PrinterBlock:hover .PrinterInfoMark:hover {
background: var(--main-color-hover);
}
.ModelCheckBox
{
position: absolute;
height: 6px;
bottom: 0;
left: 10%;
width: 80%;
background: var(--button-bg-hover)
}
.ModelCheckBox.ModelCheckBoxSelected
{
background: var(--main-color-fixed)
}
img.ModelThumbnail
{
width: 100%;
height: 100%;
}
.PName
{
font-weight: 600;
line-height: 20px; /* ORCA */
text-align: center;
width: 100%;
color: var(--fg-color-text);
}
.pNozzel
{
display: none;
align-items: center;
justify-content:flex-start;
color: #5A5A5A;
padding-left: 0px; /* ORCA Align checkboxes with with model text */
}
.pNozzel input
{
vertical-align: middle;
margin-right: 5px;
}
.LayoutSelector {
position: absolute;
right:21px;
top:14px;
}
.LayoutSelector .TabGroup {
display: flex;
padding: 2px;
gap: 2px;
border-radius: 6px;
background-color: var(--bg-color-alt);
}
.LayoutSelector .icon16 {
opacity: .8;
}
.LayoutSelector .TabButton {
padding: 7px;
border-radius: 4px;
}
.LayoutSelector .TabButton.selected {background: var(--main-color)}
.LayoutSelector .TabButton.selected:hover {background: var(--main-color-hover)}
.LayoutSelector .TabButton.selected .icon16 {background: #FFF}
.LayoutSelector .TabButton:nth-of-type(1) .icon16 {--icon-url: var(--icon-layout-list)}
.LayoutSelector .TabButton:nth-of-type(2) .icon16 {--icon-url: var(--icon-layout-compact)}
.LayoutSelector .TabButton:nth-of-type(3) .icon16 {--icon-url: var(--icon-layout-cover)}
/* LAYOUT */
#Content[layout="compact-list"] .PrinterArea {
grid-template-columns: repeat(4, 1fr);
}
#Content[layout="compact-list"] .PImg {
display: none;
}
#Content[layout="compact-list"] .OneVendorBlock {
margin-bottom: 15px;
}
#Content[layout="compact-cover"] .PrinterArea {
grid-template-columns: repeat(3, 1fr);
}
#Content[layout="compact-cover"] .PImg {
width: 60px;
min-width: 60px;
height: 60px;
}
#Content[layout|="compact"] .PName {
text-align: left;
}
#Content[layout|="compact"] .PrinterBlock {
flex-direction: row;
padding: 5px 5px 5px 18px;
}
#Content[layout|="compact"] .ModelCheckBox {
width: 6px;
height: 80%;
left:0;
top:10%
}
#Content[layout|="compact"] .OneVendorBlock:last-of-type {
margin-bottom: 0px;
}
/*-----Notice-----*/
#NoticeMask
{
background-color: #000;
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
opacity: 0.05;
display: none;
}
#NoticeBody
{
display: none;
width: 400px;
border-width: 1px;
border-style: solid;
border-radius: 4px;
background-color: inherit;
position: absolute;
left: 50%;
top: 200px;
margin-left: -200px;
}
#NoticeBar
{
background-color:#00f0d8;
height: 40px;
line-height: 40px;
color: #fff;
text-align: center;
}
#NoticeContent
{
padding: 4mm 10mm;
}
#NoticeBtns
{
margin-top: 4mm;
display: flex;
justify-content:flex-end;
}
.search {
position: absolute;
left:66px;
top: 14px;
width: 34px;
height: 34px;
z-index: 99;
overflow: hidden;
}
.search:focus-within,
.search[hasvalue="1"] {
width: calc(100% - 194px);
}
.searchTerm {
width: 100%;
height: 100%;
padding: 4px 5px;
border-radius: 6px;
outline: none;
box-sizing: border-box;
background: var(--button-bg-normal);
border: 1px solid var(--button-bg-normal);
}
@media (prefers-reduced-motion: no-preference) {
.searchTerm {
transition: background-color .2s
}
}
.searchTerm,
.search-placeholder {
line-height: 24px; /* ORCA center text vertically */
font-size: 14px;
}
.search:focus-within .searchTerm,
.search[hasvalue="1"] .searchTerm {
padding-left:33px;
background: var(--bg-color);
border-color: var(--main-color);
}
.search[hasvalue="1"]:not(:focus-within, :hover) .searchTerm {
border-color: var(--border-color);
}
.search:not(:focus-within, [hasvalue="1"]) .searchTerm {
cursor: default;
}
.search:not(:focus-within, [hasvalue="1"]) .searchTerm:hover {
background: var(--button-bg-hover);
}
.search-placeholder {
color: var(--fg-color-disabled);
left: 33px;
}
.searchTerm:not(:placeholder-shown) + .search-placeholder {
opacity: 0;
}
.search-icon,
.search-placeholder {
position: absolute;
top: 50%;
transform: translateY(-50%);
pointer-events: none;
}
.search-icon {
left: 9px;
--icon-url: var(--icon-search);
}
.SidebarBtn {
position: absolute;
left: 20px;
top: 14px;
padding: 9px;
border-radius: 6px;
}
.SidebarBtn .icon16 {
--icon-url: var(--icon-sidebar);
}
#SidebarContainer {
position: absolute;
top: 0;
left: -240px;
right: 0;
height: 100%;
z-index: 999999;
display: flex;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
#SidebarContainer {
transition: background-color .2s, left .2s
}
}
#SidebarContainer[open="1"] {
left: 0px;
pointer-events: all;
background: rgba(0,0,0,.3);
}
#Sidebar {
flex: 0 0 220px;
background: var(--bg-color);
box-shadow: 5px 0 20px rgba(0,0,0,.2);
padding: 15px 0;
overflow-y: auto;
}
#Sidebar .title {
font-size: 17px;
line-height: 17px;
font-weight: 600;
padding: 0 0 5px 20px;
}
#Sidebar .SidebarItem {
width: 100%;
padding: 2px 10px 2px 20px;
color:var(--fg-color-text);
font-size: 14px;
border: 1px solid transparent;
box-sizing: border-box;
}
#Sidebar .SidebarItem:hover {
border-color: var(--main-color);
}
#SidebarContainer .back {
flex: 1;
}
/* UNIQUE STYLES */

View File

@@ -1,395 +1,15 @@
// UNIQUE FUNCTIONS
// Keep in here for future additions
function OnInit()
{
//let strInput=JSON.stringify(cData);
//HandleModelList(cData);
TranslatePage();
RequestProfile();
}
function RequestProfile()
{
var tSend={};
tSend['sequence_id']=Math.round(new Date() / 1000);
tSend['command']="request_userguide_profile";
SendWXMessage( JSON.stringify(tSend) );
}
function HandleStudio( pVal )
{
// alert(strInput);
// alert(JSON.stringify(strInput));
//
// let pVal=IsJson(strInput);
// if(pVal==null)
// {
// alert("Msg Format Error is not Json");
// return;
// }
let strCmd=pVal['command'];
//alert(strCmd);
if(strCmd=='response_userguide_profile')
{
HandleModelList(pVal['response']);
}
}
function ShowPrinterThumb(pItem, strImg)
{
$(pItem).attr('src',strImg);
$(pItem).attr('onerror',null);
}
function ChooseModel( vendor, ModelName )
{
let ChooseItem=$(".ModelCheckBox[vendor='"+vendor+"'][model='"+ModelName+"']");
if(ChooseItem!=null)
{
if( $(ChooseItem).hasClass('ModelCheckBoxSelected') )
$(ChooseItem).removeClass('ModelCheckBoxSelected');
else
$(ChooseItem).addClass('ModelCheckBoxSelected');
SetModelSelect(vendor, ModelName, $(ChooseItem).hasClass('ModelCheckBoxSelected'));
}
}
function HandleModelList( pVal )
{
if( !pVal.hasOwnProperty("model") )
return;
pModel=pVal['model'];
// ORCA ensure list correctly ordered
pModel = pModel.sort((a, b)=>(a["vendor"].localeCompare(b["vendor"])))
pModel = [ // move custom printers to top
...pModel.filter(i=>i.vendor === "Custom"),
...pModel.filter(i=>i.vendor !== "Custom")
];
let nTotal=pModel.length;
let ModelHtml={};
for(let n=0;n<nTotal;n++)
{
let OneModel=pModel[n];
let strVendor=OneModel['vendor'];
//Add Vendor Html Node
if($(".OneVendorBlock[vendor='"+strVendor+"']").length==0)
{
let sVV=strVendor;
if( sVV=="BBL" )
sVV="Bambu Lab";
if( sVV=="Custom")
sVV="Custom Printer";
if( sVV=="Other")
sVV="Orca colosseum";
let HtmlNewVendor='<div class="OneVendorBlock" Vendor="'+strVendor+'">'+
'<div class="BlockBanner">'+
' <a>'+sVV+'</a>'+
' <div class="BannerBtns" onClick="ChooseVendor('+"\'"+strVendor+"\'"+')">'+
' <div class="modelCount"></div>' +
' <input type="checkbox" class="VendorCheckbox"/>'+
' </div>'+
//' <div class="BannerBtns">'+
//' <div class="ButtonStyleConfirm ButtonTypeWindow trans" tid="t11" onClick="SelectPrinterAll('+"\'"+strVendor+"\'"+')">all</div>'+
//' <div class="ButtonStyleRegular ButtonTypeWindow trans" tid="t12" onClick="SelectPrinterNone('+"\'"+strVendor+"\'"+')">none</div>'+
//' </div>'+
'</div>'+
'<div class="PrinterArea"> '+
'</div>'+
'</div>';
$('#Content').append(HtmlNewVendor);
}
let ModelName=OneModel['model'];
//Collect Html Node Nozzel Html
if( !ModelHtml.hasOwnProperty(strVendor))
ModelHtml[strVendor]='';
ModelHtml[strVendor]+=CreatePrinterBlock(OneModel); // ORCA
}
//Update Nozzel Html Append
for( let key in ModelHtml )
{
$(".OneVendorBlock[vendor='"+key+"'] .PrinterArea").append( ModelHtml[key] );
}
//Update Checkbox
for(let m=0;m<nTotal;m++)
{
let OneModel=pModel[m];
let SelectList=OneModel['nozzle_selected'];
if(SelectList!='')
{
ChooseModel(OneModel['vendor'], OneModel['model']);
}
}
const $SidebarVendors = $('#SidebarVendors');
let SidebarHTML = "";
$(`.OneVendorBlock`).each((i, el)=>{
UpdateVendorCheckbox(el.getAttribute("vendor"));
SidebarHTML +=`<div class="SidebarItem" onclick="scrollToVendor(this.textContent)">${el.getAttribute('vendor')}</div>`;
});
$SidebarVendors.html(SidebarHTML)
// let AlreadySelect=$(".ModelCheckBoxSelected");
// let nSelect=AlreadySelect.length;
// if(nSelect==0)
// {
// $("div.OneVendorBlock[vendor='"+BBL+"'] .ModelCheckBox").addClass('ModelCheckBoxSelected');
// }
TranslatePage();
}
function scrollToVendor(vendor) {
const el = $(".OneVendorBlock[vendor='"+vendor+"']")[0];
if (el){
document.getElementById('SidebarContainer').setAttribute('open', '0');
document.getElementById('Content').scrollTo({top: el.offsetTop, behavior: "smooth"});
}
}
function SetModelSelect(vendor, model, checked) {
if (!ModelNozzleSelected.hasOwnProperty(vendor) && !checked) {
return;
}
if (!ModelNozzleSelected.hasOwnProperty(vendor) && checked) {
ModelNozzleSelected[vendor] = {};
}
let oVendor = ModelNozzleSelected[vendor];
if (oVendor.hasOwnProperty(model) || checked) {
oVendor[model] = checked;
}
UpdateVendorCheckbox(vendor)
}
function GetModelSelect(vendor, model) {
if (!ModelNozzleSelected.hasOwnProperty(vendor)) {
return false;
}
let oVendor = ModelNozzleSelected[vendor];
if (!oVendor.hasOwnProperty(model)) {
return false;
}
return oVendor[model];
}
function FilterModelList(keyword) {
//Save checkbox state
let ModelSelect = $('.ModelCheckBox');
for (let n = 0; n < ModelSelect.length; n++) {
let OneItem = ModelSelect[n];
let strModel = OneItem.getAttribute("model");
let strVendor = OneItem.getAttribute("vendor");
SetModelSelect(strVendor, strModel, $(OneItem).hasClass('ModelCheckBoxSelected'));
}
$('.search')[0].setAttribute("hasvalue", keyword ? "1" : "0")
let nTotal = pModel.length;
let ModelHtml = {};
let kwSplit = keyword.toLowerCase().match(/\S+/g) || [];
$('#Content').empty();
for (let n = 0; n < nTotal; n++) {
let OneModel = pModel[n];
let strVendor = OneModel['vendor'];
let search = (OneModel['name'] + '\0' + strVendor).toLowerCase();
if (!kwSplit.every(s => search.includes(s)))
continue;
//Add Vendor Html Node
if ($(".OneVendorBlock[vendor='" + strVendor + "']").length == 0) {
let sVV = strVendor;
if (sVV == "BBL")
sVV = "Bambu Lab";
if (sVV == "Custom")
sVV = "Custom Printer";
if (sVV == "Other")
sVV = "Orca colosseum";
let HtmlNewVendor = '<div class="OneVendorBlock" Vendor="' + strVendor + '">' +
'<div class="BlockBanner">' +
' <a>' + sVV + '</a>' +
' <div class="BannerBtns" onClick="ChooseVendor('+"\'"+strVendor+"\'"+')">'+
' <div class="modelCount"></div>' +
' <input type="checkbox" class="VendorCheckbox"/>'+
' </div>'+
//' <div class="BannerBtns">' +
//' <div class="ButtonStyleConfirm ButtonTypeWindow trans" tid="t11" onClick="SelectPrinterAll(' + "\'" + strVendor + "\'" + ')">all</div>' +
//' <div class="ButtonStyleRegular ButtonTypeWindow trans" tid="t12" onClick="SelectPrinterNone(' + "\'" + strVendor + "\'" + ')">none</div>' +
//' </div>' +
'</div>' +
'<div class="PrinterArea"> ' +
'</div>' +
'</div>';
$('#Content').append(HtmlNewVendor);
}
//Collect Html Node Nozzel Html
if (!ModelHtml.hasOwnProperty(strVendor))
ModelHtml[strVendor] = '';
ModelHtml[strVendor]+=CreatePrinterBlock(OneModel); // ORCA
}
//Update Nozzel Html Append
for (let key in ModelHtml) {
let obj = $(".OneVendorBlock[vendor='" + key + "'] .PrinterArea");
obj.empty();
obj.append(ModelHtml[key]);
}
//Update Checkbox
ModelSelect = $('.ModelCheckBox');
for (let n = 0; n < ModelSelect.length; n++) {
let OneItem = ModelSelect[n];
let strModel = OneItem.getAttribute("model");
let strVendor = OneItem.getAttribute("vendor");
let checked = GetModelSelect(strVendor, strModel);
if (checked)
$(OneItem).addClass('ModelCheckBoxSelected');
else
$(OneItem).removeClass('ModelCheckBoxSelected');
}
const $SidebarVendors = $('#SidebarVendors');
let SidebarHTML = "";
$(`.OneVendorBlock`).each((i, el)=>{
UpdateVendorCheckbox(el.getAttribute("vendor"));
SidebarHTML +=`<div class="SidebarItem" onclick="scrollToVendor(this.textContent)">${el.getAttribute('vendor')}</div>`;
});
$SidebarVendors.html(SidebarHTML)
const $content = $('#Content');
$content.css("padding-right", $content[0].scrollHeight > $content[0].clientHeight ? "10px" : "20px");
// let AlreadySelect=$(".ModelCheckBoxSelected");
// let nSelect=AlreadySelect.length;
// if(nSelect==0)
// {
// $("div.OneVendorBlock[vendor='"+BBL+"'] .ModelCheckBox").addClass('ModelCheckBoxSelected');
// }
TranslatePage();
}
function CreatePrinterBlock(OneModel)
{
// ORCA use single functuon to create blocks to simplify code
let vendor = OneModel['vendor']
vendorName = vendor=="BBL" ? "Bambu Lab" : vendor=="Custom" ? "Generic Printer" : vendor;
let modelName = OneModel['name'];
// Most of it unneeded. this can be applied in profiles
if( vendor=="Custom")
modelName = modelName.split(" ")[1];
// these uses different case in name; seckit, ratrig, blocks
else if (modelName.toLowerCase().startsWith(vendorName.toLowerCase()))
modelName = modelName.slice(vendorName.length);
// these not matches. have to fix in profiles to reduce conditions in here;
else if (vendor == "MagicMaker" && modelName.startsWith("MM"))
modelName = modelName.slice(("MM").length);
else if (vendor == "OrcaArena")
modelName = modelName.slice(("Orca Arena").length);
else if (vendor == "RolohaunDesign" && modelName.startsWith("Rolohaun"))
modelName = modelName.slice(("Rolohaun").length);
return '<div class="PrinterBlock" onClick="ChooseModel(\''+vendor+'\',\''+OneModel['model']+'\')">'+
'<div class="PImg">'+
'<img class="ModelThumbnail" src="' + OneModel['cover'] + '" />'+
'</div>'+
'<div class="PrinterInfoMark">?</div>'+
'<div class="PrinterInfo">'+
//' <div class="title trans">Print volume</div>'+
//' <div class="value">' + OneModel['printable_height'] + '</div>'+
' <div class="title trans">Nozzle</div>'+
' <div class="value">' + OneModel['nozzle_diameter'].replaceAll(";", " · ") + '</div>'+
'</div>'+
'<div style="display: flex;">'+
' <div class="ModelCheckBox" vendor="' +vendor+ '" model="'+OneModel['model']+'"></div>'+
' <div class="PName">'+ modelName +'</div>'+ // ><p>'+ vendorName +'</p>
'</div>'+
'</div>';
}
function SelectPrinterAll( sVendor )
{
$("div.OneVendorBlock[vendor='"+sVendor+"'] .ModelCheckBox").addClass('ModelCheckBoxSelected');
$("div.OneVendorBlock[vendor='"+sVendor+"'] .ModelCheckBox").each(function() {
let strModel = this.getAttribute("model");
SetModelSelect(sVendor, strModel, true);
});
}
function SelectPrinterNone( sVendor )
{
$("div.OneVendorBlock[vendor='"+sVendor+"'] .ModelCheckBox").removeClass('ModelCheckBoxSelected');
$("div.OneVendorBlock[vendor='"+sVendor+"'] .ModelCheckBox").each(function() {
let strModel = this.getAttribute("model");
SetModelSelect(sVendor, strModel, false);
});
}
function ChooseVendor(sVendor) {
const $cbs = $(`.OneVendorBlock[vendor='${sVendor}'] .ModelCheckBox`);
const sel = $cbs.length && $cbs.not('.ModelCheckBoxSelected').length;
sel ? $cbs.addClass('ModelCheckBoxSelected')
: $cbs.removeClass('ModelCheckBoxSelected');
$cbs.each((i, el)=>{SetModelSelect(sVendor, el.getAttribute('model'), sel)});
}
function UpdateVendorCheckbox(sVendor) {
const $vb = $(`.OneVendorBlock[vendor='${sVendor}']`);
const $cbs = $vb.find(`.ModelCheckBox`);
const $vcb = $vb.find(`.VendorCheckbox`);
const selCount = $cbs.filter('.ModelCheckBoxSelected').length;
const allSel = selCount === $cbs.length && selCount > 0;
const nonSel = selCount === 0;
$vcb.prop({checked: allSel , indeterminate: !allSel && !nonSel});
$vb.find(".modelCount").text(selCount + " / " + $cbs.length);
}
function GotoFilamentPage()
{
let nChoose=OnExitFilter();
@@ -397,97 +17,3 @@ function GotoFilamentPage()
if(nChoose>0)
window.open('../22/index.html','_self');
}
function OnExitFilter() {
let nTotal = 0;
let ModelAll = {};
for (vendor in ModelNozzleSelected) {
for (model in ModelNozzleSelected[vendor]) {
if (!ModelNozzleSelected[vendor][model])
continue;
if (!ModelAll.hasOwnProperty(model)) {
//alert("ADD: "+strModel);
ModelAll[model] = {};
ModelAll[model]["model"] = model;
}
nTotal++;
}
}
var tSend = {};
tSend['sequence_id'] = Math.round(new Date() / 1000);
tSend['command'] = "save_userguide_models";
tSend['data'] = ModelAll;
SendWXMessage(JSON.stringify(tSend));
return nTotal;
}
//
function OnExit()
{
let ModelAll={};
let ModelSelect=$(".ModelCheckBoxSelected");
let nTotal=ModelSelect.length;
if( nTotal==0 )
{
ShowNotice(1);
return 0;
}
for(let n=0;n<nTotal;n++)
{
let OneItem=ModelSelect[n];
let strModel=OneItem.getAttribute("model");
//alert(strModel+strVendor+strNozzel);
if(!ModelAll.hasOwnProperty(strModel))
{
//alert("ADD: "+strModel);
ModelAll[strModel]={};
ModelAll[strModel]["model"]=strModel;
}
}
var tSend={};
tSend['sequence_id']=Math.round(new Date() / 1000);
tSend['command']="save_userguide_models";
tSend['data']=ModelAll;
SendWXMessage( JSON.stringify(tSend) );
return nTotal;
}
function ShowNotice( nShow )
{
if(nShow==0)
{
$("#NoticeMask").hide();
$("#NoticeBody").hide();
}
else
{
$("#NoticeMask").show();
$("#NoticeBody").show();
}
}

View File

@@ -0,0 +1,441 @@
#Content {
overflow-y:auto;
padding: 0 10px 0 20px; /* ORCA Specify & Reduce horizontal paddings to fit 4 items per row */
height: 100%;
}
/* VENDOR BLOCK */
.OneVendorBlock {
position: relative;
margin-bottom: 7px;
}
.OneVendorBlock:last-of-type {
margin-bottom: 36px;
}
.BlockBanner {
position: sticky;
top: 0;
left: 0;
padding: 0px;
border-bottom: 2px solid var(--main-color);
width: 100%;
display: flex;
align-items: center;
z-index: 100;
background-color: var(--bg-color-secondary);
box-sizing: border-box;
}
.BannerBtns {
display: flex;
white-space: nowrap;
justify-content: space-around;
align-items: center;
text-align: center;
margin-right: 5px; /* ORCA align buttons with end of horizontal separator/line */
margin-left: auto;
}
.BlockBanner a {
line-height: 30px;
height: 30px;
font-size: 17px;
font-weight: 600;
padding: 0px 10px;
color: var(--fg-color-text);
}
.BlockBanner .modelCount {
margin: 0 15px 0 auto;
font-size: 14px;
line-height: 14px;
height: 15px;
color: var(--fg-color-label);
}
.VendorCheckbox {
transform: scale(1.3);
}
.PrinterArea {
padding: 7px 0px; /* ORCA Reduce horizontal paddings to fit 4 items per row */
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 7px;
}
/* PRINTER BLOCK */
.PrinterBlock {
display: flex;
align-items: center;
text-align: center;
flex-direction: column;
gap:10px;
padding: 15px 10px 10px 10px;
background-color: var(--bg-color-secondary);
position: relative;
border: 1px solid transparent
}
.PrinterBlock:hover {
background-color: var(--focus-bg-item);
border-color:var(--main-color);
}
.PImg {
width:120px; /* ORCA use covers as 120x120px but use source file as 240x240 for better quality on hidpi */
height:120px; /* ORCA fit image to fill frame */
}
.PrinterInfo,
.PrinterInfoMark {
position: absolute;
right: 4px;
top: 4px;
opacity: 0;
border-radius: 11px;
line-height: 19px;
font-size: 14px;
}
.PrinterInfo {
--card-animation-delay: .8s; /* open info with delay on list / compact view to prevent them appear while mouse movements */
left: 4px;
width: auto;
z-index: 9998;
height: fit-content;
border-color: var(--border-color);
background: var(--bg-color);
padding: 10px;
text-align: left;
color: var(--fg-color-text);
pointer-events: none;
}
#Content[layout="large-cover"] .PrinterInfo {
--card-animation-delay: .3s;
}
.PrinterInfo .title {font-weight: 700}
.PrinterInfo .value {font-weight: 400}
.PrinterInfoMark:hover + .PrinterInfo {
animation: infoCard 0s forwards var(--card-animation-delay);
}
@keyframes infoCard {100% {
opacity: 1;
box-shadow: 0 5px 10px rgba(0,0,0,.2);
}}
.PrinterInfoMark {
width: 20px;
height: 20px;
background: var(--main-color);
border: 1px solid var(--main-color);
z-index: 9999;
color: #FFF;
text-align: center;
}
.PrinterBlock:hover .PrinterInfoMark {
opacity: 1;
}
.PrinterBlock:hover .PrinterInfoMark:hover {
background: var(--main-color-hover);
}
.ModelCheckBox {
position: absolute;
height: 6px;
bottom: 0;
left: 10%;
width: 80%;
background: var(--button-bg-hover)
}
.ModelCheckBox.ModelCheckBoxSelected {
background: var(--main-color-fixed)
}
img.ModelThumbnail {
width: 100%;
height: 100%;
}
.PName {
font-weight: 600;
line-height: 20px; /* ORCA */
text-align: center;
width: 100%;
color: var(--fg-color-text);
}
/* LAYOUT SELECTOR */
.LayoutSelector {
position: absolute;
right:21px;
top:14px;
}
.LayoutSelector .TabGroup {
display: flex;
padding: 2px;
gap: 2px;
border-radius: 6px;
background-color: var(--bg-color-alt);
}
.LayoutSelector .icon16 {
opacity: .8;
}
.LayoutSelector .TabButton {
padding: 7px;
border-radius: 4px;
}
.LayoutSelector .TabButton.selected {background: var(--main-color)}
.LayoutSelector .TabButton.selected:hover {background: var(--main-color-hover)}
.LayoutSelector .TabButton.selected .icon16 {background: #FFF}
.LayoutSelector .TabButton:nth-of-type(1) .icon16 {--icon-url: var(--icon-layout-list)}
.LayoutSelector .TabButton:nth-of-type(2) .icon16 {--icon-url: var(--icon-layout-compact)}
.LayoutSelector .TabButton:nth-of-type(3) .icon16 {--icon-url: var(--icon-layout-cover)}
/* LAYOUT */
#Content[layout="compact-list"] .PrinterArea {
grid-template-columns: repeat(4, 1fr);
}
#Content[layout="compact-list"] .PImg {
display: none;
}
#Content[layout="compact-list"] .OneVendorBlock {
margin-bottom: 15px;
}
#Content[layout="compact-cover"] .PrinterArea {
grid-template-columns: repeat(3, 1fr);
}
#Content[layout="compact-cover"] .PImg {
width: 60px;
min-width: 60px;
height: 60px;
}
#Content[layout|="compact"] .PName {
text-align: left;
}
#Content[layout|="compact"] .PrinterBlock {
flex-direction: row;
padding: 5px 5px 5px 18px;
}
#Content[layout|="compact"] .ModelCheckBox {
width: 6px;
height: 80%;
left:0;
top:10%
}
#Content[layout|="compact"] .OneVendorBlock:last-of-type {
margin-bottom: 0px;
}
/* SEARCH */
.search {
position: absolute;
left:66px;
top: 14px;
width: 34px;
height: 34px;
z-index: 99;
overflow: hidden;
}
.search:focus-within,
.search[hasvalue="1"] {
width: calc(100% - 194px);
}
.searchTerm {
width: 100%;
height: 100%;
padding: 4px 5px;
border-radius: 6px;
outline: none;
box-sizing: border-box;
background: var(--button-bg-normal);
border: 1px solid var(--button-bg-normal);
}
@media (prefers-reduced-motion: no-preference) {
.searchTerm {
transition: background-color .2s
}
}
.searchTerm,
.search-placeholder {
line-height: 24px; /* ORCA center text vertically */
font-size: 14px;
}
.search:focus-within .searchTerm,
.search[hasvalue="1"] .searchTerm {
padding-left:33px;
background: var(--bg-color);
border-color: var(--main-color);
}
.search[hasvalue="1"]:not(:focus-within, :hover) .searchTerm {
border-color: var(--border-color);
}
.search:not(:focus-within, [hasvalue="1"]) .searchTerm {
cursor: default;
}
.search:not(:focus-within, [hasvalue="1"]) .searchTerm:hover {
background: var(--button-bg-hover);
}
.search-placeholder {
color: var(--fg-color-disabled);
left: 33px;
}
.searchTerm:not(:placeholder-shown) + .search-placeholder {
opacity: 0;
}
.search-icon,
.search-placeholder {
position: absolute;
top: 50%;
transform: translateY(-50%);
pointer-events: none;
}
.search-icon {
left: 9px;
--icon-url: var(--icon-search);
}
/* SIDEBAR */
.SidebarBtn {
position: absolute;
left: 20px;
top: 14px;
padding: 9px;
border-radius: 6px;
}
.SidebarBtn .icon16 {
--icon-url: var(--icon-sidebar);
}
#SidebarContainer {
position: absolute;
top: 0;
left: -240px;
right: 0;
height: 100%;
z-index: 999999;
display: flex;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
#SidebarContainer {
transition: background-color .2s, left .2s
}
}
#SidebarContainer[open="1"] {
left: 0px;
pointer-events: all;
background: rgba(0,0,0,.3);
}
#Sidebar {
flex: 0 0 220px;
background: var(--bg-color);
box-shadow: 5px 0 20px rgba(0,0,0,.2);
padding: 15px 0;
overflow-y: auto;
}
#Sidebar .title {
font-size: 17px;
line-height: 17px;
font-weight: 600;
padding: 0 0 5px 20px;
}
#Sidebar .SidebarItem {
width: 100%;
padding: 2px 10px 2px 20px;
color:var(--fg-color-text);
font-size: 14px;
border: 1px solid transparent;
box-sizing: border-box;
}
#Sidebar .SidebarItem:hover {
border-color: var(--main-color);
}
#SidebarContainer .back {
flex: 1;
}
/* NOTICE POPUP */
#NoticeMask {
background-color: #000;
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
opacity: 0.05;
display: none;
}
#NoticeBody {
display: none;
width: 400px;
border-width: 1px;
border-style: solid;
border-radius: 4px;
background-color: inherit;
position: absolute;
left: 50%;
top: 200px;
margin-left: -200px;
}
#NoticeBar {
background-color:#00f0d8;
height: 40px;
line-height: 40px;
color: #fff;
text-align: center;
}
#NoticeContent {
padding: 4mm 10mm;
}
#NoticeBtns {
margin-top: 4mm;
display: flex;
justify-content:flex-end;
}

View File

@@ -0,0 +1,632 @@
var pModel = {};
var ModelNozzleSelected = {};
let SearchBox;
let $content;
function InitGlobalVariables()
{
SearchBox = document.querySelector('.searchTerm');
$content = $('#Content');
}
function RequestProfile()
{
var tSend={};
tSend['sequence_id']=Math.round(new Date() / 1000);
tSend['command']="request_userguide_profile";
SendWXMessage( JSON.stringify(tSend) );
}
function HandleStudio( pVal )
{
// alert(strInput);
// alert(JSON.stringify(strInput));
//
// let pVal=IsJson(strInput);
// if(pVal==null)
// {
// alert("Msg Format Error is not Json");
// return;
// }
let strCmd=pVal['command'];
//alert(strCmd);
if(strCmd=='response_userguide_profile')
{
HandleModelList(pVal['response']);
}
}
function HandleModelList( pVal )
{
if( !pVal.hasOwnProperty("model") )
return;
pModel=pVal['model'];
// ORCA ensure list correctly ordered
pModel = pModel.sort((a, b)=>(a["vendor"].localeCompare(b["vendor"])))
pModel = [ // move custom printers to top
...pModel.filter(i=>i.vendor === "Custom"),
...pModel.filter(i=>i.vendor !== "Custom")
];
let nTotal=pModel.length;
let ModelHtml={};
for(let n=0;n<nTotal;n++)
{
let OneModel=pModel[n];
let strVendor=OneModel['vendor'];
//Add Vendor Html Node
if($(".OneVendorBlock[vendor='"+strVendor+"']").length==0)
{
let HtmlNewVendor = CreateVendorBlock(strVendor);
$('#Content').append(HtmlNewVendor);
}
let ModelName=OneModel['model'];
//Collect Html Node Nozzel Html
if( !ModelHtml.hasOwnProperty(strVendor))
ModelHtml[strVendor]='';
ModelHtml[strVendor] += CreatePrinterBlock(OneModel); // ORCA
}
//Update Nozzel Html Append
for( let key in ModelHtml )
{
$(".OneVendorBlock[vendor='"+key+"'] .PrinterArea").append( ModelHtml[key] );
}
//Update Checkbox
for(let m=0;m<nTotal;m++)
{
let OneModel=pModel[m];
let SelectList=OneModel['nozzle_selected'];
if(SelectList!='') {
ChooseModel(OneModel['vendor'], OneModel['model']);
}
}
UpdateSidebarVendors();
// let AlreadySelect=$(".ModelCheckBoxSelected");
// let nSelect=AlreadySelect.length;
// if(nSelect==0)
// {
// $("div.OneVendorBlock[vendor='"+BBL+"'] .ModelCheckBox").addClass('ModelCheckBoxSelected');
// }
TranslatePage();
}
function SetModelSelect(vendor, model, checked) {
if (!ModelNozzleSelected.hasOwnProperty(vendor) && !checked) {
return;
}
if (!ModelNozzleSelected.hasOwnProperty(vendor) && checked) {
ModelNozzleSelected[vendor] = {};
}
let oVendor = ModelNozzleSelected[vendor];
if (oVendor.hasOwnProperty(model) || checked) {
oVendor[model] = checked;
}
UpdateVendorCheckbox(vendor)
}
function GetModelSelect(vendor, model) {
if (!ModelNozzleSelected.hasOwnProperty(vendor)) {
return false;
}
let oVendor = ModelNozzleSelected[vendor];
if (!oVendor.hasOwnProperty(model)) {
return false;
}
return oVendor[model];
}
function ChooseModel(vendor, ModelName)
{
let ChooseItem=$(".ModelCheckBox[vendor='"+vendor+"'][model='"+ModelName+"']");
if(ChooseItem.length > 0) {
if( $(ChooseItem).hasClass('ModelCheckBoxSelected') )
$(ChooseItem).removeClass('ModelCheckBoxSelected');
else
$(ChooseItem).addClass('ModelCheckBoxSelected');
SetModelSelect(vendor, ModelName, $(ChooseItem).hasClass('ModelCheckBoxSelected'));
}
}
function FilterModelList(keyword) {
//Save checkbox state
let ModelSelect = $('.ModelCheckBox');
for (let n = 0; n < ModelSelect.length; n++) {
let OneItem = ModelSelect[n];
let strModel = OneItem.getAttribute("model");
let strVendor = OneItem.getAttribute("vendor");
SetModelSelect(strVendor, strModel, $(OneItem).hasClass('ModelCheckBoxSelected'));
}
$('.search')[0].setAttribute("hasvalue", keyword ? "1" : "0")
let nTotal = pModel.length;
let ModelHtml = {};
let kwSplit = keyword.toLowerCase().match(/\S+/g) || [];
$('#Content').empty();
for (let n = 0; n < nTotal; n++) {
let OneModel = pModel[n];
let strVendor = OneModel['vendor'];
let search = (OneModel['name'] + '\0' + strVendor).toLowerCase();
if (!kwSplit.every(s => search.includes(s)))
continue;
//Add Vendor Html Node
if ($(".OneVendorBlock[vendor='" + strVendor + "']").length == 0) {
let HtmlNewVendor = CreateVendorBlock(strVendor);
$('#Content').append(HtmlNewVendor);
}
//Collect Html Node Nozzel Html
if (!ModelHtml.hasOwnProperty(strVendor))
ModelHtml[strVendor] = '';
ModelHtml[strVendor] += CreatePrinterBlock(OneModel); // ORCA
}
//Update Nozzel Html Append
for (let key in ModelHtml) {
let obj = $(".OneVendorBlock[vendor='" + key + "'] .PrinterArea");
obj.empty();
obj.append(ModelHtml[key]);
}
//Update Checkbox
ModelSelect = $('.ModelCheckBox');
for (let n = 0; n < ModelSelect.length; n++) {
let OneItem = ModelSelect[n];
let strModel = OneItem.getAttribute("model");
let strVendor = OneItem.getAttribute("vendor");
let checked = GetModelSelect(strVendor, strModel);
if (checked)
$(OneItem).addClass('ModelCheckBoxSelected');
else
$(OneItem).removeClass('ModelCheckBoxSelected');
}
UpdateSidebarVendors();
$content.css("padding-right", $content[0].scrollHeight > $content[0].clientHeight ? "10px" : "20px");
// let AlreadySelect=$(".ModelCheckBoxSelected");
// let nSelect=AlreadySelect.length;
// if(nSelect==0)
// {
// $("div.OneVendorBlock[vendor='"+BBL+"'] .ModelCheckBox").addClass('ModelCheckBoxSelected');
// }
TranslatePage();
}
function textInput(obj) {
FilterModelList(obj.value);
}
function CreateVendorBlock(vendorName)
{
let alt = vendorName;
if( alt == "BBL" )
alt = "Bambu Lab";
if( alt == "Custom")
alt = "Custom Printer";
if( alt == "Other")
alt = "Orca colosseum";
return '<div class="OneVendorBlock" Vendor="' + vendorName + '">' +
' <div class="BlockBanner">' +
' <a>' + alt + '</a>' +
' <div class="BannerBtns" onClick="ChooseVendor('+"\'"+vendorName+"\'"+')">'+
' <div class="modelCount"></div>' +
' <input type="checkbox" class="VendorCheckbox"/>'+
' </div>'+
' </div>' +
' <div class="PrinterArea"> ' +
' </div>' +
'</div>';
}
function CreatePrinterBlock(OneModel)
{
let vendor = OneModel['vendor']
let vendorName = vendor=="BBL" ? "Bambu Lab" : vendor=="Custom" ? "Generic Printer" : vendor;
let modelName = OneModel['name'];
// Most of it unneeded. this can be applied in profiles
if( vendor=="Custom")
modelName = modelName.split(" ")[1];
// these uses different case in name; seckit, ratrig, blocks
else if (modelName.toLowerCase().startsWith(vendorName.toLowerCase()))
modelName = modelName.slice(vendorName.length);
// these not matches. have to fix in profiles to reduce conditions in here;
else if (vendor == "MagicMaker" && modelName.startsWith("MM"))
modelName = modelName.slice(("MM").length);
else if (vendor == "OrcaArena")
modelName = modelName.slice(("Orca Arena").length);
else if (vendor == "RolohaunDesign" && modelName.startsWith("Rolohaun"))
modelName = modelName.slice(("Rolohaun").length);
return '<div class="PrinterBlock" onClick="ChooseModel(\''+vendor+'\',\''+OneModel['model']+'\')">'+
' <div class="PImg">'+
' <img class="ModelThumbnail" src="' + OneModel['cover'] + '" />'+
' </div>'+
' <div class="PrinterInfoMark">?</div>'+
' <div class="PrinterInfo">'+
' <div class="title trans">Nozzle</div>'+
' <div class="value">' + OneModel['nozzle_diameter'].replaceAll(";", " · ") + '</div>'+
' </div>'+
' <div style="display: flex;">'+
' <div class="ModelCheckBox" vendor="' +vendor+ '" model="'+OneModel['model']+'"></div>'+
' <div class="PName">'+ modelName +'</div>'+ // ><p>'+ vendorName +'</p>
' </div>'+
'</div>';
}
function scrollToVendor(vendor) {
const el = $(".OneVendorBlock[vendor='"+vendor+"']")[0];
if (el){
document.getElementById('SidebarContainer').setAttribute('open', '0');
document.getElementById('Content').scrollTo({top: el.offsetTop, behavior: "smooth"});
}
}
function UpdateSidebarVendors()
{
let SidebarHTML = "";
$(`.OneVendorBlock`).each((i, el)=>{
UpdateVendorCheckbox(el.getAttribute("vendor"));
SidebarHTML +=`<div class="SidebarItem" onclick="scrollToVendor(this.textContent)">${el.getAttribute('vendor')}</div>`;
});
$('#SidebarVendors').html(SidebarHTML)
}
function ChooseVendor(sVendor) { // automatically selects / unselects all
const $cbs = $(`.OneVendorBlock[vendor='${sVendor}'] .ModelCheckBox`);
const sel = $cbs.length && $cbs.not('.ModelCheckBoxSelected').length;
sel ? $cbs.addClass('ModelCheckBoxSelected')
: $cbs.removeClass('ModelCheckBoxSelected');
$cbs.each((i, el)=>{SetModelSelect(sVendor, el.getAttribute('model'), sel)});
}
function UpdateVendorCheckbox(sVendor) {
const $vb = $(`.OneVendorBlock[vendor='${sVendor}']`);
const $cbs = $vb.find(`.ModelCheckBox`);
const $vcb = $vb.find(`.VendorCheckbox`);
const selCount = $cbs.filter('.ModelCheckBoxSelected').length;
const allSel = selCount === $cbs.length && selCount > 0;
const nonSel = selCount === 0;
$vcb.prop({checked: allSel , indeterminate: !allSel && !nonSel});
$vb.find(".modelCount").text(selCount + " / " + $cbs.length);
}
function OnExit()
{
let ModelAll={};
let ModelSelect=$(".ModelCheckBoxSelected");
let nTotal=ModelSelect.length;
if( nTotal==0 ) {
ShowNotice(1);
return 0;
}
for(let n=0;n<nTotal;n++)
{
let OneItem=ModelSelect[n];
let strModel=OneItem.getAttribute("model");
//alert(strModel+strVendor+strNozzel);
if(!ModelAll.hasOwnProperty(strModel))
{
//alert("ADD: "+strModel);
ModelAll[strModel]={};
ModelAll[strModel]["model"]=strModel;
}
}
var tSend={};
tSend['sequence_id']=Math.round(new Date() / 1000);
tSend['command']="save_userguide_models";
tSend['data']=ModelAll;
SendWXMessage( JSON.stringify(tSend) );
return nTotal;
}
function OnExitFilter() {
let nTotal = 0;
let ModelAll = {};
for (let vendor in ModelNozzleSelected) {
for (let model in ModelNozzleSelected[vendor]) {
if (!ModelNozzleSelected[vendor][model])
continue;
if (!ModelAll.hasOwnProperty(model)) {
//alert("ADD: "+strModel);
ModelAll[model] = {};
ModelAll[model]["model"] = model;
}
nTotal++;
}
}
var tSend = {};
tSend['sequence_id'] = Math.round(new Date() / 1000);
tSend['command'] = "save_userguide_models";
tSend['data'] = ModelAll;
SendWXMessage(JSON.stringify(tSend));
return nTotal;
}
function ShowNotice( nShow )
{
if(nShow==0) {
$("#NoticeMask").hide();
$("#NoticeBody").hide();
}
else {
$("#NoticeMask").show();
$("#NoticeBody").show();
}
}
// SNAPPY SCROLLING WITHOUT LAGS
const SNAP_DELAY = 600;
const SNAP_DURATION = 200;
const SNAP_CORR = 8; // error correction / tolerance
let scrollTimer = null;
let lastScrollTop = 0;
let scrollDir = 'down';
let isSnapping = false;
let snapRafId = null;
let lastSnapTarget = null;
let waitingForUserScroll = false;
function findSnap(cur, dir) {
if (lastSnapTarget !== null && Math.abs(cur - lastSnapTarget) < SNAP_CORR) return null;
const savedScroll = cur;
$content[0].scrollTop = 0; // Temporarily scroll to 0 so getBoundingClientRect can get absolute positions
let bcTop = el=>(el.getBoundingClientRect().top);
const contentTop = bcTop($content[0]);
const bannerH = ($content.find('.BlockBanner')[0] || {}).offsetHeight || 0;
const firstCard = $content.find('.PrinterBlock')[0];
const firstArea = $content.find('.PrinterArea')[0];
const cardGap = (firstCard && firstArea) ? (bcTop(firstCard) - bcTop(firstArea)) : 0;
const candidates = $content.find('.BlockBanner, .PrinterBlock').get();
if (dir === 'up') candidates.reverse();
let result = lastSeen = null;
for (const el of candidates) {
const snapTo = Math.round(
el.classList.contains('BlockBanner')
? (bcTop(el.closest('.OneVendorBlock')) - contentTop)
: Math.max(0, bcTop(el) - contentTop - bannerH - cardGap)
);
if (snapTo != lastSeen){
lastSeen = snapTo;
if (dir === 'down' && snapTo > cur + SNAP_CORR) { result = snapTo; break; }
if (dir === 'up' && snapTo < cur - SNAP_CORR) { result = snapTo; break; }
}
}
$content[0].scrollTop = savedScroll; // Restore scroll position
return result;
}
function smoothScrollTo(target) {
if (snapRafId) {
cancelAnimationFrame(snapRafId);
snapRafId = null;
}
const el = $content[0];
const from = el.scrollTop;
const dist = target - from;
const t0 = performance.now();
const ease = t => t < 0.5 ? 2*t*t : -1 + (4 - 2*t)*t;
function onDone() {
el.scrollTop = target;
lastScrollTop = lastSnapTarget = target;
waitingForUserScroll = true;
clearTimeout(scrollTimer);
scrollTimer = null;
snapRafId = null;
isSnapping = false;
}
if (Math.abs(dist) < 2)
return onDone();
snapRafId = requestAnimationFrame(function step(now) {
const p = Math.min((now - t0) / SNAP_DURATION, 1);
el.scrollTop = from + dist * ease(p);
if (p < 1)
snapRafId = requestAnimationFrame(step);
else
onDone();
});
}
function armSnap() {
waitingForUserScroll = false;
lastSnapTarget = null;
}
function initScrollEvents() {
$content.on('scroll', function() {
if (isSnapping) return;
if (this.scrollTop > lastScrollTop + 1) scrollDir = 'down';
else if (this.scrollTop < lastScrollTop - 1) scrollDir = 'up';
lastScrollTop = this.scrollTop;
if (waitingForUserScroll) return;
clearTimeout(scrollTimer);
scrollTimer = setTimeout(()=>{
if (isSnapping) return;
const target = findSnap($content[0].scrollTop, scrollDir);
if (target){
isSnapping = true;
smoothScrollTo(target);
}
}, SNAP_DELAY);
});
let touchY = 0;
$content[0].addEventListener('touchstart', e => {
touchY = e.touches[0].clientY;
armSnap();
}, { passive: true });
$content[0].addEventListener('touchmove', e => {
const dy = touchY - e.touches[0].clientY;
if (Math.abs(dy) > 3)
scrollDir = dy > 0 ? 'down' : 'up';
}, { passive: true });
// Re-arm snap system on user scroll
$content[0].addEventListener('wheel', armSnap, { passive: true });
// Re-arm on after scrollbar usage
$content[0].addEventListener('pointerdown', e => {
if (e.target === $content[0])
armSnap();
});
// Re-arm on keyboard scroll or focus changes
document.addEventListener('keydown', e => {
if (document.activeElement != SearchBox){
let scrollKeys = ['ArrowUp','ArrowDown','PageUp','PageDown',' '];
let hasFocus = $content[0].contains(document.activeElement);
if(scrollKeys.includes(e.key) || (hasFocus && e.which == 9))
armSnap();
}
});
// ORCA unfocus search bar while scrolling and its content empty
$content[0].addEventListener("scroll", () => {
if (document.activeElement === SearchBox && SearchBox.value == "")
SearchBox.blur();
});
}
document.addEventListener('DOMContentLoaded', initScrollEvents);
// LAYOUT SELECTOR
function LayoutMode(value) {
let LayoutSelector = document.querySelector('.LayoutSelector > .TabGroup');
let LayoutBtns = Array.from(LayoutSelector.children);
let LayoutTypes = ["compact-list","compact-cover","large-cover"];
if($content[0].getAttribute("layout") === value)
return;
// find current visible vendor and scroll to it after layout change
let target = null;
for (const el of $content.find('.OneVendorBlock')) {
if (el.getBoundingClientRect().bottom - $content[0].getBoundingClientRect().top >= -1) {
target = el.getAttribute("vendor");
break;
}
}
LayoutBtns.forEach(el => el.classList.remove('selected'));
LayoutBtns[LayoutTypes.indexOf(value)].classList.add('selected');
$content[0].setAttribute("layout", value);
if (target) scrollToVendor(target);
}
document.addEventListener('DOMContentLoaded', () => LayoutMode("large-cover"));
// KEY EVENTS
function initKeyEvents(closeOnESC) {
document.onkeydown = function (event) {
var e = event || window.event || arguments.callee.caller.arguments[0];
let sidebar = document.getElementById('SidebarContainer');
if (e.keyCode == 27){
if(sidebar.getAttribute('open') == "1") { // prefer to close sidebar first if its open
sidebar.setAttribute('open', '0');
}
else if (closeOnESC){
ClosePage();
}
}
// ORCA focus search bar on key input
// SearchBox not in focus && writable character && non modifier
if (document.activeElement != SearchBox && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
SearchBox.focus();
}
// Close sidebar on any key input
sidebar.setAttribute('open', '0');
//if (window.event) {
// try { e.keyCode = 0; } catch (e) { }
// e.returnValue = true;
//}
};
}

View File

@@ -6,6 +6,7 @@
<title>引导_P21</title>
<link rel="stylesheet" type="text/css" href="../../include/global.css" /> <!-- ORCA One for all-->
<link rel="stylesheet" type="text/css" href="../css/common.css" />
<link rel="stylesheet" type="text/css" href="../21/common.css" /> <!-- ORCA use common sources for setup guide and standalone dialog -->
<link rel="stylesheet" type="text/css" href="21.css" />
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
<script type="text/javascript" src="test.js"></script>
@@ -14,7 +15,8 @@
<script type="text/javascript" src="../../data/text.js"></script>
<script type="text/javascript" src="../js/globalapi.js"></script>
<script type="text/javascript" src="../js/common.js"></script>
<script type="text/javascript" src="21.js"></script>
<script type="text/javascript" src="../21/common.js"></script> <!-- ORCA use common sources for setup guide and standalone dialog -->
<script type="text/javascript" src="21.js"></script>
</head>
<body onLoad="OnInit()">
<div id="Title">
@@ -49,93 +51,33 @@
<div id="Content" class="thin-scroll">
<!--<div class="OneVendorBlock" Vendor="BBL">
<div class="BlockBanner">
<a>BBL-3DP</a>
<div class="BannerBtns">
<div class="ButtonStyleConfirm ButtonTypeWindow trans" onClick="SelectPrinterAll('BBL')">所有</div>
<div class="ButtonStyleRegular ButtonTypeWindow trans" onClick="SelectPrinterNone('BBL')"></div>
<!-- EXAMPLE GENERATED CODE BLOCK
<div class="OneVendorBlock" Vendor="VendorName">
<div class="BlockBanner">
<a>VendorName</a>
<div class="BannerBtns" onClick="ChooseVendor('VendorName')" >
<div class="modelCount"></div>
<input type="checkbox" class="VendorCheckbox" />
</div>
</div>
<div class="PrinterArea">
<div class="PrinterBlock" onClick="ChooseModel('VendorName','ModelName')" >
<div class="PImg" >
<img class="ModelThumbnail" src="CoverPath" />
</div>
<div class="PrinterInfoMark">?</div>
<div class="PrinterInfo">
<div class="title trans">Nozzle</div>
<div class="value">nozzleInfo</div>
</div>
<div style="display: flex;">
<div class="ModelCheckBox" vendor="' +vendor+ '" model="'+OneModel['model']+'"></div>
<div class="PName">modelName</div>
</div>
</div>
</div>
</div>
<div class="PrinterArea">
<div class="PrinterBlock">
<div class="PImg">
<img class="ModelThumbnail" src="p2.jpg" />
<div class="ModelCheckBox ModelCheckBoxSelected" model="BBL-3DP-V5NORMAL" onClick="ChooseModel('BBL-3DP-V5NORMAL')"></div>
</div>
<div class="PName">BBL-3DP-V4NORMAL</div>
<div class="pNozzel TextS2"><input id="ZZ" type="checkbox" model="BBL-3DP-V4NORMAL" nozzel="0.4" vendor="BBL" />0.4mm nozzle</div>
<div class="pNozzel TextS2"><input type="checkbox" model="BBL-3DP-V4NORMAL" nozzel="0.1" vendor="BBL" />0.1mm nozzle</div>
</div>
<div class="PrinterBlock">
<div class="PImg">
<img class="ModelThumbnail" src="p2.jpg" />
<div class="ModelCheckBox"></div>
</div>
<div class="PName">BBL-3DP-V4NORMAL</div>
<div class="pNozzel TextS2"><input type="checkbox" model="BBL-3DP-V5NORMAL" nozzel="0.4" vendor="BBL" />0.4mm nozzle</div>
<div class="pNozzel TextS2"><input type="checkbox" model="BBL-3DP-V5NORMAL" nozzel="0.2" vendor="BBL" />0.22mm nozzle</div>
<div class="pNozzel TextS2"><input type="checkbox" model="BBL-3DP-V5NORMAL" nozzel="0.1" vendor="BBL" />0.1mm nozzle</div>
</div>
<div class="PrinterBlock">
<div class="PImg">
<img class="ModelThumbnail" src="p2.jpg" />
<div class="ModelCheckBox"></div>
</div>
<div class="PName">BBL-3DP-V4NORMAL</div>
<div class="pNozzel TextS2"><input id="ZZ" type="checkbox" model="BBL-3DP-V4NORMAL" nozzel="0.4" vendor="BBL" />0.4mm nozzle</div>
<div class="pNozzel TextS2"><input type="checkbox" model="BBL-3DP-V4NORMAL" nozzel="0.1" vendor="BBL" />0.11mm nozzle</div>
</div>
<div class="PrinterBlock">
<div class="PImg">
<img class="ModelThumbnail" src="p2.jpg" />
<div class="ModelCheckBox ModelCheckBoxSelected"></div>
</div>
<div class="PName">BBL-3DP-V4NORMAL</div>
<div class="pNozzel TextS2"><input type="checkbox" model="BBL-3DP-V5NORMAL" nozzel="0.4" vendor="BBL" />0.4mm nozzle</div>
<div class="pNozzel TextS2"><input type="checkbox" model="BBL-3DP-V5NORMAL" nozzel="0.2" vendor="BBL" />0.22mm nozzle</div>
<div class="pNozzel TextS2"><input type="checkbox" model="BBL-3DP-V5NORMAL" nozzel="0.1" vendor="BBL" />0.1mm nozzle</div>
</div>
</div>
</div>
<div class="OneVendorBlock" Vendor="BAMBU">
<div class="BlockBanner">
<a>BAMBU-3DP</a>
<div class="BannerBtns">
<div class="SmallBtn_Green trans" onClick="SelectPrinterAll('BAMBU')">所有</div>
<div class="SmallBtn trans" onClick="SelectPrinterNone('BAMBU')">无</div>
</div>
</div>
<div class="PrinterArea">
<div class="PrinterBlock">
<div class="PImg">
<img class="ModelThumbnail" src="p2.jpg" />
<div class="ModelCheckBox ModelCheckBoxSelected"></div>
</div>
<div class="PName TextS1">BBL-3DP-V4NORMAL</div>
<div class="pNozzel TextS2"><input type="checkbox" model="BBL-3DP-V4NORMAL" nozzel="0.4" vendor="BAMBU" />0.4mm nozzle</div>
<div class="pNozzel TextS2"><input type="checkbox" model="BBL-3DP-V4NORMAL" nozzel="0.1" vendor="BAMBU" />0.1mm nozzle</div>
</div>
<div class="PrinterBlock">
<div class="PImg">
<img class="ModelThumbnail" src="p2.jpg" />
<div class="ModelCheckBox ModelCheckBoxSelected"></div>
</div>
<div class="PName TextS1">BBL-3DP-V4NORMAL</div>
<div class="pNozzel TextS2"><input type="checkbox" model="BBL-3DP-V5NORMAL" nozzel="0.4" vendor="BAMBU" />0.4mm nozzle</div>
<div class="pNozzel TextS2"><input type="checkbox" model="BBL-3DP-V5NORMAL" nozzel="0.2" vendor="BAMBU" />0.2mm nozzle</div>
<div class="pNozzel TextS2"><input type="checkbox" model="BBL-3DP-V5NORMAL" nozzel="0.1" vendor="BAMBU" />0.1mm nozzle</div>
</div>
</div>
</div>-->
-->
</div>
<div id="AcceptArea">
@@ -153,212 +95,10 @@
</div>
</div>
</div>
</body>
<script>
const SearchBox = document.querySelector('.searchTerm');
document.onkeydown = function (event) {
var e = event || window.event || arguments.callee.caller.arguments[0];
// ORCA focus search bar on key input
// SearchBox not in focus && writable character && non modifier
if (document.activeElement != SearchBox && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
SearchBox.focus();
}
// Close sidebar
document.getElementById('SidebarContainer').setAttribute('open', '0')
//if (window.event) {
// try { e.keyCode = 0; } catch (e) { }
// e.returnValue = true;
//}
};
let pModel = {};
let ModelNozzleSelected = {};
function textInput(obj) {
FilterModelList(obj.value);
}
const $content = $('#Content');
// SNAPPY SCROLLING WITHOUT LAGS
const SNAP_DELAY = 600;
const SNAP_DURATION = 200;
const SNAP_CORR = 8; // error correction / tolerance
let scrollTimer = null;
let lastScrollTop = 0;
let scrollDir = 'down';
let isSnapping = false;
let snapRafId = null;
let lastSnapTarget = null;
let waitingForUserScroll = false;
function findSnap(cur, dir) {
if (lastSnapTarget !== null && Math.abs(cur - lastSnapTarget) < SNAP_CORR) return null;
const savedScroll = cur;
$content[0].scrollTop = 0; // Temporarily scroll to 0 so getBoundingClientRect can get absolute positions
let bcTop = el=>(el.getBoundingClientRect().top);
const contentTop = bcTop($content[0]);
const bannerH = ($content.find('.BlockBanner')[0] || {}).offsetHeight || 0;
const firstCard = $content.find('.PrinterBlock')[0];
const firstArea = $content.find('.PrinterArea')[0];
const cardGap = (firstCard && firstArea) ? (bcTop(firstCard) - bcTop(firstArea)) : 0;
const candidates = $content.find('.BlockBanner, .PrinterBlock').get();
if (dir === 'up') candidates.reverse();
let result = lastSeen = null;
for (const el of candidates) {
const snapTo = Math.round(
el.classList.contains('BlockBanner')
? (bcTop(el.closest('.OneVendorBlock')) - contentTop)
: Math.max(0, bcTop(el) - contentTop - bannerH - cardGap)
);
if (snapTo != lastSeen){
lastSeen = snapTo;
if (dir === 'down' && snapTo > cur + SNAP_CORR) { result = snapTo; break; }
if (dir === 'up' && snapTo < cur - SNAP_CORR) { result = snapTo; break; }
}
}
$content[0].scrollTop = savedScroll; // Restore scroll position
return result;
}
function smoothScrollTo(target) {
if (snapRafId) {
cancelAnimationFrame(snapRafId);
snapRafId = null;
}
const el = $content[0];
const from = el.scrollTop;
const dist = target - from;
const t0 = performance.now();
const ease = t => t < 0.5 ? 2*t*t : -1 + (4 - 2*t)*t;
function onDone() {
el.scrollTop = target;
lastScrollTop = lastSnapTarget = target;
waitingForUserScroll = true;
clearTimeout(scrollTimer);
scrollTimer = null;
snapRafId = null;
isSnapping = false;
}
if (Math.abs(dist) < 2)
return onDone();
snapRafId = requestAnimationFrame(function step(now) {
const p = Math.min((now - t0) / SNAP_DURATION, 1);
el.scrollTop = from + dist * ease(p);
if (p < 1)
snapRafId = requestAnimationFrame(step);
else
onDone();
});
}
function armSnap() {
waitingForUserScroll = false;
lastSnapTarget = null;
}
$content.on('scroll', function() {
if (isSnapping) return;
if (this.scrollTop > lastScrollTop + 1) scrollDir = 'down';
else if (this.scrollTop < lastScrollTop - 1) scrollDir = 'up';
lastScrollTop = this.scrollTop;
if (waitingForUserScroll) return;
clearTimeout(scrollTimer);
scrollTimer = setTimeout(()=>{
if (isSnapping) return;
const target = findSnap($content[0].scrollTop, scrollDir);
if (target){
isSnapping = true;
smoothScrollTo(target);
}
}, SNAP_DELAY);
});
let touchY = 0;
$content[0].addEventListener('touchstart', e => {
touchY = e.touches[0].clientY;
armSnap();
}, { passive: true });
$content[0].addEventListener('touchmove', e => {
const dy = touchY - e.touches[0].clientY;
if (Math.abs(dy) > 3)
scrollDir = dy > 0 ? 'down' : 'up';
}, { passive: true });
// Re-arm snap system on user scroll
$content[0].addEventListener('wheel', armSnap, { passive: true });
// Re-arm on after scrollbar usage
$content[0].addEventListener('pointerdown', e => {
if (e.target === $content[0])
armSnap();
});
// Re-arm on keyboard scroll or focus changes
document.addEventListener('keydown', e => {
if (document.activeElement != SearchBox){
let scrollKeys = ['ArrowUp','ArrowDown','PageUp','PageDown',' '];
let hasFocus = $content[0].contains(document.activeElement);
if(scrollKeys.includes(e.key) || (hasFocus && e.which == 9))
armSnap();
}
});
// ORCA unfocus search bar while scrolling and its content empty
$content[0].addEventListener("scroll", () => {
if (document.activeElement === SearchBox && SearchBox.value == "")
SearchBox.blur();
});
// LAYOUT SELECTOR
const LayoutSelector = document.querySelector('.LayoutSelector > .TabGroup');
const LayoutBtns = Array.from(LayoutSelector.children);
const LayoutTypes = ["compact-list","compact-cover","large-cover"];
function LayoutMode(value) {
if($content[0].getAttribute("layout") === value)
return;
// find current visible vendor and scroll to it after layout change
let target = null;
for (const el of $content.find('.OneVendorBlock')) {
if (el.getBoundingClientRect().bottom - $content[0].getBoundingClientRect().top >= -1) {
target = el.getAttribute("vendor");
break;
}
}
LayoutBtns.forEach(el => el.classList.remove('selected'));
LayoutBtns[LayoutTypes.indexOf(value)].classList.add('selected');
$content[0].setAttribute("layout", value);
if (target) scrollToVendor(target);
}
LayoutMode("large-cover");
initKeyEvents(false); // dont close on ESC
InitGlobalVariables();
</script>
</html>

View File

@@ -1,269 +1,7 @@
.ChooseBlock
{
display:flex;
line-height: 32px;
}
.CName
{
width:130px;
font-weight: 700;
height: 100%;
text-align: right;
white-space: nowrap;
flex-shrink: 0;
}
#ItemBlockArea
{
display:flex;
overflow-y:scroll;
flex-wrap:wrap;
flex-direction: row;
padding: 0 0 0 8px;
}
.MItem
{
width:33%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 4px !important;
top: -100px; /* ORCA this will be activated when item filtered with position:absolute */
}
.MItem label
{
margin-right: 0px !important;
}
#NoticeMask
{
background-color: #000;
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
opacity: 0.05;
display: none;
}
#NoticeBody
{
display: none;
width: 500px;
border-width: 1px;
border-style: solid;
border-radius: 4px;
background-color: inherit;
position: absolute;
left: 50%;
top: 200px;
margin-left: -250px;
}
#NoticeBar
{
background-color: var(--main-color);
height: 40px;
line-height: 40px;
color: #fff;
text-align: center;
}
#NoticeContent
{
padding: 4mm 10mm;
}
#NoticeBtns
{
margin-top: 4mm;
display: flex;
justify-content:flex-end;
}
#GotoNetPluginBtn
{
display: none;
}
/* ORCA column browser */
#Content {
padding: 10px 15px 5px;
height: 100%;
}
.cbr-browser-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 210px auto;
width: 100%;
height: 100%;
border: 1px solid var(--border-color);
box-sizing: border-box;
}
.cbr-column:last-child {
grid-column: 1 / -1;
border-top: 1px solid var(--border-color);
}
.cbr-column {
display: flex;
flex-direction: column;
overflow: hidden;
}
.cbr-column:nth-child(-n+2) {
border-right: 1px solid var(--border-color);
}
.cbr-column .CValues {
display: grid;
}
.CValues label {
margin-right: 0 !important;
}
.cbr-column-title-container {
position: sticky;
background: var(--bg-color-secondary);
display: flex;
align-items: center;
border-bottom: 1px solid var(--border-color);
}
.cbr-search-bar,
.cbr-filter-bar {
font-size: 16px;
background: var(--bg-color-secondary);
border: 1px solid transparent;
padding: 2px 27px 2px 27px;
line-height: 24px;
}
.cbr-search-bar {
width: calc(100% - 18px);
}
.cbr-filter-bar {
border-color: var(--border-color);
width: 160px;
height:24px;
}
.cbr-column-title-container .ComboBox > select {
margin: 3px 0;
height: 30px;
}
.cbr-column-title-container input:is(:hover,:focus) {
border-color: var(--main-color);
outline: none;
}
.cbr-column-title-container input:is(:focus) {
background: var(--focus-bg-box);
}
.cbr-filter-box {
position: relative;
margin: 3px;
}
.list-item-count {
color:var(--fg-color-label);
margin-left:10px
}
.cbr-filter-btns {
display: flex;
margin: 5px 5px 5px auto;
}
.cbr-filter-btns div:first-of-type {
margin-left: 10px;
}
.cbr-filter-mode-filter {
display: none;
}
.clear-icon,
.search-icon,
.filter-icon {
position: absolute;
top: 50%;
transform: translateY(-50%);
-webkit-mask-image: var(--url);
mask-image: var(--url);
width: 16px;
height: 16px;
background-color: var(--icon-color);
pointer-events:none;
}
.filter-icon {--url: var(--icon-filter)}
.search-icon {--url: var(--icon-search)}
.clear-icon {--url: var(--icon-input-clear)}
.search-icon,
.filter-icon {
left: 6px;
}
.clear-icon {
right: 6px;
display: none;
}
.cbr-search-bar:not(:placeholder-shown) ~ .clear-icon,
.cbr-filter-bar:not(:placeholder-shown) ~ .clear-icon {
display: block;
}
input[onclear="1"]{
cursor:default
}
.cbr-search-placeholder,
.cbr-filter-placeholder {
position: absolute;
top: 50%;
transform: translateY(-50%);
font-size: 16px;
color: var(--fg-color-label);
pointer-events: none;
line-height: 24px;
left: 27px;
}
.cbr-search-bar:not(:placeholder-shown) + .cbr-search-placeholder,
.cbr-filter-bar:not(:placeholder-shown) + .cbr-filter-placeholder {
opacity: 0;
}
.cbr-content {
overflow-y: auto;
}
.cbr-content div {
padding-left: 8px;
}
.cbr-content label {
margin-right: 0 !important;
padding: 1px 0 !important;
}
.cbr-content div.cbr-no-items {
#GotoNetPluginBtn {
display: none;
}

View File

@@ -1,24 +1,8 @@
var m_ProfileItem;
var FilamentPriority=new Array( "pla","abs","pet","tpu","pc");
var VendorPriority=new Array("generic");
function OnInit()
{
TranslatePage();
RequestProfile();
}
function RequestProfile()
{
var tSend={};
tSend['sequence_id']=Math.round(new Date() / 1000);
tSend['command']="request_userguide_profile";
SendWXMessage( JSON.stringify(tSend) );
}
function HandleStudio(pVal)
@@ -30,537 +14,19 @@ function HandleStudio(pVal)
{
m_ProfileItem=pVal['response'];
SortUI();
InstallNetworkPlugin();
}
}
function GetFilamentShortname( sName )
function InstallNetworkPlugin()
{
let sShort=sName.split('@')[0].trim();
return sShort;
}
function SortUI()
{
var ModelList=new Array();
let nMode=m_ProfileItem["model"].length;
for(let n=0;n<nMode;n++)
{
let OneMode=m_ProfileItem["model"][n];
if( OneMode["nozzle_selected"]!="" )
ModelList.push(OneMode);
}
//model
let HtmlMode='';
nMode=ModelList.length;
for(let n=0;n<nMode;n++)
{
let sModel=ModelList[n];
/* ORCA use label tag to allow checkbox to toggle when user ckicked to text */
HtmlMode+='<label><input type="checkbox" mode="'+sModel['model']+'" nozzle="'+sModel['nozzle_selected']+'" onChange="MachineClick()" /><span>'+sModel['model']+'</span></label>';
}
$('#MachineList .CValues').append(HtmlMode);
$('#MachineList .CValues input').prop("checked",true);
//if(nMode<=1)
//{
// $('#MachineList').hide();
//}
//Filament - Create sorted array with generic vendor first
let FilamentArray=new Array();
let GenericFilamentArray=new Array();
for( let key in m_ProfileItem['filament'] )
{
let OneFila=m_ProfileItem['filament'][key];
if(OneFila['vendor'].toLowerCase() === 'generic')
GenericFilamentArray.push({key: key, data: OneFila});
else
FilamentArray.push({key: key, data: OneFila});
}
// Combine arrays with generic filaments first
let SortedFilamentArray = GenericFilamentArray.concat(FilamentArray);
let HtmlFilament='';
let SelectNumber=0;
var TypeHtmlArray={};
var VendorHtmlArray={};
for( let n=0; n<SortedFilamentArray.length; n++ )
{
let filamentItem = SortedFilamentArray[n];
let key = filamentItem.key;
let OneFila = filamentItem.data;
//alert(JSON.stringify(OneFila));
let fWholeName=OneFila['name'].trim();
let fShortName=GetFilamentShortname( OneFila['name'] );
let fVendor=OneFila['vendor'];
let fType=OneFila['type'];
let fSelect=OneFila['selected'];
let fModel=OneFila['models']
let bFind=false;
//let bCheck=$("#MachineList input:first").prop("checked");
if( fModel=='')
{
// Orca: hide
bFind=true;
}
else
{
//check in modellist
let nModelAll=ModelList.length;
for(let m=0;m<nModelAll;m++)
{
let sOne=ModelList[m];
let OneName=sOne['model'];
let NozzleArray=sOne["nozzle_selected"].split(';');
let nNozzle=NozzleArray.length;
for( let b=0;b<nNozzle;b++ )
{
let nowModel= OneName+"++"+NozzleArray[b];
if(fModel.indexOf(nowModel)>=0)
{
bFind=true;
break;
}
}
}
}
if(bFind)
{
//Type
let LowType=fType.toLowerCase();
if(!TypeHtmlArray.hasOwnProperty(LowType))
{
/* ORCA use label tag to allow checkbox to toggle when user ckicked to text */
let HtmlType='<label><input type="checkbox" filatype="'+fType+'" onChange="FilaClick()" /><span>'+fType+'</span></label>';
TypeHtmlArray[LowType]=HtmlType;
}
//Vendor
let lowVendor=fVendor.toLowerCase();
if(!VendorHtmlArray.hasOwnProperty(lowVendor))
{
/* ORCA use label tag to allow checkbox to toggle when user ckicked to text */
let HtmlVendor='<label><input type="checkbox" vendor="'+fVendor+'" onChange="VendorClick()" /><span>'+fVendor+'</span></label>';
VendorHtmlArray[lowVendor]=HtmlVendor;
}
//Filament
let pFila=$("#ItemBlockArea input[vendor='"+fVendor+"'][filatype='"+fType+"'][name='"+fShortName+"']");
if(pFila.length==0)
{
/* ORCA use label tag to allow checkbox to toggle when user ckicked to text */
let HtmlFila='<label class="MItem"><input type="checkbox" onChange="UpdateStats()" vendor="'+fVendor+'" filatype="'+fType+'" filalist="'+fWholeName+';'+'" model="'+fModel+'" name="'+fShortName+'" /><span>'+fShortName+'</span></label>';
$("#ItemBlockArea").append(HtmlFila);
}
else
{
let strModel=pFila.attr("model");
let strFilalist=pFila.attr("filalist");
if(strModel == '' || fModel == '')
pFila.attr("model", '');
else
pFila.attr("model", strModel+fModel);
pFila.attr("filalist", strFilalist+fWholeName+';');
}
if(fSelect*1==1)
{
//alert( fWholeName+' - '+fShortName+' - '+fVendor+' - '+fType+' - '+fSelect+' - '+fModel );
$("#ItemBlockArea input[vendor='"+fVendor+"'][filatype='"+fType+"'][name='"+fShortName+"']").prop("checked",true);
SelectNumber++;
}
// else
// $("#ItemBlockArea input[vendor='"+fVendor+"'][model='"+fModel+"'][filatype='"+fType+"'][name='"+key+"']").prop("checked",false);
}
}
//Sort TypeArray
let TypeAdvNum=FilamentPriority.length;
for( let n=0;n<TypeAdvNum;n++ )
{
let strType=FilamentPriority[n];
if( TypeHtmlArray.hasOwnProperty( strType ) )
{
$("#FilatypeList .CValues").append( TypeHtmlArray[strType] );
delete( TypeHtmlArray[strType] );
}
}
for(let key in TypeHtmlArray )
{
$("#FilatypeList .CValues").append( TypeHtmlArray[key] );
}
$("#FilatypeList .CValues input").prop("checked",true);
//Sort VendorArray
let VendorAdvNum=VendorPriority.length;
for( let n=0;n<VendorAdvNum;n++ )
{
let strVendor=VendorPriority[n];
if( VendorHtmlArray.hasOwnProperty( strVendor ) )
{
$("#VendorList .CValues").append( VendorHtmlArray[strVendor] );
delete( VendorHtmlArray[strVendor] );
}
}
for(let key in VendorHtmlArray )
{
$("#VendorList .CValues").append( VendorHtmlArray[key] );
}
$("#VendorList .CValues input").prop("checked",true);
//------
if(SelectNumber==0)
ChooseDefaultFilament();
//--If Need Install Network Plugin
if(m_ProfileItem["network_plugin_install"]!='1' || (m_ProfileItem["network_plugin_install"]=='1' && m_ProfileItem["network_plugin_compability"]=='0') )
{
$("#AcceptBtn").hide();
$("#GotoNetPluginBtn").show();
}
UpdateStats();
}
function ChooseAllMachine()
{
let bCheck=$("#MachineList input:first").prop("checked");
$("#MachineList input").prop("checked",bCheck);
SortFilament();
}
function MachineClick()
{
let nChecked=$("#MachineList input:gt(0):checked").length
let nAll =$("#MachineList input:gt(0)").length
if(nAll==nChecked)
{
$("#MachineList input:first").prop("checked",true);
}
else
{
$("#MachineList input:first").prop("checked",false);
}
SortFilament();
}
function ChooseAllFilament()
{
let bCheck=$("#FilatypeList input:first").prop("checked");
$("#FilatypeList input").prop("checked",bCheck);
SortFilament();
}
function FilaClick()
{
let nChecked=$("#FilatypeList input:gt(0):checked").length
let nAll =$("#FilatypeList input:gt(0)").length
if(nAll==nChecked)
{
$("#FilatypeList input:first").prop("checked",true);
}
else
{
$("#FilatypeList input:first").prop("checked",false);
}
SortFilament();
}
function ChooseAllVendor()
{
let bCheck=$("#VendorList input:first").prop("checked");
$("#VendorList input").prop("checked",bCheck);
SortFilament();
}
function VendorClick()
{
let nChecked=$("#VendorList input:gt(0):checked").length
let nAll =$("#VendorList input:gt(0)").length
if(nAll==nChecked)
{
$("#VendorList input:first").prop("checked",true);
}
else
{
$("#VendorList input:first").prop("checked",false);
}
SortFilament();
}
function SortFilament()
{
let FilaNodes=$("#ItemBlockArea .MItem");
let nFilament=FilaNodes.length;
//$("#ItemBlockArea .MItem").hide();
//ModelList
let pModel=$("#MachineList input:checked");
let nModel=pModel.length;
let ModelList=new Array();
for(let n=0;n<nModel;n++)
{
let OneModel=pModel[n];
let mName=OneModel.getAttribute("mode");
if( mName=='all' )
{
continue;
}
else
{
let mNozzle=OneModel.getAttribute("nozzle");
let NozzleArray=mNozzle.split(';');
for( let bb=0;bb<NozzleArray.length;bb++ )
{
let NewModel='['+mName+'++'+NozzleArray[bb]+']';
ModelList.push( NewModel );
}
}
}
//TypeList
let pType=$("#FilatypeList input:gt(0):checked");
let nType=pType.length;
let TypeList=new Array();
for(let n=0;n<nType;n++)
{
let OneType=pType[n];
TypeList.push( OneType.getAttribute("filatype") );
}
//VendorList
let pVendor=$("#VendorList input:gt(0):checked");
let nVendor=pVendor.length;
let VendorList=new Array();
for(let n=0;n<nVendor;n++)
{
let OneVendor=pVendor[n];
VendorList.push( OneVendor.getAttribute("vendor") );
}
//Update Filament UI
for(let m=0;m<nFilament;m++)
{
let OneNode=FilaNodes[m];
let OneFF=OneNode.getElementsByTagName("input")[0];
let fModel=OneFF.getAttribute("model");
let fVendor=OneFF.getAttribute("vendor");
let fType=OneFF.getAttribute("filatype");
let fName=OneFF.getAttribute("name");
if(TypeList.in_array(fType) && VendorList.in_array(fVendor))
{
let HasModel=false;
for(let m=0;m<ModelList.length;m++)
{
let ModelSrc=ModelList[m];
if( fModel.indexOf(ModelSrc)>=0)
{
HasModel=true;
break;
}
}
if(HasModel || fModel=='')
$(OneNode).show();
else
$(OneNode).hide();
}
else{
$(OneNode).hide();
//alert(fName) //debug non common filament type
}
}
UpdateStats();
}
function UpdateStats()
{
let $i = $("#ItemBlockArea");
let $allItems = $i.find(".MItem");
let $visibleItems = $i.find(".MItem:visible");
let $filteredItems = $visibleItems.filter(function() { return $(this).css('position') !== 'absolute'});
let visibleCount = Math.min($filteredItems.length, $visibleItems.length);
$(".list-item-count").text(
$i.find("input:checked").length + " / " +
$allItems.length +
($allItems.length > visibleCount ? (" [" + visibleCount + "]") : "") // filtered items
);
}
function ChooseDefaultFilament()
{
//ModelList
let pModel=$("#MachineList input:gt(0)");
let nModel=pModel.length;
let ModelList=new Array();
for(let n=0;n<nModel;n++)
{
let OneModel=pModel[n];
ModelList.push( OneModel.getAttribute("mode") );
}
//DefaultMaterialList
let DefaultMaterialString=new Array();
let nMode=m_ProfileItem["model"].length;
for(let n=0;n<nMode;n++)
{
let OneMode=m_ProfileItem["model"][n];
let ModeName=OneMode['model'];
let DefaultM=OneMode['materials'];
if( ModelList.indexOf(ModeName)>-1 )
{
DefaultMaterialString+=OneMode['materials']+';';
}
}
let DefaultMaterialArray=DefaultMaterialString.split(';');
//alert(DefaultMaterialString);
//Filament
let FilaNodes=$("#ItemBlockArea .MItem");
let nFilament=FilaNodes.length;
for(let m=0;m<nFilament;m++)
{
let OneNode=FilaNodes[m];
let OneFF=OneNode.getElementsByTagName("input")[0];
$(OneFF).prop("checked",false);
let filamentList=GetFilamentShortname(OneFF.getAttribute("filalist"));
//alert(filamentList);
let filamentArray=filamentList.split(';')
let HasModel=false;
let NowFilaLength=filamentArray.length;
for(let p=0;p<NowFilaLength;p++)
{
let NowFila=filamentArray[p];
if( NowFila!='' && DefaultMaterialArray.indexOf(NowFila)>-1)
{
HasModel=true;
break;
}
}
if(HasModel)
$(OneFF).prop("checked",true);
}
ShowNotice(0);
UpdateStats();
}
function SelectAllFilament( nShow )
{
// ORCA add ability to only select / unselect filted items
if (document.querySelector('.cbr-filter-bar').value) {
$('#ItemBlockArea .MItem:visible input')
.filter(function() {return $(this).closest('.MItem').css('position') !== 'absolute'})
.prop("checked", nShow != 0);
}
else {
$('#ItemBlockArea .MItem:visible input').prop("checked",nShow!=0);
}
}
function ShowNotice( nShow )
{
if(nShow==0)
{
$("#NoticeMask").hide();
$("#NoticeBody").hide();
}
else
{
$("#NoticeMask").show();
$("#NoticeBody").show();
}
}
function ResponseFilamentResult()
{
let FilaSelectedList= $("#ItemBlockArea input:checked");
let nAll=FilaSelectedList.length;
if( nAll==0 )
{
ShowNotice(1);
return false;
}
let FilaArray=new Array();
for(let n=0;n<nAll;n++)
{
let strFilalist=FilaSelectedList[n].getAttribute("filalist");
if(strFilalist) {
let filaNames = strFilalist.split(';');
for(let i=0; i<filaNames.length; i++) {
let fname = filaNames[i].trim();
if(fname !== '')
FilaArray.push(fname);
}
}
}
var tSend={};
tSend['sequence_id']=Math.round(new Date() / 1000);
tSend['command']="save_userguide_filaments";
tSend['data']={};
tSend['data']['filament']=FilaArray;
SendWXMessage( JSON.stringify(tSend) );
return true;
}
function ReturnPreviewPage()
{
let nMode=m_ProfileItem["model"].length;
@@ -571,7 +37,6 @@ function ReturnPreviewPage()
document.location.href="../21/index.html";
}
function GotoNetPluginPage()
{
let bRet=ResponseFilamentResult();
@@ -596,8 +61,3 @@ function FinishGuide()
}
//window.location.href="../6/index.html";
}

View File

@@ -0,0 +1,250 @@
#Content {
height: 100%;
}
.ChooseBlock {
display:flex;
line-height: 32px;
}
.CName {
width:130px;
font-weight: 700;
height: 100%;
text-align: right;
white-space: nowrap;
flex-shrink: 0;
}
#ItemBlockArea {
display:flex;
overflow-y:scroll;
flex-wrap:wrap;
flex-direction: row;
padding: 0 0 0 8px;
}
.MItem {
width:33%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 4px !important;
top: -100px; /* ORCA this will be activated when item filtered with position:absolute */
}
.MItem label {
margin-right: 0px !important;
}
/* ORCA COLUMN BROWSER */
.cbr-browser-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 210px auto;
width: 100%;
height: 100%;
border: 1px solid var(--border-color);
box-sizing: border-box;
}
.cbr-column:last-child {
grid-column: 1 / -1;
border-top: 1px solid var(--border-color);
}
.cbr-column {
display: flex;
flex-direction: column;
overflow: hidden;
}
.cbr-column:nth-child(-n+2) {
border-right: 1px solid var(--border-color);
}
.cbr-column .CValues {
display: grid;
}
.CValues label {
margin-right: 0 !important;
}
.cbr-column-title-container {
position: sticky;
background: var(--bg-color-secondary);
display: flex;
align-items: center;
border-bottom: 1px solid var(--border-color);
}
.cbr-search-bar,
.cbr-filter-bar {
font-size: 16px;
background: var(--bg-color-secondary);
border: 1px solid transparent;
padding: 2px 27px 2px 27px;
line-height: 24px;
}
.cbr-search-bar {
width: calc(100% - 18px);
}
.cbr-filter-bar {
border-color: var(--border-color);
width: 160px;
height:24px;
}
.cbr-column-title-container .ComboBox > select {
margin: 3px 0;
height: 30px;
}
.cbr-column-title-container input:is(:hover,:focus) {
border-color: var(--main-color);
outline: none;
}
.cbr-column-title-container input:is(:focus) {
background: var(--focus-bg-box);
}
.cbr-filter-box {
position: relative;
margin: 3px;
}
.list-item-count {
color:var(--fg-color-label);
margin-left:10px
}
.cbr-filter-btns {
display: flex;
margin: 5px 5px 5px auto;
}
.cbr-filter-btns div:first-of-type {
margin-left: 10px;
}
.cbr-filter-mode-filter {
display: none;
}
.clear-icon,
.search-icon,
.filter-icon {
position: absolute;
top: 50%;
transform: translateY(-50%);
-webkit-mask-image: var(--url);
mask-image: var(--url);
width: 16px;
height: 16px;
background-color: var(--icon-color);
pointer-events:none;
}
.filter-icon {--url: var(--icon-filter)}
.search-icon {--url: var(--icon-search)}
.clear-icon {--url: var(--icon-input-clear)}
.search-icon,
.filter-icon {
left: 6px;
}
.clear-icon {
right: 6px;
display: none;
}
.cbr-search-bar:not(:placeholder-shown) ~ .clear-icon,
.cbr-filter-bar:not(:placeholder-shown) ~ .clear-icon {
display: block;
}
input[onclear="1"] {
cursor:default
}
.cbr-search-placeholder,
.cbr-filter-placeholder {
position: absolute;
top: 50%;
transform: translateY(-50%);
font-size: 16px;
color: var(--fg-color-label);
pointer-events: none;
line-height: 24px;
left: 27px;
}
.cbr-search-bar:not(:placeholder-shown) + .cbr-search-placeholder,
.cbr-filter-bar:not(:placeholder-shown) + .cbr-filter-placeholder {
opacity: 0;
}
.cbr-content {
overflow-y: auto;
}
.cbr-content div {
padding-left: 8px;
}
.cbr-content label {
margin-right: 0 !important;
padding: 1px 0 !important;
}
.cbr-content div.cbr-no-items {
display: none;
}
/* NOTICE POPUP */
#NoticeMask {
background-color: #000;
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
opacity: 0.05;
display: none;
}
#NoticeBody {
display: none;
width: 500px;
border-width: 1px;
border-style: solid;
border-radius: 4px;
background-color: inherit;
position: absolute;
left: 50%;
top: 200px;
margin-left: -250px;
}
#NoticeBar {
background-color: var(--main-color);
height: 40px;
line-height: 40px;
color: #fff;
text-align: center;
}
#NoticeContent {
padding: 4mm 10mm;
}
#NoticeBtns {
margin-top: 4mm;
display: flex;
justify-content:flex-end;
}

View File

@@ -0,0 +1,614 @@
var m_ProfileItem;
var FilamentPriority = new Array( "pla","abs","pet","tpu","pc");
var VendorPriority = new Array("generic");
function RequestProfile()
{
var tSend={};
tSend['sequence_id']=Math.round(new Date() / 1000);
tSend['command']="request_userguide_profile";
SendWXMessage( JSON.stringify(tSend) );
}
function GetFilamentShortname( sName )
{
let sShort=sName.split('@')[0].trim();
return sShort;
}
function SortUI()
{
var ModelList=new Array();
let nMode=m_ProfileItem["model"].length;
for(let n=0;n<nMode;n++)
{
let OneMode=m_ProfileItem["model"][n];
if( OneMode["nozzle_selected"]!="" )
ModelList.push(OneMode);
}
//model
let HtmlMode='';
nMode=ModelList.length;
for(let n=0;n<nMode;n++)
{
let sModel=ModelList[n];
/* ORCA use label tag to allow checkbox to toggle when user ckicked to text */
HtmlMode+='<label><input type="checkbox" mode="'+sModel['model']+'" nozzle="'+sModel['nozzle_selected']+'" onChange="MachineClick()" /><span>'+sModel['model']+'</span></label>';
}
$('#MachineList .CValues').append(HtmlMode);
$('#MachineList .CValues input').prop("checked",true);
//if(nMode<=1)
//{
// $('#MachineList').hide();
//}
//Filament - Create sorted array with generic vendor first
let FilamentArray=new Array();
let GenericFilamentArray=new Array();
for( let key in m_ProfileItem['filament'] )
{
let OneFila=m_ProfileItem['filament'][key];
if(OneFila['vendor'].toLowerCase() === 'generic')
GenericFilamentArray.push({key: key, data: OneFila});
else
FilamentArray.push({key: key, data: OneFila});
}
// Combine arrays with generic filaments first
let SortedFilamentArray = GenericFilamentArray.concat(FilamentArray);
let HtmlFilament='';
let SelectNumber=0;
var TypeHtmlArray={};
var VendorHtmlArray={};
for( let n=0; n<SortedFilamentArray.length; n++ )
{
let filamentItem = SortedFilamentArray[n];
let key = filamentItem.key;
let OneFila = filamentItem.data;
//alert(JSON.stringify(OneFila));
let fWholeName=OneFila['name'].trim();
let fShortName=GetFilamentShortname( OneFila['name'] );
let fVendor=OneFila['vendor'];
let fType=OneFila['type'];
let fSelect=OneFila['selected'];
let fModel=OneFila['models']
let bFind=false;
//let bCheck=$("#MachineList input:first").prop("checked");
if( fModel=='')
{
// Orca: hide
bFind=true;
}
else
{
//check in modellist
let nModelAll=ModelList.length;
for(let m=0;m<nModelAll;m++)
{
let sOne=ModelList[m];
let OneName=sOne['model'];
let NozzleArray=sOne["nozzle_selected"].split(';');
let nNozzle=NozzleArray.length;
for( let b=0;b<nNozzle;b++ )
{
let nowModel= OneName+"++"+NozzleArray[b];
if(fModel.indexOf(nowModel)>=0)
{
bFind=true;
break;
}
}
}
}
if(bFind)
{
//Type
let LowType=fType.toLowerCase();
if(!TypeHtmlArray.hasOwnProperty(LowType))
{
/* ORCA use label tag to allow checkbox to toggle when user ckicked to text */
let HtmlType='<label><input type="checkbox" filatype="'+fType+'" onChange="FilaClick()" /><span>'+fType+'</span></label>';
TypeHtmlArray[LowType]=HtmlType;
}
//Vendor
let lowVendor=fVendor.toLowerCase();
if(!VendorHtmlArray.hasOwnProperty(lowVendor))
{
/* ORCA use label tag to allow checkbox to toggle when user ckicked to text */
let HtmlVendor='<label><input type="checkbox" vendor="'+fVendor+'" onChange="VendorClick()" /><span>'+fVendor+'</span></label>';
VendorHtmlArray[lowVendor]=HtmlVendor;
}
//Filament
let pFila=$("#ItemBlockArea input[vendor='"+fVendor+"'][filatype='"+fType+"'][name='"+fShortName+"']");
if(pFila.length==0)
{
/* ORCA use label tag to allow checkbox to toggle when user ckicked to text */
let HtmlFila='<label class="MItem"><input type="checkbox" onChange="UpdateStats()" vendor="'+fVendor+'" filatype="'+fType+'" filalist="'+fWholeName+';'+'" model="'+fModel+'" name="'+fShortName+'" /><span>'+fShortName+'</span></label>';
$("#ItemBlockArea").append(HtmlFila);
}
else
{
let strModel=pFila.attr("model");
let strFilalist=pFila.attr("filalist");
if(strModel == '' || fModel == '')
pFila.attr("model", '');
else
pFila.attr("model", strModel+fModel);
pFila.attr("filalist", strFilalist+fWholeName+';');
}
if(fSelect*1==1)
{
//alert( fWholeName+' - '+fShortName+' - '+fVendor+' - '+fType+' - '+fSelect+' - '+fModel );
$("#ItemBlockArea input[vendor='"+fVendor+"'][filatype='"+fType+"'][name='"+fShortName+"']").prop("checked",true);
SelectNumber++;
}
// else
// $("#ItemBlockArea input[vendor='"+fVendor+"'][model='"+fModel+"'][filatype='"+fType+"'][name='"+key+"']").prop("checked",false);
}
}
//Sort TypeArray
let TypeAdvNum=FilamentPriority.length;
for( let n=0;n<TypeAdvNum;n++ )
{
let strType=FilamentPriority[n];
if( TypeHtmlArray.hasOwnProperty( strType ) )
{
$("#FilatypeList .CValues").append( TypeHtmlArray[strType] );
delete( TypeHtmlArray[strType] );
}
}
for(let key in TypeHtmlArray )
{
$("#FilatypeList .CValues").append( TypeHtmlArray[key] );
}
$("#FilatypeList .CValues input").prop("checked",true);
//Sort VendorArray
let VendorAdvNum=VendorPriority.length;
for( let n=0;n<VendorAdvNum;n++ )
{
let strVendor=VendorPriority[n];
if( VendorHtmlArray.hasOwnProperty( strVendor ) )
{
$("#VendorList .CValues").append( VendorHtmlArray[strVendor] );
delete( VendorHtmlArray[strVendor] );
}
}
for(let key in VendorHtmlArray )
{
$("#VendorList .CValues").append( VendorHtmlArray[key] );
}
$("#VendorList .CValues input").prop("checked",true);
if(SelectNumber==0)
ChooseDefaultFilament();
UpdateStats();
}
function ChooseAllMachine()
{
let bCheck=$("#MachineList input:first").prop("checked");
$("#MachineList input").prop("checked",bCheck);
SortFilament();
}
function MachineClick()
{
let nChecked=$("#MachineList input:gt(0):checked").length
let nAll =$("#MachineList input:gt(0)").length
if(nAll==nChecked) {
$("#MachineList input:first").prop("checked",true);
}
else {
$("#MachineList input:first").prop("checked",false);
}
SortFilament();
}
function ChooseAllFilament()
{
let bCheck=$("#FilatypeList input:first").prop("checked");
$("#FilatypeList input").prop("checked",bCheck);
SortFilament();
}
function FilaClick()
{
let nChecked=$("#FilatypeList input:gt(0):checked").length
let nAll =$("#FilatypeList input:gt(0)").length
if(nAll==nChecked) {
$("#FilatypeList input:first").prop("checked",true);
}
else {
$("#FilatypeList input:first").prop("checked",false);
}
SortFilament();
}
function ChooseAllVendor()
{
let bCheck=$("#VendorList input:first").prop("checked");
$("#VendorList input").prop("checked",bCheck);
SortFilament();
}
function VendorClick()
{
let nChecked=$("#VendorList input:gt(0):checked").length
let nAll =$("#VendorList input:gt(0)").length
if(nAll==nChecked) {
$("#VendorList input:first").prop("checked",true);
}
else {
$("#VendorList input:first").prop("checked",false);
}
SortFilament();
}
function SortFilament()
{
let FilaNodes=$("#ItemBlockArea .MItem");
let nFilament=FilaNodes.length;
//$("#ItemBlockArea .MItem").hide();
//ModelList
let pModel=$("#MachineList input:checked");
let nModel=pModel.length;
let ModelList=new Array();
for(let n=0;n<nModel;n++)
{
let OneModel=pModel[n];
let mName=OneModel.getAttribute("mode");
if( mName=='all' )
{
continue;
}
else
{
let mNozzle=OneModel.getAttribute("nozzle");
let NozzleArray=mNozzle.split(';');
for( let bb=0;bb<NozzleArray.length;bb++ )
{
let NewModel='['+mName+'++'+NozzleArray[bb]+']';
ModelList.push( NewModel );
}
}
}
//TypeList
let pType=$("#FilatypeList input:gt(0):checked");
let nType=pType.length;
let TypeList=new Array();
for(let n=0;n<nType;n++)
{
let OneType=pType[n];
TypeList.push( OneType.getAttribute("filatype") );
}
//VendorList
let pVendor=$("#VendorList input:gt(0):checked");
let nVendor=pVendor.length;
let VendorList=new Array();
for(let n=0;n<nVendor;n++)
{
let OneVendor=pVendor[n];
VendorList.push( OneVendor.getAttribute("vendor") );
}
//Update Filament UI
for(let m=0;m<nFilament;m++)
{
let OneNode=FilaNodes[m];
let OneFF=OneNode.getElementsByTagName("input")[0];
let fModel=OneFF.getAttribute("model");
let fVendor=OneFF.getAttribute("vendor");
let fType=OneFF.getAttribute("filatype");
let fName=OneFF.getAttribute("name");
if(TypeList.in_array(fType) && VendorList.in_array(fVendor))
{
let HasModel=false;
for(let m=0;m<ModelList.length;m++)
{
let ModelSrc=ModelList[m];
if( fModel.indexOf(ModelSrc)>=0)
{
HasModel=true;
break;
}
}
if(HasModel || fModel=='')
$(OneNode).show();
else
$(OneNode).hide();
}
else{
$(OneNode).hide();
//alert(fName) //debug non common filament type
}
}
UpdateStats();
}
function UpdateStats()
{
let $i = $("#ItemBlockArea");
let $allItems = $i.find(".MItem");
let $visibleItems = $i.find(".MItem:visible");
let $filteredItems = $visibleItems.filter(function() { return $(this).css('position') !== 'absolute'});
let visibleCount = Math.min($filteredItems.length, $visibleItems.length);
$(".list-item-count").text(
$i.find("input:checked").length + " / " +
$allItems.length +
($allItems.length > visibleCount ? (" [" + visibleCount + "]") : "") // filtered items
);
}
function SelectAllFilament( nShow )
{
// ORCA add ability to only select / unselect filted items
if (document.querySelector('.cbr-filter-bar').value) {
$('#ItemBlockArea .MItem:visible input')
.filter(function() {return $(this).closest('.MItem').css('position') !== 'absolute'})
.prop("checked", nShow != 0);
}
else {
$('#ItemBlockArea .MItem:visible input').prop("checked",nShow!=0);
}
UpdateStats();
}
function ShowNotice( nShow )
{
if(nShow==0) {
$("#NoticeMask").hide();
$("#NoticeBody").hide();
}
else {
$("#NoticeMask").show();
$("#NoticeBody").show();
}
}
function ChooseDefaultFilament()
{
//ModelList
let pModel=$("#MachineList input:gt(0)");
let nModel=pModel.length;
let ModelList=new Array();
for(let n=0;n<nModel;n++)
{
let OneModel=pModel[n];
ModelList.push( OneModel.getAttribute("mode") );
}
//DefaultMaterialList
let DefaultMaterialString = "";
let nMode=m_ProfileItem["model"].length;
for(let n=0;n<nMode;n++)
{
let OneMode=m_ProfileItem["model"][n];
let ModeName=OneMode['model'];
let DefaultM=OneMode['materials'];
if( ModelList.indexOf(ModeName)>-1 )
{
DefaultMaterialString+=OneMode['materials']+';';
}
}
let DefaultMaterialArray=DefaultMaterialString.split(';');
//alert(DefaultMaterialString);
//Filament
let FilaNodes=$("#ItemBlockArea .MItem");
let nFilament=FilaNodes.length;
for(let m=0;m<nFilament;m++)
{
let OneNode=FilaNodes[m];
let OneFF=OneNode.getElementsByTagName("input")[0];
$(OneFF).prop("checked",false);
let filamentList=GetFilamentShortname(OneFF.getAttribute("filalist"));
//alert(filamentList);
let filamentArray=filamentList.split(';')
let HasModel=false;
let NowFilaLength=filamentArray.length;
for(let p=0;p<NowFilaLength;p++)
{
let NowFila=filamentArray[p];
if( NowFila!='' && DefaultMaterialArray.indexOf(NowFila)>-1)
{
HasModel=true;
break;
}
}
if(HasModel)
$(OneFF).prop("checked",true);
}
ShowNotice(0);
UpdateStats();
}
function ResponseFilamentResult()
{
let FilaSelectedList= $("#ItemBlockArea input:checked");
let nAll=FilaSelectedList.length;
if( nAll==0 )
{
ShowNotice(1);
return false;
}
let FilaArray=new Array();
for(let n=0;n<nAll;n++)
{
let strFilalist=FilaSelectedList[n].getAttribute("filalist");
if(strFilalist) {
let filaNames = strFilalist.split(';');
for(let i=0; i<filaNames.length; i++) {
let fname = filaNames[i].trim();
if(fname !== '')
FilaArray.push(fname);
}
}
}
var tSend={};
tSend['sequence_id']=Math.round(new Date() / 1000);
tSend['command']="save_userguide_filaments";
tSend['data']={};
tSend['data']['filament']=FilaArray;
SendWXMessage( JSON.stringify(tSend) );
return true;
}
function addClearBtnEvents(el){
el.addEventListener('click', e => {
if (el.getAttribute("onclear") == "1") {
el.value = '';
el.dispatchEvent(new Event('input', {bubbles: true}));
}
});
el.addEventListener('mousemove', e => {
const rc = el.getBoundingClientRect();
const onRight = el.value && (e.clientX - rc.left > rc.width - 32);
el.setAttribute("onclear", onRight ? "1" : "0");
});
el.addEventListener('mouseleave', e => {
el.setAttribute("onclear", "0");
});
}
function initInputEvents(){
document.querySelectorAll('.cbr-search-bar').forEach(searchBar => {
searchBar.addEventListener('input', function() {
const search = this.value.trim().toLowerCase(),
list = this.closest('.cbr-column').querySelector('.cbr-content'),
items = list.querySelectorAll('label');
let hidden = 0;
items.forEach((item, i) => {
if(i == 0){
item.style.display ="block";
return;
};
const text = item.querySelector("span").textContent.toLowerCase();
const hide = search && !text.includes(search);
item.style.display = hide ? "none" : "block";
if(hide) hidden++;
});
if(items.length - hidden == 1){
items[0].style.display = "none";
hidden++;
}
list.querySelector('.cbr-no-items').style.display = (hidden === items.length) ? "block" : "none";
});
addClearBtnEvents(searchBar);
});
const filterBar = document.querySelector('.cbr-filter-bar');
const filterModeFilter = document.querySelector('.cbr-filter-mode-filter' );
const filterModeVisible = document.querySelector('.cbr-filter-mode-visible');
filterBar.addEventListener('input', function() {
const search = this.value.trim().toLowerCase();
const list = this.closest('.cbr-column').querySelector('.cbr-content');
const items = list.querySelectorAll('label');
let hidden = 0;
filterModeFilter.style.display = search ? "block" : "none";
filterModeVisible.style.display = search ? "none" : "block";
const showSel = search == "::checked";
const showUnsel = search == "::unchecked";
if(showSel || showUnsel){
items.forEach(item => {
const cb = item.querySelector("input");
const hide = showSel ? !cb.checked : cb.checked;
item.style.position = hide ? "absolute" : "unset";
if(hide) hidden++;
});
}
else {
items.forEach(item => {
const text = item.querySelector("span").textContent.toLowerCase();
const hide = search && !text.includes(search);
item.style.position = hide ? "absolute" : "unset";
if(hide) hidden++;
});
}
list.querySelector('.cbr-no-items').style.display = (hidden === items.length) ? "block" : "none";
UpdateStats();
});
addClearBtnEvents(filterBar);
document.querySelector('#filter-tags').addEventListener('change', e => {
let v = e.target.value;
filterBar.value = v == "1" ? "::checked" : "::unchecked";
filterBar.dispatchEvent(new Event('input', {bubbles: true}));
filterBar.focus();
e.target.value = 0; // reset back to make dropdown items always selectable
});
}

View File

@@ -6,6 +6,7 @@
<title>引导_P21</title>
<link rel="stylesheet" type="text/css" href="../../include/global.css" /> <!-- ORCA One for all-->
<link rel="stylesheet" type="text/css" href="../css/common.css" />
<link rel="stylesheet" type="text/css" href="../22/common.css" /> <!-- ORCA use common sources for setup guide and standalone dialog -->
<link rel="stylesheet" type="text/css" href="22.css" />
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
<script type="text/javascript" src="test.js"></script>
@@ -14,6 +15,7 @@
<script type="text/javascript" src="../../data/text.js"></script>
<script type="text/javascript" src="../js/globalapi.js"></script>
<script type="text/javascript" src="../js/common.js"></script>
<script type="text/javascript" src="../22/common.js"></script> <!-- ORCA use common sources for setup guide and standalone dialog -->
<script type="text/javascript" src="./22.js"></script>
</head>
<body onLoad="OnInit()">
@@ -129,98 +131,6 @@
// e.returnValue = false;
//}
};
function addClearBtnEvents(el){
el.addEventListener('click', e => {
if (el.getAttribute("onclear") == "1") {
el.value = '';
el.dispatchEvent(new Event('input', {bubbles: true}));
}
});
el.addEventListener('mousemove', e => {
const rc = el.getBoundingClientRect();
const onRight = el.value && (e.clientX - rc.left > rc.width - 32);
el.setAttribute("onclear", onRight ? "1" : "0");
});
el.addEventListener('mouseleave', e => {
el.setAttribute("onclear", "0");
});
}
document.querySelectorAll('.cbr-search-bar').forEach(searchBar => {
searchBar.addEventListener('input', function() {
const search = this.value.trim().toLowerCase(),
list = this.closest('.cbr-column').querySelector('.cbr-content'),
items = list.querySelectorAll('label');
let hidden = 0;
items.forEach((item, i) => {
if(i == 0){
item.style.display ="block";
return;
};
const text = item.querySelector("span").textContent.toLowerCase();
const hide = search && !text.includes(search);
item.style.display = hide ? "none" : "block";
if(hide) hidden++;
});
if(items.length - hidden == 1){
items[0].style.display = "none";
hidden++;
}
list.querySelector('.cbr-no-items').style.display = (hidden === items.length) ? "block" : "none";
});
addClearBtnEvents(searchBar);
});
const filterBar = document.querySelector('.cbr-filter-bar');
const filterModeFilter = document.querySelector('.cbr-filter-mode-filter' );
const filterModeVisible = document.querySelector('.cbr-filter-mode-visible');
filterBar.addEventListener('input', function() {
const search = this.value.trim().toLowerCase();
const list = this.closest('.cbr-column').querySelector('.cbr-content');
const items = list.querySelectorAll('label');
let hidden = 0;
filterModeFilter.style.display = search ? "block" : "none";
filterModeVisible.style.display = search ? "none" : "block";
const showSel = search == "::checked";
const showUnsel = search == "::unchecked";
if(showSel || showUnsel){
items.forEach(item => {
const cb = item.querySelector("input");
const hide = showSel ? !cb.checked : cb.checked;
item.style.position = hide ? "absolute" : "unset";
if(hide) hidden++;
});
}
else {
items.forEach(item => {
const text = item.querySelector("span").textContent.toLowerCase();
const hide = search && !text.includes(search);
item.style.position = hide ? "absolute" : "unset";
if(hide) hidden++;
});
}
list.querySelector('.cbr-no-items').style.display = (hidden === items.length) ? "block" : "none";
UpdateStats();
});
addClearBtnEvents(filterBar);
document.querySelector('#filter-tags').addEventListener('change', e => {
let v = e.target.value;
filterBar.value = v == "1" ? "::checked" : "::unchecked";
filterBar.dispatchEvent(new Event('input', {bubbles: true}));
filterBar.focus();
e.target.value = 0; // reset back to make dropdown items always selectable
});
initInputEvents();
</script>
</html>

View File

@@ -1,108 +1,5 @@
.ChooseBlock
{
display:flex;
line-height: 32px;
}
.CName
{
width:130px;
font-weight: 700;
height: 100%;
text-align: right;
white-space: nowrap;
flex-shrink: 0;
}
#ItemBlockArea
{
display:flex;
overflow-y:scroll;
flex-wrap:wrap;
flex-direction: row;
padding: 0 0 0 8px;
}
.MItem
{
width:33%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 4px !important;
top: -100px; /* ORCA this will be activated when item filtered with position:absolute */
}
.MItem label
{
margin-right: 0px !important;
}
#NoticeMask
{
background-color: #000;
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
opacity: 0.05;
display: none;
}
#NoticeBody
{
display: none;
width: 500px;
border-width: 1px;
border-style: solid;
border-radius: 4px;
background-color: inherit;
position: absolute;
left: 50%;
top: 200px;
margin-left: -250px;
}
#NoticeBar
{
background-color: var(--main-color);
height: 40px;
line-height: 40px;
color: #fff;
text-align: center;
}
#NoticeContent
{
padding: 4mm 10mm;
}
#NoticeBtns
{
margin-top: 4mm;
display: flex;
justify-content:flex-end;
}
#SystemFilamentsArea
{
display: none;
flex-direction: column;
height: 100%;
}
#CFilament_Btn_Area
{
display: flex;
align-items: center;
height: 30px;
}
#Title
{
/* TABS SYSTEM / CUSTOM */
#Title {
margin: 0px 40px;
border-bottom: 1px solid var(--border-color);
display: flex;
@@ -111,37 +8,44 @@
align-items: center;
}
#Title div
{
#Title div {
cursor: pointer;
font-size: 24px;
}
#Title div.TitleSelected
{
#Title div.TitleSelected {
height: calc(100% - 6px);
display: flex;
align-items: center;
border-bottom: 6px solid var(--main-color);
}
#Title div.TitleUnselected
{
#Title div.TitleUnselected {
height: 100%;
display: flex;
align-items: center;
color: #000;
}
#CustomFilamentsArea
{
/* SYSTEM FILAMENTS PAGE */
body:has(#SystemFilamentBtn.TitleSelected) #Content { /* :has selector browser support 2023+ */
padding: 15px 15px 5px;
}
#SystemFilamentsArea {
display: none;
flex-direction: column;
height: 100%;
}
/* CUSTOM FILAMENTS PAGE */
#CustomFilamentsArea {
display: flex;
flex-direction: column;
height: 100%;
}
#CFilament_List
{
#CFilament_List {
display:flex;
overflow-y:auto;
flex-wrap:wrap;
@@ -152,8 +56,7 @@
height: 100%;
}
.CFilament_Item
{
.CFilament_Item {
display: flex;
align-items: center;
margin-right: 10%;
@@ -164,200 +67,21 @@
margin-right: 2%;
}
.CFilament_Name
{
.CFilament_Name {
width: 100%;
overflow: hidden;
white-space: nowrap; /* ?????? */
text-overflow: ellipsis; /* ????????? */
}
.CFilament_EditBtn
{
cursor: pointer;
width: 20px;
height: 20px;
}
.CFilament_EditBtn:hover
{
}
/* ORCA column browser */
#Content {
height: 100%;
}
body:has(#SystemFilamentBtn.TitleSelected) #Content { /* :has selector browser support 2023+ */
padding: 15px 15px 5px;
}
.cbr-browser-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 210px auto;
width: 100%;
height: 100%;
border: 1px solid var(--border-color);
box-sizing: border-box;
}
.cbr-column:last-child {
grid-column: 1 / -1;
border-top: 1px solid var(--border-color);
}
.cbr-column {
display: flex;
flex-direction: column;
overflow: hidden;
}
.cbr-column:nth-child(-n+2) {
border-right: 1px solid var(--border-color);
}
.cbr-column .CValues {
display: grid;
}
.CValues label {
margin-right: 0 !important;
}
.cbr-column-title-container {
position: sticky;
background: var(--bg-color-secondary);
#CFilament_Btn_Area {
display: flex;
align-items: center;
border-bottom: 1px solid var(--border-color);
}
.cbr-search-bar,
.cbr-filter-bar {
font-size: 16px;
background: var(--bg-color-secondary);
border: 1px solid transparent;
padding: 2px 27px 2px 27px;
line-height: 24px;
}
.cbr-search-bar {
width: calc(100% - 18px);
}
.cbr-filter-bar {
border-color: var(--border-color);
width: 160px;
height:24px;
}
.cbr-column-title-container .ComboBox > select {
margin: 3px 0;
height: 30px;
}
.cbr-column-title-container input:is(:hover,:focus) {
border-color: var(--main-color);
outline: none;
}
.cbr-column-title-container input:is(:focus) {
background: var(--focus-bg-box);
}
.cbr-filter-box {
position: relative;
margin: 3px;
}
.list-item-count {
color:var(--fg-color-label);
margin-left:10px
}
.cbr-filter-btns {
display: flex;
margin: 5px 5px 5px auto;
}
.cbr-filter-btns div:first-of-type {
margin-left: 10px;
}
.cbr-filter-mode-filter {
display: none;
}
.clear-icon,
.search-icon,
.filter-icon {
position: absolute;
top: 50%;
transform: translateY(-50%);
-webkit-mask-image: var(--url);
mask-image: var(--url);
width: 16px;
height: 16px;
background-color: var(--icon-color);
pointer-events:none;
}
.filter-icon {--url: var(--icon-filter)}
.search-icon {--url: var(--icon-search)}
.clear-icon {--url: var(--icon-input-clear)}
.search-icon,
.filter-icon {
left: 6px;
}
.clear-icon {
right: 6px;
display: none;
}
.cbr-search-bar:not(:placeholder-shown) ~ .clear-icon,
.cbr-filter-bar:not(:placeholder-shown) ~ .clear-icon {
display: block;
}
input[onclear="1"]{
cursor:default
}
.cbr-search-placeholder,
.cbr-filter-placeholder {
position: absolute;
top: 50%;
transform: translateY(-50%);
font-size: 16px;
color: var(--fg-color-label);
pointer-events: none;
line-height: 24px;
left: 27px;
}
.cbr-search-bar:not(:placeholder-shown) + .cbr-search-placeholder,
.cbr-filter-bar:not(:placeholder-shown) + .cbr-filter-placeholder {
opacity: 0;
}
.cbr-content {
overflow-y: auto;
}
.cbr-content div {
padding-left: 8px;
}
.cbr-content label {
margin-right: 0 !important;
padding: 1px 0 !important;
}
.cbr-content div.cbr-no-items {
display: none;
.CFilament_EditBtn {
cursor: pointer;
width: 20px;
height: 20px;
}

View File

@@ -1,8 +1,3 @@
var m_ProfileItem;
var FilamentPriority=new Array( "pla","abs","pet","tpu","pc");
var VendorPriority=new Array("generic");
function OnInit()
{
TranslatePage();
@@ -15,15 +10,6 @@ function OnInit()
//OnSelectMenu(2);
}
function RequestProfile()
{
var tSend={};
tSend['sequence_id']=Math.round(new Date() / 1000);
tSend['command']="request_userguide_profile";
SendWXMessage( JSON.stringify(tSend) );
}
function HandleStudio(pVal)
{
let strCmd=pVal['command'];
@@ -40,505 +26,6 @@ function HandleStudio(pVal)
}
}
function GetFilamentShortname( sName )
{
let sShort=sName.split('@')[0].trim();
return sShort;
}
function SortUI()
{
var ModelList=new Array();
let nMode=m_ProfileItem["model"].length;
for(let n=0;n<nMode;n++)
{
let OneMode=m_ProfileItem["model"][n];
if( OneMode["nozzle_selected"]!="" )
ModelList.push(OneMode);
}
//model
let HtmlMode='';
nMode=ModelList.length;
for(let n=0;n<nMode;n++)
{
let sModel=ModelList[n];
/* ORCA use label tag to allow checkbox to toggle when user ckicked to text */
HtmlMode+='<label><input type="checkbox" mode="'+sModel['model']+'" nozzle="'+sModel['nozzle_selected']+'" onChange="MachineClick()" /><span>'+sModel['model']+'</span></label>';
}
$('#MachineList .CValues').append(HtmlMode);
$('#MachineList .CValues input').prop("checked",true);
//if(nMode<=1)
//{
// $('#MachineList').hide();
//}
//Filament - Create sorted array with generic vendor first
let FilamentArray=new Array();
let GenericFilamentArray=new Array();
for( let key in m_ProfileItem['filament'] )
{
let OneFila=m_ProfileItem['filament'][key];
if(OneFila['vendor'].toLowerCase() === 'generic')
GenericFilamentArray.push({key: key, data: OneFila});
else
FilamentArray.push({key: key, data: OneFila});
}
// Combine arrays with generic filaments first
let SortedFilamentArray = GenericFilamentArray.concat(FilamentArray);
let HtmlFilament='';
let SelectNumber=0;
var TypeHtmlArray={};
var VendorHtmlArray={};
for( let n=0; n<SortedFilamentArray.length; n++ )
{
let filamentItem = SortedFilamentArray[n];
let key = filamentItem.key;
let OneFila = filamentItem.data;
//alert(JSON.stringify(OneFila));
let fWholeName=OneFila['name'].trim();
let fShortName=GetFilamentShortname( OneFila['name'] );
let fVendor=OneFila['vendor'];
let fType=OneFila['type'];
let fSelect=OneFila['selected'];
let fModel=OneFila['models']
let bFind=false;
//let bCheck=$("#MachineList input:first").prop("checked");
if( fModel=='')
{
bFind=true;
}
else
{
//check in modellist
let nModelAll=ModelList.length;
for(let m=0;m<nModelAll;m++)
{
let sOne=ModelList[m];
let OneName=sOne['model'];
let NozzleArray=sOne["nozzle_selected"].split(';');
let nNozzle=NozzleArray.length;
for( let b=0;b<nNozzle;b++ )
{
let nowModel= OneName+"++"+NozzleArray[b];
if(fModel.indexOf(nowModel)>=0)
{
bFind=true;
break;
}
}
}
}
if(bFind)
{
//Type
let LowType=fType.toLowerCase();
if(!TypeHtmlArray.hasOwnProperty(LowType))
{
/* ORCA use label tag to allow checkbox to toggle when user ckicked to text */
let HtmlType='<label><input type="checkbox" filatype="'+fType+'" onChange="FilaClick()" /><span>'+fType+'</span></label>';
TypeHtmlArray[LowType]=HtmlType;
}
//Vendor
let lowVendor=fVendor.toLowerCase();
if(!VendorHtmlArray.hasOwnProperty(lowVendor))
{
/* ORCA use label tag to allow checkbox to toggle when user ckicked to text */
let HtmlVendor='<label><input type="checkbox" vendor="'+fVendor+'" onChange="VendorClick()" /><span>'+fVendor+'</span></label>';
VendorHtmlArray[lowVendor]=HtmlVendor;
}
//Filament
let pFila=$("#ItemBlockArea input[vendor='"+fVendor+"'][filatype='"+fType+"'][name='"+fShortName+"']");
if(pFila.length==0)
{
/* ORCA use label tag to allow checkbox to toggle when user ckicked to text */
let HtmlFila='<label class="MItem"><input type="checkbox" onChange="UpdateStats()" vendor="'+fVendor+'" filatype="'+fType+'" filalist="'+fWholeName+';'+'" model="'+fModel+'" name="'+fShortName+'" /><span>'+fShortName+'</span></label>';
$("#ItemBlockArea").append(HtmlFila);
}
else
{
let strModel=pFila.attr("model");
let strFilalist=pFila.attr("filalist");
if(strModel == '' || fModel == '')
pFila.attr("model", '');
else
pFila.attr("model", strModel+fModel);
pFila.attr("filalist", strFilalist+fWholeName+';');
}
if(fSelect*1==1)
{
//alert( fWholeName+' - '+fShortName+' - '+fVendor+' - '+fType+' - '+fSelect+' - '+fModel );
$("#ItemBlockArea input[vendor='"+fVendor+"'][filatype='"+fType+"'][name='"+fShortName+"']").prop("checked",true);
SelectNumber++;
}
// else
// $("#ItemBlockArea input[vendor='"+fVendor+"'][model='"+fModel+"'][filatype='"+fType+"'][name='"+key+"']").prop("checked",false);
}
}
//Sort TypeArray
let TypeAdvNum=FilamentPriority.length;
for( let n=0;n<TypeAdvNum;n++ )
{
let strType=FilamentPriority[n];
if( TypeHtmlArray.hasOwnProperty( strType ) )
{
$("#FilatypeList .CValues").append( TypeHtmlArray[strType] );
delete( TypeHtmlArray[strType] );
}
}
for(let key in TypeHtmlArray )
{
$("#FilatypeList .CValues").append( TypeHtmlArray[key] );
}
$("#FilatypeList .CValues input").prop("checked",true);
//Sort VendorArray
let VendorAdvNum=VendorPriority.length;
for( let n=0;n<VendorAdvNum;n++ )
{
let strVendor=VendorPriority[n];
if( VendorHtmlArray.hasOwnProperty( strVendor ) )
{
$("#VendorList .CValues").append( VendorHtmlArray[strVendor] );
delete( VendorHtmlArray[strVendor] );
}
}
for(let key in VendorHtmlArray )
{
$("#VendorList .CValues").append( VendorHtmlArray[key] );
}
$("#VendorList .CValues input").prop("checked",true);
//------
if(SelectNumber==0)
ChooseDefaultFilament();
UpdateStats();
}
function ChooseAllMachine()
{
let bCheck=$("#MachineList input:first").prop("checked");
$("#MachineList input").prop("checked",bCheck);
SortFilament();
}
function MachineClick()
{
let nChecked=$("#MachineList input:gt(0):checked").length
let nAll =$("#MachineList input:gt(0)").length
if(nAll==nChecked)
{
$("#MachineList input:first").prop("checked",true);
}
else
{
$("#MachineList input:first").prop("checked",false);
}
SortFilament();
}
function ChooseAllFilament()
{
let bCheck=$("#FilatypeList input:first").prop("checked");
$("#FilatypeList input").prop("checked",bCheck);
SortFilament();
}
function FilaClick()
{
let nChecked=$("#FilatypeList input:gt(0):checked").length
let nAll =$("#FilatypeList input:gt(0)").length
if(nAll==nChecked)
{
$("#FilatypeList input:first").prop("checked",true);
}
else
{
$("#FilatypeList input:first").prop("checked",false);
}
SortFilament();
}
function ChooseAllVendor()
{
let bCheck=$("#VendorList input:first").prop("checked");
$("#VendorList input").prop("checked",bCheck);
SortFilament();
}
function VendorClick()
{
let nChecked=$("#VendorList input:gt(0):checked").length
let nAll =$("#VendorList input:gt(0)").length
if(nAll==nChecked)
{
$("#VendorList input:first").prop("checked",true);
}
else
{
$("#VendorList input:first").prop("checked",false);
}
SortFilament();
}
function SortFilament()
{
let FilaNodes=$("#ItemBlockArea .MItem");
let nFilament=FilaNodes.length;
//$("#ItemBlockArea .MItem").hide();
//ModelList
let pModel=$("#MachineList input:checked");
let nModel=pModel.length;
let ModelList=new Array();
for(let n=0;n<nModel;n++)
{
let OneModel=pModel[n];
let mName=OneModel.getAttribute("mode");
if( mName=='all' )
{
continue;
}
else
{
let mNozzle=OneModel.getAttribute("nozzle");
let NozzleArray=mNozzle.split(';');
for( let bb=0;bb<NozzleArray.length;bb++ )
{
let NewModel='['+mName+'++'+NozzleArray[bb]+']';
ModelList.push( NewModel );
}
}
}
//TypeList
let pType=$("#FilatypeList input:gt(0):checked");
let nType=pType.length;
let TypeList=new Array();
for(let n=0;n<nType;n++)
{
let OneType=pType[n];
TypeList.push( OneType.getAttribute("filatype") );
}
//VendorList
let pVendor=$("#VendorList input:gt(0):checked");
let nVendor=pVendor.length;
let VendorList=new Array();
for(let n=0;n<nVendor;n++)
{
let OneVendor=pVendor[n];
VendorList.push( OneVendor.getAttribute("vendor") );
}
//Update Filament UI
for(let m=0;m<nFilament;m++)
{
let OneNode=FilaNodes[m];
let OneFF=OneNode.getElementsByTagName("input")[0];
let fModel=OneFF.getAttribute("model");
let fVendor=OneFF.getAttribute("vendor");
let fType=OneFF.getAttribute("filatype");
let fName=OneFF.getAttribute("name");
if(TypeList.in_array(fType) && VendorList.in_array(fVendor))
{
let HasModel=false;
for(let m=0;m<ModelList.length;m++)
{
let ModelSrc=ModelList[m];
if( fModel.indexOf(ModelSrc)>=0)
{
HasModel=true;
break;
}
}
if(HasModel || fModel=='')
$(OneNode).show();
else
$(OneNode).hide();
}
else{
$(OneNode).hide();
//alert(fName) //debug non common filament type
}
}
UpdateStats();
}
function UpdateStats()
{
let $i = $("#ItemBlockArea");
let $allItems = $i.find(".MItem");
let $visibleItems = $i.find(".MItem:visible");
let $filteredItems = $visibleItems.filter(function() { return $(this).css('position') !== 'absolute'});
let visibleCount = Math.min($filteredItems.length, $visibleItems.length);
$(".list-item-count").text(
$i.find("input:checked").length + " / " +
$allItems.length +
($allItems.length > visibleCount ? (" [" + visibleCount + "]") : "") // filtered items
);
}
function ChooseDefaultFilament()
{
//ModelList
let pModel=$("#MachineList input:gt(0):checked");
let nModel=pModel.length;
let ModelList=new Array();
for(let n=0;n<nModel;n++)
{
let OneModel=pModel[n];
ModelList.push( OneModel.getAttribute("mode") );
}
//Filament
let FilaNodes=$("#ItemBlockArea .MItem");
let nFilament=FilaNodes.length;
for(let m=0;m<nFilament;m++)
{
let OneNode=FilaNodes[m];
let OneFF=OneNode.getElementsByTagName("input")[0];
$(OneFF).prop("checked",false);
let fModel=OneFF.getAttribute("model");
let HasModel=false;
for(let m=0;m<nModel;m++)
{
let ModelSrc=ModelList[m];
if( fModel.indexOf(ModelSrc)>=0)
{
HasModel=true;
break;
}
}
if(HasModel)
$(OneFF).prop("checked",true);
}
ShowNotice(0);
}
function SelectAllFilament( nShow )
{
// ORCA add ability to only select / unselect filted items
if (document.querySelector('.cbr-filter-bar').value) {
$('#ItemBlockArea .MItem:visible input')
.filter(function() {return $(this).closest('.MItem').css('position') !== 'absolute'})
.prop("checked", nShow != 0);
}
else {
$('#ItemBlockArea .MItem:visible input').prop("checked",nShow!=0);
}
UpdateStats();
}
function ShowNotice( nShow )
{
if(nShow==0)
{
$("#NoticeMask").hide();
$("#NoticeBody").hide();
}
else
{
$("#NoticeMask").show();
$("#NoticeBody").show();
}
}
function ResponseFilamentResult()
{
let FilaSelectedList= $("#ItemBlockArea input:checked");
let nAll=FilaSelectedList.length;
if( nAll==0 )
{
ShowNotice(1);
return false;
}
let FilaArray=new Array();
for(let n=0;n<nAll;n++)
{
let strFilalist=FilaSelectedList[n].getAttribute("filalist");
if(strFilalist) {
let filaNames = strFilalist.split(';');
for(let i=0; i<filaNames.length; i++) {
let fname = filaNames[i].trim();
if(fname !== '')
FilaArray.push(fname);
}
}
}
var tSend={};
tSend['sequence_id']=Math.round(new Date() / 1000);
tSend['command']="save_userguide_filaments";
tSend['data']={};
tSend['data']['filament']=FilaArray;
SendWXMessage( JSON.stringify(tSend) );
return true;
}
function CancelSelect()
{
var tSend={};
@@ -549,7 +36,6 @@ function CancelSelect()
SendWXMessage( JSON.stringify(tSend) );
}
function ConfirmSelect()
{
let bRet=ResponseFilamentResult();
@@ -566,7 +52,6 @@ function ConfirmSelect()
}
}
function OnSelectMenu( nIndex )
{
switch(nIndex)
@@ -633,7 +118,6 @@ function UpdateCustomFilaments( CFList )
$('#CFilament_List').html(strHtml);
}
function OnClickCustomFilamentAdd()
{
//alert('Create New Custom Filament');
@@ -657,5 +141,3 @@ function CFEdit( fid )
SendWXMessage( JSON.stringify(tSend) );
}

View File

@@ -6,6 +6,7 @@
<title>引导_P21</title>
<link rel="stylesheet" type="text/css" href="../../include/global.css" /> <!-- ORCA One for all-->
<link rel="stylesheet" type="text/css" href="../css/common.css" />
<link rel="stylesheet" type="text/css" href="../22/common.css" /> <!-- ORCA use common sources for setup guide and standalone dialog -->
<link rel="stylesheet" type="text/css" href="23.css" />
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
<script type="text/javascript" src="../js/jquery-3.6.0.min.js"></script>
@@ -13,6 +14,7 @@
<script type="text/javascript" src="../../data/text.js"></script>
<script type="text/javascript" src="../js/globalapi.js"></script>
<script type="text/javascript" src="../js/common.js"></script>
<script type="text/javascript" src="../22/common.js"></script> <!-- ORCA use common sources for setup guide and standalone dialog -->
<script type="text/javascript" src="./23.js"></script>
</head>
<body onLoad="OnInit()">
@@ -150,97 +152,6 @@
}
}, { passive: false });
function addClearBtnEvents(el){
el.addEventListener('click', e => {
if (el.getAttribute("onclear") == "1") {
el.value = '';
el.dispatchEvent(new Event('input', {bubbles: true}));
}
});
el.addEventListener('mousemove', e => {
const rc = el.getBoundingClientRect();
const onRight = el.value && (e.clientX - rc.left > rc.width - 32);
el.setAttribute("onclear", onRight ? "1" : "0");
});
el.addEventListener('mouseleave', e => {
el.setAttribute("onclear", "0");
});
}
document.querySelectorAll('.cbr-search-bar').forEach(searchBar => {
searchBar.addEventListener('input', function() {
const search = this.value.trim().toLowerCase(),
list = this.closest('.cbr-column').querySelector('.cbr-content'),
items = list.querySelectorAll('label');
let hidden = 0;
items.forEach((item, i) => {
if(i == 0){
item.style.display ="block";
return;
};
const text = item.querySelector("span").textContent.toLowerCase();
const hide = search && !text.includes(search);
item.style.display = hide ? "none" : "block";
if(hide) hidden++;
});
if(items.length - hidden == 1){
items[0].style.display = "none";
hidden++;
}
list.querySelector('.cbr-no-items').style.display = (hidden === items.length) ? "block" : "none";
});
addClearBtnEvents(searchBar);
});
const filterBar = document.querySelector('.cbr-filter-bar');
const filterModeFilter = document.querySelector('.cbr-filter-mode-filter' );
const filterModeVisible = document.querySelector('.cbr-filter-mode-visible');
filterBar.addEventListener('input', function() {
const search = this.value.trim().toLowerCase();
const list = this.closest('.cbr-column').querySelector('.cbr-content');
const items = list.querySelectorAll('label');
let hidden = 0;
filterModeFilter.style.display = search ? "block" : "none";
filterModeVisible.style.display = search ? "none" : "block";
const showSel = search == "::checked";
const showUnsel = search == "::unchecked";
if(showSel || showUnsel){
items.forEach(item => {
const cb = item.querySelector("input");
const hide = showSel ? !cb.checked : cb.checked;
item.style.position = hide ? "absolute" : "unset";
if(hide) hidden++;
});
}
else {
items.forEach(item => {
const text = item.querySelector("span").textContent.toLowerCase();
const hide = search && !text.includes(search);
item.style.position = hide ? "absolute" : "unset";
if(hide) hidden++;
});
}
list.querySelector('.cbr-no-items').style.display = (hidden === items.length) ? "block" : "none";
UpdateStats();
});
addClearBtnEvents(filterBar);
document.querySelector('#filter-tags').addEventListener('change', e => {
let v = e.target.value;
filterBar.value = v == "1" ? "::checked" : "::unchecked";
filterBar.dispatchEvent(new Event('input', {bubbles: true}));
filterBar.focus();
e.target.value = 0; // reset back to make dropdown items always selectable
});
initInputEvents();
</script>
</html>

View File

@@ -1,473 +1,5 @@
#Content
{
overflow-y:auto;
padding: 0 10px 0 20px; /* ORCA Specify & Reduce horizontal paddings to fit 4 items per row */
height: 100%;
}
.OneVendorBlock {
position: relative;
margin-bottom: 7px;
}
.OneVendorBlock:last-of-type {
margin-bottom: 36px;
}
.BlockBanner
{
position: sticky;
top: 0;
left: 0;
padding: 0px;
border-bottom: 2px solid var(--main-color);
width: 100%;
display: flex;
align-items: center;
z-index: 100;
background-color: var(--bg-color-secondary);
box-sizing: border-box;
}
.BannerBtns
{
display: flex;
white-space: nowrap;
justify-content: space-around;
align-items: center;
text-align: center;
margin-right: 5px; /* ORCA align buttons with end of horizontal separator/line */
margin-left: auto;
}
.BlockBanner a
{
line-height: 30px;
height: 30px;
font-size: 17px;
font-weight: 600;
padding: 0px 10px;
color: var(--fg-color-text);
}
.BlockBanner .modelCount {
margin: 0 15px 0 auto;
font-size: 14px;
line-height: 14px;
height: 15px;
color: var(--fg-color-label);
}
.VendorCheckbox {
transform: scale(1.3);
}
.PrinterArea
{
padding: 7px 0px; /* ORCA Reduce horizontal paddings to fit 4 items per row */
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 7px;
}
.PrinterBlock
{
display: flex;
align-items: center;
text-align: center;
flex-direction: column;
gap:10px;
padding: 15px 10px 10px 10px;
background-color: var(--bg-color-secondary);
position: relative;
border: 1px solid transparent
}
.PrinterBlock:hover {
background-color: var(--focus-bg-item);
border-color:var(--main-color);
}
.PImg {
width:120px; /* ORCA use covers as 120x120px but use source file as 240x240 for better quality on hidpi */
height:120px; /* ORCA fit image to fill frame */
}
.PrinterInfo,
.PrinterInfoMark {
position: absolute;
right: 4px;
top: 4px;
opacity: 0;
border-radius: 11px;
line-height: 19px;
font-size: 14px;
}
.PrinterInfo {
--card-animation-delay: .8s; /* open info with delay on list / compact view to prevent them appear while mouse movements */
--card-info-height: fit-content;
left: 4px;
width: auto;
z-index: 9998;
height: var(--card-info-height);
border-color: var(--border-color);
background: var(--bg-color);
padding: 10px;
text-align: left;
color: var(--fg-color-text);
pointer-events: none;
}
#Content[layout="2"] .PrinterInfo {
--card-animation-delay: .3s;
--card-info-height: 116px;
}
.PrinterInfo .title {font-weight: 700}
.PrinterInfo .value {font-weight: 400}
.PrinterInfoMark:hover + .PrinterInfo {
animation: infoCard 0s forwards var(--card-animation-delay);
}
@keyframes infoCard {100% {
opacity: 1;
box-shadow: 0 5px 10px rgba(0,0,0,.2);
}}
.PrinterInfoMark {
width: 20px;
height: 20px;
background: var(--main-color);
border: 1px solid var(--main-color);
z-index: 9999;
color: #FFF;
text-align: center;
}
.PrinterBlock:hover .PrinterInfoMark {
opacity: 1;
}
.PrinterBlock:hover .PrinterInfoMark:hover {
background: var(--main-color-hover);
}
.ModelCheckBox
{
position: absolute;
height: 6px;
bottom: 0;
left: 10%;
width: 80%;
background: var(--button-bg-hover)
}
.ModelCheckBox.ModelCheckBoxSelected
{
background: var(--main-color-fixed)
}
img.ModelThumbnail
{
width: 100%;
height: 100%;
}
.PName
{
font-weight: 600;
line-height: 20px; /* ORCA */
text-align: center;
width: 100%;
color: var(--fg-color-text);
}
.pNozzel
{
display: none;
align-items: center;
justify-content:flex-start;
color: #5A5A5A;
padding-left: 0px; /* ORCA Align checkboxes with with model text */
}
.pNozzel input
{
vertical-align: middle;
margin-right: 5px;
}
.LayoutSelector {
position: absolute;
right:21px;
top:14px;
}
.LayoutSelector .TabGroup {
display: flex;
padding: 2px;
gap: 2px;
border-radius: 6px;
background-color: var(--bg-color-alt);
}
.LayoutSelector .icon16 {
opacity: .8;
}
.LayoutSelector .TabButton {
padding: 7px;
border-radius: 4px;
}
.LayoutSelector .TabButton.selected {background: var(--main-color)}
.LayoutSelector .TabButton.selected:hover {background: var(--main-color-hover)}
.LayoutSelector .TabButton.selected .icon16 {background: #FFF}
.LayoutSelector .TabButton:nth-of-type(1) .icon16 {--icon-url: var(--icon-layout-list)}
.LayoutSelector .TabButton:nth-of-type(2) .icon16 {--icon-url: var(--icon-layout-compact)}
.LayoutSelector .TabButton:nth-of-type(3) .icon16 {--icon-url: var(--icon-layout-cover)}
/* UNIQUE STYLES */
#CreateBtn {
margin: 0 auto 0 0;
}
/* LAYOUT */
#Content[layout="compact-list"] .PrinterArea {
grid-template-columns: repeat(4, 1fr);
}
#Content[layout="compact-list"] .PImg {
display: none;
}
#Content[layout="compact-list"] .OneVendorBlock {
margin-bottom: 15px;
}
#Content[layout="compact-cover"] .PrinterArea {
grid-template-columns: repeat(3, 1fr);
}
#Content[layout="compact-cover"] .PImg {
width: 60px;
min-width: 60px;
height: 60px;
}
#Content[layout|="compact"] .PName {
text-align: left;
}
#Content[layout|="compact"] .PrinterBlock {
flex-direction: row;
padding: 5px 5px 5px 18px;
}
#Content[layout|="compact"] .ModelCheckBox {
width: 6px;
height: 80%;
left:0;
top:10%
}
#Content[layout|="compact"] .OneVendorBlock:last-of-type {
margin-bottom: 0px;
}
/*-----Notice-----*/
#NoticeMask
{
background-color: #000;
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
opacity: 0.05;
display: none;
}
#NoticeBody
{
display: none;
width: 400px;
border-width: 1px;
border-style: solid;
border-radius: 4px;
background-color: inherit;
position: absolute;
left: 50%;
top: 200px;
margin-left: -200px;
}
#NoticeBar
{
background-color:#00f0d8;
height: 40px;
line-height: 40px;
color: #fff;
text-align: center;
}
#NoticeContent
{
padding: 4mm 10mm;
}
#NoticeBtns
{
margin-top: 4mm;
display: flex;
justify-content:flex-end;
}
.search {
position: absolute;
left:66px;
top: 14px;
width: 34px;
height: 34px;
z-index: 99;
overflow: hidden;
}
.search:focus-within,
.search[hasvalue="1"] {
width: calc(100% - 194px);
}
.searchTerm {
width: 100%;
height: 100%;
padding: 4px 5px;
border-radius: 6px;
outline: none;
box-sizing: border-box;
background: var(--button-bg-normal);
border: 1px solid var(--button-bg-normal);
}
@media (prefers-reduced-motion: no-preference) {
.searchTerm {
transition: background-color .2s
}
}
.searchTerm,
.search-placeholder {
line-height: 24px; /* ORCA center text vertically */
font-size: 14px;
}
.search:focus-within .searchTerm,
.search[hasvalue="1"] .searchTerm {
padding-left:33px;
background: var(--bg-color);
border-color: var(--main-color);
}
.search[hasvalue="1"]:not(:focus-within, :hover) .searchTerm {
border-color: var(--border-color);
}
.search:not(:focus-within, [hasvalue="1"]) .searchTerm {
cursor: default;
}
.search:not(:focus-within, [hasvalue="1"]) .searchTerm:hover {
background: var(--button-bg-hover);
}
.search-placeholder {
color: var(--fg-color-disabled);
left: 33px;
}
.searchTerm:not(:placeholder-shown) + .search-placeholder {
opacity: 0;
}
.search-icon,
.search-placeholder {
position: absolute;
top: 50%;
transform: translateY(-50%);
pointer-events: none;
}
.search-icon {
left: 9px;
--icon-url: var(--icon-search);
}
.SidebarBtn {
position: absolute;
left: 20px;
top: 14px;
padding: 9px;
border-radius: 6px;
}
.SidebarBtn .icon16 {
--icon-url: var(--icon-sidebar);
}
#SidebarContainer {
position: absolute;
top: 0;
left: -240px;
right: 0;
height: 100%;
z-index: 999999;
display: flex;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
#SidebarContainer {
transition: background-color .2s, left .2s
}
}
#SidebarContainer[open="1"] {
left: 0px;
pointer-events: all;
background: rgba(0,0,0,.3);
}
#Sidebar {
flex: 0 0 220px;
background: var(--bg-color);
box-shadow: 5px 0 20px rgba(0,0,0,.2);
padding: 15px 0;
overflow-y: auto;
}
#Sidebar .title {
font-size: 17px;
line-height: 17px;
font-weight: 600;
padding: 0 0 5px 20px;
}
#Sidebar .SidebarItem {
width: 100%;
padding: 2px 10px 2px 20px;
color:var(--fg-color-text);
font-size: 14px;
border: 1px solid transparent;
box-sizing: border-box;
}
#Sidebar .SidebarItem:hover {
border-color: var(--main-color);
}
#SidebarContainer .back {
flex: 1;
}

View File

@@ -1,485 +1,15 @@
// UNIQUE FUNCTIONS
// Keep in here for future additions
function OnInit()
{
//let strInput=JSON.stringify(cData);
//HandleModelList(cData);
TranslatePage();
RequestProfile();
}
function RequestProfile()
{
var tSend={};
tSend['sequence_id']=Math.round(new Date() / 1000);
tSend['command']="request_userguide_profile";
SendWXMessage( JSON.stringify(tSend) );
}
function HandleStudio( pVal )
{
// alert(strInput);
// alert(JSON.stringify(strInput));
//
// let pVal=IsJson(strInput);
// if(pVal==null)
// {
// alert("Msg Format Error is not Json");
// return;
// }
let strCmd=pVal['command'];
//alert(strCmd);
if(strCmd=='response_userguide_profile')
{
HandleModelList(pVal['response']);
}
}
function ShowPrinterThumb(pItem, strImg)
{
$(pItem).attr('src',strImg);
$(pItem).attr('onerror',null);
}
function ChooseModel( vendor, ModelName )
{
let ChooseItem=$(".ModelCheckBox[vendor='"+vendor+"'][model='"+ModelName+"']");
if(ChooseItem!=null)
{
if( $(ChooseItem).hasClass('ModelCheckBoxSelected') )
$(ChooseItem).removeClass('ModelCheckBoxSelected');
else
$(ChooseItem).addClass('ModelCheckBoxSelected');
SetModelSelect(vendor, ModelName, $(ChooseItem).hasClass('ModelCheckBoxSelected'));
}
}
function HandleModelList( pVal )
{
if( !pVal.hasOwnProperty("model") )
return;
pModel=pVal['model'];
// ORCA ensure list correctly ordered
pModel = pModel.sort((a, b)=>(a["vendor"].localeCompare(b["vendor"])))
pModel = [ // move custom printers to top
...pModel.filter(i=>i.vendor === "Custom"),
...pModel.filter(i=>i.vendor !== "Custom")
];
let nTotal=pModel.length;
let ModelHtml={};
for(let n=0;n<nTotal;n++)
{
let OneModel=pModel[n];
let strVendor=OneModel['vendor'];
//Add Vendor Html Node
if($(".OneVendorBlock[vendor='"+strVendor+"']").length==0)
{
let sVV=strVendor;
if( sVV=="BBL" )
sVV="Bambu Lab";
if( sVV=="Custom")
sVV="Custom Printer";
if( sVV=="Other")
sVV="Orca colosseum";
let HtmlNewVendor='<div class="OneVendorBlock" Vendor="'+strVendor+'">'+
'<div class="BlockBanner">'+
' <a>'+sVV+'</a>'+
' <div class="BannerBtns" onClick="ChooseVendor('+"\'"+strVendor+"\'"+')">'+
' <div class="modelCount"></div>' +
' <input type="checkbox" class="VendorCheckbox"/>'+
' </div>'+
//' <div class="BannerBtns">'+
//' <div class="ButtonStyleConfirm ButtonTypeWindow trans" tid="t11" onClick="SelectPrinterAll('+"\'"+strVendor+"\'"+')">all</div>'+
//' <div class="ButtonStyleRegular ButtonTypeWindow trans" tid="t12" onClick="SelectPrinterNone('+"\'"+strVendor+"\'"+')">none</div>'+
//' </div>'+
'</div>'+
'<div class="PrinterArea"> '+
'</div>'+
'</div>';
$('#Content').append(HtmlNewVendor);
}
let ModelName=OneModel['model'];
//Collect Html Node Nozzel Html
if( !ModelHtml.hasOwnProperty(strVendor))
ModelHtml[strVendor]='';
ModelHtml[strVendor]+=CreatePrinterBlock(OneModel); // ORCA
}
//Update Nozzel Html Append
for( let key in ModelHtml )
{
$(".OneVendorBlock[vendor='"+key+"'] .PrinterArea").append( ModelHtml[key] );
}
//Update Checkbox
for(let m=0;m<nTotal;m++)
{
let OneModel=pModel[m];
let SelectList=OneModel['nozzle_selected'];
if(SelectList!='')
{
ChooseModel(OneModel['vendor'], OneModel['model']);
}
}
const $SidebarVendors = $('#SidebarVendors');
let SidebarHTML = "";
$(`.OneVendorBlock`).each((i, el)=>{
UpdateVendorCheckbox(el.getAttribute("vendor"));
SidebarHTML +=`<div class="SidebarItem" onclick="scrollToVendor(this.textContent)">${el.getAttribute('vendor')}</div>`;
});
$SidebarVendors.html(SidebarHTML)
// let AlreadySelect=$(".ModelCheckBoxSelected");
// let nSelect=AlreadySelect.length;
// if(nSelect==0)
// {
// $("div.OneVendorBlock[vendor='"+BBL+"'] .ModelCheckBox").addClass('ModelCheckBoxSelected');
// }
TranslatePage();
}
function scrollToVendor(vendor) {
const el = $(".OneVendorBlock[vendor='"+vendor+"']")[0];
if (el){
document.getElementById('SidebarContainer').setAttribute('open', '0');
document.getElementById('Content').scrollTo({top: el.offsetTop, behavior: "smooth"});
}
}
function SetModelSelect(vendor, model, checked) {
if (!ModelNozzleSelected.hasOwnProperty(vendor) && !checked) {
return;
}
if (!ModelNozzleSelected.hasOwnProperty(vendor) && checked) {
ModelNozzleSelected[vendor] = {};
}
let oVendor = ModelNozzleSelected[vendor];
if (oVendor.hasOwnProperty(model) || checked) {
oVendor[model] = checked;
}
UpdateVendorCheckbox(vendor)
}
function GetModelSelect(vendor, model) {
if (!ModelNozzleSelected.hasOwnProperty(vendor)) {
return false;
}
let oVendor = ModelNozzleSelected[vendor];
if (!oVendor.hasOwnProperty(model)) {
return false;
}
return oVendor[model];
}
function FilterModelList(keyword) {
//Save checkbox state
let ModelSelect = $('.ModelCheckBox');
for (let n = 0; n < ModelSelect.length; n++) {
let OneItem = ModelSelect[n];
let strModel = OneItem.getAttribute("model");
let strVendor = OneItem.getAttribute("vendor");
SetModelSelect(strVendor, strModel, $(OneItem).hasClass('ModelCheckBoxSelected'));
}
$('.search')[0].setAttribute("hasvalue", keyword ? "1" : "0")
let nTotal = pModel.length;
let ModelHtml = {};
let kwSplit = keyword.toLowerCase().match(/\S+/g) || [];
$('#Content').empty();
for (let n = 0; n < nTotal; n++) {
let OneModel = pModel[n];
let strVendor = OneModel['vendor'];
let search = (OneModel['name'] + '\0' + strVendor).toLowerCase();
if (!kwSplit.every(s => search.includes(s)))
continue;
//Add Vendor Html Node
if ($(".OneVendorBlock[vendor='" + strVendor + "']").length == 0) {
let sVV = strVendor;
if (sVV == "BBL")
sVV = "Bambu Lab";
if (sVV == "Custom")
sVV = "Custom Printer";
if (sVV == "Other")
sVV = "Orca colosseum";
let HtmlNewVendor = '<div class="OneVendorBlock" Vendor="' + strVendor + '">' +
'<div class="BlockBanner">' +
' <a>' + sVV + '</a>' +
' <div class="BannerBtns" onClick="ChooseVendor('+"\'"+strVendor+"\'"+')">'+
' <div class="modelCount"></div>' +
' <input type="checkbox" class="VendorCheckbox"/>'+
' </div>'+
//' <div class="BannerBtns">' +
//' <div class="ButtonStyleConfirm ButtonTypeWindow trans" tid="t11" onClick="SelectPrinterAll(' + "\'" + strVendor + "\'" + ')">all</div>' +
//' <div class="ButtonStyleRegular ButtonTypeWindow trans" tid="t12" onClick="SelectPrinterNone(' + "\'" + strVendor + "\'" + ')">none</div>' +
//' </div>' +
'</div>' +
'<div class="PrinterArea"> ' +
'</div>' +
'</div>';
$('#Content').append(HtmlNewVendor);
}
//Collect Html Node Nozzel Html
if (!ModelHtml.hasOwnProperty(strVendor))
ModelHtml[strVendor] = '';
ModelHtml[strVendor]+=CreatePrinterBlock(OneModel); // ORCA
}
//Update Nozzel Html Append
for (let key in ModelHtml) {
let obj = $(".OneVendorBlock[vendor='" + key + "'] .PrinterArea");
obj.empty();
obj.append(ModelHtml[key]);
}
//Update Checkbox
ModelSelect = $('.ModelCheckBox');
for (let n = 0; n < ModelSelect.length; n++) {
let OneItem = ModelSelect[n];
let strModel = OneItem.getAttribute("model");
let strVendor = OneItem.getAttribute("vendor");
let checked = GetModelSelect(strVendor, strModel);
if (checked)
$(OneItem).addClass('ModelCheckBoxSelected');
else
$(OneItem).removeClass('ModelCheckBoxSelected');
}
const $SidebarVendors = $('#SidebarVendors');
let SidebarHTML = "";
$(`.OneVendorBlock`).each((i, el)=>{
UpdateVendorCheckbox(el.getAttribute("vendor"));
SidebarHTML +=`<div class="SidebarItem" onclick="scrollToVendor(this.textContent)">${el.getAttribute('vendor')}</div>`;
});
$SidebarVendors.html(SidebarHTML)
const $content = $('#Content');
$content.css("padding-right", $content[0].scrollHeight > $content[0].clientHeight ? "10px" : "20px");
// let AlreadySelect=$(".ModelCheckBoxSelected");
// let nSelect=AlreadySelect.length;
// if(nSelect==0)
// {
// $("div.OneVendorBlock[vendor='"+BBL+"'] .ModelCheckBox").addClass('ModelCheckBoxSelected');
// }
TranslatePage();
}
function CreatePrinterBlock(OneModel)
{
// ORCA use single functuon to create blocks to simplify code
let vendor = OneModel['vendor']
vendorName = vendor=="BBL" ? "Bambu Lab" : vendor=="Custom" ? "Generic Printer" : vendor;
let modelName = OneModel['name'];
// Most of it unneeded. this can be applied in profiles
if( vendor=="Custom")
modelName = modelName.split(" ")[1];
// these uses different case in name; seckit, ratrig, blocks
else if (modelName.toLowerCase().startsWith(vendorName.toLowerCase()))
modelName = modelName.slice(vendorName.length);
// these not matches. have to fix in profiles to reduce conditions in here;
else if (vendor == "MagicMaker" && modelName.startsWith("MM"))
modelName = modelName.slice(("MM").length);
else if (vendor == "OrcaArena")
modelName = modelName.slice(("Orca Arena").length);
else if (vendor == "RolohaunDesign" && modelName.startsWith("Rolohaun"))
modelName = modelName.slice(("Rolohaun").length);
return '<div class="PrinterBlock" onClick="ChooseModel(\''+vendor+'\',\''+OneModel['model']+'\')">'+
'<div class="PImg">'+
'<img class="ModelThumbnail" src="' + OneModel['cover'] + '" />'+
'</div>'+
'<div class="PrinterInfoMark">?</div>'+
'<div class="PrinterInfo">'+
//' <div class="title trans">Print volume</div>'+
//' <div class="value">' + OneModel['printable_height'] + '</div>'+
' <div class="title trans">Nozzle</div>'+
' <div class="value">' + OneModel['nozzle_diameter'].replaceAll(";", " · ") + '</div>'+
'</div>'+
'<div style="display: flex;">'+
' <div class="ModelCheckBox" vendor="' +vendor+ '" model="'+OneModel['model']+'"></div>'+
' <div class="PName">'+ modelName +'</div>'+ // ><p>'+ vendorName +'</p>
'</div>'+
'</div>';
}
function SelectPrinterAll( sVendor )
{
$("div.OneVendorBlock[vendor='"+sVendor+"'] .ModelCheckBox").addClass('ModelCheckBoxSelected');
$("div.OneVendorBlock[vendor='"+sVendor+"'] .ModelCheckBox").each(function() {
let strModel = this.getAttribute("model");
SetModelSelect(sVendor, strModel, true);
});
}
function SelectPrinterNone( sVendor )
{
$("div.OneVendorBlock[vendor='"+sVendor+"'] .ModelCheckBox").removeClass('ModelCheckBoxSelected');
$("div.OneVendorBlock[vendor='"+sVendor+"'] .ModelCheckBox").each(function() {
let strModel = this.getAttribute("model");
SetModelSelect(sVendor, strModel, false);
});
}
function ChooseVendor(sVendor) {
const $cbs = $(`.OneVendorBlock[vendor='${sVendor}'] .ModelCheckBox`);
const sel = $cbs.length && $cbs.not('.ModelCheckBoxSelected').length;
sel ? $cbs.addClass('ModelCheckBoxSelected')
: $cbs.removeClass('ModelCheckBoxSelected');
$cbs.each((i, el)=>{SetModelSelect(sVendor, el.getAttribute('model'), sel)});
}
function UpdateVendorCheckbox(sVendor) {
const $vb = $(`.OneVendorBlock[vendor='${sVendor}']`);
const $cbs = $vb.find(`.ModelCheckBox`);
const $vcb = $vb.find(`.VendorCheckbox`);
const selCount = $cbs.filter('.ModelCheckBoxSelected').length;
const allSel = selCount === $cbs.length && selCount > 0;
const nonSel = selCount === 0;
$vcb.prop({checked: allSel , indeterminate: !allSel && !nonSel});
$vb.find(".modelCount").text(selCount + " / " + $cbs.length);
}
function OnExitFilter() {
let nTotal = 0;
let ModelAll = {};
for (vendor in ModelNozzleSelected) {
for (model in ModelNozzleSelected[vendor]) {
if (!ModelNozzleSelected[vendor][model])
continue;
if (!ModelAll.hasOwnProperty(model)) {
//alert("ADD: "+strModel);
ModelAll[model] = {};
ModelAll[model]["model"] = model;
}
nTotal++;
}
}
var tSend = {};
tSend['sequence_id'] = Math.round(new Date() / 1000);
tSend['command'] = "save_userguide_models";
tSend['data'] = ModelAll;
SendWXMessage(JSON.stringify(tSend));
return nTotal;
}
//
function OnExit()
{
let ModelAll={};
let ModelSelect=$(".ModelCheckBoxSelected");
let nTotal=ModelSelect.length;
if( nTotal==0 )
{
ShowNotice(1);
return 0;
}
for(let n=0;n<nTotal;n++)
{
let OneItem=ModelSelect[n];
let strModel=OneItem.getAttribute("model");
//alert(strModel+strVendor+strNozzel);
if(!ModelAll.hasOwnProperty(strModel))
{
//alert("ADD: "+strModel);
ModelAll[strModel]={};
ModelAll[strModel]["model"]=strModel;
}
}
var tSend={};
tSend['sequence_id']=Math.round(new Date() / 1000);
tSend['command']="save_userguide_models";
tSend['data']=ModelAll;
SendWXMessage( JSON.stringify(tSend) );
return nTotal;
}
function ShowNotice( nShow )
{
if(nShow==0)
{
$("#NoticeMask").hide();
$("#NoticeBody").hide();
}
else
{
$("#NoticeMask").show();
$("#NoticeBody").show();
}
}
function CancelSelect()
{
var tSend={};
@@ -490,7 +20,6 @@ function CancelSelect()
SendWXMessage( JSON.stringify(tSend) );
}
function ConfirmSelect()
{
let nChoose=OnExitFilter();
@@ -516,7 +45,3 @@ function CreateNewPrinter()
SendWXMessage( JSON.stringify(tSend) );
}

View File

@@ -6,6 +6,7 @@
<title>引导_P21</title>
<link rel="stylesheet" type="text/css" href="../../include/global.css" /> <!-- ORCA One for all-->
<link rel="stylesheet" type="text/css" href="../css/common.css" />
<link rel="stylesheet" type="text/css" href="../21/common.css" /> <!-- ORCA use common sources for setup guide and standalone dialog -->
<link rel="stylesheet" type="text/css" href="24.css" />
<link rel="stylesheet" type="text/css" href="../css/dark.css" />
<!-- <script type="text/javascript" src="test.js"></script> -->
@@ -13,8 +14,9 @@
<script type="text/javascript" src="../js/json2.js"></script>
<script type="text/javascript" src="../../data/text.js"></script>
<script type="text/javascript" src="../js/globalapi.js"></script>
<!-- <script type="text/javascript" src="../js/common.js"></script> -->
<script type="text/javascript" src="24.js"></script>
<script type="text/javascript" src="../js/common.js"></script>
<script type="text/javascript" src="../21/common.js"></script> <!-- ORCA use common sources for setup guide and standalone dialog -->
<script type="text/javascript" src="24.js"></script>
</head>
<body onLoad="OnInit()">
<div id="Title">
@@ -49,65 +51,33 @@
<div id="Content" class="thin-scroll">
<!--<div class="OneVendorBlock" Vendor="BBL">
<div class="BlockBanner">
<div class="BannerBtns">
<div class="ButtonStyleConfirm ButtonTypeWindow" onClick="SelectPrinterAll('BBL')">所有</div>
<div class="ButtonStyleRegular ButtonTypeWindow" onClick="SelectPrinterNone('BBL')">无</div>
<!-- EXAMPLE GENERATED CODE BLOCK
<div class="OneVendorBlock" Vendor="VendorName">
<div class="BlockBanner">
<a>VendorName</a>
<div class="BannerBtns" onClick="ChooseVendor('VendorName')" >
<div class="modelCount"></div>
<input type="checkbox" class="VendorCheckbox" />
</div>
</div>
<a>BBL-3DP</a>
</div>
<div class="PrinterArea">
<div class="PrinterBlock">
<div class="PImg"><img src="p2.jpg" /></div>
<div class="PName">BBL-3DP-V4NORMAL</div>
<div class="pNozzel"><input id="ZZ" type="checkbox" model="BBL-3DP-V4NORMAL" nozzel="0.4" vendor="BBL" />0.4mm nozzle</div>
<div class="pNozzel"><input type="checkbox" model="BBL-3DP-V4NORMAL" nozzel="0.1" vendor="BBL" />0.1mm nozzle</div>
</div>
<div class="PrinterBlock">
<div class="PImg"><img src="p1.jpg" /></div>
<div class="PName">BBL-3DP-V4NORMAL</div>
<div class="pNozzel"><input type="checkbox" model="BBL-3DP-V5NORMAL" nozzel="0.4" vendor="BBL" />0.4mm nozzle</div>
<div class="pNozzel"><input type="checkbox" model="BBL-3DP-V5NORMAL" nozzel="0.2" vendor="BBL" />0.2mm nozzle</div>
<div class="pNozzel"><input type="checkbox" model="BBL-3DP-V5NORMAL" nozzel="0.1" vendor="BBL" />0.1mm nozzle</div>
</div>
</div>
</div>
<div class="OneVendorBlock" Vendor="BAMBU">
<div class="BlockBanner">
<div class="BannerBtns">
<div class="Banner-Btn-green" onClick="SelectPrinterAll('BAMBU')">所有</div>
<div class="Banner-Btn" onClick="SelectPrinterNone('BAMBU')">无</div>
<div class="PrinterArea">
<div class="PrinterBlock" onClick="ChooseModel('VendorName','ModelName')" >
<div class="PImg" >
<img class="ModelThumbnail" src="CoverPath" />
</div>
<div class="PrinterInfoMark">?</div>
<div class="PrinterInfo">
<div class="title trans">Nozzle</div>
<div class="value">nozzleInfo</div>
</div>
<div style="display: flex;">
<div class="ModelCheckBox" vendor="' +vendor+ '" model="'+OneModel['model']+'"></div>
<div class="PName">modelName</div>
</div>
</div>
</div>
<a>BBL-3DP</a>
</div>
<div class="PrinterArea">
<div class="PrinterBlock">
<div class="PImg"><img src="p2.jpg" /></div>
<div class="PName">BBL-3DP-V4NORMAL</div>
<div class="pNozzel"><input type="checkbox" model="BBL-3DP-V4NORMAL" nozzel="0.4" vendor="BAMBU" />0.4mm nozzle</div>
<div class="pNozzel"><input type="checkbox" model="BBL-3DP-V4NORMAL" nozzel="0.1" vendor="BAMBU" />0.1mm nozzle</div>
</div>
<div class="PrinterBlock">
<div class="PImg"><img src="p1.jpg" /></div>
<div class="PName">BBL-3DP-V4NORMAL</div>
<div class="pNozzel"><input type="checkbox" model="BBL-3DP-V5NORMAL" nozzel="0.4" vendor="BAMBU" />0.4mm nozzle</div>
<div class="pNozzel"><input type="checkbox" model="BBL-3DP-V5NORMAL" nozzel="0.2" vendor="BAMBU" />0.2mm nozzle</div>
<div class="pNozzel"><input type="checkbox" model="BBL-3DP-V5NORMAL" nozzel="0.1" vendor="BAMBU" />0.1mm nozzle</div>
</div>
</div>
</div>-->
-->
</div>
<div id="AcceptArea">
@@ -126,215 +96,10 @@
</div>
</div>
</div>
</body>
<script>
const SearchBox = document.querySelector('.searchTerm');
document.onkeydown = function (event) {
var e = event || window.event || arguments.callee.caller.arguments[0];
if (e.keyCode == 27)
ClosePage();
// ORCA focus search bar on key input
// SearchBox not in focus && writable character && non modifier
if (document.activeElement != SearchBox && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
SearchBox.focus();
}
// Close sidebar
document.getElementById('SidebarContainer').setAttribute('open', '0')
//if (window.event) {
// try { e.keyCode = 0; } catch (e) { }
// e.returnValue = true;
//}
};
let pModel = {};
let ModelNozzleSelected = {};
function textInput(obj) {
FilterModelList(obj.value);
}
const $content = $('#Content');
// SNAPPY SCROLLING WITHOUT LAGS
const SNAP_DELAY = 600;
const SNAP_DURATION = 200;
const SNAP_CORR = 8; // error correction / tolerance
let scrollTimer = null;
let lastScrollTop = 0;
let scrollDir = 'down';
let isSnapping = false;
let snapRafId = null;
let lastSnapTarget = null;
let waitingForUserScroll = false;
function findSnap(cur, dir) {
if (lastSnapTarget !== null && Math.abs(cur - lastSnapTarget) < SNAP_CORR) return null;
const savedScroll = cur;
$content[0].scrollTop = 0; // Temporarily scroll to 0 so getBoundingClientRect can get absolute positions
let bcTop = el=>(el.getBoundingClientRect().top);
const contentTop = bcTop($content[0]);
const bannerH = ($content.find('.BlockBanner')[0] || {}).offsetHeight || 0;
const firstCard = $content.find('.PrinterBlock')[0];
const firstArea = $content.find('.PrinterArea')[0];
const cardGap = (firstCard && firstArea) ? (bcTop(firstCard) - bcTop(firstArea)) : 0;
const candidates = $content.find('.BlockBanner, .PrinterBlock').get();
if (dir === 'up') candidates.reverse();
let result = lastSeen = null;
for (const el of candidates) {
const snapTo = Math.round(
el.classList.contains('BlockBanner')
? (bcTop(el.closest('.OneVendorBlock')) - contentTop)
: Math.max(0, bcTop(el) - contentTop - bannerH - cardGap)
);
if (snapTo != lastSeen){
lastSeen = snapTo;
if (dir === 'down' && snapTo > cur + SNAP_CORR) { result = snapTo; break; }
if (dir === 'up' && snapTo < cur - SNAP_CORR) { result = snapTo; break; }
}
}
$content[0].scrollTop = savedScroll; // Restore scroll position
return result;
}
function smoothScrollTo(target) {
if (snapRafId) {
cancelAnimationFrame(snapRafId);
snapRafId = null;
}
const el = $content[0];
const from = el.scrollTop;
const dist = target - from;
const t0 = performance.now();
const ease = t => t < 0.5 ? 2*t*t : -1 + (4 - 2*t)*t;
function onDone() {
el.scrollTop = target;
lastScrollTop = lastSnapTarget = target;
waitingForUserScroll = true;
clearTimeout(scrollTimer);
scrollTimer = null;
snapRafId = null;
isSnapping = false;
}
if (Math.abs(dist) < 2)
return onDone();
snapRafId = requestAnimationFrame(function step(now) {
const p = Math.min((now - t0) / SNAP_DURATION, 1);
el.scrollTop = from + dist * ease(p);
if (p < 1)
snapRafId = requestAnimationFrame(step);
else
onDone();
});
}
function armSnap() {
waitingForUserScroll = false;
lastSnapTarget = null;
}
$content.on('scroll', function() {
if (isSnapping) return;
if (this.scrollTop > lastScrollTop + 1) scrollDir = 'down';
else if (this.scrollTop < lastScrollTop - 1) scrollDir = 'up';
lastScrollTop = this.scrollTop;
if (waitingForUserScroll) return;
clearTimeout(scrollTimer);
scrollTimer = setTimeout(()=>{
if (isSnapping) return;
const target = findSnap($content[0].scrollTop, scrollDir);
if (target){
isSnapping = true;
smoothScrollTo(target);
}
}, SNAP_DELAY);
});
let touchY = 0;
$content[0].addEventListener('touchstart', e => {
touchY = e.touches[0].clientY;
armSnap();
}, { passive: true });
$content[0].addEventListener('touchmove', e => {
const dy = touchY - e.touches[0].clientY;
if (Math.abs(dy) > 3)
scrollDir = dy > 0 ? 'down' : 'up';
}, { passive: true });
// Re-arm snap system on user scroll
$content[0].addEventListener('wheel', armSnap, { passive: true });
// Re-arm on after scrollbar usage
$content[0].addEventListener('pointerdown', e => {
if (e.target === $content[0])
armSnap();
});
// Re-arm on keyboard scroll or focus changes
document.addEventListener('keydown', e => {
if (document.activeElement != SearchBox){
let scrollKeys = ['ArrowUp','ArrowDown','PageUp','PageDown',' '];
let hasFocus = $content[0].contains(document.activeElement);
if(scrollKeys.includes(e.key) || (hasFocus && e.which == 9))
armSnap();
}
});
// ORCA unfocus search bar while scrolling and its content empty
$content[0].addEventListener("scroll", () => {
if (document.activeElement === SearchBox && SearchBox.value == "")
SearchBox.blur();
});
// LAYOUT SELECTOR
const LayoutSelector = document.querySelector('.LayoutSelector > .TabGroup');
const LayoutBtns = Array.from(LayoutSelector.children);
const LayoutTypes = ["compact-list","compact-cover","large-cover"];
function LayoutMode(value) {
if($content[0].getAttribute("layout") === value)
return;
// find current visible vendor and scroll to it after layout change
let target = null;
for (const el of $content.find('.OneVendorBlock')) {
if (el.getBoundingClientRect().bottom - $content[0].getBoundingClientRect().top >= -1) {
target = el.getAttribute("vendor");
break;
}
}
LayoutBtns.forEach(el => el.classList.remove('selected'));
LayoutBtns[LayoutTypes.indexOf(value)].classList.add('selected');
$content[0].setAttribute("layout", value);
if (target) scrollToVendor(target);
}
LayoutMode("large-cover");
initKeyEvents(true); // close on ESC
InitGlobalVariables();
</script>
</html>

View File

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

View File

@@ -237,10 +237,6 @@ else ()
COMMAND ln -sf OrcaSlicer orca-slicer
WORKING_DIRECTORY "$<TARGET_FILE_DIR:OrcaSlicer>"
VERBATIM)
else ()
add_custom_command(TARGET OrcaSlicer POST_BUILD
WORKING_DIRECTORY "$<TARGET_FILE_DIR:OrcaSlicer>"
VERBATIM)
endif ()
if (XCODE)
# Because of Debug/Release/etc. configurations (similar to MSVC) the slic3r binary is located in an extra level

View File

@@ -1357,6 +1357,10 @@ int CLI::run(int argc, char **argv)
else {
set_logging_level(2);
}
const ConfigOptionString* opt_logfile = m_config.opt<ConfigOptionString>("logfile");
if (opt_logfile) {
set_logging_file(opt_logfile->value);
}
global_begin_time = (long long)Slic3r::Utils::get_current_time_utc();
BOOST_LOG_TRIVIAL(warning) << boost::format("cli mode, Current OrcaSlicer Version %1%")%SoftFever_VERSION;

Some files were not shown because too many files have changed in this diff Show More