Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc9203126d | ||
|
|
8c2a1198d6 | ||
|
|
193cfc6dbf | ||
|
|
86905a8a20 | ||
|
|
d4fabbf7c8 | ||
|
|
51efb24752 | ||
|
|
cf9ec18df5 | ||
|
|
258f927a0f | ||
|
|
6aa613ccf0 | ||
|
|
7599868797 | ||
|
|
81ec931990 | ||
|
|
8fd97b5120 | ||
|
|
aacc36b9d2 | ||
|
|
26f5fd6251 | ||
|
|
5d73410281 | ||
|
|
b75af485ce | ||
|
|
6a7763f08d | ||
|
|
70e5b330be | ||
|
|
5e94368863 | ||
|
|
0df9b782bb | ||
|
|
d5403ccc94 | ||
|
|
32d690ecee | ||
|
|
303d7a1a07 | ||
|
|
c0e6db227d | ||
|
|
a078155890 | ||
|
|
3b6e27d725 | ||
|
|
6254ab643a | ||
|
|
9ab0178dd0 | ||
|
|
1cbf97568d | ||
|
|
7a2fe7d64b | ||
|
|
ae138090f1 | ||
|
|
e028476d2a | ||
|
|
96464ccdf6 | ||
|
|
76e0168d1e | ||
|
|
bb7dfdc808 | ||
|
|
f1658855c8 | ||
|
|
888012c30e | ||
|
|
16efd3458b | ||
|
|
b050d5b924 | ||
|
|
368bf91bbb | ||
|
|
15aff97c35 | ||
|
|
63544e3459 | ||
|
|
b73e1b7999 | ||
|
|
8df8de11a5 | ||
|
|
6e7d5b0a9b | ||
|
|
721ec56f22 | ||
|
|
7d6e1f85c8 | ||
|
|
011005e12a | ||
|
|
987c57dc15 | ||
|
|
0a336941f4 | ||
|
|
48d07a831d | ||
|
|
4e7fa93981 | ||
|
|
ea90f45127 | ||
|
|
c7b4e8ef84 | ||
|
|
8f1103f064 | ||
|
|
6e42a9b0ae | ||
|
|
e77ba5f672 | ||
|
|
4bc300933e | ||
|
|
5cfd91a309 | ||
|
|
db0e788d35 | ||
|
|
d2ba88c93d | ||
|
|
fc5ac6d2a5 | ||
|
|
64ddc1fbba |
@@ -8,6 +8,7 @@ on:
|
||||
paths:
|
||||
- 'deps/**'
|
||||
- 'deps_src/**'
|
||||
- 'cmake/**'
|
||||
- 'src/**'
|
||||
- '**/CMakeLists.txt'
|
||||
- 'version.inc'
|
||||
@@ -31,6 +32,7 @@ on:
|
||||
paths:
|
||||
- 'deps/**'
|
||||
- 'deps_src/**'
|
||||
- 'cmake/**'
|
||||
- 'src/**'
|
||||
- '**/CMakeLists.txt'
|
||||
- 'version.inc'
|
||||
|
||||
@@ -33,6 +33,8 @@ jobs:
|
||||
ubuntu-ver: '2404'
|
||||
ubuntu-ver-str: '_Ubuntu2404'
|
||||
ORCA_UPDATER_SIG_KEY: ${{ secrets.ORCA_UPDATER_SIG_KEY }}
|
||||
NSIS_VERSION: '3.13'
|
||||
NSIS_SHA256: BA63DFFC4410EE89193E1CB5A41989991BD77C61068DA17E3156D136B7B0B3D8
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -427,29 +429,46 @@ jobs:
|
||||
if: runner.os == 'Windows'
|
||||
uses: microsoft/setup-msbuild@v3
|
||||
|
||||
- name: Install nsis
|
||||
# NSIS builds the installer. A pinned portable copy is kept in the Actions
|
||||
# cache, so most runs never download it, and a cache miss fetches the
|
||||
# release archive from SourceForge instead of going through the Chocolatey
|
||||
# community feed, which hosted runners often cannot reach. Prepending it to
|
||||
# PATH also makes cpack use it over the NSIS preinstalled on some images.
|
||||
- name: Restore NSIS
|
||||
id: nsis-cache
|
||||
if: runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||
uses: actions/cache/restore@v6
|
||||
with:
|
||||
path: ${{ runner.temp }}/nsis
|
||||
key: nsis-${{ env.NSIS_VERSION }}
|
||||
|
||||
- name: Install NSIS
|
||||
if: runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||
shell: pwsh
|
||||
# The Chocolatey community feed intermittently 504s, and `choco install`
|
||||
# exits 0 when package resolution fails that way. Unchecked, the job then
|
||||
# builds for ~25 minutes before `cpack -G NSIS` reports a missing makensis.
|
||||
# Retry the install and verify makensis itself, so a real failure stops here.
|
||||
run: |
|
||||
dir "C:/Program Files (x86)/Windows Kits/10/Include"
|
||||
$nsisDir = Join-Path ${env:ProgramFiles(x86)} 'NSIS'
|
||||
$nsisDir = Join-Path $env:RUNNER_TEMP 'nsis'
|
||||
$makensis = Join-Path $nsisDir 'makensis.exe'
|
||||
for ($attempt = 1; $attempt -le 3 -and -not (Test-Path $makensis); $attempt++) {
|
||||
if ($attempt -gt 1) { Start-Sleep -Seconds (15 * $attempt) }
|
||||
Write-Host "::group::choco install nsis (attempt $attempt)"
|
||||
choco install nsis --yes --no-progress
|
||||
Write-Host "::endgroup::"
|
||||
}
|
||||
if (-not (Test-Path $makensis)) {
|
||||
throw "NSIS install failed: $makensis not found after 3 attempts."
|
||||
$zip = Join-Path $env:RUNNER_TEMP "nsis-$env:NSIS_VERSION.zip"
|
||||
curl.exe -fsSL --retry 5 --retry-all-errors --retry-delay 15 -o $zip "https://downloads.sourceforge.net/project/nsis/NSIS%203/$env:NSIS_VERSION/nsis-$env:NSIS_VERSION.zip"
|
||||
if ($LASTEXITCODE -ne 0) { throw "NSIS $env:NSIS_VERSION download failed." }
|
||||
if ((Get-FileHash $zip -Algorithm SHA256).Hash -ne $env:NSIS_SHA256) {
|
||||
throw "NSIS $env:NSIS_VERSION archive does not match its pinned SHA256."
|
||||
}
|
||||
Expand-Archive $zip $env:RUNNER_TEMP
|
||||
Move-Item (Join-Path $env:RUNNER_TEMP "nsis-$env:NSIS_VERSION") $nsisDir
|
||||
}
|
||||
& $makensis /VERSION
|
||||
$nsisDir | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8
|
||||
|
||||
- name: Save NSIS
|
||||
if: runner.os == 'Windows' && !vars.SELF_HOSTED && steps.nsis-cache.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v6
|
||||
with:
|
||||
path: ${{ runner.temp }}/nsis
|
||||
key: nsis-${{ env.NSIS_VERSION }}
|
||||
|
||||
- name: Build slicer Win
|
||||
if: runner.os == 'Windows'
|
||||
working-directory: ${{ github.workspace }}
|
||||
|
||||
@@ -1345,7 +1345,8 @@ set (CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME})
|
||||
set (CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/resources/images\\\\OrcaSlicer.ico")
|
||||
set (CPACK_NSIS_MUI_ICON "${CPACK_PACKAGE_ICON}")
|
||||
set (CPACK_NSIS_MUI_UNIICON "${CPACK_PACKAGE_ICON}")
|
||||
set (CPACK_NSIS_INSTALLED_ICON_NAME "$INSTDIR\\\\orca-slicer.exe")
|
||||
# Relative to the install dir: CPack's NSIS template prefixes $INSTDIR itself.
|
||||
set (CPACK_NSIS_INSTALLED_ICON_NAME "orca-slicer.exe")
|
||||
set (CPACK_PACKAGE_CHECKSUM SHA256)
|
||||
set (CPACK_PACKAGE_INSTALL_REGISTRY_KEY "OrcaSlicer")
|
||||
set (CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
|
||||
|
||||
@@ -86,7 +86,8 @@ The [wiki](https://www.orcaslicer.com/wiki) aims to provide a detailed explanati
|
||||
## Stable Release
|
||||
|
||||
📥 **[Download the Latest Stable Release](https://github.com/OrcaSlicer/OrcaSlicer/releases/latest)**
|
||||
Visit our GitHub Releases page for the latest stable version of OrcaSlicer, recommended for most users.
|
||||
Visit our GitHub Releases page for the latest stable version of OrcaSlicer, recommended for most users.
|
||||
Windows release binaries are code signed; see our [Code signing policy](#code-signing-policy).
|
||||
|
||||
## Nightly Builds
|
||||
|
||||
@@ -244,6 +245,16 @@ OrcaSlicer began in that same spirit, drawing from BambuStudio, PrusaSlicer, and
|
||||
|
||||
The OrcaSlicer logo was designed by community member [Justin Levine](https://github.com/jal-co).
|
||||
|
||||
# Code Signing Policy
|
||||
|
||||
Free code signing provided by [SignPath.io](https://about.signpath.io), certificate by [SignPath Foundation](https://signpath.org).
|
||||
|
||||
Windows release binaries are built by GitHub Actions from this repository and signed through the SignPath Foundation program. Every signing request is manually approved.
|
||||
|
||||
**Team roles:** [SoftFever](https://github.com/SoftFever) is the committer, reviewer and approver for all signed releases.
|
||||
|
||||
**Privacy policy:** See the [OrcaSlicer privacy policy](https://www.orcaslicer.com/privacy-policy/).
|
||||
|
||||
# License
|
||||
|
||||
- **OrcaSlicer** is licensed under the GNU Affero General Public License, version 3.
|
||||
|
||||
@@ -8,7 +8,7 @@ SCRIPT_PATH=$(dirname "$(readlink -f "${0}")")
|
||||
pushd "${SCRIPT_PATH}" > /dev/null
|
||||
|
||||
function usage() {
|
||||
echo "Usage: ./${SCRIPT_NAME} [-1][-b][-c][-d][-D][-e][-F][-g][-h][-i][-j N][-J N][-p][-r][-s][-t][-u][-l][-L]"
|
||||
echo "Usage: ./${SCRIPT_NAME} [-1][-b][-c][-d][-D][-e][-F][-g][-h][-i][-j N][-J N][-p][-r][-s][-t][-u][-l][-L] [-- CMAKE_ARGS...]"
|
||||
echo " -1: limit builds to one core (where possible)"
|
||||
echo " -j N: limit builds to N cores (where possible)"
|
||||
echo " -J N: build up to N dependencies at a time, each still using -j jobs (default: 1)"
|
||||
@@ -29,11 +29,15 @@ function usage() {
|
||||
echo " -u: install system dependencies (asks for sudo password; build prerequisite)"
|
||||
echo " -l: use Clang instead of GCC (default: GCC)"
|
||||
echo " -L: use ld.lld as linker (if available)"
|
||||
echo " -- CMAKE_ARGS...: pass everything after '--' to the cmake configure step of the deps (-d) and OrcaSlicer (-s/-t) builds,"
|
||||
echo " e.g. -DCMAKE_CXX_FLAGS=\"-O2 -march=native\", -DCMAKE_CXX_COMPILER=g++-14, -DCMAKE_EXE_LINKER_FLAGS=-fuse-ld=mold."
|
||||
echo " They come last on the cmake command line, so they override what -l and -L set."
|
||||
echo "For a first use, you want to './${SCRIPT_NAME} -u'"
|
||||
echo " and then './${SCRIPT_NAME} -dsi'"
|
||||
echo "For a GitHub Actions-like Linux build locally, use './${SCRIPT_NAME} -g -istrlL'"
|
||||
echo "Use './${SCRIPT_NAME} -gF -istrlL' to rebuild the cached runner image first."
|
||||
echo "Set ORCA_CONTAINER_CLI, ORCA_DOCKER_IMAGE, ORCA_DOCKER_BASE_IMAGE, or ORCA_DOCKER_CMAKE_VERSION to override the container runtime, cached image tag, base image, or CMake version."
|
||||
echo "DEPS_EXTRA_BUILD_ARGS and ORCA_EXTRA_BUILD_ARGS add whitespace-separated cmake configure arguments to the deps and OrcaSlicer builds; prefer '--' for arguments that contain spaces."
|
||||
}
|
||||
|
||||
SLIC3R_PRECOMPILED_HEADERS="ON"
|
||||
@@ -131,6 +135,20 @@ while getopts ":1j:J:bcCdDeFghiprstulL" opt ; do
|
||||
esac
|
||||
done
|
||||
|
||||
# getopts stops at '--'; whatever follows is handed to cmake unchanged.
|
||||
if [[ ${OPTIND} -le $# ]] ; then
|
||||
separator_index=$((OPTIND-1))
|
||||
if [[ "${!separator_index}" != "--" ]] ; then
|
||||
echo "Unexpected argument '${!OPTIND}': cmake arguments must follow '--', aborting."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
shift $((OPTIND-1))
|
||||
EXTRA_CMAKE_ARGS=("$@")
|
||||
if [[ ${#EXTRA_CMAKE_ARGS[@]} -gt 0 ]] ; then
|
||||
FORWARDED_ARGS+=("--" "${EXTRA_CMAKE_ARGS[@]}")
|
||||
fi
|
||||
|
||||
if [ ${OPTIND} -eq 1 ] ; then
|
||||
usage
|
||||
exit 1
|
||||
@@ -547,7 +565,7 @@ if [[ -n "${BUILD_DEPS}" ]] ; then
|
||||
BUILD_ARGS+=(-DCMAKE_BUILD_TYPE="${BUILD_CONFIG}")
|
||||
fi
|
||||
|
||||
print_and_run cmake -S deps -B deps/$BUILD_DIR "${CMAKE_C_CXX_COMPILER_CLANG[@]}" "${CMAKE_LLD_LINKER_ARGS[@]}" "${CMAKE_CCACHE_ARGS[@]}" -G Ninja "${COLORED_OUTPUT}" "${BUILD_ARGS[@]}"
|
||||
print_and_run cmake -S deps -B deps/$BUILD_DIR "${CMAKE_C_CXX_COMPILER_CLANG[@]}" "${CMAKE_LLD_LINKER_ARGS[@]}" "${CMAKE_CCACHE_ARGS[@]}" -G Ninja "${COLORED_OUTPUT}" "${BUILD_ARGS[@]}" "${EXTRA_CMAKE_ARGS[@]}"
|
||||
# The top-level build runs one dependency at a time by default, which keeps the console
|
||||
# output readable and lets that dependency's own build use all of CMAKE_BUILD_PARALLEL_LEVEL.
|
||||
# -J raises the top level instead, and -j still applies in full to every dependency, so the
|
||||
@@ -593,7 +611,8 @@ if [[ -n "${BUILD_ORCA}" ]] || [[ -n "${BUILD_TESTS}" ]] ; then
|
||||
-DSLIC3R_PCH=${SLIC3R_PRECOMPILED_HEADERS} \
|
||||
-DORCA_TOOLS=ON \
|
||||
"${COLORED_OUTPUT}" \
|
||||
"${BUILD_ARGS[@]}"
|
||||
"${BUILD_ARGS[@]}" \
|
||||
"${EXTRA_CMAKE_ARGS[@]}"
|
||||
echo "done"
|
||||
if [[ -n "${BUILD_ORCA}" ]]; then
|
||||
echo "Building OrcaSlicer ..."
|
||||
|
||||
@@ -42,6 +42,7 @@ call :add_arg build_deps bool d deps "Download and build the dependencies, neede
|
||||
call :add_arg build_slicer bool s slicer "Build OrcaSlicer"
|
||||
call :add_arg build_tests bool "" tests "Build the unit tests"
|
||||
call :add_arg run_tests bool "" run-tests "Build the unit tests and run them"
|
||||
call :add_arg make_installer bool "" installer "Build OrcaSlicer and package it into an NSIS installer"
|
||||
call :add_arg pack_deps bool p pack "Bundle the built dependencies into a zip file"
|
||||
call :add_arg install_deps bool u install-deps "Install or update CMake, Perl and Git with WinGet"
|
||||
call :add_arg install_vs string "" install-vs "Also install Visual Studio: buildtools or ide"
|
||||
@@ -185,6 +186,9 @@ if "%build_deps%%build_slicer%%pack_deps%%install_deps%%install_vs%" == "" (
|
||||
if "%run_tests%" == "ON" set "build_slicer=ON"
|
||||
)
|
||||
|
||||
REM The installer packages the slicer build, so it always needs one.
|
||||
if "%make_installer%" == "ON" set "build_slicer=ON"
|
||||
|
||||
REM Options like --config or -j only shape a build. Without one of the actions
|
||||
REM there is nothing for them to shape, so say so rather than resolving a whole
|
||||
REM build and reporting it took no time. The block above may have added one.
|
||||
@@ -222,6 +226,30 @@ if "%build_slicer%" == "ON" if "%install_slicer%" == "ON" if not "%slicer_target
|
||||
echo --install needs the executable, but --slicer-target names "%slicer_target%".
|
||||
exit /b 1
|
||||
)
|
||||
REM cpack runs the same install, so it has the same need.
|
||||
if "%make_installer%" == "ON" if not "%slicer_target%" == "" if /I not "%slicer_target%" == "OrcaSlicer" (
|
||||
echo --installer needs the executable, but --slicer-target names "%slicer_target%".
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM cpack finds makensis on PATH or through the registry key the NSIS installer
|
||||
REM writes, so look in the same places, and before the build rather than after
|
||||
REM it. The value is read past its REG_SZ marker because the name column is
|
||||
REM localised and may hold spaces.
|
||||
if not "%make_installer%" == "ON" goto :nsis_ready
|
||||
if "%dry_run%" == "ON" goto :nsis_ready
|
||||
where makensis >nul 2>nul && goto :nsis_ready
|
||||
for %%v in (32 64) do (
|
||||
for /f "delims=" %%l in ('reg query "HKLM\SOFTWARE\NSIS" /ve /reg:%%v 2^>nul ^| findstr REG_SZ') do (
|
||||
set "nsis_line=%%l"
|
||||
set "nsis_line=!nsis_line:*REG_SZ=!"
|
||||
for /f "tokens=*" %%d in ("!nsis_line!") do if exist "%%d\makensis.exe" goto :nsis_ready
|
||||
)
|
||||
)
|
||||
echo NSIS was not found, and --installer needs it to build the installer.
|
||||
echo Install it with "winget install NSIS.NSIS", then run this again.
|
||||
exit /b 1
|
||||
:nsis_ready
|
||||
if not "%vs_version%" == "" if "!vs_gen_%vs_version%!" == "" (
|
||||
echo Unknown Visual Studio release "%vs_version%". Known releases: 2019, 2022, 2026.
|
||||
exit /b 1
|
||||
@@ -734,6 +762,14 @@ if "%build_slicer%" == "ON" (
|
||||
call :print_and_run cmake --build "%build_dir%" --target install --config %build_type%
|
||||
%error_check%
|
||||
)
|
||||
|
||||
REM cpack installs into its own staging tree, so this does not need -i.
|
||||
REM Unlike CI it skips the preset cache, whose packaging step prunes the
|
||||
REM checkout's preset JSONs.
|
||||
if "%make_installer%" == "ON" (
|
||||
call :print_and_run cpack -G NSIS -C %build_type% --config "%build_dir%\CPackConfig.cmake" -B "%build_dir%"
|
||||
%error_check%
|
||||
)
|
||||
)
|
||||
|
||||
REM Elapsed wall clock. The 1%%a-100 trick strips a leading zero, which set /A
|
||||
@@ -820,6 +856,16 @@ REM worked out the same way in either run.
|
||||
if "%build_slicer%" == "ON" if not "%linked%" == "ON" echo Target %slicer_target%
|
||||
if "%build_slicer%" == "ON" if not "%using_ninja%" == "ON" echo Solution %build_full%\!solution!
|
||||
if "%pack_deps%" == "ON" if defined bundle echo Bundle !bundle!
|
||||
if "%make_installer%" == "ON" (
|
||||
REM The file name carries the version, which only CMake knows, so name
|
||||
REM the newest match, or the pattern when there is none yet.
|
||||
set "installer="
|
||||
for /f "delims=" %%f in ('dir /b /o-d "!build_full!\OrcaSlicer_Windows_Installer_*.exe" 2^>nul') do (
|
||||
if not defined installer set "installer=!build_full!\%%f"
|
||||
)
|
||||
if not defined installer set "installer=!build_full!\OrcaSlicer_Windows_Installer_*.exe"
|
||||
echo Installer !installer!
|
||||
)
|
||||
|
||||
echo.
|
||||
echo Next
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
# Find the wxWidgets module based on the information provided by the Perl Alien::wxWidgets module.
|
||||
|
||||
# Check for the Perl & PerlLib modules
|
||||
include(LibFindMacros)
|
||||
libfind_package(AlienWx Perl)
|
||||
libfind_package(AlienWx PerlLibs)
|
||||
|
||||
if (AlienWx_DEBUG)
|
||||
message(STATUS " AlienWx_FIND_COMPONENTS=${AlienWx_FIND_COMPONENTS}")
|
||||
endif()
|
||||
|
||||
# Execute an Alien::Wx module to find the relevant information regarding
|
||||
# the wxWidgets used by the Perl interpreter.
|
||||
# Perl specific stuff
|
||||
set(AlienWx_TEMP_INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/AlienWx_TEMP_INCLUDE.txt)
|
||||
execute_process(
|
||||
COMMAND ${PERL_EXECUTABLE} -e "
|
||||
# Import Perl modules.
|
||||
use strict;
|
||||
use warnings;
|
||||
use Text::ParseWords;
|
||||
|
||||
BEGIN {
|
||||
# CMake sets the environment variables CC and CXX to the detected C compiler.
|
||||
# There is an issue with the Perl ExtUtils::CBuilder, which does not handle whitespaces
|
||||
# in the paths correctly on Windows, so we rather drop the CMake auto-detected paths.
|
||||
delete \$ENV{CC};
|
||||
delete \$ENV{CXX};
|
||||
}
|
||||
|
||||
use Alien::wxWidgets;
|
||||
use ExtUtils::CppGuess;
|
||||
|
||||
# Test for a Visual Studio compiler
|
||||
my \$cpp_guess = ExtUtils::CppGuess->new;
|
||||
my \$mswin = \$^O eq 'MSWin32';
|
||||
my \$msvc = \$cpp_guess->is_msvc;
|
||||
|
||||
# List of wxWidgets components to be used.
|
||||
my @components = split /;/, '${AlienWx_FIND_COMPONENTS}';
|
||||
|
||||
# Query the available data from Alien::wxWidgets.
|
||||
my \$version = Alien::wxWidgets->version;
|
||||
my \$config = Alien::wxWidgets->config;
|
||||
my \$compiler = Alien::wxWidgets->compiler;
|
||||
my \$linker = Alien::wxWidgets->linker;
|
||||
my \$include_path = ' ' . Alien::wxWidgets->include_path;
|
||||
my \$defines = ' ' . Alien::wxWidgets->defines;
|
||||
my \$cflags = Alien::wxWidgets->c_flags;
|
||||
my \$linkflags = Alien::wxWidgets->link_flags;
|
||||
my \$libraries = ' ' . Alien::wxWidgets->libraries(@components);
|
||||
my \$gui_toolkit = Alien::wxWidgets->config->{toolkit};
|
||||
#my @libraries = Alien::wxWidgets->link_libraries(@components);
|
||||
#my @implib = Alien::wxWidgets->import_libraries(@components);
|
||||
#my @shrlib = Alien::wxWidgets->shared_libraries(@components);
|
||||
#my @keys = Alien::wxWidgets->library_keys; # 'gl', 'adv', ...
|
||||
#my \$library_path = Alien::wxWidgets->shared_library_path;
|
||||
#my \$key = Alien::wxWidgets->key;
|
||||
#my \$prefix = Alien::wxWidgets->prefix;
|
||||
|
||||
my \$filename = '${AlienWx_TEMP_INCLUDE}';
|
||||
open(my $fh, '>', \$filename) or die \"Could not open file '\$filename' \$!\";
|
||||
|
||||
# Convert a space separated lists to CMake semicolon separated lists,
|
||||
# escape the backslashes,
|
||||
# export the resulting list to a temp file.
|
||||
sub cmake_set_var {
|
||||
my (\$varname, \$content) = @_;
|
||||
# Remove line separators.
|
||||
\$content =~ s/\\r|\\n//g;
|
||||
# Escape the path separators.
|
||||
\$content =~ s/\\\\/\\\\\\\\\\\\\\\\/g;
|
||||
my @words = shellwords(\$content);
|
||||
print \$fh \"set(AlienWx_\$varname \\\"\" . join(';', @words) . \"\\\")\\n\";
|
||||
}
|
||||
cmake_set_var('VERSION', \$version);
|
||||
\$include_path =~ s/ -I/ /g;
|
||||
cmake_set_var('INCLUDE_DIRS', \$include_path);
|
||||
\$libraries =~ s/ -L/ -LIBPATH:/g if \$msvc;
|
||||
cmake_set_var('LIBRARIES', \$libraries);
|
||||
#cmake_set_var('LIBRARY_DIRS', );
|
||||
#\$defines =~ s/ -D/ /g;
|
||||
cmake_set_var('DEFINITIONS', \$defines);
|
||||
#cmake_set_var('DEFINITIONS_DEBUG', );
|
||||
cmake_set_var('CXX_FLAGS', \$cflags);
|
||||
cmake_set_var('GUI_TOOLKIT', \$gui_toolkit);
|
||||
close \$fh;
|
||||
")
|
||||
include(${AlienWx_TEMP_INCLUDE})
|
||||
file(REMOVE ${AlienWx_TEMP_INCLUDE})
|
||||
unset(AlienWx_TEMP_INCLUDE)
|
||||
|
||||
if (AlienWx_DEBUG)
|
||||
message(STATUS " AlienWx_VERSION = ${AlienWx_VERSION}")
|
||||
message(STATUS " AlienWx_INCLUDE_DIRS = ${AlienWx_INCLUDE_DIRS}")
|
||||
message(STATUS " AlienWx_LIBRARIES = ${AlienWx_LIBRARIES}")
|
||||
message(STATUS " AlienWx_LIBRARY_DIRS = ${AlienWx_LIBRARY_DIRS}")
|
||||
message(STATUS " AlienWx_DEFINITIONS = ${AlienWx_DEFINITIONS}")
|
||||
message(STATUS " AlienWx_DEFINITIONS_DEBUG = ${AlienWx_DEFINITIONS_DEBUG}")
|
||||
message(STATUS " AlienWx_CXX_FLAGS = ${AlienWx_CXX_FLAGS}")
|
||||
message(STATUS " AlienWx_GUI_TOOLKIT = ${AlienWx_GUI_TOOLKIT}")
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package_handle_standard_args(AlienWx
|
||||
REQUIRED_VARS AlienWx_INCLUDE_DIRS AlienWx_LIBRARIES
|
||||
# HANDLE_COMPONENTS
|
||||
VERSION_VAR AlienWx_VERSION)
|
||||
@@ -1,88 +0,0 @@
|
||||
# Find the dependencies for linking with the Perl runtime library.
|
||||
|
||||
# Check for the Perl & PerlLib modules
|
||||
include(LibFindMacros)
|
||||
libfind_package(PerlEmbed Perl)
|
||||
libfind_package(PerlEmbed PerlLibs)
|
||||
|
||||
# Execute an Alien::Wx module to find the relevant information regarding
|
||||
# the wxWidgets used by the Perl interpreter.
|
||||
# Perl specific stuff
|
||||
set(PerlEmbed_TEMP_INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/PerlEmbed_TEMP_INCLUDE.txt)
|
||||
execute_process(
|
||||
COMMAND ${PERL_EXECUTABLE} -MExtUtils::Embed -e "
|
||||
# Import Perl modules.
|
||||
use strict;
|
||||
use warnings;
|
||||
use Config;
|
||||
use Text::ParseWords;
|
||||
use ExtUtils::CppGuess;
|
||||
|
||||
# Test for a Visual Studio compiler
|
||||
my \$cpp_guess = ExtUtils::CppGuess->new;
|
||||
my \$mswin = \$^O eq 'MSWin32';
|
||||
my \$msvc = \$cpp_guess->is_msvc;
|
||||
|
||||
# Query the available data from Alien::wxWidgets.
|
||||
my \$ccflags;
|
||||
my \$ldflags;
|
||||
{ local *STDOUT; open STDOUT, '>', \\\$ccflags; ccflags; }
|
||||
{ local *STDOUT; open STDOUT, '>', \\\$ldflags; ldopts; }
|
||||
\$ccflags = ' ' . \$ccflags;
|
||||
\$ldflags = ' ' . \$ldflags;
|
||||
|
||||
my \$filename = '${PerlEmbed_TEMP_INCLUDE}';
|
||||
open(my $fh, '>', \$filename) or die \"Could not open file '\$filename' \$!\";
|
||||
|
||||
# Convert a space separated lists to CMake semicolon separated lists,
|
||||
# escape the backslashes,
|
||||
# export the resulting list to a temp file.
|
||||
sub cmake_set_var {
|
||||
my (\$varname, \$content) = @_;
|
||||
# Remove line separators.
|
||||
\$content =~ s/\\r|\\n//g;
|
||||
# Escape the path separators.
|
||||
\$content =~ s/\\\\/\\\\\\\\\\\\\\\\/g;
|
||||
my @words = shellwords(\$content);
|
||||
print \$fh \"set(PerlEmbed_\$varname \\\"\" . join(';', @words) . \"\\\")\\n\";
|
||||
}
|
||||
cmake_set_var('ARCHNAME', \$Config{archname});
|
||||
cmake_set_var('CCFLAGS', \$ccflags);
|
||||
\$ldflags =~ s/ -L/ -LIBPATH:/g if \$msvc;
|
||||
cmake_set_var('LD', \$Config{ld});
|
||||
cmake_set_var('LDFLAGS', \$ldflags);
|
||||
cmake_set_var('CCCDLFLAGS', \$Config{cccdlflags});
|
||||
cmake_set_var('LDDLFLAGS', \$Config{lddlflags});
|
||||
cmake_set_var('DLEXT', \$Config{dlext});
|
||||
close \$fh;
|
||||
")
|
||||
include(${PerlEmbed_TEMP_INCLUDE})
|
||||
file(REMOVE ${PerlEmbed_TEMP_INCLUDE})
|
||||
unset(PerlEmbed_TEMP_INCLUDE)
|
||||
|
||||
if (PerlEmbed_DEBUG)
|
||||
# First show the configuration extracted by FindPerl & FindPerlLibs:
|
||||
message(STATUS " PERL_INCLUDE_PATH = ${PERL_INCLUDE_PATH}")
|
||||
message(STATUS " PERL_LIBRARY = ${PERL_LIBRARY}")
|
||||
message(STATUS " PERL_EXECUTABLE = ${PERL_EXECUTABLE}")
|
||||
message(STATUS " PERL_SITESEARCH = ${PERL_SITESEARCH}")
|
||||
message(STATUS " PERL_SITELIB = ${PERL_SITELIB}")
|
||||
message(STATUS " PERL_VENDORARCH = ${PERL_VENDORARCH}")
|
||||
message(STATUS " PERL_VENDORLIB = ${PERL_VENDORLIB}")
|
||||
message(STATUS " PERL_ARCHLIB = ${PERL_ARCHLIB}")
|
||||
message(STATUS " PERL_PRIVLIB = ${PERL_PRIVLIB}")
|
||||
message(STATUS " PERL_EXTRA_C_FLAGS = ${PERL_EXTRA_C_FLAGS}")
|
||||
# Second show the configuration extracted by this module (FindPerlEmbed):
|
||||
message(STATUS " PerlEmbed_ARCHNAME = ${PerlEmbed_ARCHNAME}")
|
||||
message(STATUS " PerlEmbed_CCFLAGS = ${PerlEmbed_CCFLAGS}")
|
||||
message(STATUS " PerlEmbed_CCCDLFLAGS = ${PerlEmbed_CCCDLFLAGS}")
|
||||
message(STATUS " LD = ${PerlEmbed_LD}")
|
||||
message(STATUS " PerlEmbed_LDFLAGS = ${PerlEmbed_LDFLAGS}")
|
||||
message(STATUS " PerlEmbed_LDDLFLAGS = ${PerlEmbed_LDDLFLAGS}")
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package_handle_standard_args(PerlEmbed
|
||||
REQUIRED_VARS PerlEmbed_CCFLAGS PerlEmbed_LDFLAGS
|
||||
VERSION_VAR PERL_VERSION)
|
||||
@@ -1,265 +0,0 @@
|
||||
# Version 2.2
|
||||
# Public Domain, originally written by Lasse Kärkkäinen <tronic>
|
||||
# Maintained at https://github.com/Tronic/cmake-modules
|
||||
# Please send your improvements as pull requests on Github.
|
||||
|
||||
# Find another package and make it a dependency of the current package.
|
||||
# This also automatically forwards the "REQUIRED" argument.
|
||||
# Usage: libfind_package(<prefix> <another package> [extra args to find_package])
|
||||
macro (libfind_package PREFIX PKG)
|
||||
set(${PREFIX}_args ${PKG} ${ARGN})
|
||||
if (${PREFIX}_FIND_REQUIRED)
|
||||
set(${PREFIX}_args ${${PREFIX}_args} REQUIRED)
|
||||
endif()
|
||||
find_package(${${PREFIX}_args})
|
||||
set(${PREFIX}_DEPENDENCIES ${${PREFIX}_DEPENDENCIES};${PKG})
|
||||
unset(${PREFIX}_args)
|
||||
endmacro()
|
||||
|
||||
# A simple wrapper to make pkg-config searches a bit easier.
|
||||
# Works the same as CMake's internal pkg_check_modules but is always quiet.
|
||||
macro (libfind_pkg_check_modules)
|
||||
find_package(PkgConfig QUIET)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(${ARGN} QUIET)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Avoid useless copy&pasta by doing what most simple libraries do anyway:
|
||||
# pkg-config, find headers, find library.
|
||||
# Usage: libfind_pkg_detect(<prefix> <pkg-config args> FIND_PATH <name> [other args] FIND_LIBRARY <name> [other args])
|
||||
# E.g. libfind_pkg_detect(SDL2 sdl2 FIND_PATH SDL.h PATH_SUFFIXES SDL2 FIND_LIBRARY SDL2)
|
||||
function (libfind_pkg_detect PREFIX)
|
||||
# Parse arguments
|
||||
set(argname pkgargs)
|
||||
foreach (i ${ARGN})
|
||||
if ("${i}" STREQUAL "FIND_PATH")
|
||||
set(argname pathargs)
|
||||
elseif ("${i}" STREQUAL "FIND_LIBRARY")
|
||||
set(argname libraryargs)
|
||||
else()
|
||||
set(${argname} ${${argname}} ${i})
|
||||
endif()
|
||||
endforeach()
|
||||
if (NOT pkgargs)
|
||||
message(FATAL_ERROR "libfind_pkg_detect requires at least a pkg_config package name to be passed.")
|
||||
endif()
|
||||
# Find library
|
||||
libfind_pkg_check_modules(${PREFIX}_PKGCONF ${pkgargs})
|
||||
if (pathargs)
|
||||
find_path(${PREFIX}_INCLUDE_DIR NAMES ${pathargs} HINTS ${${PREFIX}_PKGCONF_INCLUDE_DIRS})
|
||||
endif()
|
||||
if (libraryargs)
|
||||
find_library(${PREFIX}_LIBRARY NAMES ${libraryargs} HINTS ${${PREFIX}_PKGCONF_LIBRARY_DIRS})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Extracts a version #define from a version.h file, output stored to <PREFIX>_VERSION.
|
||||
# Usage: libfind_version_header(Foobar foobar/version.h FOOBAR_VERSION_STR)
|
||||
# Fourth argument "QUIET" may be used for silently testing different define names.
|
||||
# This function does nothing if the version variable is already defined.
|
||||
function (libfind_version_header PREFIX VERSION_H DEFINE_NAME)
|
||||
# Skip processing if we already have a version or if the include dir was not found
|
||||
if (${PREFIX}_VERSION OR NOT ${PREFIX}_INCLUDE_DIR)
|
||||
return()
|
||||
endif()
|
||||
set(quiet ${${PREFIX}_FIND_QUIETLY})
|
||||
# Process optional arguments
|
||||
foreach(arg ${ARGN})
|
||||
if (arg STREQUAL "QUIET")
|
||||
set(quiet TRUE)
|
||||
else()
|
||||
message(AUTHOR_WARNING "Unknown argument ${arg} to libfind_version_header ignored.")
|
||||
endif()
|
||||
endforeach()
|
||||
# Read the header and parse for version number
|
||||
set(filename "${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
|
||||
if (NOT EXISTS ${filename})
|
||||
if (NOT quiet)
|
||||
message(AUTHOR_WARNING "Unable to find ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
file(READ "${filename}" header)
|
||||
string(REGEX REPLACE ".*#[ \t]*define[ \t]*${DEFINE_NAME}[ \t]*\"([^\n]*)\".*" "\\1" match "${header}")
|
||||
# No regex match?
|
||||
if (match STREQUAL header)
|
||||
if (NOT quiet)
|
||||
message(AUTHOR_WARNING "Unable to find \#define ${DEFINE_NAME} \"<version>\" from ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
# Export the version string
|
||||
set(${PREFIX}_VERSION "${match}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Do the final processing once the paths have been detected.
|
||||
# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain
|
||||
# all the variables, each of which contain one include directory.
|
||||
# Ditto for ${PREFIX}_PROCESS_LIBS and library files.
|
||||
# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES.
|
||||
# Also handles errors in case library detection was required, etc.
|
||||
function (libfind_process PREFIX)
|
||||
# Skip processing if already processed during this configuration run
|
||||
if (${PREFIX}_FOUND)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(found TRUE) # Start with the assumption that the package was found
|
||||
|
||||
# Did we find any files? Did we miss includes? These are for formatting better error messages.
|
||||
set(some_files FALSE)
|
||||
set(missing_headers FALSE)
|
||||
|
||||
# Shorthands for some variables that we need often
|
||||
set(quiet ${${PREFIX}_FIND_QUIETLY})
|
||||
set(required ${${PREFIX}_FIND_REQUIRED})
|
||||
set(exactver ${${PREFIX}_FIND_VERSION_EXACT})
|
||||
set(findver "${${PREFIX}_FIND_VERSION}")
|
||||
set(version "${${PREFIX}_VERSION}")
|
||||
|
||||
# Lists of config option names (all, includes, libs)
|
||||
unset(configopts)
|
||||
set(includeopts ${${PREFIX}_PROCESS_INCLUDES})
|
||||
set(libraryopts ${${PREFIX}_PROCESS_LIBS})
|
||||
|
||||
# Process deps to add to
|
||||
foreach (i ${PREFIX} ${${PREFIX}_DEPENDENCIES})
|
||||
if (DEFINED ${i}_INCLUDE_OPTS OR DEFINED ${i}_LIBRARY_OPTS)
|
||||
# The package seems to export option lists that we can use, woohoo!
|
||||
list(APPEND includeopts ${${i}_INCLUDE_OPTS})
|
||||
list(APPEND libraryopts ${${i}_LIBRARY_OPTS})
|
||||
else()
|
||||
# If plural forms don't exist or they equal singular forms
|
||||
if ((NOT DEFINED ${i}_INCLUDE_DIRS AND NOT DEFINED ${i}_LIBRARIES) OR
|
||||
({i}_INCLUDE_DIR STREQUAL ${i}_INCLUDE_DIRS AND ${i}_LIBRARY STREQUAL ${i}_LIBRARIES))
|
||||
# Singular forms can be used
|
||||
if (DEFINED ${i}_INCLUDE_DIR)
|
||||
list(APPEND includeopts ${i}_INCLUDE_DIR)
|
||||
endif()
|
||||
if (DEFINED ${i}_LIBRARY)
|
||||
list(APPEND libraryopts ${i}_LIBRARY)
|
||||
endif()
|
||||
else()
|
||||
# Oh no, we don't know the option names
|
||||
message(FATAL_ERROR "We couldn't determine config variable names for ${i} includes and libs. Aieeh!")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if (includeopts)
|
||||
list(REMOVE_DUPLICATES includeopts)
|
||||
endif()
|
||||
|
||||
if (libraryopts)
|
||||
list(REMOVE_DUPLICATES libraryopts)
|
||||
endif()
|
||||
|
||||
string(REGEX REPLACE ".*[ ;]([^ ;]*(_INCLUDE_DIRS|_LIBRARIES))" "\\1" tmp "${includeopts} ${libraryopts}")
|
||||
if (NOT tmp STREQUAL "${includeopts} ${libraryopts}")
|
||||
message(AUTHOR_WARNING "Plural form ${tmp} found in config options of ${PREFIX}. This works as before but is now deprecated. Please only use singular forms INCLUDE_DIR and LIBRARY, and update your find scripts for LibFindMacros > 2.0 automatic dependency system (most often you can simply remove the PROCESS variables entirely).")
|
||||
endif()
|
||||
|
||||
# Include/library names separated by spaces (notice: not CMake lists)
|
||||
unset(includes)
|
||||
unset(libs)
|
||||
|
||||
# Process all includes and set found false if any are missing
|
||||
foreach (i ${includeopts})
|
||||
list(APPEND configopts ${i})
|
||||
if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND")
|
||||
list(APPEND includes "${${i}}")
|
||||
else()
|
||||
set(found FALSE)
|
||||
set(missing_headers TRUE)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Process all libraries and set found false if any are missing
|
||||
foreach (i ${libraryopts})
|
||||
list(APPEND configopts ${i})
|
||||
if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND")
|
||||
list(APPEND libs "${${i}}")
|
||||
else()
|
||||
set (found FALSE)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Version checks
|
||||
if (found AND findver)
|
||||
if (NOT version)
|
||||
message(WARNING "The find module for ${PREFIX} does not provide version information, so we'll just assume that it is OK. Please fix the module or remove package version requirements to get rid of this warning.")
|
||||
elseif (version VERSION_LESS findver OR (exactver AND NOT version VERSION_EQUAL findver))
|
||||
set(found FALSE)
|
||||
set(version_unsuitable TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# If all-OK, hide all config options, export variables, print status and exit
|
||||
if (found)
|
||||
foreach (i ${configopts})
|
||||
mark_as_advanced(${i})
|
||||
endforeach()
|
||||
if (NOT quiet)
|
||||
message(STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
|
||||
if (LIBFIND_DEBUG)
|
||||
message(STATUS " ${PREFIX}_DEPENDENCIES=${${PREFIX}_DEPENDENCIES}")
|
||||
message(STATUS " ${PREFIX}_INCLUDE_OPTS=${includeopts}")
|
||||
message(STATUS " ${PREFIX}_INCLUDE_DIRS=${includes}")
|
||||
message(STATUS " ${PREFIX}_LIBRARY_OPTS=${libraryopts}")
|
||||
message(STATUS " ${PREFIX}_LIBRARIES=${libs}")
|
||||
endif()
|
||||
set (${PREFIX}_INCLUDE_OPTS ${includeopts} PARENT_SCOPE)
|
||||
set (${PREFIX}_LIBRARY_OPTS ${libraryopts} PARENT_SCOPE)
|
||||
set (${PREFIX}_INCLUDE_DIRS ${includes} PARENT_SCOPE)
|
||||
set (${PREFIX}_LIBRARIES ${libs} PARENT_SCOPE)
|
||||
set (${PREFIX}_FOUND TRUE PARENT_SCOPE)
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Format messages for debug info and the type of error
|
||||
set(vars "Relevant CMake configuration variables:\n")
|
||||
foreach (i ${configopts})
|
||||
mark_as_advanced(CLEAR ${i})
|
||||
set(val ${${i}})
|
||||
if ("${val}" STREQUAL "${i}-NOTFOUND")
|
||||
set (val "<not found>")
|
||||
elseif (val AND NOT EXISTS ${val})
|
||||
set (val "${val} (does not exist)")
|
||||
else()
|
||||
set(some_files TRUE)
|
||||
endif()
|
||||
set(vars "${vars} ${i}=${val}\n")
|
||||
endforeach()
|
||||
set(vars "${vars}You may use CMake GUI, cmake -D or ccmake to modify the values. Delete CMakeCache.txt to discard all values and force full re-detection if necessary.\n")
|
||||
if (version_unsuitable)
|
||||
set(msg "${PREFIX} ${${PREFIX}_VERSION} was found but")
|
||||
if (exactver)
|
||||
set(msg "${msg} only version ${findver} is acceptable.")
|
||||
else()
|
||||
set(msg "${msg} version ${findver} is the minimum requirement.")
|
||||
endif()
|
||||
else()
|
||||
if (missing_headers)
|
||||
set(msg "We could not find development headers for ${PREFIX}. Do you have the necessary dev package installed?")
|
||||
elseif (some_files)
|
||||
set(msg "We only found some files of ${PREFIX}, not all of them. Perhaps your installation is incomplete or maybe we just didn't look in the right place?")
|
||||
if(findver)
|
||||
set(msg "${msg} This could also be caused by incompatible version (if it helps, at least ${PREFIX} ${findver} should work).")
|
||||
endif()
|
||||
else()
|
||||
set(msg "We were unable to find package ${PREFIX}.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Fatal error out if REQUIRED
|
||||
if (required)
|
||||
set(msg "REQUIRED PACKAGE NOT FOUND\n${msg} This package is REQUIRED and you need to install it or adjust CMake configuration in order to continue building ${CMAKE_PROJECT_NAME}.")
|
||||
message(FATAL_ERROR "${msg}\n${vars}")
|
||||
endif()
|
||||
# Otherwise just print a nasty warning
|
||||
if (NOT quiet)
|
||||
message(WARNING "WARNING: MISSING PACKAGE\n${msg} This package is NOT REQUIRED and you may ignore this warning but by doing so you may miss some functionality of ${CMAKE_PROJECT_NAME}. \n${vars}")
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -1,89 +0,0 @@
|
||||
# Source: https://gist.github.com/sivachandran/3a0de157dccef822a230#file-bin2h-cmake
|
||||
# Added modifications to suit prusaslicer
|
||||
include(CMakeParseArguments)
|
||||
|
||||
# Function to wrap a given string into multiple lines at the given column position.
|
||||
# Parameters:
|
||||
# VARIABLE - The name of the CMake variable holding the string.
|
||||
# AT_COLUMN - The column position at which string will be wrapped.
|
||||
function(WRAP_STRING)
|
||||
set(oneValueArgs VARIABLE AT_COLUMN)
|
||||
cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN})
|
||||
|
||||
string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength)
|
||||
math(EXPR offset "0")
|
||||
|
||||
while(stringLength GREATER 0)
|
||||
|
||||
if(stringLength GREATER ${WRAP_STRING_AT_COLUMN})
|
||||
math(EXPR length "${WRAP_STRING_AT_COLUMN}")
|
||||
else()
|
||||
math(EXPR length "${stringLength}")
|
||||
endif()
|
||||
|
||||
string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line)
|
||||
set(lines "${lines}\n${line}")
|
||||
|
||||
math(EXPR stringLength "${stringLength} - ${length}")
|
||||
math(EXPR offset "${offset} + ${length}")
|
||||
endwhile()
|
||||
|
||||
set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Function to embed contents of a file as byte array in C/C++ header file(.h). The header file
|
||||
# will contain a byte array and integer variable holding the size of the array.
|
||||
# Parameters
|
||||
# SOURCE_FILE - The path of source file whose contents will be embedded in the header file.
|
||||
# VARIABLE_NAME - The name of the variable for the byte array. The string "_SIZE" will be append
|
||||
# to this name and will be used a variable name for size variable.
|
||||
# HEADER_FILE - The path of header file.
|
||||
# APPEND - If specified appends to the header file instead of overwriting it
|
||||
# NULL_TERMINATE - If specified a null byte(zero) will be append to the byte array. This will be
|
||||
# useful if the source file is a text file and we want to use the file contents
|
||||
# as string. But the size variable holds size of the byte array without this
|
||||
# null byte.
|
||||
# Usage:
|
||||
# bin2h(SOURCE_FILE "Logo.png" HEADER_FILE "Logo.h" VARIABLE_NAME "LOGO_PNG")
|
||||
function(BIN2H)
|
||||
set(options APPEND NULL_TERMINATE ADD_WARNING_TEXT)
|
||||
set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE)
|
||||
cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN})
|
||||
|
||||
# reads source file contents as hex string
|
||||
file(READ ${BIN2H_SOURCE_FILE} hexString HEX)
|
||||
string(LENGTH ${hexString} hexStringLength)
|
||||
|
||||
# appends null byte if asked
|
||||
if(BIN2H_NULL_TERMINATE)
|
||||
set(hexString "${hexString}00")
|
||||
endif()
|
||||
|
||||
# wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line)
|
||||
wrap_string(VARIABLE hexString AT_COLUMN 32)
|
||||
math(EXPR arraySize "${hexStringLength} / 2")
|
||||
|
||||
# adds '0x' prefix and comma suffix before and after every byte respectively
|
||||
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString})
|
||||
# removes trailing comma
|
||||
string(REGEX REPLACE ", $" "" arrayValues ${arrayValues})
|
||||
|
||||
# converts the variable name into proper C identifier
|
||||
string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
|
||||
# string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
|
||||
|
||||
# declares byte array and the length variables
|
||||
set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };")
|
||||
set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};")
|
||||
set(warnTxt "")
|
||||
if (BIN2H_ADD_WARNING_TEXT)
|
||||
set(warnTxt "/* WARN: This file is auto-generated from ${BIN2H_SOURCE_FILE} */\n")
|
||||
endif ()
|
||||
|
||||
set(declarations "${warnTxt}${arrayDefinition}\n\n${arraySizeDefinition}\n\n")
|
||||
if(BIN2H_APPEND)
|
||||
file(APPEND ${BIN2H_HEADER_FILE} "${declarations}")
|
||||
else()
|
||||
file(WRITE ${BIN2H_HEADER_FILE} "${declarations}")
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -1,71 +0,0 @@
|
||||
From b32e63f75046d186d93ee7d627c978f2f7c892f3 Mon Sep 17 00:00:00 2001
|
||||
From: Steve Dower <steve.dower@python.org>
|
||||
Date: Fri, 10 Jul 2026 14:04:00 +0100
|
||||
Subject: [PATCH] [3.13] gh-153438: Update NuGet download URL (GH-153482)
|
||||
(GH-153515)
|
||||
|
||||
gh-153438: Update NuGet download URL (GH-153482)
|
||||
(cherry picked from commit 106eb532ea3b243423e62a702719e9d3c0e40c16)
|
||||
(cherry picked from commit 62eb50d65d538dda5164f9c4a097a896454a0d1c)
|
||||
|
||||
Co-authored-by: Steve Dower <steve.dower@python.org>
|
||||
Co-authored-by: Harjoth Khara <harjoth.khara@gmail.com>
|
||||
---
|
||||
Doc/using/windows.rst | 6 +++---
|
||||
.../Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst | 2 ++
|
||||
PCbuild/find_python.bat | 2 +-
|
||||
Tools/msi/get_externals.bat | 2 +-
|
||||
4 files changed, 7 insertions(+), 5 deletions(-)
|
||||
create mode 100644 Misc/NEWS.d/next/Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst
|
||||
|
||||
diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst
|
||||
index 2a507675044666..4800789ca2d6cc 100644
|
||||
--- a/Doc/using/windows.rst
|
||||
+++ b/Doc/using/windows.rst
|
||||
@@ -414,9 +414,9 @@ on using nuget. What follows is a summary that is sufficient for Python
|
||||
developers.
|
||||
|
||||
The ``nuget.exe`` command line tool may be downloaded directly from
|
||||
-``https://aka.ms/nugetclidl``, for example, using curl or PowerShell. With the
|
||||
-tool, the latest version of Python for 64-bit or 32-bit machines is installed
|
||||
-using::
|
||||
+``https://dist.nuget.org/win-x86-commandline/latest/nuget.exe``, for example,
|
||||
+using curl or PowerShell. With the tool, the latest version of Python for
|
||||
+64-bit or 32-bit machines is installed using::
|
||||
|
||||
nuget.exe install python -ExcludeVersion -OutputDirectory .
|
||||
nuget.exe install pythonx86 -ExcludeVersion -OutputDirectory .
|
||||
diff --git a/Misc/NEWS.d/next/Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst b/Misc/NEWS.d/next/Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst
|
||||
new file mode 100644
|
||||
index 00000000000000..edab8e6ba7b259
|
||||
--- /dev/null
|
||||
+++ b/Misc/NEWS.d/next/Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst
|
||||
@@ -0,0 +1,2 @@
|
||||
+Update Windows build and installer tooling and documentation to use the
|
||||
+current download URL for ``nuget.exe``.
|
||||
diff --git a/PCbuild/find_python.bat b/PCbuild/find_python.bat
|
||||
index 0af367a3efafad..9612a2860ef9c3 100644
|
||||
--- a/PCbuild/find_python.bat
|
||||
+++ b/PCbuild/find_python.bat
|
||||
@@ -52,7 +52,7 @@
|
||||
@set _Py_HOST_PYTHON=%HOST_PYTHON%
|
||||
@if "%_Py_HOST_PYTHON%"=="" set _Py_HOST_PYTHON=py
|
||||
@if "%_Py_NUGET%"=="" (set _Py_NUGET=%_Py_EXTERNALS_DIR%\nuget.exe)
|
||||
-@if "%_Py_NUGET_URL%"=="" (set _Py_NUGET_URL=https://aka.ms/nugetclidl)
|
||||
+@if "%_Py_NUGET_URL%"=="" (set _Py_NUGET_URL=https://dist.nuget.org/win-x86-commandline/latest/nuget.exe)
|
||||
@if NOT exist "%_Py_NUGET%" (
|
||||
@if not "%_Py_Quiet%"=="1" @echo Downloading nuget...
|
||||
@rem NB: Must use single quotes around NUGET here, NOT double!
|
||||
diff --git a/Tools/msi/get_externals.bat b/Tools/msi/get_externals.bat
|
||||
index f6602ce9588ff4..c7c7e9f470bc25 100644
|
||||
--- a/Tools/msi/get_externals.bat
|
||||
+++ b/Tools/msi/get_externals.bat
|
||||
@@ -6,7 +6,7 @@ set HERE=%~dp0
|
||||
if "%PCBUILD%"=="" (set PCBUILD=%HERE%..\..\PCbuild\)
|
||||
if "%EXTERNALS_DIR%"=="" (set EXTERNALS_DIR=%HERE%..\..\externals\windows-installer)
|
||||
if "%NUGET%"=="" (set NUGET=%EXTERNALS_DIR%\..\nuget.exe)
|
||||
-if "%NUGET_URL%"=="" (set NUGET_URL=https://aka.ms/nugetclidl)
|
||||
+if "%NUGET_URL%"=="" (set NUGET_URL=https://dist.nuget.org/win-x86-commandline/latest/nuget.exe)
|
||||
|
||||
set DO_FETCH=true
|
||||
set DO_CLEAN=false
|
||||
@@ -8,20 +8,45 @@ set(_python_url "https://www.python.org/ftp/python/${_python_version}/Python-${_
|
||||
set(_python_sha256 "c08bc65a81971c1dd5783182826503369466c7e67374d1646519adf05207b684")
|
||||
|
||||
|
||||
set(_patch_cmd "")
|
||||
if(WIN32)
|
||||
|
||||
# Fix python build failure on Windows if python is not available, due to wrong nuget download URL
|
||||
# See https://github.com/python/cpython/issues/153438
|
||||
# Patch from https://github.com/python/cpython/pull/153608
|
||||
# This patch has not been merged to 3.12 yet so we need to apply it manually
|
||||
#
|
||||
# Without core.autocrlf=false the patched find_python.bat comes out LF and
|
||||
# cmd.exe cannot find its goto labels.
|
||||
set(_patch_cmd git init
|
||||
&& ${GIT_EXECUTABLE} -c core.autocrlf=false apply --verbose
|
||||
--ignore-space-change --whitespace=fix
|
||||
${CMAKE_CURRENT_LIST_DIR}/01-windows-nuget.patch)
|
||||
# Build-time Python for PCbuild's scripts, pinned because 3.15 cannot run the 3.12 scripts.
|
||||
set(DEP_PYTHON_HOST "" CACHE FILEPATH
|
||||
"Python 3.10-3.13 that runs CPython's build scripts; empty downloads a pinned one from nuget.org")
|
||||
if(DEP_PYTHON_HOST)
|
||||
execute_process(
|
||||
COMMAND "${DEP_PYTHON_HOST}" -E -c "import sys; print('%d.%d' % sys.version_info[:2])"
|
||||
OUTPUT_VARIABLE _python_host_minor
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
RESULT_VARIABLE _python_host_result
|
||||
)
|
||||
if(NOT _python_host_result EQUAL 0 OR _python_host_minor VERSION_LESS 3.10 OR _python_host_minor VERSION_GREATER 3.13)
|
||||
message(FATAL_ERROR "DEP_PYTHON_HOST must be Python 3.10 to 3.13, got '${_python_host_minor}' from ${DEP_PYTHON_HOST}")
|
||||
endif()
|
||||
file(TO_NATIVE_PATH "${DEP_PYTHON_HOST}" _python_host)
|
||||
else()
|
||||
set(_python_host_version "3.13.16")
|
||||
if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64")
|
||||
set(_python_host_package pythonarm64)
|
||||
set(_python_host_sha256 bfd77aa5b0edff4a7936a3220e8b79e7c78f864ce13e8fa2c835d9946e11694a)
|
||||
else()
|
||||
set(_python_host_package pythonx86)
|
||||
set(_python_host_sha256 c65cf47664b33286dfc5f2a17303668dd59e057869815ed9b270fb3866c1dd15)
|
||||
endif()
|
||||
set(_python_host_dir "${CMAKE_CURRENT_BINARY_DIR}/dep_python3_host-prefix/src/dep_python3_host")
|
||||
ExternalProject_Add(dep_python3_host
|
||||
URL "https://api.nuget.org/v3-flatcontainer/${_python_host_package}/${_python_host_version}/${_python_host_package}.${_python_host_version}.nupkg"
|
||||
URL_HASH SHA256=${_python_host_sha256}
|
||||
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/python3
|
||||
# Renames the .nupkg to .zip so ExternalProject extracts it.
|
||||
DOWNLOAD_NAME ${_python_host_package}.${_python_host_version}.zip
|
||||
SOURCE_DIR "${_python_host_dir}"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
file(TO_NATIVE_PATH "${_python_host_dir}/tools/python.exe" _python_host)
|
||||
set(_python_depends dep_python3_host)
|
||||
endif()
|
||||
|
||||
if(MSVC_VERSION EQUAL 1800)
|
||||
set(_python_platform_toolset v120)
|
||||
@@ -63,6 +88,47 @@ if(WIN32)
|
||||
# release python3xx.lib; Py_DEBUG could not load release plugin modules.
|
||||
set(_python_pcbuild_config Release)
|
||||
|
||||
# CPython's own libraries, fetched here instead of by get_externals.bat, which ignores failed
|
||||
# downloads. Must match PCbuild/get_externals.bat for _python_version.
|
||||
set(_python_externals
|
||||
# repo folder commit sha256 of the archive
|
||||
source-deps bzip2-1.0.8 05301997b2f9590f49c672cf3dfd3d3dfa7ad521 44b15bede52b32f8673a2976621a847258b041243c003e30f4d9a05214785fe5
|
||||
source-deps sqlite-3.49.1.0 cb7a3997059739fe9c63b2819aeda7c6907510ef 586fe469463f5b27b749f9eef1938baa8e8a12030341e96160a371356c2d6759
|
||||
source-deps xz-5.2.5 c6bc0c612605622aaef101a33a751f9de2ecc193 d99882a8f9fd48be0e605e27e3c077e5eaab370f6f52ebcc8ff754480ffdf0bc
|
||||
source-deps zlib-1.3.1 4dc98e1909830e2bdc2a9cc2236e3c5d5037335b 39d867c083ebc37c77cf03a442f87c0f83db006eb64343bd4a19f1c84c26f50c
|
||||
bin-deps libffi-3.4.4 94cb9a1c7feb608adf2b9f8fe2dbd6925ffbf90d 6b0f53490e0dd958708bff32df689cf2163c214147fcb8edb76a403fa6a877ca
|
||||
bin-deps openssl-bin-3.0.16.2 1174fd43d858425c345b16d631716fb98ba492ea b741fd1411a36cb899fee2c39b70a4492f4bc1c6e2301d67df32e9754118a63b
|
||||
)
|
||||
set(_python_externals_dir "${CMAKE_CURRENT_BINARY_DIR}/dep_python3_externals")
|
||||
list(LENGTH _python_externals _python_externals_len)
|
||||
math(EXPR _python_externals_last "${_python_externals_len} - 1")
|
||||
foreach(_i RANGE 0 ${_python_externals_last} 4)
|
||||
math(EXPR _j "${_i} + 1")
|
||||
math(EXPR _k "${_i} + 2")
|
||||
math(EXPR _l "${_i} + 3")
|
||||
list(GET _python_externals ${_i} _ext_repo)
|
||||
list(GET _python_externals ${_j} _ext_name)
|
||||
list(GET _python_externals ${_k} _ext_commit)
|
||||
list(GET _python_externals ${_l} _ext_sha256)
|
||||
ExternalProject_Add(dep_python3_ext_${_ext_name}
|
||||
URL "https://github.com/python/cpython-${_ext_repo}/archive/${_ext_commit}.zip"
|
||||
URL_HASH SHA256=${_ext_sha256}
|
||||
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/python3
|
||||
DOWNLOAD_NAME cpython-${_ext_repo}-${_ext_name}.zip
|
||||
SOURCE_DIR "${_python_externals_dir}/${_ext_name}"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
list(APPEND _python_depends dep_python3_ext_${_ext_name})
|
||||
endforeach()
|
||||
file(TO_NATIVE_PATH "${_python_externals_dir}" _python_externals_native)
|
||||
|
||||
# PCbuild runs PYTHON without -E, so PYTHONHOME and PYTHONPATH are cleared.
|
||||
set(_python_env_args --unset=PYTHONHOME --unset=PYTHONPATH "PYTHON=${_python_host}"
|
||||
"EXTERNALS_DIR=${_python_externals_native}"
|
||||
"GIT_CEILING_DIRECTORIES=<SOURCE_DIR>/..")
|
||||
|
||||
# CPython's PCbuild needs a 64-bit-hosted toolchain: find_msbuild.bat picks the
|
||||
# 32-bit Bin\MSBuild.exe, whose x86 cl.exe/link.exe run out of address space
|
||||
# (fatal C1002 "out of heap space") building the LTCG-optimized pythoncore.
|
||||
@@ -71,7 +137,6 @@ if(WIN32)
|
||||
# then hosts arm64 tools on its own; the amd64 MSBuild still defaults to x86, so
|
||||
# PreferredToolArchitecture pins it to x64. Scoped to this build step, so
|
||||
# CPython's own sources stay untouched.
|
||||
set(_python_env_args "GIT_CEILING_DIRECTORIES=<SOURCE_DIR>/..")
|
||||
if(CMAKE_GENERATOR_INSTANCE) # empty for non-VS generators (e.g. Ninja)
|
||||
set(_python_msbuild "${CMAKE_GENERATOR_INSTANCE}/MSBuild/Current/Bin/${_python_msbuild_host}/MSBuild.exe")
|
||||
if(EXISTS "${_python_msbuild}")
|
||||
@@ -284,12 +349,12 @@ endif()
|
||||
ExternalProject_Add(dep_python3
|
||||
URL "${_python_url}"
|
||||
URL_HASH SHA256=${_python_sha256}
|
||||
PATCH_COMMAND ${_patch_cmd}
|
||||
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/python3
|
||||
BUILD_IN_SOURCE ON
|
||||
CONFIGURE_COMMAND ${_conf_cmd}
|
||||
BUILD_COMMAND ${_build_cmd}
|
||||
INSTALL_COMMAND ${_install_cmd}
|
||||
DEPENDS ${_python_depends}
|
||||
)
|
||||
|
||||
# Python depends on OpenSSL and ZLIB
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
# Color picker
|
||||
|
||||
The color picker is a local HTML dialog hosted by `ColorPickerDialog`, a
|
||||
`WebViewHostDialog` subclass. Its header and implementation own the ordered
|
||||
selection contract and shared filament conversion. Bridge validation, favorites
|
||||
persistence, placement and gettext strings remain private to the implementation.
|
||||
Its colors use the existing `ColorRGBA` utility.
|
||||
It uses a native title bar and fixed window border, allowing dragging but no
|
||||
manual resizing or maximization. Native title-bar colors use the application's
|
||||
shared dialog dark-theme update on creation and theme changes.
|
||||
Like SpeedDial, the host disables browser zoom accelerators, restores native
|
||||
WebView focus on activation and readiness, and synchronizes layout and the macOS
|
||||
viewport before repainting the backend. Activation never dismisses this modal
|
||||
dialog; focus restoration preserves an active editor and its partial input.
|
||||
The initialized page reports
|
||||
its intrinsic content height; native code validates the current page identifier
|
||||
and bounded numeric height, converts CSS pixels to device-independent window
|
||||
size, and fits within the display's work area. Identical sizes are ignored. The
|
||||
page observes content rather than viewport height, so resizing does not create
|
||||
a feedback loop; oversized content remains scrollable.
|
||||
The panel snapshots the triggering color or More Colors button's screen rectangle.
|
||||
It aligns below the button, flips above when needed, and clamps to that button's
|
||||
display work area on initial display. Later content and DPI changes update only
|
||||
the client size, preserving the position chosen by dragging the title bar.
|
||||
wxGTK clears the dialog's default
|
||||
parent-centering constraint and reapplies its native position after showing,
|
||||
bypassing wxGTK's requested-position cache. Absolute top-level placement remains
|
||||
subject to the window manager; Wayland compositors control it. The official filament palette's
|
||||
existing placement is independent of this custom panel.
|
||||
A solid selection contains one color; a gradient contains exactly two ordered
|
||||
endpoints. The bridge represents these as `{"type":"solid|gradient",
|
||||
"colors":["#RRGGBBAA", ...]}`. RGB input is also accepted and becomes opaque.
|
||||
Native validation rejects malformed hex and incorrect cardinality.
|
||||
|
||||
The project filament color action and the official filament picker's More Colors
|
||||
action enable two-endpoint gradients and independent endpoint alpha. The preset
|
||||
combo box reads project colors in their stored vector order locally and applies
|
||||
changes through `sync_colour_config`,
|
||||
retaining the existing RGB/RGBA profile/project formats and dirty marking.
|
||||
Sidebar gradient and segmented multicolor swatches draw colors in the supplied
|
||||
order without sorting them.
|
||||
Opaque colors use `#RRGGBB`; nonopaque colors use `#RRGGBBAA`, including fully
|
||||
transparent alpha `00`. Initial selections, alpha-only edits and cancellation
|
||||
retain stored alpha. Ordered
|
||||
custom results bypass the official palette's `FilamentColor` set. Choosing an
|
||||
official swatch retains its existing palette behavior.
|
||||
The Linux sidebar's Change extruder color menu uses this same custom editor and
|
||||
the filament swatch anchor, including alpha, ordered gradients and configuration syncing.
|
||||
|
||||
Striped colors and gradients with more than two endpoints cannot be represented
|
||||
by this editor. A notice explains that the current selection is retained; the
|
||||
editor starts from the first color, and unchanged confirmation is a no-op.
|
||||
Cancellation is also a no-op. If the WebView backend cannot initialize, a local
|
||||
unavailable panel offers Cancel and Escape, without opening a system color picker.
|
||||
|
||||
Generic color option fields use an ordinary color button on every platform and
|
||||
open the same panel with gradients and alpha disabled. The panel is anchored to
|
||||
the field button. Empty or invalid field values remain undefined (the empty
|
||||
string), distinct from opaque black. Right-click resets to undefined. Cancel does
|
||||
not notify the field; confirmation and reset notify only when its RGB string
|
||||
changes. Programmatic assignments remain silent, and reading a field never
|
||||
writes legacy favorites.
|
||||
|
||||
AMS material settings retain their fixed/AMS swatches and first-level popup. Only
|
||||
its custom-color action opens the solid, opaque editor, anchored to that custom
|
||||
control. The transient popup releases its grab while the modal is open and returns
|
||||
to the same selection on cancellation. Confirmation uses the existing default-color
|
||||
and packed RGBA event path. Device permission/status checks remain at the first-level
|
||||
entry.
|
||||
|
||||
Texture import's color-mapping Add Material action opens a solid, opaque editor
|
||||
anchored to the mapping row. The existing filament limit is checked before opening.
|
||||
The first-level material popup closes as an action; its callback is copied before
|
||||
dismissal, so popup destruction does not invalidate the modal's completion path.
|
||||
Confirmation invokes the existing virtual-filament callback once; cancellation
|
||||
adds no material.
|
||||
|
||||
Native gettext strings are installed at document start. Static page labels and
|
||||
palette names use stable English keys; RAL codes, channel symbols, and numeric
|
||||
labels remain data. The palette color values do not depend on the UI language.
|
||||
The application locale also sets the document language. Numeric editor validation
|
||||
uses the application's gettext messages, rather than browser language defaults;
|
||||
missing translations fall back to the stable English keys.
|
||||
|
||||
The pure color/state regressions run with
|
||||
`node --test resources/web/dialog/ColorPickerDialog/colorpicker.test.js`.
|
||||
Optional real-browser regressions live beside them in
|
||||
`colorpicker.browser.test.js`. They use an existing Playwright installation
|
||||
(`ORCA_PLAYWRIGHT_MODULE` can name its module path) and an installed browser
|
||||
(`ORCA_BROWSER_EXECUTABLE` can name its executable), without adding a production
|
||||
dependency. They cover bridge initialization, capability combinations, invalid
|
||||
editor recovery, ordered endpoint alpha, favorites, gettext keys, and live theme
|
||||
changes. These browser checks complement native contract/persistence tests; they
|
||||
do not establish the full native modal confirmation and favorites journey.
|
||||
|
||||
Gradient and alpha capabilities are independent and default off. Unsupported
|
||||
gradients are rejected; disabled alpha normalizes the selected result to opaque.
|
||||
Favorites retain both capabilities independently of the current caller. The page
|
||||
stores alpha as a byte and only converts to percentage when displaying or editing
|
||||
opacity, so switching endpoints does not change alpha precision.
|
||||
|
||||
The page starts disabled. Each document supplies a page identifier in its ready
|
||||
message, receives native initialization, and acknowledges it before native code
|
||||
accepts confirmation or favorite updates. Repeated initialization does not reset
|
||||
edits, and messages from an obsolete document are ignored. Native WebView message
|
||||
handling is deferred and guarded by a lifetime token. Only a validated confirmation
|
||||
sets the optional result. Cancel, Escape and native window close leave it empty.
|
||||
|
||||
Favorites belong to application configuration, separately from the selected result,
|
||||
in the editor configuration returned by `AppConfig::config_path()` under `data_dir()`.
|
||||
The `color_picker` section has string `version` equal to `1` and a `favorites`
|
||||
string containing a JSON array of typed selections. Native helpers normalize and
|
||||
deduplicate this array in order and limit it to 24 entries. Updates replace the
|
||||
entire section and immediately call `AppConfig::save()`, so accepted favorite
|
||||
changes survive cancellation. Empty arrays are saved explicitly. Core `AppConfig`
|
||||
only stores the raw section; color validation belongs to the GUI boundary.
|
||||
|
||||
When the section is absent, valid solid colors from `custom_color_list` are imported
|
||||
once, without changing that legacy section. The legacy native picker saves decimal
|
||||
`r,g,b,a` byte strings; hexadecimal RGB and RGBA strings are also supported. Migration
|
||||
strictly validates all four decimal channels and preserves alpha. Gradient strings
|
||||
and malformed values are ignored. The new version and an empty array are
|
||||
saved even when there is nothing to import. A present section with an unknown or
|
||||
missing version is left untouched and disables favorite writes. Malformed version
|
||||
1 data is displayed as empty and remains on disk until the user explicitly saves
|
||||
a valid replacement. Other configuration sections and project/profile color
|
||||
formats are independent of this storage.
|
||||
|
||||
Interface colors consume the host's `data-orca-theme` and `--orca-*` contract through
|
||||
shared styles. The picker opts into scoped global control roles. Application theme
|
||||
changes update UI surfaces without reloading the page or changing color data.
|
||||
@@ -0,0 +1,66 @@
|
||||
# Focus mode (hiding inactive plates) — High Level Design
|
||||
|
||||
## Purpose and scope
|
||||
|
||||
"Focus mode" is an entry of the canvas menu in the bottom left corner of Prepare. Turned on (eye
|
||||
lit), the 3D view hides the inactive plates and shows the current plate alone, so a project with
|
||||
many plates can be worked on one plate at a time. Turned off, every plate is shown. It is a view
|
||||
setting: it changes nothing in the model, the slice or the project file, and it does not reach
|
||||
plate thumbnails. The choice is kept in the app config as `focus_mode`, off by default.
|
||||
|
||||
Preview needs no such option, as it already draws the current plate alone and has its own plate
|
||||
toolbar. The assembly view and the Design tab do not lay objects out on plates, so the entry is
|
||||
disabled there.
|
||||
|
||||
## What is shown
|
||||
|
||||
The current plate is drawn with its bed, label and icons; the other plates are not drawn at all. The
|
||||
world axes, which Prepare draws at the corner of the first plate, move to the corner of the current
|
||||
plate, where Preview draws them.
|
||||
|
||||
An object instance is shown when its footprint, the XY bounding box of the convex hulls of its
|
||||
volumes, overlaps the current plate, or when it is selected. The test is made per instance, so the
|
||||
parts of an object are shown or hidden together, and a wipe tower follows its plate the same way.
|
||||
It is geometric rather than the plate membership `PartPlateList` keeps, because an instance stays on
|
||||
the plate it was first placed on: an object of another plate that reaches over this one, or one too
|
||||
large for any plate, would otherwise be invisible while it takes room on the current plate. A
|
||||
selected instance stays visible so that what a selection or a gizmo acts on is never hidden, for
|
||||
instance an object picked in the object list on another plate.
|
||||
|
||||
## Hiding
|
||||
|
||||
A hidden object is neither drawn nor picked. `GLCanvas3D::_update_inactive_plates_visibility()`
|
||||
runs at the start of each frame of Prepare. It clears `GLVolume::is_active` on the volumes of the
|
||||
hidden instances and deactivates their raycasters, which every render pass, the hover and rectangle
|
||||
selection, the shadow and center of mass markers already respect. It also deactivates the raycasters
|
||||
of the other plates, whose icons would otherwise still take clicks where nothing is drawn. The state
|
||||
persists between frames, so the raycasts made while handling the mouse, such as the anchor of a pan,
|
||||
see the same scene as the frame.
|
||||
|
||||
Other features clear `is_active` too: gizmos hide the objects they do not edit and show them all
|
||||
again when they close. `GLVolume::on_hidden_plate` records which volumes this update hid, so it only
|
||||
shows again what it hid itself, and it waits for a gizmo that hides objects to close before doing
|
||||
so. A volume another feature made active again is hidden again on the next frame. While Focus mode
|
||||
is off and nothing is left hidden, the update returns at once.
|
||||
|
||||
## Switching plates
|
||||
|
||||
The other plates cannot be clicked while Focus mode hides them, so a compact counterpart of the Preview
|
||||
plate toolbar takes their place: a column of plate thumbnails in the top left corner, below the top
|
||||
toolbar, shown when the project has more than one plate and no gizmo is open. The thumbnails are the
|
||||
ones the Preview toolbar shows (`PartPlate::thumbnail_data`); the canvas rebuilds its textures when
|
||||
`Plater::plate_toolbar_image_version()` changes, a counter each consumer tracks on its own so that the
|
||||
Preview toolbar's dirty flag is left alone. That counter moves after almost every edit, so the
|
||||
thumbnail of the current plate, the only one edited while the others are hidden, is drawn again each
|
||||
time, and the other plates' only once an edit to them has invalidated theirs. The current plate has an
|
||||
accent border, a hovered one the gray border of the Preview toolbar, empty plates are dimmed and the
|
||||
plate number sits in the corner; the tooltip gives the plate name. A click selects the plate and
|
||||
clears the selection, as a click on a plate row of the object list does. The column scrolls when it
|
||||
does not fit above the 3D navigator or the canvas toolbar. Its scrollbar works as the Preview
|
||||
toolbar's, with which it shares its style: it shows only while the mouse is over the column or drags
|
||||
the bar, and the mouse wheel scrolls the column either way.
|
||||
|
||||
Whatever selects a plate while the others are hidden, the camera moves its target over the new plate
|
||||
and keeps its angle, distance and height (`PartPlateList::select_plate()`), so the plate comes into
|
||||
view where the previous one was. A zoom to all plates, as after loading a project or adding a plate,
|
||||
frames the current plate instead. Turning Focus mode on does the same, so the current plate fills the view.
|
||||
@@ -15,8 +15,9 @@ Outlines of centerlines that cross each other overlap at every crossing, which
|
||||
over-extrudes the wall intersections. The line-crossing patterns Grid,
|
||||
Triangles, Tri-hexagon and Cubic therefore build centerlines that never cross
|
||||
(`FillRectilinear::fill_surface_trapezoidal()`), and so do Adaptive Cubic and
|
||||
Support Cubic (`FillAdaptive`); the other patterns outline their usual
|
||||
centerlines.
|
||||
Support Cubic (`FillAdaptive`). 3D Honeycomb skips `multiline_fill()` and draws
|
||||
its N lines itself as parallel copies of each wave, which never cross
|
||||
(`Fill3DHoneycomb`). The other patterns outline their usual centerlines.
|
||||
|
||||
## Non-crossing centerlines
|
||||
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
# Tooltip illustrations
|
||||
|
||||
The texture-displacement panel's tooltips can carry a picture under their text: a still image, or a
|
||||
short animation that loops while the tooltip is open. Several settings in that panel describe a shape
|
||||
rather than a number - what Rotation turns, what Tile repeats, what Invert turns inside out - and a
|
||||
sentence about a shape is read twice and understood once.
|
||||
|
||||
## Where a tooltip is drawn
|
||||
|
||||
`GLGizmoTextureDisplacement::panel_tooltip()` replaces `ImGuiWrapper::tooltip()` throughout the panel.
|
||||
It differs in two ways.
|
||||
|
||||
It places the tooltip beside the panel instead of under the mouse. The panel is pinned to the right
|
||||
edge of the canvas, so a tooltip following the mouse covers the control it is explaining, and one
|
||||
carrying a picture covers most of the panel with it. The tooltip goes to the left of
|
||||
`m_tooltip_anchor_min`/`_max` - the panel's own screen rectangle, or the texture picker's while that
|
||||
popup is up and the tooltip comes from inside it - and to the right only when there is no room on the
|
||||
left. This is the placement the picker popup itself already uses.
|
||||
|
||||
ImGui normally keeps a tooltip glued to the mouse and ignores `SetNextWindowPos()`. Orca's imgui
|
||||
branch honours a position set for a tooltip (see the `ImGuiWindowFlags_Tooltip` branch of `Begin()` in
|
||||
`deps_src/imgui/imgui.cpp`) and still clamps the result inside the canvas, which is what keeps a tall
|
||||
tooltip near the bottom edge on screen.
|
||||
|
||||
It also gives the tooltip a fixed width rather than one derived from its text, because a picture has
|
||||
to be laid out against something, and a column of tooltips that are all one width is steadier to read.
|
||||
|
||||
## Where the pictures live
|
||||
|
||||
`resources/images/texture_displacement/`, as PNG, JPG, BMP or GIF. A tooltip names them by file:
|
||||
|
||||
```cpp
|
||||
hover_tip(_u8L("Repeats the texture across the painted area. ..."),
|
||||
{ { "tile_off.png", _L("Off") }, { "tile_on.png", _L("On") } });
|
||||
```
|
||||
|
||||
Several in one tooltip are laid out side by side at equal widths, which is how a setting is shown as a
|
||||
comparison - the same model at two values of it. The caption under each is translated; the file name
|
||||
is not.
|
||||
|
||||
A file that is missing or will not decode is skipped, and a tooltip whose pictures are all missing is
|
||||
exactly the text tooltip it was before. So the art for a tooltip can land after the tooltip does, and
|
||||
a half-finished set never breaks the panel.
|
||||
|
||||
## When a tooltip appears
|
||||
|
||||
A tooltip waits for the pointer to rest on its control for 0.45 s. The panel is dense and the tooltip
|
||||
lands on the model beside it, so with no wait a sweep from the top of the panel down to Bake flashes a
|
||||
dozen large panels over the scene. Once one has just been up, the wait drops to 0.1 s for 0.7 s
|
||||
afterwards, so reading several settings in a row stays quick - but not to zero, or that same sweep
|
||||
would flash again the moment one tooltip had been seen.
|
||||
|
||||
No tooltip appears at all while a control is being used - a slider dragged, a value typed into one, a
|
||||
combo open, a layer card being dragged. The pointer sits on the very thing being edited, so a tooltip
|
||||
there covers the model exactly while the user is watching it change. The full wait comes back
|
||||
afterwards rather than the short one: having just let go of a slider is not a reason to be shown a
|
||||
picture of it.
|
||||
|
||||
A pointer resting on a control produces no events, and the canvas only renders when something asks it
|
||||
to, so the wait has to ask for its own frames, and so does an animation once one is on screen. So does
|
||||
a tooltip that has just appeared, animated or not: ImGui hides a window on the first frame it is
|
||||
submitted while it measures it, and does so every time a tooltip reappears because those windows are
|
||||
recycled, so the frame a tooltip is decided on is never the frame it is seen on. Both use
|
||||
`GLCanvas3D::request_extra_frame()`, which ends `on_idle()` with `evt.RequestMore()` and so obliges wx
|
||||
to deliver the next idle. `schedule_extra_frame()` is not enough on its own: it only arranges a timer
|
||||
whose event an idle event is assumed to follow, and on_idle renders nothing unless the canvas was
|
||||
already dirty when it ran. Asking for frames as fast as they come is safe here because which frame is
|
||||
drawn comes from the clock, not from the frame count, so a redraw that arrives early simply draws the
|
||||
same frame again.
|
||||
|
||||
## Decoding and playback
|
||||
|
||||
`slic3r/GUI/AnimatedTexture.hpp` decodes a file once and uploads one GL texture per frame. Stills go
|
||||
through `wxImage`; GIFs go through `wxGIFDecoder`, whose raw palette indices are composited here frame
|
||||
by frame, replaying the disposal method each frame asks for. That replay is what makes an animation
|
||||
look continuous: a GIF frame is a sub-rectangle drawn over what came before it, so an animation that
|
||||
only re-sends the pixels that changed draws as a flicker of disconnected patches without it.
|
||||
|
||||
A frame delay of 0 or 1 hundredths of a second is read as 100 ms, the convention browsers settle on,
|
||||
so an animation authored against that plays at the speed it was authored at.
|
||||
|
||||
The animation restarts when its tooltip opens, rather than running off a free-running clock: these are
|
||||
short loops of one setting going from one value to another, and joining one halfway through shows the
|
||||
end of a change the user never saw the start of.
|
||||
|
||||
Which frame is drawn is measured on a real clock, not `ImGui::GetTime()`. Nothing in OrcaSlicer ever sets
|
||||
`io.DeltaTime`, so it keeps imgui's default of 1/60 per frame and imgui's clock counts frames rather
|
||||
than seconds. On a canvas that renders only when asked, that is not a clock at all: an animation driven
|
||||
by it crawls while the canvas is idle and races while a moving mouse is rendering it flat out.
|
||||
|
||||
## Making one
|
||||
|
||||
`scripts/gen_texture_displacement_tips.py` draws the lot, in four languages, picked by what the
|
||||
setting actually is:
|
||||
|
||||
- **A shaded relief**, for the settings that are about a pattern: Depth, Tile, Tile size, Rotation,
|
||||
Repeat/Mirror, Smoothing, Edge fade, Invert, Blend and the Normal, Fast, Checker and Distortion
|
||||
views. One motif - a ring inside a square frame - runs through all of them, because using one shape
|
||||
everywhere is what lets two pictures be compared: whatever differs between them is the setting,
|
||||
since nothing else is.
|
||||
- **A flat mesh of triangles**, for the settings that are about the mesh or about a tool: the paint
|
||||
tools, brush size, the connected-area fill, subdivision, feature-adaptive refinement, remeshing,
|
||||
hard edges, slivers and the wireframe view. These carry the one accent colour in the set, meaning
|
||||
"painted", because that is the only thing in such a picture that is not geometry.
|
||||
- **A section**, for Midlevel and for smoothing the geometry. The reason generalises: shading reads
|
||||
slopes, so a height field moved up or down as a whole shades identically to where it started, and
|
||||
any setting whose meaning is *where the surface sits relative to where it was* is invisible from
|
||||
above and has to be drawn from the side.
|
||||
- **A flat ramp of greys**, for Mix filaments, Mixed colors and Denoise. Those are about which
|
||||
filament a spot ends up as; lighting one would only add a second thing changing between two
|
||||
pictures meant to differ in one.
|
||||
|
||||
The five Mapping pictures are one ball with a checker laid on it five ways, which is the whole of what
|
||||
choosing a projection does - except Unwrap, which is not a projection onto the model at all and so is
|
||||
drawn as the flat layout it produces.
|
||||
|
||||
Captures of the real tool are still the first choice for anything involving a real model or real
|
||||
filament colour: Bake, the mixed-colour count on a photograph, Adjust placement, the frame window and
|
||||
the UV editor's seam tool have no picture yet for that reason.
|
||||
|
||||
Either way:
|
||||
|
||||
- Square, around 256 px (192 for an animation, where every frame ships). The tooltip is about 20 em
|
||||
wide, so that is roughly native size on a 100% display and downscales cleanly above it. A single
|
||||
picture is capped at 10 em tall and centred, two side by side take half the width each.
|
||||
- Neutral grey. These say what a shape does; colour in one reads as a third thing the setting does,
|
||||
and has to work against both themes.
|
||||
- Animations loop seamlessly and stay short - 16 frames at 100 ms, under about 150 KB. They sit in
|
||||
`resources/`, which ships with every copy of the application. A sweep driven by a cosine over the
|
||||
frame count loops with no step, since it starts and ends at the same value and the same rate.
|
||||
- No text in the picture. Captions are translated; pixels are not.
|
||||
@@ -82,6 +82,7 @@ src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoAssembly.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoAssembly.hpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoAlignment.cpp
|
||||
src/slic3r/GUI/GUI.cpp
|
||||
src/slic3r/GUI/GUI_App.cpp
|
||||
src/slic3r/GUI/GUI_AuxiliaryList.cpp
|
||||
@@ -214,6 +215,7 @@ src/libslic3r/GCode.cpp
|
||||
src/libslic3r/GCodeWriter.cpp
|
||||
src/libslic3r/GCode/ToolOrdering.cpp
|
||||
src/libslic3r/GCode/SeamPlacer.cpp
|
||||
src/libslic3r/GCode/GCodeStatistics.cpp
|
||||
src/libslic3r/ExtrusionEntity.cpp
|
||||
src/libslic3r/Flow.cpp
|
||||
src/libslic3r/Format/AMF.cpp
|
||||
@@ -323,6 +325,7 @@ src/slic3r/GUI/BaseTransparentDPIFrame.cpp
|
||||
src/slic3r/GUI/CloneDialog.cpp
|
||||
src/slic3r/GUI/ColorDecomposeDialog.cpp
|
||||
src/slic3r/GUI/ColorDecomposeSupport.cpp
|
||||
src/slic3r/GUI/ColorPickerDialog.cpp
|
||||
src/slic3r/GUI/ConfigWizard.cpp
|
||||
src/slic3r/GUI/DeviceCore/DevCalib.cpp
|
||||
src/slic3r/GUI/DeviceCore/DevUpgrade.cpp
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><line x1="7.5" y1=".5" x2="7.5" y2="2.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><line x1="7.5" y1="6.5" x2="7.5" y2="8.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><line x1="7.5" y1="12.5" x2="7.5" y2="14.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><rect x="5.5" y="2.5" width="4" height="4" style="fill:none; stroke:#009688; stroke-miterlimit:10;"/><rect x="1.5" y="8.5" width="12" height="4" style="fill:none; stroke:#7c8282; stroke-miterlimit:10;"/></svg>
|
||||
|
After Width: | Height: | Size: 684 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><line x1="7.5" y1=".5" x2="7.5" y2="2.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><line x1="7.5" y1="6.5" x2="7.5" y2="8.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><line x1="7.5" y1="12.5" x2="7.5" y2="14.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><rect x="5.5" y="2.5" width="4" height="4" style="fill:none; stroke:#009688; stroke-miterlimit:10;"/><rect x="1.5" y="8.5" width="12" height="4" style="fill:none; stroke:#949494; stroke-miterlimit:10;"/></svg>
|
||||
|
After Width: | Height: | Size: 684 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><rect x="2.5" y="8.5" width="10" height="4" style="fill:none; stroke:#7c8282; stroke-miterlimit:10;"/><line x1="14.5" y1=".5" x2="14.5" y2="14.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><rect x="8.5" y="2.5" width="4" height="4" style="fill:none; stroke:#009688; stroke-miterlimit:10;"/></svg>
|
||||
|
After Width: | Height: | Size: 439 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><rect x="2.5" y="8.5" width="10" height="4" style="fill:none; stroke:#949494; stroke-miterlimit:10;"/><line x1="14.5" y1=".5" x2="14.5" y2="14.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><rect x="8.5" y="2.5" width="4" height="4" style="fill:none; stroke:#009688; stroke-miterlimit:10;"/></svg>
|
||||
|
After Width: | Height: | Size: 439 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><rect x="2.5" y="8.5" width="10" height="4" style="fill:none; stroke:#7c8282; stroke-miterlimit:10;"/><line x1=".5" y1=".5" x2=".5" y2="14.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><rect x="2.5" y="2.5" width="4" height="4" style="fill:none; stroke:#009688; stroke-miterlimit:10;"/></svg>
|
||||
|
After Width: | Height: | Size: 435 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><rect x="2.5" y="8.5" width="10" height="4" style="fill:none; stroke:#949494; stroke-miterlimit:10;"/><line x1=".5" y1=".5" x2=".5" y2="14.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><rect x="2.5" y="2.5" width="4" height="4" style="fill:none; stroke:#009688; stroke-miterlimit:10;"/></svg>
|
||||
|
After Width: | Height: | Size: 435 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><line x1=".5" y1="7.5" x2="2.5" y2="7.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><line x1="6.5" y1="7.5" x2="8.5" y2="7.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><line x1="12.5" y1="7.5" x2="14.5" y2="7.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><rect x="2.5" y="5.5" width="4" height="4" transform="translate(-3 12) rotate(-90)" style="fill:none; stroke:#009688; stroke-miterlimit:10;"/><rect x="5.5" y="5.5" width="10" height="4" transform="translate(3 18) rotate(-90)" style="fill:none; stroke:#7c8282; stroke-miterlimit:10;"/></svg>
|
||||
|
After Width: | Height: | Size: 765 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><line x1=".5" y1="7.5" x2="2.5" y2="7.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><line x1="6.5" y1="7.5" x2="8.5" y2="7.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><line x1="12.5" y1="7.5" x2="14.5" y2="7.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><rect x="2.5" y="5.5" width="4" height="4" transform="translate(-3 12) rotate(-90)" style="fill:none; stroke:#009688; stroke-miterlimit:10;"/><rect x="5.5" y="5.5" width="10" height="4" transform="translate(3 18) rotate(-90)" style="fill:none; stroke:#949494; stroke-miterlimit:10;"/></svg>
|
||||
|
After Width: | Height: | Size: 765 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><line x1=".5" y1=".5" x2="14.5" y2=".5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><rect x="2.5" y="2.5" width="4" height="4" transform="translate(0 9) rotate(-90)" style="fill:none; stroke:#009688; stroke-miterlimit:10;"/><rect x="5.5" y="5.5" width="10" height="4" transform="translate(3 18) rotate(-90)" style="fill:none; stroke:#7c8282; stroke-miterlimit:10;"/></svg>
|
||||
|
After Width: | Height: | Size: 514 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><line x1=".5" y1=".5" x2="14.5" y2=".5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><rect x="2.5" y="2.5" width="4" height="4" transform="translate(0 9) rotate(-90)" style="fill:none; stroke:#009688; stroke-miterlimit:10;"/><rect x="5.5" y="5.5" width="10" height="4" transform="translate(3 18) rotate(-90)" style="fill:none; stroke:#949494; stroke-miterlimit:10;"/></svg>
|
||||
|
After Width: | Height: | Size: 514 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><line x1=".5" y1="14.5" x2="14.5" y2="14.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><rect x="2.5" y="8.5" width="4" height="4" transform="translate(-6 15) rotate(-90)" style="fill:none; stroke:#009688; stroke-miterlimit:10;"/><rect x="5.5" y="5.5" width="10" height="4" transform="translate(3 18) rotate(-90)" style="fill:none; stroke:#7c8282; stroke-miterlimit:10;"/></svg>
|
||||
|
After Width: | Height: | Size: 520 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><line x1=".5" y1="14.5" x2="14.5" y2="14.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><rect x="2.5" y="8.5" width="4" height="4" transform="translate(-6 15) rotate(-90)" style="fill:none; stroke:#009688; stroke-miterlimit:10;"/><rect x="5.5" y="5.5" width="10" height="4" transform="translate(3 18) rotate(-90)" style="fill:none; stroke:#949494; stroke-miterlimit:10;"/></svg>
|
||||
|
After Width: | Height: | Size: 520 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><polygon points="14.5 7.5 7.5 10.5 .5 7.5 7.5 4.5 14.5 7.5" style="fill:none; stroke:#7c8282; stroke-linejoin:round;"/><polyline points="9.5 .5 7.5 2.5 5.5 .5" style="fill:none; stroke:#009688; stroke-linecap:round; stroke-linejoin:round;"/><polyline points="5.5 14.5 7.5 12.5 9.5 14.5" style="fill:none; stroke:#009688; stroke-linecap:round; stroke-linejoin:round;"/></svg>
|
||||
|
After Width: | Height: | Size: 479 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><polygon points="14.5 7.5 7.5 10.5 .5 7.5 7.5 4.5 14.5 7.5" style="fill:none; stroke:#949494; stroke-linejoin:round;"/><polyline points="9.5 .5 7.5 2.5 5.5 .5" style="fill:none; stroke:#009688; stroke-linecap:round; stroke-linejoin:round;"/><polyline points="5.5 14.5 7.5 12.5 9.5 14.5" style="fill:none; stroke:#009688; stroke-linecap:round; stroke-linejoin:round;"/></svg>
|
||||
|
After Width: | Height: | Size: 479 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><polygon points="14.5 3.5 7.5 6.5 .5 3.5 7.5 .5 14.5 3.5" style="fill:none; stroke:#7c8282; stroke-linejoin:round;"/><line x1="7.5" y1="8.5" x2="7.5" y2="14.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><polyline points="5.5 10.5 7.5 8.5 9.5 10.5" style="fill:none; stroke:#009688; stroke-linecap:round; stroke-linejoin:round;"/></svg>
|
||||
|
After Width: | Height: | Size: 478 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><polygon points="14.5 3.5 7.5 6.5 .5 3.5 7.5 .5 14.5 3.5" style="fill:none; stroke:#949494; stroke-linejoin:round;"/><line x1="7.5" y1="8.5" x2="7.5" y2="14.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><polyline points="5.5 10.5 7.5 8.5 9.5 10.5" style="fill:none; stroke:#009688; stroke-linecap:round; stroke-linejoin:round;"/></svg>
|
||||
|
After Width: | Height: | Size: 478 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><polygon points="14.5 11.5 7.5 14.5 .5 11.5 7.5 8.5 14.5 11.5" style="fill:none; stroke:#7c8282; stroke-linejoin:round;"/><line x1="7.5" y1=".5" x2="7.5" y2="6.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><polyline points="9.5 4.5 7.5 6.5 5.5 4.5" style="fill:none; stroke:#009688; stroke-linecap:round; stroke-linejoin:round;"/></svg>
|
||||
|
After Width: | Height: | Size: 479 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><polygon points="14.5 11.5 7.5 14.5 .5 11.5 7.5 8.5 14.5 11.5" style="fill:none; stroke:#949494; stroke-linejoin:round;"/><line x1="7.5" y1=".5" x2="7.5" y2="6.5" style="fill:none; stroke:#009688; stroke-linecap:square; stroke-miterlimit:10;"/><polyline points="9.5 4.5 7.5 6.5 5.5 4.5" style="fill:none; stroke:#009688; stroke-linecap:round; stroke-linejoin:round;"/></svg>
|
||||
|
After Width: | Height: | Size: 479 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><rect x="-2.5" y="5.5" width="10" height="4" transform="translate(-5 10) rotate(-90)" style="fill:none; stroke:#009688; stroke-linejoin:round;"/><rect x="7.5" y="5.5" width="10" height="4" transform="translate(5 20) rotate(-90)" style="fill:none; stroke:#009688; stroke-linejoin:round;"/><line x1="7.5" y1="5.5" x2="7.5" y2="9.5" style="fill:none; stroke:#7c8282; stroke-linecap:square; stroke-miterlimit:10;"/></svg>
|
||||
|
After Width: | Height: | Size: 522 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><rect x="-2.5" y="5.5" width="10" height="4" transform="translate(-5 10) rotate(-90)" style="fill:none; stroke:#009688; stroke-linejoin:round;"/><rect x="7.5" y="5.5" width="10" height="4" transform="translate(5 20) rotate(-90)" style="fill:none; stroke:#009688; stroke-linejoin:round;"/><line x1="7.5" y1="5.5" x2="7.5" y2="9.5" style="fill:none; stroke:#949494; stroke-linecap:square; stroke-miterlimit:10;"/></svg>
|
||||
|
After Width: | Height: | Size: 522 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><rect x="2.5" y=".5" width="10" height="4" style="fill:none; stroke:#009688; stroke-linejoin:round;"/><rect x="2.5" y="10.5" width="10" height="4" style="fill:none; stroke:#009688; stroke-linejoin:round;"/><line x1="9.5" y1="7.5" x2="5.5" y2="7.5" style="fill:none; stroke:#7c8282; stroke-linecap:square; stroke-miterlimit:10;"/></svg>
|
||||
|
After Width: | Height: | Size: 440 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><rect x="2.5" y=".5" width="10" height="4" style="fill:none; stroke:#009688; stroke-linejoin:round;"/><rect x="2.5" y="10.5" width="10" height="4" style="fill:none; stroke:#009688; stroke-linejoin:round;"/><line x1="9.5" y1="7.5" x2="5.5" y2="7.5" style="fill:none; stroke:#949494; stroke-linecap:square; stroke-miterlimit:10;"/></svg>
|
||||
|
After Width: | Height: | Size: 440 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><polygon points="14.5 3.5 7.5 6.5 .5 3.5 7.5 .5 14.5 3.5" style="fill:none; stroke:#009688; stroke-linejoin:round;"/><polyline points="2.83 10.5 .5 11.5 7.5 14.5 14.5 11.5 12.17 10.5" style="fill:none; stroke:#009688; stroke-linejoin:round;"/><polyline points="2.83 6.5 .5 7.5 7.5 10.5 14.5 7.5 12.17 6.5" style="fill:none; stroke:#7c8282; stroke-linejoin:round;"/></svg>
|
||||
|
After Width: | Height: | Size: 476 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><polygon points="14.5 3.5 7.5 6.5 .5 3.5 7.5 .5 14.5 3.5" style="fill:none; stroke:#009688; stroke-linejoin:round;"/><polyline points="2.83 10.5 .5 11.5 7.5 14.5 14.5 11.5 12.17 10.5" style="fill:none; stroke:#009688; stroke-linejoin:round;"/><polyline points="2.83 6.5 .5 7.5 7.5 10.5 14.5 7.5 12.17 6.5" style="fill:none; stroke:#949494; stroke-linejoin:round;"/></svg>
|
||||
|
After Width: | Height: | Size: 476 B |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 107 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 111 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 120 KiB |