Compare commits

..

11 Commits

Author SHA1 Message Date
Ian Bassi
daa75b3fa0 Revert "Forced pattern , separed to > 9 extruder"
This reverts commit 42b506ad85.
2026-06-10 08:27:02 -03:00
Ian Bassi
42b506ad85 Forced pattern , separed to > 9 extruder 2026-06-01 11:40:31 -03:00
Ian Bassi
84c7186674 Support extended triangle paint states up to 32
Extend TriangleSelector serialization to encode leaf facet paint states up to 32 by adding an escaped second nibble (12-bit path: wwwwzzzzxxyy). Implemented a push_nibble helper and an extended-prefix (0b1110) to signal the extra nibble. Updated deserialize, update_used_states and has_facets to decode the new format while preserving legacy behavior for 3..16. Adjusted asserts and state handling accordingly. Added a unit test and include for TriangleSelector to verify round-trip of paint states above 16.
2026-06-01 09:24:55 -03:00
Ian Bassi
9670da7ddd Increase selecting color shortcut 2026-06-01 09:24:54 -03:00
Ian Bassi
c858360ee6 Paint up to 32 2026-06-01 09:24:54 -03:00
Ian Bassi
1ecedd3187 Improve virtual color namings and added for parts 2026-06-01 09:24:54 -03:00
Ian Bassi
0346c4931a Allow mixed filament for Filament for features
Preserve mixed-physical filament handling and UI separation. Clamp filament indices in PresetBundle using total mixed filament count and treat support vs feature slots differently. Update ConfigManipulation to forbid mixed (virtual) IDs for support slots while allowing mixed IDs for feature slots, and reset out-of-range values. Refactor Plater DynamicFilamentList to support an include_mixed mode, improve labels/icons and ID mapping, and introduce separate dynamic_feature_filament_list and dynamic_support_filament_list instances (registered per choice). Add update_dynamic_filament_list() and use it when filaments change or sync occurs.
2026-06-01 09:24:54 -03:00
Ian Bassi
227bdb77da Preserve explicit feature filament overrides
Keep legacy "Filament for Features" behavior by treating an explicit sparse-infill filament choice as an override even when enable_infill_filament_override is not set. In ToolOrdering.cpp add explicit_sparse_override detection (sparse_infill_filament != wall_filament and both > 0) so base-infill logic respects explicit feature filament selection. In PrintObject.cpp stop clearing feature override flags when an extruder is set to "Default" (0), so parent-scope feature overrides are preserved instead of being reset. This avoids unintentionally removing feature filament overrides when a scope uses the default extruder.
2026-06-01 09:24:54 -03:00
SoftFever
2a8782b8f6 fix build errors 2026-06-01 09:24:54 -03:00
SoftFever
c0dfe50bc5 Update from FS at b3c41fda4.
Slicing
  - align merge_segmented_layers shape with FS apply_mm_segmentation
    (size = num_facets_states, loop from 0, no -1 shift); painted mixed
    regions were previously attributed to filament_id-1 of intent.
    apply_fuzzy_skin_segmentation reads channel 1;
    apply_mixed_surface_indentation uses segmentation_channel_filament_id
  - port apply_mixed_surface_indentation, apply_mixed_component_surface_offsets,
    apply_mixed_region_surface_offsets, apply_surface_emboss_mixed_region_override,
    plus surface_emboss_mixed_* debug subsystem
  - refactor apply_mm_segmentation (by-value MM, bias_mode, surface-type-
    preserving intersection, region normalization, post-MM dump); hoist MM
    segmentation into slice_volumes so mixed apply_* flow can mutate it
  - restore clear_local_z_plan() invalidation hooks
    (PrintObject.cpp:805/1264/1286)

  GCode
  - add LayerTools::preserve_extruder_order, honored by collect_extruders,
    both reorder_extruders overloads, and
    reorder_filaments_for_minimum_flush_volume; helpers
    append_unique_preserve_order / remove_duplicates_preserve_order
  - wire MixedFilamentManager::ordered_perimeter_extruders for grouped
    manual-pattern walls; set preserve_extruder_order when >= 2
  - mixed-aware support: layer_height set for support-only layers,
    ExtrusionRole-based has_support/has_interface with erMixed short-
    circuit, support_filament / support_interface_filament routed through
    resolve_mixed

  Print
  - materialize mixed_filament_pointillism_{pixel_size,line_gap} in
    PrintApply's option-tracking block so in-session edits diff correctly

  GUI
  - Tab::on_value_change: dithering_local_z_mode cascading clears, 17-key
    project_config sync, update_mixed_filament_panel(false) on
    mixed_filament_component_bias_enabled change
  - GUI_Factories: physical_filaments_count, ui_ordered_filament_ids,
    filament_menu_item_name; filaments_count includes enabled mixed
    virtuals; right-click 'Change filament' submenus iterate UI-ordered IDs

  Tests
  - sentinel asserting MultiMaterialSegmentation uses FS-aligned shape
    (39 -> 40)
2026-06-01 09:24:54 -03:00
SoftFever
0e0e34c8b4 init work to integrate OrcaSlicer-FullSpectrum fork Integrations up to commit b3c41fda41.
- libslic3r: vendor FilamentMixer; MixedFilamentManager (auto-gen, resolve,
    serialize; manual-pattern / gradient / pointillism); 19 new PrintConfig
    keys; PresetBundle owns the canonical manager with 3MF + AppConfig
    roundtrip and AMS-safe strip+restore; Print owns the slicing-time copy
    with PrintApply auto-regen on color change; TriangleSelector::
    shift_states_above + filament-id remap; inset_idx propagation through
    ExtrusionPath/Loop/MultiPath copy/assign.
  - Slicing: virtual filament IDs in painted regions (same-physical channels
    collapse when mixed_filament_region_collapse is on); ByObject
    collect_filament_data expands mixed slots; pair-cadence + whole-object +
    3+component Local-Z plan generators; LocalZOrderOptimizer utility.
  - GCode + ToolOrdering: LayerTools resolves virtual IDs through wall /
    infill / sparse / solid queries; SameLayerPointillisme in process_layer
    (uniform-segment + grouped per-perimeter-index splitters); WipeTower2
    Local-Z reservation + sub-layer G-code emission; per-layer infill
    filament override.
  - PartPlate: get_extruders* expand virtual slots into physical components;
    CLI path rebuilds a local manager from full_config.
  - GUI: five widget files extracted from FS Plater.cpp (~5000 LOC) —
    MixedMixPreview, MixedGradientSelector + WeightsDialog,
    MixedFilamentColorMapPanel, MixedFilamentColorMatchDialog (ΔE₀₀ recipe
    search), MixedFilamentConfigPanel; Sidebar Mixed Filaments panel
    (drag-reorder, enable/delete, Add Gradient/Pattern/Color); Tab exposure
    of mixed-filament / dithering / per-layer infill-override settings +
    ConfigManipulation visibility and slot-validation rules;
    BBLMixedFilamentBroken / BBLSingleExtruderMixedFilamentRisk
    notifications + slice gate; WipeTowerDialog edits physical P×P
    sub-matrix; bounds-safe extruder_id guards in 3DScene / GLCanvas3D /
    GLGizmoMmuSegmentation; change_filament merge guard and
    on_filaments_delete is_mixed_before_delete propagation.
  - Tests: 4 Catch2 tests for 3MF roundtrip (auto/custom persistence,
    PresetBundle string path, total_filaments stability); full-pipeline
    slice E2E deferred — TODO in file.

Co-authored-by: Rad <radugheorghiu96@gmail.com>
Co-authored-by: Justin Hayes <justinh@rahb.ca>
Co-authored-by: Calogero Guagenti <calogeroguagenti@gmail.com>
Co-authored-by: xSil3nt <ahmedshazin21@gmail.com>
Co-authored-by: ratdoux <62392831+ratdoux@users.noreply.github.com>

Update TriangleSelector.cpp

Co-Authored-By: Rad <radugheorghiu96@gmail.com>
Co-Authored-By: Justin Hayes <justinh@rahb.ca>
Co-Authored-By: Calogero Guagenti <calogeroguagenti@gmail.com>
Co-Authored-By: xSil3nt <ahmedshazin21@gmail.com>
Co-Authored-By: ratdoux <62392831+ratdoux@users.noreply.github.com>
2026-06-01 09:24:53 -03:00
199 changed files with 33395 additions and 18159 deletions

View File

@@ -211,12 +211,6 @@ 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,26 +50,6 @@ 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,7 +45,4 @@ test.js
.clangd
internal_docs/
*.flatpak
/flatpak-repo/
config.desc
tools/__pycache__/
src/slic3r/GUI/generated/
/flatpak-repo/

View File

@@ -721,6 +721,7 @@ 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
@@ -736,6 +737,7 @@ 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()
@@ -870,11 +872,6 @@ 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,10 +545,6 @@ 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,12 +180,6 @@ 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
@@ -210,7 +204,6 @@ 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,15 +126,6 @@ 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,15 +57,6 @@ 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

@@ -1,99 +0,0 @@
# 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()

171
doc/MixedFilament.md Normal file
View File

@@ -0,0 +1,171 @@
# 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

@@ -1,490 +0,0 @@
# 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,3 +250,7 @@ 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,19 +4,7 @@
# Icezaza, 2026.
#
msgid ""
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"
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"
msgid "right"
msgstr "ขวา"
@@ -9620,10 +9608,10 @@ msgid "Normal"
msgstr "ปกติ"
msgid "Resonance Compensation"
msgstr "การชดเชยการสั่นพ้อ"
msgstr "การชดเชยเสียงสะท้อ"
msgid "Resonance Avoidance Speed"
msgstr "ความเร็วการหลีกเลี่ยงการสั่นพ้อ"
msgstr "ความเร็วการหลีกเลี่ยงเสียงสะท้อ"
msgid "Frequency"
msgstr "ความถี่"
@@ -9770,7 +9758,7 @@ msgid "Continue"
msgstr "ดำเนินการต่อ"
msgid "Back"
msgstr "ลั"
msgstr "ย้อนกลั"
msgid "Don't warn again for this preset"
msgstr "ไม่ต้องเตือนอีกสำหรับค่าที่กำหนดล่วงหน้านี้"
@@ -9811,7 +9799,7 @@ msgid "Transfer"
msgstr "โอนย้าย"
msgid "Don't save"
msgstr "ไม่บันทึก"
msgstr "อย่าบันทึก"
msgid "Discard"
msgstr "ทิ้ง"
@@ -11864,10 +11852,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 "
@@ -11879,7 +11867,7 @@ msgid ""
msgstr "รีดเส้นรอบวงที่มีส่วนยื่นออกมาในทิศทางย้อนกลับบนชั้นคู่ รูปแบบการสลับนี้สามารถปรับปรุงระยะยื่นที่สูงชันได้อย่างมาก\n\nการตั้งค่านี้ยังช่วยลดการบิดงอของชิ้นส่วนเนื่องจากการลดความเค้นในผนังชิ้นส่วนอีกด้วย"
msgid "Reverse only internal perimeters"
msgstr "กลับด้านเฉพาะขอบเขตภายในเท่านั้น"
msgstr "ย้อนกลับเฉพาะขอบเขตภายในเท่านั้น"
msgid ""
"Apply the reverse perimeters logic only on internal perimeters.\n"
@@ -11914,7 +11902,7 @@ msgid "Sacrificial layer"
msgstr "ชั้นบูชายัญ"
msgid "Reverse threshold"
msgstr "เกณฑ์การกลับด้าน"
msgstr "เกณฑ์ย้อนกลับ"
msgid "Overhang reversal threshold"
msgstr "เกณฑ์การกลับรายการส่วนเกิน"
@@ -14407,25 +14395,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.02",
"version": "02.04.00.00",
"force_update": "0",
"description": "Elegoo configurations",
"machine_model_list": [
@@ -286,10 +286,6 @@
"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"
@@ -318,42 +314,6 @@
"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"
@@ -410,322 +370,6 @@
"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"
@@ -810,82 +454,6 @@
"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"
@@ -970,26 +538,6 @@
"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,258 +68,6 @@
"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

@@ -1,53 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,47 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,47 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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

@@ -1,14 +0,0 @@
{
"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 +1,470 @@
/* UNIQUE STYLES */
#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;
}

View File

@@ -1,15 +1,395 @@
// 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();
@@ -17,3 +397,97 @@ 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

@@ -1,441 +0,0 @@
#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

@@ -1,632 +0,0 @@
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,7 +6,6 @@
<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>
@@ -15,8 +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="../21/common.js"></script> <!-- ORCA use common sources for setup guide and standalone dialog -->
<script type="text/javascript" src="21.js"></script>
<script type="text/javascript" src="21.js"></script>
</head>
<body onLoad="OnInit()">
<div id="Title">
@@ -51,33 +49,93 @@
<div id="Content" class="thin-scroll">
<!-- 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 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>
</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">
@@ -95,10 +153,212 @@
</div>
</div>
</div>
</body>
<script>
initKeyEvents(false); // dont close on ESC
InitGlobalVariables();
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");
</script>
</html>

View File

@@ -1,7 +1,269 @@
#Content {
padding: 10px 15px 5px;
.ChooseBlock
{
display:flex;
line-height: 32px;
}
#GotoNetPluginBtn {
.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 {
display: none;
}

View File

@@ -1,8 +1,24 @@
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)
@@ -14,19 +30,537 @@ function HandleStudio(pVal)
{
m_ProfileItem=pVal['response'];
SortUI();
InstallNetworkPlugin();
}
}
function InstallNetworkPlugin()
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();
//--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;
@@ -37,6 +571,7 @@ function ReturnPreviewPage()
document.location.href="../21/index.html";
}
function GotoNetPluginPage()
{
let bRet=ResponseFilamentResult();
@@ -61,3 +596,8 @@ function FinishGuide()
}
//window.location.href="../6/index.html";
}

View File

@@ -1,250 +0,0 @@
#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

@@ -1,614 +0,0 @@
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,7 +6,6 @@
<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>
@@ -15,7 +14,6 @@
<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()">
@@ -131,6 +129,98 @@
// e.returnValue = false;
//}
};
initInputEvents();
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
});
</script>
</html>

View File

@@ -1,5 +1,108 @@
/* TABS SYSTEM / CUSTOM */
#Title {
.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
{
margin: 0px 40px;
border-bottom: 1px solid var(--border-color);
display: flex;
@@ -8,44 +111,37 @@
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;
}
/* 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 {
#CustomFilamentsArea
{
display: flex;
flex-direction: column;
height: 100%;
}
#CFilament_List {
#CFilament_List
{
display:flex;
overflow-y:auto;
flex-wrap:wrap;
@@ -56,7 +152,8 @@ body:has(#SystemFilamentBtn.TitleSelected) #Content { /* :has selector browser s
height: 100%;
}
.CFilament_Item {
.CFilament_Item
{
display: flex;
align-items: center;
margin-right: 10%;
@@ -67,21 +164,200 @@ body:has(#SystemFilamentBtn.TitleSelected) #Content { /* :has selector browser s
margin-right: 2%;
}
.CFilament_Name {
.CFilament_Name
{
width: 100%;
overflow: hidden;
white-space: nowrap; /* ?????? */
text-overflow: ellipsis; /* ????????? */
}
#CFilament_Btn_Area {
display: flex;
align-items: center;
height: 30px;
}
.CFilament_EditBtn {
.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);
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;
}

View File

@@ -1,3 +1,8 @@
var m_ProfileItem;
var FilamentPriority=new Array( "pla","abs","pet","tpu","pc");
var VendorPriority=new Array("generic");
function OnInit()
{
TranslatePage();
@@ -10,6 +15,15 @@ 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'];
@@ -26,6 +40,505 @@ 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={};
@@ -36,6 +549,7 @@ function CancelSelect()
SendWXMessage( JSON.stringify(tSend) );
}
function ConfirmSelect()
{
let bRet=ResponseFilamentResult();
@@ -52,6 +566,7 @@ function ConfirmSelect()
}
}
function OnSelectMenu( nIndex )
{
switch(nIndex)
@@ -118,6 +633,7 @@ function UpdateCustomFilaments( CFList )
$('#CFilament_List').html(strHtml);
}
function OnClickCustomFilamentAdd()
{
//alert('Create New Custom Filament');
@@ -141,3 +657,5 @@ function CFEdit( fid )
SendWXMessage( JSON.stringify(tSend) );
}

View File

@@ -6,7 +6,6 @@
<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>
@@ -14,7 +13,6 @@
<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()">
@@ -152,6 +150,97 @@
}
}, { passive: false });
initInputEvents();
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
});
</script>
</html>

View File

@@ -1,5 +1,473 @@
#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,15 +1,485 @@
// 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={};
@@ -20,6 +490,7 @@ function CancelSelect()
SendWXMessage( JSON.stringify(tSend) );
}
function ConfirmSelect()
{
let nChoose=OnExitFilter();
@@ -45,3 +516,7 @@ function CreateNewPrinter()
SendWXMessage( JSON.stringify(tSend) );
}

View File

@@ -6,7 +6,6 @@
<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> -->
@@ -14,9 +13,8 @@
<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="../21/common.js"></script> <!-- ORCA use common sources for setup guide and standalone dialog -->
<script type="text/javascript" src="24.js"></script>
<!-- <script type="text/javascript" src="../js/common.js"></script> -->
<script type="text/javascript" src="24.js"></script>
</head>
<body onLoad="OnInit()">
<div id="Title">
@@ -51,33 +49,65 @@
<div id="Content" class="thin-scroll">
<!-- 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 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>
</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>
<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">
@@ -96,10 +126,215 @@
</div>
</div>
</div>
</body>
<script>
initKeyEvents(true); // close on ESC
InitGlobalVariables();
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");
</script>
</html>

View File

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

View File

@@ -237,6 +237,10 @@ 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,10 +1357,6 @@ 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