mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-13 19:21:50 +08:00
Merge branch 'master' into dev
This commit is contained in:
commit
96e674525d
1
.gitignore
vendored
1
.gitignore
vendored
@ -17,3 +17,4 @@ local-lib
|
|||||||
/.vscode/
|
/.vscode/
|
||||||
build-linux/*
|
build-linux/*
|
||||||
deps/build-linux/*
|
deps/build-linux/*
|
||||||
|
**/.DS_Store
|
||||||
|
@ -478,13 +478,27 @@ find_package(cereal REQUIRED)
|
|||||||
# l10n
|
# l10n
|
||||||
set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/localization")
|
set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/localization")
|
||||||
add_custom_target(gettext_make_pot
|
add_custom_target(gettext_make_pot
|
||||||
COMMAND xgettext --keyword=L --keyword=_L --keyword=_u8L --keyword=L_CONTEXT:1,2c --keyword=_L_PLURAL:1,2 --add-comments=TRN --from-code=UTF-8 --debug
|
COMMAND xgettext --keyword=L --keyword=_L --keyword=_u8L --keyword=L_CONTEXT:1,2c --keyword=_L_PLURAL:1,2 --add-comments=TRN --from-code=UTF-8 --debug --boost
|
||||||
-f "${L10N_DIR}/list.txt"
|
-f "${L10N_DIR}/list.txt"
|
||||||
-o "${L10N_DIR}/PrusaSlicer.pot"
|
-o "${L10N_DIR}/PrusaSlicer.pot"
|
||||||
COMMAND hintsToPot ${SLIC3R_RESOURCES_DIR} ${L10N_DIR}
|
COMMAND hintsToPot ${SLIC3R_RESOURCES_DIR} ${L10N_DIR}
|
||||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||||
COMMENT "Generate pot file from strings in the source tree"
|
COMMENT "Generate pot file from strings in the source tree"
|
||||||
)
|
)
|
||||||
|
add_custom_target(gettext_merge_po_with_pot
|
||||||
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||||
|
COMMENT "Merge localization po with new generted pot file"
|
||||||
|
)
|
||||||
|
file(GLOB L10N_PO_FILES "${L10N_DIR}/*/PrusaSlicer*.po")
|
||||||
|
foreach(po_file ${L10N_PO_FILES})
|
||||||
|
GET_FILENAME_COMPONENT(po_dir "${po_file}" DIRECTORY)
|
||||||
|
SET(po_new_file "${po_dir}/PrusaSlicer_.po")
|
||||||
|
add_custom_command(
|
||||||
|
TARGET gettext_merge_po_with_pot PRE_BUILD
|
||||||
|
COMMAND msgmerge -N -o ${po_file} ${po_file} "${L10N_DIR}/PrusaSlicer.pot"
|
||||||
|
DEPENDS ${po_file}
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
add_custom_target(gettext_po_to_mo
|
add_custom_target(gettext_po_to_mo
|
||||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||||
COMMENT "Generate localization po files (binary) from mo files (texts)"
|
COMMENT "Generate localization po files (binary) from mo files (texts)"
|
||||||
@ -495,7 +509,8 @@ foreach(po_file ${L10N_PO_FILES})
|
|||||||
SET(mo_file "${po_dir}/PrusaSlicer.mo")
|
SET(mo_file "${po_dir}/PrusaSlicer.mo")
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
TARGET gettext_po_to_mo PRE_BUILD
|
TARGET gettext_po_to_mo PRE_BUILD
|
||||||
COMMAND msgfmt ARGS -o ${mo_file} ${po_file}
|
COMMAND msgfmt ARGS --check-format -o ${mo_file} ${po_file}
|
||||||
|
#COMMAND msgfmt ARGS --check-compatibility -o ${mo_file} ${po_file}
|
||||||
DEPENDS ${po_file}
|
DEPENDS ${po_file}
|
||||||
)
|
)
|
||||||
endforeach()
|
endforeach()
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
@ECHO Performs initial build or rebuild of the app (build) and deps (build/deps).
|
@ECHO Performs initial build or rebuild of the app (build) and deps (build/deps).
|
||||||
@ECHO Default options are determined from build directories and system state.
|
@ECHO Default options are determined from build directories and system state.
|
||||||
@ECHO.
|
@ECHO.
|
||||||
@ECHO Usage: build_win [-ARCH ^<arch^>] [-CONFIG ^<config^>] [-DESTDIR ^<directory^>]
|
@ECHO Usage: build_win [-ARCH ^<arch^>] [-CONFIG ^<config^>] [-VERSION ^<version^>]
|
||||||
|
@ECHO [-PRODUCT ^<product^>] [-DESTDIR ^<directory^>]
|
||||||
@ECHO [-STEPS ^<all^|all-dirty^|app^|app-dirty^|deps^|deps-dirty^>]
|
@ECHO [-STEPS ^<all^|all-dirty^|app^|app-dirty^|deps^|deps-dirty^>]
|
||||||
@ECHO [-RUN ^<console^|custom^|none^|viewer^|window^>]
|
@ECHO [-RUN ^<console^|custom^|none^|viewer^|window^>]
|
||||||
@ECHO.
|
@ECHO.
|
||||||
@ -14,6 +15,10 @@
|
|||||||
@ECHO Default: %PS_ARCH_HOST%
|
@ECHO Default: %PS_ARCH_HOST%
|
||||||
@ECHO -c -CONFIG MSVC project config
|
@ECHO -c -CONFIG MSVC project config
|
||||||
@ECHO Default: %PS_CONFIG_DEFAULT%
|
@ECHO Default: %PS_CONFIG_DEFAULT%
|
||||||
|
@ECHO -v -VERSION Major version number of MSVC installation to use for build
|
||||||
|
@ECHO Default: %PS_VERSION_SUPPORTED%
|
||||||
|
@ECHO -p -PRODUCT Product ID of MSVC installation to use for build
|
||||||
|
@ECHO Default: %PS_PRODUCT_DEFAULT%
|
||||||
@ECHO -s -STEPS Performs only the specified build steps:
|
@ECHO -s -STEPS Performs only the specified build steps:
|
||||||
@ECHO all - clean and build deps and app
|
@ECHO all - clean and build deps and app
|
||||||
@ECHO all-dirty - build deps and app without cleaning
|
@ECHO all-dirty - build deps and app without cleaning
|
||||||
@ -55,6 +60,23 @@ SET PS_DEPS_PATH_FILE_NAME=.DEPS_PATH.txt
|
|||||||
SET PS_DEPS_PATH_FILE=%~dp0deps\build\%PS_DEPS_PATH_FILE_NAME%
|
SET PS_DEPS_PATH_FILE=%~dp0deps\build\%PS_DEPS_PATH_FILE_NAME%
|
||||||
SET PS_CONFIG_LIST="Debug;MinSizeRel;Release;RelWithDebInfo"
|
SET PS_CONFIG_LIST="Debug;MinSizeRel;Release;RelWithDebInfo"
|
||||||
|
|
||||||
|
REM The officially supported toolchain version is 16 (Visual Studio 2019)
|
||||||
|
REM TODO: Update versions after Boost gets rolled to 1.78 or later
|
||||||
|
SET PS_VERSION_SUPPORTED=16
|
||||||
|
SET PS_VERSION_EXCEEDED=17
|
||||||
|
SET VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe
|
||||||
|
IF NOT EXIST "%VSWHERE%" SET VSWHERE=%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe
|
||||||
|
FOR /F "tokens=4 USEBACKQ delims=." %%I IN (`"%VSWHERE%" -nologo -property productId`) DO SET PS_PRODUCT_DEFAULT=%%I
|
||||||
|
IF "%PS_PRODUCT_DEFAULT%" EQU "" (
|
||||||
|
SET EXIT_STATUS=-1
|
||||||
|
@ECHO ERROR: No Visual Studio installation found. 1>&2
|
||||||
|
GOTO :HELP
|
||||||
|
)
|
||||||
|
REM Default to the latest supported version if multiple are available
|
||||||
|
FOR /F "tokens=1 USEBACKQ delims=." %%I IN (
|
||||||
|
`^""%VSWHERE%" -version "[%PS_VERSION_SUPPORTED%,%PS_VERSION_EXCEEDED%)" -latest -nologo -property catalog_buildVersion^"`
|
||||||
|
) DO SET PS_VERSION_SUPPORTED=%%I
|
||||||
|
|
||||||
REM Probe build directories and system state for reasonable default arguments
|
REM Probe build directories and system state for reasonable default arguments
|
||||||
pushd %~dp0
|
pushd %~dp0
|
||||||
SET PS_CONFIG=RelWithDebInfo
|
SET PS_CONFIG=RelWithDebInfo
|
||||||
@ -62,6 +84,8 @@ SET PS_ARCH=%PROCESSOR_ARCHITECTURE:amd64=x64%
|
|||||||
CALL :TOLOWER PS_ARCH
|
CALL :TOLOWER PS_ARCH
|
||||||
SET PS_RUN=none
|
SET PS_RUN=none
|
||||||
SET PS_DESTDIR=
|
SET PS_DESTDIR=
|
||||||
|
SET PS_VERSION=
|
||||||
|
SET PS_PRODUCT=%PS_PRODUCT_DEFAULT%
|
||||||
CALL :RESOLVE_DESTDIR_CACHE
|
CALL :RESOLVE_DESTDIR_CACHE
|
||||||
|
|
||||||
REM Set up parameters used by help menu
|
REM Set up parameters used by help menu
|
||||||
@ -75,7 +99,7 @@ SET EXIT_STATUS=1
|
|||||||
SET PS_CURRENT_STEP=arguments
|
SET PS_CURRENT_STEP=arguments
|
||||||
SET PARSER_STATE=
|
SET PARSER_STATE=
|
||||||
SET PARSER_FAIL=
|
SET PARSER_FAIL=
|
||||||
FOR %%I in (%*) DO CALL :PARSE_OPTION "ARCH CONFIG DESTDIR STEPS RUN" PARSER_STATE "%%~I"
|
FOR %%I in (%*) DO CALL :PARSE_OPTION "ARCH CONFIG DESTDIR STEPS RUN VERSION PRODUCT" PARSER_STATE "%%~I"
|
||||||
IF "%PARSER_FAIL%" NEQ "" (
|
IF "%PARSER_FAIL%" NEQ "" (
|
||||||
@ECHO ERROR: Invalid switch: %PARSER_FAIL% 1>&2
|
@ECHO ERROR: Invalid switch: %PARSER_FAIL% 1>&2
|
||||||
GOTO :HELP
|
GOTO :HELP
|
||||||
@ -124,6 +148,15 @@ IF "%PS_RUN%" NEQ "none" IF "%PS_STEPS:~0,4%" EQU "deps" (
|
|||||||
@ECHO ERROR: RUN=none is the only valid option for STEPS "deps" or "deps-dirty"
|
@ECHO ERROR: RUN=none is the only valid option for STEPS "deps" or "deps-dirty"
|
||||||
GOTO :HELP
|
GOTO :HELP
|
||||||
)
|
)
|
||||||
|
IF DEFINED PS_VERSION (
|
||||||
|
SET /A PS_VERSION_EXCEEDED=%PS_VERSION% + 1
|
||||||
|
) ELSE SET PS_VERSION=%PS_VERSION_SUPPORTED%
|
||||||
|
SET MSVC_FILTER=-products Microsoft.VisualStudio.Product.%PS_PRODUCT% -version "[%PS_VERSION%,%PS_VERSION_EXCEEDED%)"
|
||||||
|
FOR /F "tokens=* USEBACKQ" %%I IN (`^""%VSWHERE%" %MSVC_FILTER% -nologo -property installationPath^"`) DO SET MSVC_DIR=%%I
|
||||||
|
IF NOT EXIST "%MSVC_DIR%" (
|
||||||
|
@ECHO ERROR: Compatible Visual Studio installation not found. 1>&2
|
||||||
|
GOTO :HELP
|
||||||
|
)
|
||||||
REM Give the user a chance to cancel if we found something odd.
|
REM Give the user a chance to cancel if we found something odd.
|
||||||
IF "%PS_ASK_TO_CONTINUE%" EQU "" GOTO :BUILD_ENV
|
IF "%PS_ASK_TO_CONTINUE%" EQU "" GOTO :BUILD_ENV
|
||||||
@ECHO.
|
@ECHO.
|
||||||
@ -142,9 +175,6 @@ SET PS_CURRENT_STEP=environment
|
|||||||
@ECHO ** Run App: %PS_RUN%
|
@ECHO ** Run App: %PS_RUN%
|
||||||
@ECHO ** Deps path: %PS_DESTDIR%
|
@ECHO ** Deps path: %PS_DESTDIR%
|
||||||
@ECHO ** Using Microsoft Visual Studio installation found at:
|
@ECHO ** Using Microsoft Visual Studio installation found at:
|
||||||
SET VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe
|
|
||||||
IF NOT EXIST "%VSWHERE%" SET VSWHERE=%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe
|
|
||||||
FOR /F "tokens=* USEBACKQ" %%I IN (`"%VSWHERE%" -nologo -property installationPath`) DO SET MSVC_DIR=%%I
|
|
||||||
@ECHO ** %MSVC_DIR%
|
@ECHO ** %MSVC_DIR%
|
||||||
CALL "%MSVC_DIR%\Common7\Tools\vsdevcmd.bat" -arch=%PS_ARCH% -host_arch=%PS_ARCH_HOST% -app_platform=Desktop
|
CALL "%MSVC_DIR%\Common7\Tools\vsdevcmd.bat" -arch=%PS_ARCH% -host_arch=%PS_ARCH_HOST% -app_platform=Desktop
|
||||||
IF %ERRORLEVEL% NEQ 0 GOTO :END
|
IF %ERRORLEVEL% NEQ 0 GOTO :END
|
||||||
@ -276,7 +306,7 @@ REM Functions and stubs start here.
|
|||||||
SET PS_DEPS_PATH_FILE_FOR_CONFIG=%~dp0build\.vs\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME%
|
SET PS_DEPS_PATH_FILE_FOR_CONFIG=%~dp0build\.vs\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME%
|
||||||
mkdir "%~dp0build\.vs\%PS_ARCH%\%PS_CONFIG%" > nul 2> nul
|
mkdir "%~dp0build\.vs\%PS_ARCH%\%PS_CONFIG%" > nul 2> nul
|
||||||
REM Copy a legacy file if we don't have one in the proper location.
|
REM Copy a legacy file if we don't have one in the proper location.
|
||||||
echo f|xcopy /D "%~dp0build\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME%" "%PS_DEPS_PATH_FILE_FOR_CONFIG%"
|
echo f|xcopy /D "%~dp0build\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME%" "%PS_DEPS_PATH_FILE_FOR_CONFIG%" > nul 2> nul
|
||||||
CALL :CANONICALIZE_PATH PS_DEPS_PATH_FILE_FOR_CONFIG
|
CALL :CANONICALIZE_PATH PS_DEPS_PATH_FILE_FOR_CONFIG
|
||||||
IF EXIST "%PS_DEPS_PATH_FILE_FOR_CONFIG%" (
|
IF EXIST "%PS_DEPS_PATH_FILE_FOR_CONFIG%" (
|
||||||
FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE_FOR_CONFIG%") DO (
|
FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE_FOR_CONFIG%") DO (
|
||||||
|
2
deps/wxWidgets/wxWidgets.cmake
vendored
2
deps/wxWidgets/wxWidgets.cmake
vendored
@ -13,7 +13,7 @@ prusaslicer_add_cmake_project(wxWidgets
|
|||||||
# GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets"
|
# GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets"
|
||||||
# GIT_TAG tm_cross_compile #${_wx_git_tag}
|
# GIT_TAG tm_cross_compile #${_wx_git_tag}
|
||||||
URL https://github.com/prusa3d/wxWidgets/archive/refs/heads/v3.1.4-patched.zip
|
URL https://github.com/prusa3d/wxWidgets/archive/refs/heads/v3.1.4-patched.zip
|
||||||
URL_HASH SHA256=ed36a2159c781cce07b06378664e683ebd8cb2f51914aba9acd3bfca3d63d7d3
|
URL_HASH SHA256=78adc312e645d738945172d5ddcee16b1a55cca08e82b43379192262377a206a
|
||||||
DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG
|
DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG
|
||||||
CMAKE_ARGS
|
CMAKE_ARGS
|
||||||
-DwxBUILD_PRECOMP=ON
|
-DwxBUILD_PRECOMP=ON
|
||||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -89,6 +89,7 @@ src/libslic3r/Flow.cpp
|
|||||||
src/libslic3r/Format/3mf.cpp
|
src/libslic3r/Format/3mf.cpp
|
||||||
src/libslic3r/Format/AMF.cpp
|
src/libslic3r/Format/AMF.cpp
|
||||||
src/libslic3r/miniz_extension.cpp
|
src/libslic3r/miniz_extension.cpp
|
||||||
|
src/libslic3r/PostProcessor.cpp
|
||||||
src/libslic3r/Preset.cpp
|
src/libslic3r/Preset.cpp
|
||||||
src/libslic3r/Print.cpp
|
src/libslic3r/Print.cpp
|
||||||
src/libslic3r/SLA/Pad.cpp
|
src/libslic3r/SLA/Pad.cpp
|
||||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
resources/localization/pt_BR/PrusaSlicer.mo
Normal file
BIN
resources/localization/pt_BR/PrusaSlicer.mo
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
resources/localization/zh_CN/PrusaSlicer.mo
Normal file
BIN
resources/localization/zh_CN/PrusaSlicer.mo
Normal file
Binary file not shown.
14950
resources/localization/zh_CN/PrusaSlicer_zh_CN.po
Normal file
14950
resources/localization/zh_CN/PrusaSlicer_zh_CN.po
Normal file
File diff suppressed because it is too large
Load Diff
BIN
resources/localization/zh_TW/PrusaSlicer.mo
Normal file
BIN
resources/localization/zh_TW/PrusaSlicer.mo
Normal file
Binary file not shown.
15906
resources/localization/zh_TW/PrusaSlicer_zh_TW.po
Normal file
15906
resources/localization/zh_TW/PrusaSlicer_zh_TW.po
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -498,7 +498,7 @@ Point SeamPlacer::calculate_seam(const Layer& layer, const SeamPosition seam_pos
|
|||||||
else if (seam_position == spRear) {
|
else if (seam_position == spRear) {
|
||||||
// Object is centered around (0,0) in its current coordinate system.
|
// Object is centered around (0,0) in its current coordinate system.
|
||||||
last_pos.x() = 0;
|
last_pos.x() = 0;
|
||||||
last_pos.y() += coord_t(3. * po->bounding_box().radius());
|
last_pos.y() = coord_t(3. * po->bounding_box().radius());
|
||||||
last_pos_weight = 5.f;
|
last_pos_weight = 5.f;
|
||||||
} if (seam_position == spNearest) {
|
} if (seam_position == spNearest) {
|
||||||
// last_pos already contains current nozzle position
|
// last_pos already contains current nozzle position
|
||||||
|
@ -92,6 +92,25 @@ void Layer::restore_untyped_slices()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Similar to Layer::restore_untyped_slices()
|
||||||
|
// To improve robustness of detect_surfaces_type() when reslicing (working with typed slices), see GH issue #7442.
|
||||||
|
// Only resetting layerm->slices if Slice::extra_perimeters is always zero or it will not be used anymore
|
||||||
|
// after the perimeter generator.
|
||||||
|
void Layer::restore_untyped_slices_no_extra_perimeters()
|
||||||
|
{
|
||||||
|
if (layer_needs_raw_backup(this)) {
|
||||||
|
for (LayerRegion *layerm : m_regions)
|
||||||
|
if (! layerm->region().config().extra_perimeters.value)
|
||||||
|
layerm->slices.set(layerm->raw_slices, stInternal);
|
||||||
|
} else {
|
||||||
|
assert(m_regions.size() == 1);
|
||||||
|
LayerRegion *layerm = m_regions.front();
|
||||||
|
// This optimization is correct, as extra_perimeters are only reused by prepare_infill() with multi-regions.
|
||||||
|
//if (! layerm->region().config().extra_perimeters.value)
|
||||||
|
layerm->slices.set(this->lslices, stInternal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ExPolygons Layer::merged(float offset_scaled) const
|
ExPolygons Layer::merged(float offset_scaled) const
|
||||||
{
|
{
|
||||||
assert(offset_scaled >= 0.f);
|
assert(offset_scaled >= 0.f);
|
||||||
@ -179,7 +198,7 @@ void Layer::make_perimeters()
|
|||||||
// group slices (surfaces) according to number of extra perimeters
|
// group slices (surfaces) according to number of extra perimeters
|
||||||
std::map<unsigned short, Surfaces> slices; // extra_perimeters => [ surface, surface... ]
|
std::map<unsigned short, Surfaces> slices; // extra_perimeters => [ surface, surface... ]
|
||||||
for (LayerRegion *layerm : layerms) {
|
for (LayerRegion *layerm : layerms) {
|
||||||
for (Surface &surface : layerm->slices.surfaces)
|
for (const Surface &surface : layerm->slices.surfaces)
|
||||||
slices[surface.extra_perimeters].emplace_back(surface);
|
slices[surface.extra_perimeters].emplace_back(surface);
|
||||||
if (layerm->region().config().fill_density > layerm_config->region().config().fill_density)
|
if (layerm->region().config().fill_density > layerm_config->region().config().fill_density)
|
||||||
layerm_config = layerm;
|
layerm_config = layerm;
|
||||||
|
@ -137,6 +137,8 @@ public:
|
|||||||
//FIXME Review whether not to simplify the code by keeping the raw_slices all the time.
|
//FIXME Review whether not to simplify the code by keeping the raw_slices all the time.
|
||||||
void backup_untyped_slices();
|
void backup_untyped_slices();
|
||||||
void restore_untyped_slices();
|
void restore_untyped_slices();
|
||||||
|
// To improve robustness of detect_surfaces_type() when reslicing (working with typed slices), see GH issue #7442.
|
||||||
|
void restore_untyped_slices_no_extra_perimeters();
|
||||||
// Slices merged into islands, to be used by the elephant foot compensation to trim the individual surfaces with the shrunk merged slices.
|
// Slices merged into islands, to be used by the elephant foot compensation to trim the individual surfaces with the shrunk merged slices.
|
||||||
ExPolygons merged(float offset) const;
|
ExPolygons merged(float offset) const;
|
||||||
template <class T> bool any_internal_region_slice_contains(const T &item) const {
|
template <class T> bool any_internal_region_slice_contains(const T &item) const {
|
||||||
|
@ -51,8 +51,7 @@ void LayerRegion::slices_to_fill_surfaces_clipped()
|
|||||||
// so we're safe. This guarantees idempotence of prepare_infill() also in case
|
// so we're safe. This guarantees idempotence of prepare_infill() also in case
|
||||||
// that combine_infill() turns some fill_surface into VOID surfaces.
|
// that combine_infill() turns some fill_surface into VOID surfaces.
|
||||||
// Collect polygons per surface type.
|
// Collect polygons per surface type.
|
||||||
std::vector<SurfacesPtr> by_surface;
|
std::array<SurfacesPtr, size_t(stCount)> by_surface;
|
||||||
by_surface.assign(size_t(stCount), SurfacesPtr());
|
|
||||||
for (Surface &surface : this->slices.surfaces)
|
for (Surface &surface : this->slices.surfaces)
|
||||||
by_surface[size_t(surface.surface_type)].emplace_back(&surface);
|
by_surface[size_t(surface.surface_type)].emplace_back(&surface);
|
||||||
// Trim surfaces by the fill_boundaries.
|
// Trim surfaces by the fill_boundaries.
|
||||||
|
@ -1210,6 +1210,7 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->tooltip = L("When printing with very low layer heights, you might still want to print a thicker "
|
def->tooltip = L("When printing with very low layer heights, you might still want to print a thicker "
|
||||||
"bottom layer to improve adhesion and tolerance for non perfect build plates.");
|
"bottom layer to improve adhesion and tolerance for non perfect build plates.");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
|
def->min = 0;
|
||||||
def->ratio_over = "layer_height";
|
def->ratio_over = "layer_height";
|
||||||
def->set_default_value(new ConfigOptionFloatOrPercent(0.35, false));
|
def->set_default_value(new ConfigOptionFloatOrPercent(0.35, false));
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "Geometry.hpp"
|
#include "Geometry.hpp"
|
||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
#include "Layer.hpp"
|
#include "Layer.hpp"
|
||||||
|
#include "MutablePolygon.hpp"
|
||||||
#include "SupportMaterial.hpp"
|
#include "SupportMaterial.hpp"
|
||||||
#include "Surface.hpp"
|
#include "Surface.hpp"
|
||||||
#include "Slicing.hpp"
|
#include "Slicing.hpp"
|
||||||
@ -226,6 +227,17 @@ void PrintObject::prepare_infill()
|
|||||||
|
|
||||||
m_print->set_status(30, L("Preparing infill"));
|
m_print->set_status(30, L("Preparing infill"));
|
||||||
|
|
||||||
|
if (m_typed_slices) {
|
||||||
|
// To improve robustness of detect_surfaces_type() when reslicing (working with typed slices), see GH issue #7442.
|
||||||
|
// The preceding step (perimeter generator) only modifies extra_perimeters and the extra perimeters are only used by discover_vertical_shells()
|
||||||
|
// with more than a single region. If this step does not use Surface::extra_perimeters or Surface::extra_perimeters is always zero, it is safe
|
||||||
|
// to reset to the untyped slices before re-runnning detect_surfaces_type().
|
||||||
|
for (Layer* layer : m_layers) {
|
||||||
|
layer->restore_untyped_slices_no_extra_perimeters();
|
||||||
|
m_print->throw_if_canceled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This will assign a type (top/bottom/internal) to $layerm->slices.
|
// This will assign a type (top/bottom/internal) to $layerm->slices.
|
||||||
// Then the classifcation of $layerm->slices is transfered onto
|
// Then the classifcation of $layerm->slices is transfered onto
|
||||||
// the $layerm->fill_surfaces by clipping $layerm->fill_surfaces
|
// the $layerm->fill_surfaces by clipping $layerm->fill_surfaces
|
||||||
@ -1709,9 +1721,6 @@ void PrintObject::clip_fill_surfaces()
|
|||||||
Layer *layer = m_layers[layer_id];
|
Layer *layer = m_layers[layer_id];
|
||||||
Layer *lower_layer = m_layers[layer_id - 1];
|
Layer *lower_layer = m_layers[layer_id - 1];
|
||||||
// Detect things that we need to support.
|
// Detect things that we need to support.
|
||||||
// Cummulative slices.
|
|
||||||
Polygons slices;
|
|
||||||
polygons_append(slices, layer->lslices);
|
|
||||||
// Cummulative fill surfaces.
|
// Cummulative fill surfaces.
|
||||||
Polygons fill_surfaces;
|
Polygons fill_surfaces;
|
||||||
// Solid surfaces to be supported.
|
// Solid surfaces to be supported.
|
||||||
@ -1736,7 +1745,7 @@ void PrintObject::clip_fill_surfaces()
|
|||||||
{
|
{
|
||||||
// Get perimeters area as the difference between slices and fill_surfaces
|
// Get perimeters area as the difference between slices and fill_surfaces
|
||||||
// Only consider the area that is not supported by lower perimeters
|
// Only consider the area that is not supported by lower perimeters
|
||||||
Polygons perimeters = intersection(diff(slices, fill_surfaces), lower_layer_fill_surfaces);
|
Polygons perimeters = intersection(diff(layer->lslices, fill_surfaces), lower_layer_fill_surfaces);
|
||||||
// Only consider perimeter areas that are at least one extrusion width thick.
|
// Only consider perimeter areas that are at least one extrusion width thick.
|
||||||
//FIXME Offset2 eats out from both sides, while the perimeters are create outside in.
|
//FIXME Offset2 eats out from both sides, while the perimeters are create outside in.
|
||||||
//Should the pw not be half of the current value?
|
//Should the pw not be half of the current value?
|
||||||
@ -1746,9 +1755,15 @@ void PrintObject::clip_fill_surfaces()
|
|||||||
// Append such thick perimeters to the areas that need support
|
// Append such thick perimeters to the areas that need support
|
||||||
polygons_append(overhangs, opening(perimeters, pw));
|
polygons_append(overhangs, opening(perimeters, pw));
|
||||||
}
|
}
|
||||||
// Find new internal infill.
|
// Merge the new overhangs, find new internal infill.
|
||||||
polygons_append(overhangs, std::move(upper_internal));
|
polygons_append(upper_internal, std::move(overhangs));
|
||||||
upper_internal = intersection(overhangs, lower_layer_internal_surfaces);
|
static constexpr const auto closing_radius = scaled<float>(2.f);
|
||||||
|
upper_internal = intersection(
|
||||||
|
// Regularize the overhang regions, so that the infill areas will not become excessively jagged.
|
||||||
|
smooth_outward(
|
||||||
|
closing(upper_internal, closing_radius, ClipperLib::jtSquare, 0.),
|
||||||
|
scaled<coord_t>(0.1)),
|
||||||
|
lower_layer_internal_surfaces);
|
||||||
// Apply new internal infill to regions.
|
// Apply new internal infill to regions.
|
||||||
for (LayerRegion *layerm : lower_layer->m_regions) {
|
for (LayerRegion *layerm : lower_layer->m_regions) {
|
||||||
if (layerm->region().config().fill_density.value == 0)
|
if (layerm->region().config().fill_density.value == 0)
|
||||||
|
@ -358,8 +358,9 @@ void TriangleSelector::precompute_all_neighbors_recursive(const int facet_idx, c
|
|||||||
assert(tr->children[i] < int(m_triangles.size()));
|
assert(tr->children[i] < int(m_triangles.size()));
|
||||||
// Recursion, deep first search over the children of this triangle.
|
// Recursion, deep first search over the children of this triangle.
|
||||||
// All children of this triangle were created by splitting a single source triangle of the original mesh.
|
// All children of this triangle were created by splitting a single source triangle of the original mesh.
|
||||||
this->precompute_all_neighbors_recursive(tr->children[i], this->child_neighbors(*tr, neighbors, i),
|
const Vec3i child_neighbors = this->child_neighbors(*tr, neighbors, i);
|
||||||
this->child_neighbors_propagated(*tr, neighbors_propagated, i), neighbors_out,
|
this->precompute_all_neighbors_recursive(tr->children[i], child_neighbors,
|
||||||
|
this->child_neighbors_propagated(*tr, neighbors_propagated, i, child_neighbors), neighbors_out,
|
||||||
neighbors_propagated_out);
|
neighbors_propagated_out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -784,33 +785,29 @@ Vec3i TriangleSelector::child_neighbors(const Triangle &tr, const Vec3i &neighbo
|
|||||||
|
|
||||||
// Return neighbors of the ith child of a triangle given neighbors of the triangle.
|
// Return neighbors of the ith child of a triangle given neighbors of the triangle.
|
||||||
// If such a neighbor doesn't exist, return the neighbor from the previous depth.
|
// If such a neighbor doesn't exist, return the neighbor from the previous depth.
|
||||||
Vec3i TriangleSelector::child_neighbors_propagated(const Triangle &tr, const Vec3i &neighbors, int child_idx) const
|
Vec3i TriangleSelector::child_neighbors_propagated(const Triangle &tr, const Vec3i &neighbors_propagated, int child_idx, const Vec3i &child_neighbors) const
|
||||||
{
|
{
|
||||||
int i = tr.special_side();
|
int i = tr.special_side();
|
||||||
int j = next_idx_modulo(i, 3);
|
int j = next_idx_modulo(i, 3);
|
||||||
int k = next_idx_modulo(j, 3);
|
int k = next_idx_modulo(j, 3);
|
||||||
|
|
||||||
Vec3i out;
|
Vec3i out = child_neighbors;
|
||||||
auto replace_if_not_exists = [&out](int index_to_replace, int neighbor) {
|
auto replace_if_not_exists = [&out, &neighbors_propagated](int index_to_replace, int neighbor_idx) {
|
||||||
if (out(index_to_replace) == -1)
|
if (out(index_to_replace) == -1)
|
||||||
out(index_to_replace) = neighbor;
|
out(index_to_replace) = neighbors_propagated(neighbor_idx);
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (tr.number_of_split_sides()) {
|
switch (tr.number_of_split_sides()) {
|
||||||
case 1:
|
case 1:
|
||||||
switch (child_idx) {
|
switch (child_idx) {
|
||||||
case 0:
|
case 0:
|
||||||
out(0) = neighbors(i);
|
replace_if_not_exists(0, i);
|
||||||
out(1) = this->neighbor_child(neighbors(j), tr.verts_idxs[k], tr.verts_idxs[j], Partition::Second);
|
replace_if_not_exists(1, j);
|
||||||
replace_if_not_exists(1, neighbors(j));
|
|
||||||
out(2) = tr.children[1];
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(child_idx == 1);
|
assert(child_idx == 1);
|
||||||
out(0) = this->neighbor_child(neighbors(j), tr.verts_idxs[k], tr.verts_idxs[j], Partition::First);
|
replace_if_not_exists(0, j);
|
||||||
replace_if_not_exists(0, neighbors(j));
|
replace_if_not_exists(1, k);
|
||||||
out(1) = neighbors(k);
|
|
||||||
out(2) = tr.children[0];
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -818,25 +815,17 @@ Vec3i TriangleSelector::child_neighbors_propagated(const Triangle &tr, const Vec
|
|||||||
case 2:
|
case 2:
|
||||||
switch (child_idx) {
|
switch (child_idx) {
|
||||||
case 0:
|
case 0:
|
||||||
out(0) = this->neighbor_child(neighbors(i), tr.verts_idxs[j], tr.verts_idxs[i], Partition::Second);
|
replace_if_not_exists(0, i);
|
||||||
replace_if_not_exists(0, neighbors(i));
|
replace_if_not_exists(2, k);
|
||||||
out(1) = tr.children[1];
|
|
||||||
out(2) = this->neighbor_child(neighbors(k), tr.verts_idxs[i], tr.verts_idxs[k], Partition::First);
|
|
||||||
replace_if_not_exists(2, neighbors(k));
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
assert(child_idx == 1);
|
assert(child_idx == 1);
|
||||||
out(0) = this->neighbor_child(neighbors(i), tr.verts_idxs[j], tr.verts_idxs[i], Partition::First);
|
replace_if_not_exists(0, i);
|
||||||
replace_if_not_exists(0, neighbors(i));
|
|
||||||
out(1) = tr.children[2];
|
|
||||||
out(2) = tr.children[0];
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(child_idx == 2);
|
assert(child_idx == 2);
|
||||||
out(0) = neighbors(j);
|
replace_if_not_exists(0, j);
|
||||||
out(1) = this->neighbor_child(neighbors(k), tr.verts_idxs[i], tr.verts_idxs[k], Partition::Second);
|
replace_if_not_exists(1, k);
|
||||||
replace_if_not_exists(1, neighbors(k));
|
|
||||||
out(2) = tr.children[1];
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -845,31 +834,19 @@ Vec3i TriangleSelector::child_neighbors_propagated(const Triangle &tr, const Vec
|
|||||||
assert(tr.special_side() == 0);
|
assert(tr.special_side() == 0);
|
||||||
switch (child_idx) {
|
switch (child_idx) {
|
||||||
case 0:
|
case 0:
|
||||||
out(0) = this->neighbor_child(neighbors(0), tr.verts_idxs[1], tr.verts_idxs[0], Partition::Second);
|
replace_if_not_exists(0, 0);
|
||||||
replace_if_not_exists(0, neighbors(0));
|
replace_if_not_exists(2, 2);
|
||||||
out(1) = tr.children[3];
|
|
||||||
out(2) = this->neighbor_child(neighbors(2), tr.verts_idxs[0], tr.verts_idxs[2], Partition::First);
|
|
||||||
replace_if_not_exists(2, neighbors(2));
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
out(0) = this->neighbor_child(neighbors(0), tr.verts_idxs[1], tr.verts_idxs[0], Partition::First);
|
replace_if_not_exists(0, 0);
|
||||||
replace_if_not_exists(0, neighbors(0));
|
replace_if_not_exists(1, 1);
|
||||||
out(1) = this->neighbor_child(neighbors(1), tr.verts_idxs[2], tr.verts_idxs[1], Partition::Second);
|
|
||||||
replace_if_not_exists(1, neighbors(1));
|
|
||||||
out(2) = tr.children[3];
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
out(0) = this->neighbor_child(neighbors(1), tr.verts_idxs[2], tr.verts_idxs[1], Partition::First);
|
replace_if_not_exists(0, 1);
|
||||||
replace_if_not_exists(0, neighbors(1));
|
replace_if_not_exists(1, 2);
|
||||||
out(1) = this->neighbor_child(neighbors(2), tr.verts_idxs[0], tr.verts_idxs[2], Partition::Second);
|
|
||||||
replace_if_not_exists(1, neighbors(2));
|
|
||||||
out(2) = tr.children[3];
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(child_idx == 3);
|
assert(child_idx == 3);
|
||||||
out(0) = tr.children[1];
|
|
||||||
out(1) = tr.children[2];
|
|
||||||
out(2) = tr.children[0];
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1527,7 +1504,9 @@ void TriangleSelector::get_seed_fill_contour_recursive(const int facet_idx, cons
|
|||||||
assert(tr->children[i] < int(m_triangles.size()));
|
assert(tr->children[i] < int(m_triangles.size()));
|
||||||
// Recursion, deep first search over the children of this triangle.
|
// Recursion, deep first search over the children of this triangle.
|
||||||
// All children of this triangle were created by splitting a single source triangle of the original mesh.
|
// All children of this triangle were created by splitting a single source triangle of the original mesh.
|
||||||
this->get_seed_fill_contour_recursive(tr->children[i], this->child_neighbors(*tr, neighbors, i), this->child_neighbors_propagated(*tr, neighbors_propagated, i), edges_out);
|
const Vec3i child_neighbors = this->child_neighbors(*tr, neighbors, i);
|
||||||
|
this->get_seed_fill_contour_recursive(tr->children[i], child_neighbors,
|
||||||
|
this->child_neighbors_propagated(*tr, neighbors_propagated, i, child_neighbors), edges_out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (tr->is_selected_by_seed_fill()) {
|
} else if (tr->is_selected_by_seed_fill()) {
|
||||||
|
@ -349,7 +349,7 @@ private:
|
|||||||
int push_triangle(int a, int b, int c, int source_triangle, EnforcerBlockerType state = EnforcerBlockerType{0});
|
int push_triangle(int a, int b, int c, int source_triangle, EnforcerBlockerType state = EnforcerBlockerType{0});
|
||||||
void perform_split(int facet_idx, const Vec3i &neighbors, EnforcerBlockerType old_state);
|
void perform_split(int facet_idx, const Vec3i &neighbors, EnforcerBlockerType old_state);
|
||||||
Vec3i child_neighbors(const Triangle &tr, const Vec3i &neighbors, int child_idx) const;
|
Vec3i child_neighbors(const Triangle &tr, const Vec3i &neighbors, int child_idx) const;
|
||||||
Vec3i child_neighbors_propagated(const Triangle &tr, const Vec3i &neighbors, int child_idx) const;
|
Vec3i child_neighbors_propagated(const Triangle &tr, const Vec3i &neighbors_propagated, int child_idx, const Vec3i &child_neighbors) const;
|
||||||
// Return child of itriangle at a CCW oriented side (vertexi, vertexj), either first or 2nd part.
|
// Return child of itriangle at a CCW oriented side (vertexi, vertexj), either first or 2nd part.
|
||||||
// If itriangle == -1 or if the side sharing (vertexi, vertexj) is not split, return -1.
|
// If itriangle == -1 or if the side sharing (vertexi, vertexj) is not split, return -1.
|
||||||
enum class Partition {
|
enum class Partition {
|
||||||
|
@ -47,8 +47,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
|||||||
if (config->opt_float("layer_height") < EPSILON)
|
if (config->opt_float("layer_height") < EPSILON)
|
||||||
{
|
{
|
||||||
const wxString msg_text = _(L("Layer height is not valid.\n\nThe layer height will be reset to 0.01."));
|
const wxString msg_text = _(L("Layer height is not valid.\n\nThe layer height will be reset to 0.01."));
|
||||||
//wxMessageDialog dialog(nullptr, msg_text, _(L("Layer height")), wxICON_WARNING | wxOK);
|
MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Layer height")), wxICON_WARNING | wxOK);
|
||||||
MessageDialog dialog(nullptr, msg_text, _(L("Layer height")), wxICON_WARNING | wxOK);
|
|
||||||
DynamicPrintConfig new_conf = *config;
|
DynamicPrintConfig new_conf = *config;
|
||||||
is_msg_dlg_already_exist = true;
|
is_msg_dlg_already_exist = true;
|
||||||
dialog.ShowModal();
|
dialog.ShowModal();
|
||||||
@ -60,8 +59,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
|||||||
if (config->option<ConfigOptionFloatOrPercent>("first_layer_height")->value < EPSILON)
|
if (config->option<ConfigOptionFloatOrPercent>("first_layer_height")->value < EPSILON)
|
||||||
{
|
{
|
||||||
const wxString msg_text = _(L("First layer height is not valid.\n\nThe first layer height will be reset to 0.01."));
|
const wxString msg_text = _(L("First layer height is not valid.\n\nThe first layer height will be reset to 0.01."));
|
||||||
//wxMessageDialog dialog(nullptr, msg_text, _(L("First layer height")), wxICON_WARNING | wxOK);
|
MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("First layer height")), wxICON_WARNING | wxOK);
|
||||||
MessageDialog dialog(nullptr, msg_text, _(L("First layer height")), wxICON_WARNING | wxOK);
|
|
||||||
DynamicPrintConfig new_conf = *config;
|
DynamicPrintConfig new_conf = *config;
|
||||||
is_msg_dlg_already_exist = true;
|
is_msg_dlg_already_exist = true;
|
||||||
dialog.ShowModal();
|
dialog.ShowModal();
|
||||||
@ -90,8 +88,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
|||||||
"- Detect thin walls disabled"));
|
"- Detect thin walls disabled"));
|
||||||
if (is_global_config)
|
if (is_global_config)
|
||||||
msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable Spiral Vase?"));
|
msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable Spiral Vase?"));
|
||||||
//wxMessageDialog dialog(nullptr, msg_text, _(L("Spiral Vase")),
|
MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Spiral Vase")),
|
||||||
MessageDialog dialog(nullptr, msg_text, _(L("Spiral Vase")),
|
|
||||||
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
|
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
|
||||||
DynamicPrintConfig new_conf = *config;
|
DynamicPrintConfig new_conf = *config;
|
||||||
auto answer = dialog.ShowModal();
|
auto answer = dialog.ShowModal();
|
||||||
@ -126,8 +123,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
|||||||
"(both support_material_extruder and support_material_interface_extruder need to be set to 0)."));
|
"(both support_material_extruder and support_material_interface_extruder need to be set to 0)."));
|
||||||
if (is_global_config)
|
if (is_global_config)
|
||||||
msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable the Wipe Tower?"));
|
msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable the Wipe Tower?"));
|
||||||
//wxMessageDialog dialog (nullptr, msg_text, _(L("Wipe Tower")),
|
MessageDialog dialog (m_msg_dlg_parent, msg_text, _(L("Wipe Tower")),
|
||||||
MessageDialog dialog (nullptr, msg_text, _(L("Wipe Tower")),
|
|
||||||
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
|
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
|
||||||
DynamicPrintConfig new_conf = *config;
|
DynamicPrintConfig new_conf = *config;
|
||||||
auto answer = dialog.ShowModal();
|
auto answer = dialog.ShowModal();
|
||||||
@ -147,8 +143,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
|||||||
"need to be synchronized with the object layers."));
|
"need to be synchronized with the object layers."));
|
||||||
if (is_global_config)
|
if (is_global_config)
|
||||||
msg_text += "\n\n" + _(L("Shall I synchronize support layers in order to enable the Wipe Tower?"));
|
msg_text += "\n\n" + _(L("Shall I synchronize support layers in order to enable the Wipe Tower?"));
|
||||||
//wxMessageDialog dialog(nullptr, msg_text, _(L("Wipe Tower")),
|
MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Wipe Tower")),
|
||||||
MessageDialog dialog(nullptr, msg_text, _(L("Wipe Tower")),
|
|
||||||
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
|
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
|
||||||
DynamicPrintConfig new_conf = *config;
|
DynamicPrintConfig new_conf = *config;
|
||||||
auto answer = dialog.ShowModal();
|
auto answer = dialog.ShowModal();
|
||||||
@ -169,7 +164,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
|||||||
"- Detect bridging perimeters"));
|
"- Detect bridging perimeters"));
|
||||||
if (is_global_config)
|
if (is_global_config)
|
||||||
msg_text += "\n\n" + _(L("Shall I adjust those settings for supports?"));
|
msg_text += "\n\n" + _(L("Shall I adjust those settings for supports?"));
|
||||||
MessageDialog dialog(nullptr, msg_text, _L("Support Generator"), wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
|
MessageDialog dialog(m_msg_dlg_parent, msg_text, _L("Support Generator"), wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
|
||||||
DynamicPrintConfig new_conf = *config;
|
DynamicPrintConfig new_conf = *config;
|
||||||
auto answer = dialog.ShowModal();
|
auto answer = dialog.ShowModal();
|
||||||
if (!is_global_config || answer == wxID_YES) {
|
if (!is_global_config || answer == wxID_YES) {
|
||||||
@ -200,8 +195,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
|||||||
_(fill_pattern_def->enum_labels[it_pattern - fill_pattern_def->enum_values.begin()]));
|
_(fill_pattern_def->enum_labels[it_pattern - fill_pattern_def->enum_values.begin()]));
|
||||||
if (is_global_config)
|
if (is_global_config)
|
||||||
msg_text += "\n\n" + _L("Shall I switch to rectilinear fill pattern?");
|
msg_text += "\n\n" + _L("Shall I switch to rectilinear fill pattern?");
|
||||||
//wxMessageDialog dialog(nullptr, msg_text, _L("Infill"),
|
MessageDialog dialog(m_msg_dlg_parent, msg_text, _L("Infill"),
|
||||||
MessageDialog dialog(nullptr, msg_text, _L("Infill"),
|
|
||||||
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK) );
|
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK) );
|
||||||
DynamicPrintConfig new_conf = *config;
|
DynamicPrintConfig new_conf = *config;
|
||||||
auto answer = dialog.ShowModal();
|
auto answer = dialog.ShowModal();
|
||||||
@ -331,8 +325,7 @@ void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, con
|
|||||||
if (head_penetration > head_width) {
|
if (head_penetration > head_width) {
|
||||||
wxString msg_text = _(L("Head penetration should not be greater than the head width."));
|
wxString msg_text = _(L("Head penetration should not be greater than the head width."));
|
||||||
|
|
||||||
//wxMessageDialog dialog(nullptr, msg_text, _(L("Invalid Head penetration")), wxICON_WARNING | wxOK);
|
MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Invalid Head penetration")), wxICON_WARNING | wxOK);
|
||||||
MessageDialog dialog(nullptr, msg_text, _(L("Invalid Head penetration")), wxICON_WARNING | wxOK);
|
|
||||||
DynamicPrintConfig new_conf = *config;
|
DynamicPrintConfig new_conf = *config;
|
||||||
if (dialog.ShowModal() == wxID_OK) {
|
if (dialog.ShowModal() == wxID_OK) {
|
||||||
new_conf.set_key_value("support_head_penetration", new ConfigOptionFloat(head_width));
|
new_conf.set_key_value("support_head_penetration", new ConfigOptionFloat(head_width));
|
||||||
@ -345,8 +338,7 @@ void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, con
|
|||||||
if (pinhead_d > pillar_d) {
|
if (pinhead_d > pillar_d) {
|
||||||
wxString msg_text = _(L("Pinhead diameter should be smaller than the pillar diameter."));
|
wxString msg_text = _(L("Pinhead diameter should be smaller than the pillar diameter."));
|
||||||
|
|
||||||
//wxMessageDialog dialog(nullptr, msg_text, _(L("Invalid pinhead diameter")), wxICON_WARNING | wxOK);
|
MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Invalid pinhead diameter")), wxICON_WARNING | wxOK);
|
||||||
MessageDialog dialog(nullptr, msg_text, _(L("Invalid pinhead diameter")), wxICON_WARNING | wxOK);
|
|
||||||
|
|
||||||
DynamicPrintConfig new_conf = *config;
|
DynamicPrintConfig new_conf = *config;
|
||||||
if (dialog.ShowModal() == wxID_OK) {
|
if (dialog.ShowModal() == wxID_OK) {
|
||||||
|
@ -30,15 +30,18 @@ class ConfigManipulation
|
|||||||
// callback to propagation of changed value, if needed
|
// callback to propagation of changed value, if needed
|
||||||
std::function<void(const std::string&, const boost::any&)> cb_value_change = nullptr;
|
std::function<void(const std::string&, const boost::any&)> cb_value_change = nullptr;
|
||||||
ModelConfig* local_config = nullptr;
|
ModelConfig* local_config = nullptr;
|
||||||
|
wxWindow* m_msg_dlg_parent {nullptr};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConfigManipulation(std::function<void()> load_config,
|
ConfigManipulation(std::function<void()> load_config,
|
||||||
std::function<void(const std::string&, bool toggle, int opt_index)> cb_toggle_field,
|
std::function<void(const std::string&, bool toggle, int opt_index)> cb_toggle_field,
|
||||||
std::function<void(const std::string&, const boost::any&)> cb_value_change,
|
std::function<void(const std::string&, const boost::any&)> cb_value_change,
|
||||||
ModelConfig* local_config = nullptr) :
|
ModelConfig* local_config = nullptr,
|
||||||
|
wxWindow* msg_dlg_parent = nullptr) :
|
||||||
load_config(load_config),
|
load_config(load_config),
|
||||||
cb_toggle_field(cb_toggle_field),
|
cb_toggle_field(cb_toggle_field),
|
||||||
cb_value_change(cb_value_change),
|
cb_value_change(cb_value_change),
|
||||||
|
m_msg_dlg_parent(msg_dlg_parent),
|
||||||
local_config(local_config) {}
|
local_config(local_config) {}
|
||||||
ConfigManipulation() {}
|
ConfigManipulation() {}
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ ExtruderSequenceDialog::ExtruderSequenceDialog(const DoubleSlider::ExtrudersSequ
|
|||||||
intervals_box_sizer->Add(m_intervals_grid_sizer, 0, wxLEFT, em);
|
intervals_box_sizer->Add(m_intervals_grid_sizer, 0, wxLEFT, em);
|
||||||
option_sizer->Add(intervals_box_sizer, 0, wxEXPAND);
|
option_sizer->Add(intervals_box_sizer, 0, wxEXPAND);
|
||||||
|
|
||||||
m_random_sequence = new wxCheckBox(this, wxID_ANY, "Random sequence");
|
m_random_sequence = new wxCheckBox(this, wxID_ANY, _L("Random sequence"));
|
||||||
m_random_sequence->SetValue(m_sequence.random_sequence);
|
m_random_sequence->SetValue(m_sequence.random_sequence);
|
||||||
m_random_sequence->SetToolTip(_L("If enabled, random sequence of the selected extruders will be used."));
|
m_random_sequence->SetToolTip(_L("If enabled, random sequence of the selected extruders will be used."));
|
||||||
m_random_sequence->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& e) {
|
m_random_sequence->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& e) {
|
||||||
@ -169,7 +169,7 @@ ExtruderSequenceDialog::ExtruderSequenceDialog(const DoubleSlider::ExtrudersSequ
|
|||||||
m_color_repetition->Enable(m_sequence.random_sequence);
|
m_color_repetition->Enable(m_sequence.random_sequence);
|
||||||
});
|
});
|
||||||
|
|
||||||
m_color_repetition = new wxCheckBox(this, wxID_ANY, "Allow next color repetition");
|
m_color_repetition = new wxCheckBox(this, wxID_ANY, _L("Allow next color repetition"));
|
||||||
m_color_repetition->SetValue(m_sequence.color_repetition);
|
m_color_repetition->SetValue(m_sequence.color_repetition);
|
||||||
m_color_repetition->SetToolTip(_L("If enabled, a repetition of the next random color will be allowed."));
|
m_color_repetition->SetToolTip(_L("If enabled, a repetition of the next random color will be allowed."));
|
||||||
m_color_repetition->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& e) {m_sequence.color_repetition = e.IsChecked(); });
|
m_color_repetition->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& e) {m_sequence.color_repetition = e.IsChecked(); });
|
||||||
|
@ -291,6 +291,16 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
|
|||||||
case coString:
|
case coString:
|
||||||
case coStrings:
|
case coStrings:
|
||||||
case coFloatOrPercent: {
|
case coFloatOrPercent: {
|
||||||
|
if (m_opt.type == coFloatOrPercent && m_opt.opt_key == "first_layer_height" && !str.IsEmpty() && str.Last() == '%') {
|
||||||
|
// Workaroud to avoid of using of the % for first layer height
|
||||||
|
// see https://github.com/prusa3d/PrusaSlicer/issues/7418
|
||||||
|
wxString label = m_opt.full_label.empty() ? _(m_opt.label) : _(m_opt.full_label);
|
||||||
|
show_error(m_parent, from_u8((boost::format(_utf8(L("%s doesn't support percentage"))) % label).str()));
|
||||||
|
const wxString stVal = double_to_string(0.01, 2);
|
||||||
|
set_value(stVal, true);
|
||||||
|
m_value = into_u8(stVal);;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (m_opt.type == coFloatOrPercent && !str.IsEmpty() && str.Last() != '%')
|
if (m_opt.type == coFloatOrPercent && !str.IsEmpty() && str.Last() != '%')
|
||||||
{
|
{
|
||||||
double val = 0.;
|
double val = 0.;
|
||||||
|
@ -977,8 +977,7 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const
|
|||||||
for (const RenderPath& path : t_buffer.render_paths) {
|
for (const RenderPath& path : t_buffer.render_paths) {
|
||||||
colors.push_back(path.color);
|
colors.push_back(path.color);
|
||||||
}
|
}
|
||||||
std::sort(colors.begin(), colors.end());
|
sort_remove_duplicates(colors);
|
||||||
colors.erase(std::unique(colors.begin(), colors.end()), colors.end());
|
|
||||||
|
|
||||||
// save materials file
|
// save materials file
|
||||||
boost::filesystem::path mat_filename(filename);
|
boost::filesystem::path mat_filename(filename);
|
||||||
@ -1447,7 +1446,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
|
|||||||
static const unsigned int progress_threshold = 1000;
|
static const unsigned int progress_threshold = 1000;
|
||||||
wxProgressDialog* progress_dialog = wxGetApp().is_gcode_viewer() ?
|
wxProgressDialog* progress_dialog = wxGetApp().is_gcode_viewer() ?
|
||||||
new wxProgressDialog(_L("Generating toolpaths"), "...",
|
new wxProgressDialog(_L("Generating toolpaths"), "...",
|
||||||
100, wxGetApp().plater(), wxPD_AUTO_HIDE | wxPD_APP_MODAL) : nullptr;
|
100, wxGetApp().mainframe, wxPD_AUTO_HIDE | wxPD_APP_MODAL) : nullptr;
|
||||||
|
|
||||||
wxBusyCursor busy;
|
wxBusyCursor busy;
|
||||||
|
|
||||||
@ -2020,13 +2019,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// roles -> remove duplicates
|
// roles -> remove duplicates
|
||||||
std::sort(m_roles.begin(), m_roles.end());
|
sort_remove_duplicates(m_roles);
|
||||||
m_roles.erase(std::unique(m_roles.begin(), m_roles.end()), m_roles.end());
|
|
||||||
m_roles.shrink_to_fit();
|
m_roles.shrink_to_fit();
|
||||||
|
|
||||||
// extruder ids -> remove duplicates
|
// extruder ids -> remove duplicates
|
||||||
std::sort(m_extruder_ids.begin(), m_extruder_ids.end());
|
sort_remove_duplicates(m_extruder_ids);
|
||||||
m_extruder_ids.erase(std::unique(m_extruder_ids.begin(), m_extruder_ids.end()), m_extruder_ids.end());
|
|
||||||
m_extruder_ids.shrink_to_fit();
|
m_extruder_ids.shrink_to_fit();
|
||||||
|
|
||||||
// set layers z range
|
// set layers z range
|
||||||
@ -2374,8 +2371,10 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
RenderPath key{ tbuffer_id, color, static_cast<unsigned int>(ibuffer_id), path_id };
|
RenderPath key{ tbuffer_id, color, static_cast<unsigned int>(ibuffer_id), path_id };
|
||||||
if (render_path == nullptr || !RenderPathPropertyEqual()(*render_path, key))
|
if (render_path == nullptr || !RenderPathPropertyEqual()(*render_path, key)) {
|
||||||
render_path = const_cast<RenderPath*>(&(*buffer.render_paths.emplace(key).first));
|
buffer.render_paths.emplace_back(key);
|
||||||
|
render_path = const_cast<RenderPath*>(&buffer.render_paths.back());
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int delta_1st = 0;
|
unsigned int delta_1st = 0;
|
||||||
if (sub_path.first.s_id < m_sequential_view.current.first && m_sequential_view.current.first <= sub_path.last.s_id)
|
if (sub_path.first.s_id < m_sequential_view.current.first && m_sequential_view.current.first <= sub_path.last.s_id)
|
||||||
@ -2433,6 +2432,14 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Removes empty render paths and sort.
|
||||||
|
for (size_t b = 0; b < m_buffers.size(); ++b) {
|
||||||
|
TBuffer* buffer = const_cast<TBuffer*>(&m_buffers[b]);
|
||||||
|
buffer->render_paths.erase(std::remove_if(buffer->render_paths.begin(), buffer->render_paths.end(),
|
||||||
|
[](const auto &path){ return path.sizes.empty() || path.offsets.empty(); }),
|
||||||
|
buffer->render_paths.end());
|
||||||
|
}
|
||||||
|
|
||||||
// second pass: for buffers using instanced and batched models, update the instances render ranges
|
// second pass: for buffers using instanced and batched models, update the instances render ranges
|
||||||
for (size_t b = 0; b < m_buffers.size(); ++b) {
|
for (size_t b = 0; b < m_buffers.size(); ++b) {
|
||||||
TBuffer& buffer = const_cast<TBuffer&>(m_buffers[b]);
|
TBuffer& buffer = const_cast<TBuffer&>(m_buffers[b]);
|
||||||
@ -2624,12 +2631,7 @@ void GCodeViewer::render_toolpaths()
|
|||||||
float near_plane_height = camera.get_type() == Camera::EType::Perspective ? static_cast<float>(viewport[3]) / (2.0f * static_cast<float>(2.0 * std::tan(0.5 * Geometry::deg2rad(camera.get_fov())))) :
|
float near_plane_height = camera.get_type() == Camera::EType::Perspective ? static_cast<float>(viewport[3]) / (2.0f * static_cast<float>(2.0 * std::tan(0.5 * Geometry::deg2rad(camera.get_fov())))) :
|
||||||
static_cast<float>(viewport[3]) * 0.0005;
|
static_cast<float>(viewport[3]) * 0.0005;
|
||||||
|
|
||||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
auto shader_init_as_points = [zoom, point_size, near_plane_height](GLShaderProgram& shader) {
|
||||||
auto render_as_points = [this, zoom, point_size, near_plane_height]
|
|
||||||
#else
|
|
||||||
auto render_as_points = [zoom, point_size, near_plane_height]
|
|
||||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
|
||||||
(const TBuffer& buffer, unsigned int ibuffer_id, GLShaderProgram& shader) {
|
|
||||||
#if ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS
|
#if ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS
|
||||||
shader.set_uniform("use_fixed_screen_size", 1);
|
shader.set_uniform("use_fixed_screen_size", 1);
|
||||||
#else
|
#else
|
||||||
@ -2640,65 +2642,67 @@ void GCodeViewer::render_toolpaths()
|
|||||||
shader.set_uniform("percent_center_radius", 0.33f);
|
shader.set_uniform("percent_center_radius", 0.33f);
|
||||||
shader.set_uniform("point_size", point_size);
|
shader.set_uniform("point_size", point_size);
|
||||||
shader.set_uniform("near_plane_height", near_plane_height);
|
shader.set_uniform("near_plane_height", near_plane_height);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto render_as_points = [
|
||||||
|
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
|
this
|
||||||
|
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
|
](std::vector<RenderPath>::iterator it_path, std::vector<RenderPath>::iterator it_end, GLShaderProgram& shader, int uniform_color) {
|
||||||
glsafe(::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE));
|
glsafe(::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE));
|
||||||
glsafe(::glEnable(GL_POINT_SPRITE));
|
glsafe(::glEnable(GL_POINT_SPRITE));
|
||||||
|
|
||||||
for (const RenderPath& path : buffer.render_paths) {
|
for (auto it = it_path; it != it_end && it_path->ibuffer_id == it->ibuffer_id; ++it) {
|
||||||
if (path.ibuffer_id == ibuffer_id) {
|
const RenderPath& path = *it;
|
||||||
shader.set_uniform("uniform_color", path.color);
|
glsafe(::glUniform4fv(uniform_color, 1, static_cast<const GLfloat*>(path.color.data())));
|
||||||
glsafe(::glMultiDrawElements(GL_POINTS, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
|
glsafe(::glMultiDrawElements(GL_POINTS, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
|
||||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
++m_statistics.gl_multi_points_calls_count;
|
++m_statistics.gl_multi_points_calls_count;
|
||||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
glsafe(::glDisable(GL_POINT_SPRITE));
|
glsafe(::glDisable(GL_POINT_SPRITE));
|
||||||
glsafe(::glDisable(GL_VERTEX_PROGRAM_POINT_SIZE));
|
glsafe(::glDisable(GL_VERTEX_PROGRAM_POINT_SIZE));
|
||||||
};
|
};
|
||||||
|
|
||||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
auto shader_init_as_lines = [light_intensity](GLShaderProgram &shader) {
|
||||||
auto render_as_lines = [this, light_intensity]
|
|
||||||
#else
|
|
||||||
auto render_as_lines = [light_intensity]
|
|
||||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
|
||||||
(const TBuffer& buffer, unsigned int ibuffer_id, GLShaderProgram& shader) {
|
|
||||||
shader.set_uniform("light_intensity", light_intensity);
|
shader.set_uniform("light_intensity", light_intensity);
|
||||||
for (const RenderPath& path : buffer.render_paths) {
|
};
|
||||||
if (path.ibuffer_id == ibuffer_id) {
|
auto render_as_lines = [
|
||||||
shader.set_uniform("uniform_color", path.color);
|
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
|
this
|
||||||
|
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
|
](std::vector<RenderPath>::iterator it_path, std::vector<RenderPath>::iterator it_end, GLShaderProgram& shader, int uniform_color) {
|
||||||
|
for (auto it = it_path; it != it_end && it_path->ibuffer_id == it->ibuffer_id; ++it) {
|
||||||
|
const RenderPath& path = *it;
|
||||||
|
glsafe(::glUniform4fv(uniform_color, 1, static_cast<const GLfloat*>(path.color.data())));
|
||||||
glsafe(::glMultiDrawElements(GL_LINES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
|
glsafe(::glMultiDrawElements(GL_LINES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
|
||||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
++m_statistics.gl_multi_lines_calls_count;
|
++m_statistics.gl_multi_lines_calls_count;
|
||||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto render_as_triangles = [
|
||||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
auto render_as_triangles = [this]
|
this
|
||||||
#else
|
|
||||||
auto render_as_triangles = []
|
|
||||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
(const TBuffer& buffer, unsigned int ibuffer_id, GLShaderProgram& shader) {
|
](std::vector<RenderPath>::iterator it_path, std::vector<RenderPath>::iterator it_end, GLShaderProgram& shader, int uniform_color) {
|
||||||
for (const RenderPath& path : buffer.render_paths) {
|
for (auto it = it_path; it != it_end && it_path->ibuffer_id == it->ibuffer_id; ++it) {
|
||||||
if (path.ibuffer_id == ibuffer_id) {
|
const RenderPath& path = *it;
|
||||||
shader.set_uniform("uniform_color", path.color);
|
glsafe(::glUniform4fv(uniform_color, 1, static_cast<const GLfloat*>(path.color.data())));
|
||||||
glsafe(::glMultiDrawElements(GL_TRIANGLES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
|
glsafe(::glMultiDrawElements(GL_TRIANGLES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
|
||||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
++m_statistics.gl_multi_triangles_calls_count;
|
++m_statistics.gl_multi_triangles_calls_count;
|
||||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto render_as_instanced_model = [
|
||||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
auto render_as_instanced_model = [this]
|
this
|
||||||
#else
|
|
||||||
auto render_as_instanced_model = []
|
|
||||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
(TBuffer& buffer, GLShaderProgram & shader) {
|
](TBuffer& buffer, GLShaderProgram & shader) {
|
||||||
for (auto& range : buffer.model.instances.render_ranges.ranges) {
|
for (auto& range : buffer.model.instances.render_ranges.ranges) {
|
||||||
if (range.vbo == 0 && range.count > 0) {
|
if (range.vbo == 0 && range.count > 0) {
|
||||||
glsafe(::glGenBuffers(1, &range.vbo));
|
glsafe(::glGenBuffers(1, &range.vbo));
|
||||||
@ -2803,8 +2807,20 @@ void GCodeViewer::render_toolpaths()
|
|||||||
shader->set_uniform("emission_factor", 0.0f);
|
shader->set_uniform("emission_factor", 0.0f);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (size_t j = 0; j < buffer.indices.size(); ++j) {
|
switch (buffer.render_primitive_type) {
|
||||||
const IBuffer& i_buffer = buffer.indices[j];
|
case TBuffer::ERenderPrimitiveType::Point: shader_init_as_points(*shader); break;
|
||||||
|
case TBuffer::ERenderPrimitiveType::Line: shader_init_as_lines(*shader); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
int uniform_color = shader->get_uniform_location("uniform_color");
|
||||||
|
auto it_path = buffer.render_paths.begin();
|
||||||
|
for (unsigned int ibuffer_id = 0; ibuffer_id < static_cast<unsigned int>(buffer.indices.size()); ++ibuffer_id) {
|
||||||
|
const IBuffer& i_buffer = buffer.indices[ibuffer_id];
|
||||||
|
// Skip all paths with ibuffer_id < ibuffer_id.
|
||||||
|
for (; it_path != buffer.render_paths.end() && it_path->ibuffer_id < ibuffer_id; ++ it_path) ;
|
||||||
|
if (it_path == buffer.render_paths.end() || it_path->ibuffer_id > ibuffer_id)
|
||||||
|
// Not found. This shall not happen.
|
||||||
|
continue;
|
||||||
|
|
||||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, i_buffer.vbo));
|
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, i_buffer.vbo));
|
||||||
glsafe(::glVertexPointer(buffer.vertices.position_size_floats(), GL_FLOAT, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.position_offset_bytes()));
|
glsafe(::glVertexPointer(buffer.vertices.position_size_floats(), GL_FLOAT, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.position_offset_bytes()));
|
||||||
@ -2817,19 +2833,20 @@ void GCodeViewer::render_toolpaths()
|
|||||||
|
|
||||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_buffer.ibo));
|
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_buffer.ibo));
|
||||||
|
|
||||||
|
// Render all elements with it_path->ibuffer_id == ibuffer_id, possible with varying colors.
|
||||||
switch (buffer.render_primitive_type)
|
switch (buffer.render_primitive_type)
|
||||||
{
|
{
|
||||||
case TBuffer::ERenderPrimitiveType::Point: {
|
case TBuffer::ERenderPrimitiveType::Point: {
|
||||||
render_as_points(buffer, static_cast<unsigned int>(j), *shader);
|
render_as_points(it_path, buffer.render_paths.end(), *shader, uniform_color);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TBuffer::ERenderPrimitiveType::Line: {
|
case TBuffer::ERenderPrimitiveType::Line: {
|
||||||
glsafe(::glLineWidth(static_cast<GLfloat>(line_width(zoom))));
|
glsafe(::glLineWidth(static_cast<GLfloat>(line_width(zoom))));
|
||||||
render_as_lines(buffer, static_cast<unsigned int>(j), *shader);
|
render_as_lines(it_path, buffer.render_paths.end(), *shader, uniform_color);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TBuffer::ERenderPrimitiveType::Triangle: {
|
case TBuffer::ERenderPrimitiveType::Triangle: {
|
||||||
render_as_triangles(buffer, static_cast<unsigned int>(j), *shader);
|
render_as_triangles(it_path, buffer.render_paths.end(), *shader, uniform_color);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: { break; }
|
default: { break; }
|
||||||
|
@ -259,14 +259,6 @@ class GCodeViewer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// // for unordered_set implementation of render_paths
|
|
||||||
// struct RenderPathPropertyHash {
|
|
||||||
// size_t operator() (const RenderPath &p) const {
|
|
||||||
// // Convert the RGB value to an integer hash.
|
|
||||||
//// return (size_t(int(p.color[0] * 255) + 255 * int(p.color[1] * 255) + (255 * 255) * int(p.color[2] * 255)) * 7919) ^ size_t(p.ibuffer_id);
|
|
||||||
// return size_t(int(p.color[0] * 255) + 255 * int(p.color[1] * 255) + (255 * 255) * int(p.color[2] * 255)) ^ size_t(p.ibuffer_id);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
struct RenderPathPropertyLower {
|
struct RenderPathPropertyLower {
|
||||||
bool operator() (const RenderPath &l, const RenderPath &r) const {
|
bool operator() (const RenderPath &l, const RenderPath &r) const {
|
||||||
if (l.tbuffer_id < r.tbuffer_id)
|
if (l.tbuffer_id < r.tbuffer_id)
|
||||||
@ -319,9 +311,7 @@ class GCodeViewer
|
|||||||
|
|
||||||
std::string shader;
|
std::string shader;
|
||||||
std::vector<Path> paths;
|
std::vector<Path> paths;
|
||||||
// std::set seems to perform significantly better, at least on Windows.
|
std::vector<RenderPath> render_paths;
|
||||||
// std::unordered_set<RenderPath, RenderPathPropertyHash, RenderPathPropertyEqual> render_paths;
|
|
||||||
std::set<RenderPath, RenderPathPropertyLower> render_paths;
|
|
||||||
bool visible{ false };
|
bool visible{ false };
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
@ -2761,7 +2761,8 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt)
|
|||||||
// For some reason the Idle event is not being generated after the mouse scroll event in case of scrolling with the two fingers on the touch pad,
|
// For some reason the Idle event is not being generated after the mouse scroll event in case of scrolling with the two fingers on the touch pad,
|
||||||
// if the event is not allowed to be passed further.
|
// if the event is not allowed to be passed further.
|
||||||
// https://github.com/prusa3d/PrusaSlicer/issues/2750
|
// https://github.com/prusa3d/PrusaSlicer/issues/2750
|
||||||
evt.Skip();
|
// evt.Skip() used to trigger the needed screen refresh, but it does no more. wxWakeUpIdle() seem to work now.
|
||||||
|
wxWakeUpIdle();
|
||||||
#endif /* __WXMSW__ */
|
#endif /* __WXMSW__ */
|
||||||
|
|
||||||
// Performs layers editing updates, if enabled
|
// Performs layers editing updates, if enabled
|
||||||
|
@ -358,12 +358,38 @@ bool GLShaderProgram::set_uniform(const char* name, const Vec3d& value) const
|
|||||||
|
|
||||||
int GLShaderProgram::get_attrib_location(const char* name) const
|
int GLShaderProgram::get_attrib_location(const char* name) const
|
||||||
{
|
{
|
||||||
return (m_id > 0) ? ::glGetAttribLocation(m_id, name) : -1;
|
assert(m_id > 0);
|
||||||
|
|
||||||
|
if (m_id <= 0)
|
||||||
|
// Shader program not loaded. This should not happen.
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
auto it = std::find_if(m_attrib_location_cache.begin(), m_attrib_location_cache.end(), [name](const auto& p) { return p.first == name; });
|
||||||
|
if (it != m_attrib_location_cache.end())
|
||||||
|
// Attrib ID cached.
|
||||||
|
return it->second;
|
||||||
|
|
||||||
|
int id = ::glGetAttribLocation(m_id, name);
|
||||||
|
const_cast<GLShaderProgram*>(this)->m_attrib_location_cache.push_back({ name, id });
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GLShaderProgram::get_uniform_location(const char* name) const
|
int GLShaderProgram::get_uniform_location(const char* name) const
|
||||||
{
|
{
|
||||||
return (m_id > 0) ? ::glGetUniformLocation(m_id, name) : -1;
|
assert(m_id > 0);
|
||||||
|
|
||||||
|
if (m_id <= 0)
|
||||||
|
// Shader program not loaded. This should not happen.
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
auto it = std::find_if(m_uniform_location_cache.begin(), m_uniform_location_cache.end(), [name](const auto &p) { return p.first == name; });
|
||||||
|
if (it != m_uniform_location_cache.end())
|
||||||
|
// Uniform ID cached.
|
||||||
|
return it->second;
|
||||||
|
|
||||||
|
int id = ::glGetUniformLocation(m_id, name);
|
||||||
|
const_cast<GLShaderProgram*>(this)->m_uniform_location_cache.push_back({ name, id });
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
@ -29,6 +29,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
unsigned int m_id{ 0 };
|
unsigned int m_id{ 0 };
|
||||||
|
std::vector<std::pair<std::string, int>> m_attrib_location_cache;
|
||||||
|
std::vector<std::pair<std::string, int>> m_uniform_location_cache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~GLShaderProgram();
|
~GLShaderProgram();
|
||||||
|
@ -883,6 +883,8 @@ void GUI_App::init_app_config()
|
|||||||
dir = wxFileName::GetHomeDir() + wxS("/.config");
|
dir = wxFileName::GetHomeDir() + wxS("/.config");
|
||||||
set_data_dir((dir + "/" + GetAppName()).ToUTF8().data());
|
set_data_dir((dir + "/" + GetAppName()).ToUTF8().data());
|
||||||
#endif
|
#endif
|
||||||
|
} else {
|
||||||
|
m_datadir_redefined = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!app_config)
|
if (!app_config)
|
||||||
@ -915,6 +917,10 @@ void GUI_App::init_app_config()
|
|||||||
// returns true if found newer version and user agreed to use it
|
// returns true if found newer version and user agreed to use it
|
||||||
bool GUI_App::check_older_app_config(Semver current_version, bool backup)
|
bool GUI_App::check_older_app_config(Semver current_version, bool backup)
|
||||||
{
|
{
|
||||||
|
// If the config folder is redefined - do not check
|
||||||
|
if (m_datadir_redefined)
|
||||||
|
return false;
|
||||||
|
|
||||||
// find other version app config (alpha / beta / release)
|
// find other version app config (alpha / beta / release)
|
||||||
std::string config_path = app_config->config_path();
|
std::string config_path = app_config->config_path();
|
||||||
boost::filesystem::path parent_file_path(config_path);
|
boost::filesystem::path parent_file_path(config_path);
|
||||||
|
@ -352,6 +352,7 @@ private:
|
|||||||
void check_updates(const bool verbose);
|
void check_updates(const bool verbose);
|
||||||
|
|
||||||
bool m_init_app_config_from_older { false };
|
bool m_init_app_config_from_older { false };
|
||||||
|
bool m_datadir_redefined { false };
|
||||||
std::string m_older_data_dir_path;
|
std::string m_older_data_dir_path;
|
||||||
boost::optional<Semver> m_last_config_version;
|
boost::optional<Semver> m_last_config_version;
|
||||||
};
|
};
|
||||||
|
@ -1446,7 +1446,7 @@ void ObjectList::load_part(ModelObject& model_object, std::vector<ModelVolume*>&
|
|||||||
else
|
else
|
||||||
wxGetApp().import_model(parent, input_files);
|
wxGetApp().import_model(parent, input_files);
|
||||||
|
|
||||||
wxProgressDialog dlg(_L("Loading") + dots, "", 100, wxGetApp().plater(), wxPD_AUTO_HIDE);
|
wxProgressDialog dlg(_L("Loading") + dots, "", 100, wxGetApp().mainframe wxPD_AUTO_HIDE);
|
||||||
wxBusyCursor busy;
|
wxBusyCursor busy;
|
||||||
|
|
||||||
for (size_t i = 0; i < input_files.size(); ++i) {
|
for (size_t i = 0; i < input_files.size(); ++i) {
|
||||||
@ -1506,7 +1506,7 @@ void ObjectList::load_modifier(ModelObject& model_object, std::vector<ModelVolum
|
|||||||
else
|
else
|
||||||
wxGetApp().import_model(parent, input_files);
|
wxGetApp().import_model(parent, input_files);
|
||||||
|
|
||||||
wxProgressDialog dlg(_L("Loading") + dots, "", 100, wxGetApp().plater(), wxPD_AUTO_HIDE);
|
wxProgressDialog dlg(_L("Loading") + dots, "", 100, wxGetApp().mainframe, wxPD_AUTO_HIDE);
|
||||||
wxBusyCursor busy;
|
wxBusyCursor busy;
|
||||||
|
|
||||||
const int obj_idx = get_selected_obj_idx();
|
const int obj_idx = get_selected_obj_idx();
|
||||||
@ -4105,7 +4105,7 @@ void ObjectList::fix_through_netfabb()
|
|||||||
Plater::TakeSnapshot snapshot(plater, _L("Fix through NetFabb"));
|
Plater::TakeSnapshot snapshot(plater, _L("Fix through NetFabb"));
|
||||||
|
|
||||||
// Open a progress dialog.
|
// Open a progress dialog.
|
||||||
wxProgressDialog progress_dlg(_L("Fixing through NetFabb"), "", 100, plater,
|
wxProgressDialog progress_dlg(_L("Fixing through NetFabb"), "", 100, find_toplevel_parent(plater),
|
||||||
wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
|
wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
|
||||||
int model_idx{ 0 };
|
int model_idx{ 0 };
|
||||||
if (vol_idxs.empty()) {
|
if (vol_idxs.empty()) {
|
||||||
|
@ -110,12 +110,6 @@ bool ObjectSettings::update_settings_list()
|
|||||||
update_settings_list();
|
update_settings_list();
|
||||||
m_parent->Layout();
|
m_parent->Layout();
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Check overriden options list after deleting.
|
|
||||||
* Some options couldn't be deleted because of another one.
|
|
||||||
* Like, we couldn't delete fill pattern, if fill density is set to 100%
|
|
||||||
*/
|
|
||||||
update_config_values(config);
|
|
||||||
});
|
});
|
||||||
return btn;
|
return btn;
|
||||||
};
|
};
|
||||||
@ -227,11 +221,12 @@ void ObjectSettings::update_config_values(ModelConfig* config)
|
|||||||
update_config_values(config);
|
update_config_values(config);
|
||||||
|
|
||||||
if (is_added) {
|
if (is_added) {
|
||||||
wxTheApp->CallAfter([this]() {
|
// #ysFIXME - Delete after testing! Very likely this CallAfret is no needed
|
||||||
|
// wxTheApp->CallAfter([this]() {
|
||||||
wxWindowUpdateLocker noUpdates(m_parent);
|
wxWindowUpdateLocker noUpdates(m_parent);
|
||||||
update_settings_list();
|
update_settings_list();
|
||||||
m_parent->Layout();
|
m_parent->Layout();
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -253,9 +248,9 @@ void ObjectSettings::update_config_values(ModelConfig* config)
|
|||||||
{
|
{
|
||||||
const int obj_idx = objects_model->GetObjectIdByItem(item);
|
const int obj_idx = objects_model->GetObjectIdByItem(item);
|
||||||
assert(obj_idx >= 0);
|
assert(obj_idx >= 0);
|
||||||
|
// for object's part first of all update konfiguration from object
|
||||||
main_config.apply(wxGetApp().model().objects[obj_idx]->config.get(), true);
|
main_config.apply(wxGetApp().model().objects[obj_idx]->config.get(), true);
|
||||||
printer_technology == ptFFF ? config_manipulation.update_print_fff_config(&main_config) :
|
// and then from its own config
|
||||||
config_manipulation.update_print_sla_config(&main_config) ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main_config.apply(config->get(), true);
|
main_config.apply(config->get(), true);
|
||||||
|
@ -550,24 +550,24 @@ RENDER_AGAIN:
|
|||||||
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
|
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
|
||||||
ImGui::PushItemWidth(window_width - settings_sliders_left);
|
ImGui::PushItemWidth(window_width - settings_sliders_left);
|
||||||
m_imgui->slider_float("##offset", &offset, offset_min, offset_max, "%.1f mm");
|
m_imgui->slider_float("##offset", &offset, offset_min, offset_max, "%.1f mm");
|
||||||
if (ImGui::IsItemHovered())
|
if (m_imgui->get_last_slider_status().hovered)
|
||||||
m_imgui->tooltip((_utf8(opts[0].second->tooltip)).c_str(), max_tooltip_width);
|
m_imgui->tooltip((_utf8(opts[0].second->tooltip)).c_str(), max_tooltip_width);
|
||||||
|
|
||||||
bool slider_clicked = ImGui::IsItemClicked(); // someone clicked the slider
|
bool slider_clicked = m_imgui->get_last_slider_status().clicked; // someone clicked the slider
|
||||||
bool slider_edited = ImGui::IsItemEdited(); // someone is dragging the slider
|
bool slider_edited =m_imgui->get_last_slider_status().edited; // someone is dragging the slider
|
||||||
bool slider_released = ImGui::IsItemDeactivatedAfterEdit(); // someone has just released the slider
|
bool slider_released =m_imgui->get_last_slider_status().deactivated_after_edit; // someone has just released the slider
|
||||||
|
|
||||||
if (current_mode >= quality_mode) {
|
if (current_mode >= quality_mode) {
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
m_imgui->text(m_desc.at("quality"));
|
m_imgui->text(m_desc.at("quality"));
|
||||||
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
|
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
|
||||||
m_imgui->slider_float("##quality", &quality, quality_min, quality_max, "%.1f");
|
m_imgui->slider_float("##quality", &quality, quality_min, quality_max, "%.1f");
|
||||||
if (ImGui::IsItemHovered())
|
if (m_imgui->get_last_slider_status().hovered)
|
||||||
m_imgui->tooltip((_utf8(opts[1].second->tooltip)).c_str(), max_tooltip_width);
|
m_imgui->tooltip((_utf8(opts[1].second->tooltip)).c_str(), max_tooltip_width);
|
||||||
|
|
||||||
slider_clicked |= ImGui::IsItemClicked();
|
slider_clicked |= m_imgui->get_last_slider_status().clicked;
|
||||||
slider_edited |= ImGui::IsItemEdited();
|
slider_edited |= m_imgui->get_last_slider_status().edited;
|
||||||
slider_released |= ImGui::IsItemDeactivatedAfterEdit();
|
slider_released |= m_imgui->get_last_slider_status().deactivated_after_edit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_mode >= closing_d_mode) {
|
if (current_mode >= closing_d_mode) {
|
||||||
@ -575,12 +575,12 @@ RENDER_AGAIN:
|
|||||||
m_imgui->text(m_desc.at("closing_distance"));
|
m_imgui->text(m_desc.at("closing_distance"));
|
||||||
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
|
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
|
||||||
m_imgui->slider_float("##closing_distance", &closing_d, closing_d_min, closing_d_max, "%.1f mm");
|
m_imgui->slider_float("##closing_distance", &closing_d, closing_d_min, closing_d_max, "%.1f mm");
|
||||||
if (ImGui::IsItemHovered())
|
if (m_imgui->get_last_slider_status().hovered)
|
||||||
m_imgui->tooltip((_utf8(opts[2].second->tooltip)).c_str(), max_tooltip_width);
|
m_imgui->tooltip((_utf8(opts[2].second->tooltip)).c_str(), max_tooltip_width);
|
||||||
|
|
||||||
slider_clicked |= ImGui::IsItemClicked();
|
slider_clicked |= m_imgui->get_last_slider_status().clicked;
|
||||||
slider_edited |= ImGui::IsItemEdited();
|
slider_edited |= m_imgui->get_last_slider_status().edited;
|
||||||
slider_released |= ImGui::IsItemDeactivatedAfterEdit();
|
slider_released |= m_imgui->get_last_slider_status().deactivated_after_edit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slider_clicked) {
|
if (slider_clicked) {
|
||||||
@ -627,9 +627,9 @@ RENDER_AGAIN:
|
|||||||
//complete non-sense.
|
//complete non-sense.
|
||||||
diam = std::clamp(diam, 0.1f, diameter_upper_cap);
|
diam = std::clamp(diam, 0.1f, diameter_upper_cap);
|
||||||
m_new_hole_radius = diam / 2.f;
|
m_new_hole_radius = diam / 2.f;
|
||||||
bool clicked = ImGui::IsItemClicked();
|
bool clicked = m_imgui->get_last_slider_status().clicked;
|
||||||
bool edited = ImGui::IsItemEdited();
|
bool edited = m_imgui->get_last_slider_status().edited;
|
||||||
bool deactivated = ImGui::IsItemDeactivatedAfterEdit();
|
bool deactivated = m_imgui->get_last_slider_status().deactivated_after_edit;
|
||||||
|
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
m_imgui->text(m_desc["hole_depth"]);
|
m_imgui->text(m_desc["hole_depth"]);
|
||||||
@ -638,9 +638,9 @@ RENDER_AGAIN:
|
|||||||
// Same as above:
|
// Same as above:
|
||||||
m_new_hole_height = std::clamp(m_new_hole_height, 0.f, 100.f);
|
m_new_hole_height = std::clamp(m_new_hole_height, 0.f, 100.f);
|
||||||
|
|
||||||
clicked |= ImGui::IsItemClicked();
|
clicked |= m_imgui->get_last_slider_status().clicked;
|
||||||
edited |= ImGui::IsItemEdited();
|
edited |= m_imgui->get_last_slider_status().edited;
|
||||||
deactivated |= ImGui::IsItemDeactivatedAfterEdit();
|
deactivated |= m_imgui->get_last_slider_status().deactivated_after_edit;;
|
||||||
|
|
||||||
// Following is a nasty way to:
|
// Following is a nasty way to:
|
||||||
// - save the initial value of the slider before one starts messing with it
|
// - save the initial value of the slider before one starts messing with it
|
||||||
|
@ -859,9 +859,9 @@ void GLPaintContour::finalize_geometry()
|
|||||||
|
|
||||||
if (!this->contour_indices.empty()) {
|
if (!this->contour_indices.empty()) {
|
||||||
glsafe(::glGenBuffers(1, &this->m_contour_EBO_id));
|
glsafe(::glGenBuffers(1, &this->m_contour_EBO_id));
|
||||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_contour_EBO_id));
|
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->m_contour_EBO_id));
|
||||||
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_indices.size() * sizeof(unsigned int), this->contour_indices.data(), GL_STATIC_DRAW));
|
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->contour_indices.size() * sizeof(unsigned int), this->contour_indices.data(), GL_STATIC_DRAW));
|
||||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||||
this->contour_indices.clear();
|
this->contour_indices.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -687,16 +687,16 @@ RENDER_AGAIN:
|
|||||||
// - take correct undo/redo snapshot after the user is done with moving the slider
|
// - take correct undo/redo snapshot after the user is done with moving the slider
|
||||||
float initial_value = m_new_point_head_diameter;
|
float initial_value = m_new_point_head_diameter;
|
||||||
m_imgui->slider_float("##head_diameter", &m_new_point_head_diameter, 0.1f, diameter_upper_cap, "%.1f");
|
m_imgui->slider_float("##head_diameter", &m_new_point_head_diameter, 0.1f, diameter_upper_cap, "%.1f");
|
||||||
if (ImGui::IsItemClicked()) {
|
if (m_imgui->get_last_slider_status().clicked) {
|
||||||
if (m_old_point_head_diameter == 0.f)
|
if (m_old_point_head_diameter == 0.f)
|
||||||
m_old_point_head_diameter = initial_value;
|
m_old_point_head_diameter = initial_value;
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemEdited()) {
|
if (m_imgui->get_last_slider_status().edited) {
|
||||||
for (auto& cache_entry : m_editing_cache)
|
for (auto& cache_entry : m_editing_cache)
|
||||||
if (cache_entry.selected)
|
if (cache_entry.selected)
|
||||||
cache_entry.support_point.head_front_radius = m_new_point_head_diameter / 2.f;
|
cache_entry.support_point.head_front_radius = m_new_point_head_diameter / 2.f;
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
if (m_imgui->get_last_slider_status().deactivated_after_edit) {
|
||||||
// momentarily restore the old value to take snapshot
|
// momentarily restore the old value to take snapshot
|
||||||
for (auto& cache_entry : m_editing_cache)
|
for (auto& cache_entry : m_editing_cache)
|
||||||
if (cache_entry.selected)
|
if (cache_entry.selected)
|
||||||
@ -747,18 +747,18 @@ RENDER_AGAIN:
|
|||||||
float minimal_point_distance = static_cast<const ConfigOptionFloat*>(opts[1])->value;
|
float minimal_point_distance = static_cast<const ConfigOptionFloat*>(opts[1])->value;
|
||||||
|
|
||||||
m_imgui->slider_float("##minimal_point_distance", &minimal_point_distance, 0.f, 20.f, "%.f mm");
|
m_imgui->slider_float("##minimal_point_distance", &minimal_point_distance, 0.f, 20.f, "%.f mm");
|
||||||
bool slider_clicked = ImGui::IsItemClicked(); // someone clicked the slider
|
bool slider_clicked = m_imgui->get_last_slider_status().clicked; // someone clicked the slider
|
||||||
bool slider_edited = ImGui::IsItemEdited(); // someone is dragging the slider
|
bool slider_edited = m_imgui->get_last_slider_status().edited; // someone is dragging the slider
|
||||||
bool slider_released = ImGui::IsItemDeactivatedAfterEdit(); // someone has just released the slider
|
bool slider_released = m_imgui->get_last_slider_status().deactivated_after_edit; // someone has just released the slider
|
||||||
|
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
m_imgui->text(m_desc.at("points_density"));
|
m_imgui->text(m_desc.at("points_density"));
|
||||||
ImGui::SameLine(settings_sliders_left);
|
ImGui::SameLine(settings_sliders_left);
|
||||||
|
|
||||||
m_imgui->slider_float("##points_density", &density, 0.f, 200.f, "%.f %%");
|
m_imgui->slider_float("##points_density", &density, 0.f, 200.f, "%.f %%");
|
||||||
slider_clicked |= ImGui::IsItemClicked();
|
slider_clicked |= m_imgui->get_last_slider_status().clicked;
|
||||||
slider_edited |= ImGui::IsItemEdited();
|
slider_edited |= m_imgui->get_last_slider_status().edited;
|
||||||
slider_released |= ImGui::IsItemDeactivatedAfterEdit();
|
slider_released |= m_imgui->get_last_slider_status().deactivated_after_edit;
|
||||||
|
|
||||||
if (slider_clicked) { // stash the values of the settings so we know what to revert to after undo
|
if (slider_clicked) { // stash the values of the settings so we know what to revert to after undo
|
||||||
m_minimal_point_distance_stash = minimal_point_distance;
|
m_minimal_point_distance_stash = minimal_point_distance;
|
||||||
|
@ -503,6 +503,12 @@ bool ImGuiWrapper::slider_float(const char* label, float* v, float v_min, float
|
|||||||
str_label = str_label.substr(0, pos) + str_label.substr(pos + 2);
|
str_label = str_label.substr(0, pos) + str_label.substr(pos + 2);
|
||||||
|
|
||||||
bool ret = ImGui::SliderFloat(str_label.c_str(), v, v_min, v_max, format, power);
|
bool ret = ImGui::SliderFloat(str_label.c_str(), v, v_min, v_max, format, power);
|
||||||
|
|
||||||
|
m_last_slider_status.hovered = ImGui::IsItemHovered();
|
||||||
|
m_last_slider_status.edited = ImGui::IsItemEdited();
|
||||||
|
m_last_slider_status.clicked = ImGui::IsItemClicked();
|
||||||
|
m_last_slider_status.deactivated_after_edit = ImGui::IsItemDeactivatedAfterEdit();
|
||||||
|
|
||||||
if (!tooltip.empty() && ImGui::IsItemHovered())
|
if (!tooltip.empty() && ImGui::IsItemHovered())
|
||||||
this->tooltip(into_u8(tooltip).c_str(), max_tooltip_width);
|
this->tooltip(into_u8(tooltip).c_str(), max_tooltip_width);
|
||||||
|
|
||||||
|
@ -39,6 +39,13 @@ class ImGuiWrapper
|
|||||||
std::string m_clipboard_text;
|
std::string m_clipboard_text;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
struct LastSliderStatus {
|
||||||
|
bool hovered { false };
|
||||||
|
bool edited { false };
|
||||||
|
bool clicked { false };
|
||||||
|
bool deactivated_after_edit { false };
|
||||||
|
};
|
||||||
|
|
||||||
ImGuiWrapper();
|
ImGuiWrapper();
|
||||||
~ImGuiWrapper();
|
~ImGuiWrapper();
|
||||||
|
|
||||||
@ -63,6 +70,7 @@ public:
|
|||||||
|
|
||||||
ImVec2 get_item_spacing() const;
|
ImVec2 get_item_spacing() const;
|
||||||
float get_slider_float_height() const;
|
float get_slider_float_height() const;
|
||||||
|
const LastSliderStatus& get_last_slider_status() const { return m_last_slider_status; }
|
||||||
|
|
||||||
void set_next_window_pos(float x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f);
|
void set_next_window_pos(float x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f);
|
||||||
void set_next_window_bg_alpha(float alpha);
|
void set_next_window_bg_alpha(float alpha);
|
||||||
@ -146,6 +154,8 @@ private:
|
|||||||
|
|
||||||
static const char* clipboard_get(void* user_data);
|
static const char* clipboard_get(void* user_data);
|
||||||
static void clipboard_set(void* user_data, const char* text);
|
static void clipboard_set(void* user_data, const char* text);
|
||||||
|
|
||||||
|
LastSliderStatus m_last_slider_status;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ public:
|
|||||||
SettingsDialog m_settings_dialog;
|
SettingsDialog m_settings_dialog;
|
||||||
DiffPresetDialog diff_dialog;
|
DiffPresetDialog diff_dialog;
|
||||||
wxWindow* m_plater_page{ nullptr };
|
wxWindow* m_plater_page{ nullptr };
|
||||||
wxProgressDialog* m_progress_dialog { nullptr };
|
// wxProgressDialog* m_progress_dialog { nullptr };
|
||||||
PrintHostQueueDialog* m_printhost_queue_dlg;
|
PrintHostQueueDialog* m_printhost_queue_dlg;
|
||||||
// std::shared_ptr<ProgressStatusBar> m_statusbar;
|
// std::shared_ptr<ProgressStatusBar> m_statusbar;
|
||||||
|
|
||||||
|
@ -136,7 +136,8 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin
|
|||||||
int em = wxGetApp().em_unit();
|
int em = wxGetApp().em_unit();
|
||||||
|
|
||||||
// if message containes the table
|
// if message containes the table
|
||||||
if (msg.Contains("<tr>")) {
|
bool is_marked = msg.Contains("<tr>");
|
||||||
|
if (is_marked) {
|
||||||
int lines = msg.Freq('\n') + 1;
|
int lines = msg.Freq('\n') + 1;
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
while (pos < (int)msg.Len() && pos != wxNOT_FOUND) {
|
while (pos < (int)msg.Len() && pos != wxNOT_FOUND) {
|
||||||
@ -154,7 +155,7 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin
|
|||||||
}
|
}
|
||||||
html->SetMinSize(page_size);
|
html->SetMinSize(page_size);
|
||||||
|
|
||||||
std::string msg_escaped = xml_escape(msg.ToUTF8().data());
|
std::string msg_escaped = xml_escape(msg.ToUTF8().data(), is_marked);
|
||||||
boost::replace_all(msg_escaped, "\r\n", "<br>");
|
boost::replace_all(msg_escaped, "\r\n", "<br>");
|
||||||
boost::replace_all(msg_escaped, "\n", "<br>");
|
boost::replace_all(msg_escaped, "\n", "<br>");
|
||||||
if (monospaced_font)
|
if (monospaced_font)
|
||||||
|
@ -79,7 +79,6 @@ void OG_CustomCtrl::init_ctrl_lines()
|
|||||||
|
|
||||||
// if we have a single option with no label, no sidetext just add it directly to sizer
|
// if we have a single option with no label, no sidetext just add it directly to sizer
|
||||||
if (option_set.size() == 1 && opt_group->label_width == 0 && option_set.front().opt.full_width &&
|
if (option_set.size() == 1 && opt_group->label_width == 0 && option_set.front().opt.full_width &&
|
||||||
option_set.front().opt.label.empty() &&
|
|
||||||
option_set.front().opt.sidetext.size() == 0 && option_set.front().side_widget == nullptr &&
|
option_set.front().opt.sidetext.size() == 0 && option_set.front().side_widget == nullptr &&
|
||||||
line.get_extra_widgets().size() == 0)
|
line.get_extra_widgets().size() == 0)
|
||||||
{
|
{
|
||||||
@ -157,7 +156,6 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/)
|
|||||||
// If we have a single option with no sidetext
|
// If we have a single option with no sidetext
|
||||||
const std::vector<Option>& option_set = line.get_options();
|
const std::vector<Option>& option_set = line.get_options();
|
||||||
if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 &&
|
if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 &&
|
||||||
option_set.front().opt.label.empty() &&
|
|
||||||
option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0)
|
option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0)
|
||||||
{
|
{
|
||||||
h_pos += 3 * blinking_button_width;
|
h_pos += 3 * blinking_button_width;
|
||||||
@ -167,13 +165,14 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_multioption_line = option_set.size() > 1;
|
||||||
for (auto opt : option_set) {
|
for (auto opt : option_set) {
|
||||||
Field* field = opt_group->get_field(opt.opt_id);
|
Field* field = opt_group->get_field(opt.opt_id);
|
||||||
correct_line_height(ctrl_line.height, field->getWindow());
|
correct_line_height(ctrl_line.height, field->getWindow());
|
||||||
|
|
||||||
ConfigOptionDef option = opt.opt;
|
ConfigOptionDef option = opt.opt;
|
||||||
// add label if any
|
// add label if any
|
||||||
if (!option.label.empty()) {
|
if (is_multioption_line && !option.label.empty()) {
|
||||||
//! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1
|
//! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1
|
||||||
label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ?
|
label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ?
|
||||||
_CTX(option.label, "Layers") : _(option.label);
|
_CTX(option.label, "Layers") : _(option.label);
|
||||||
@ -581,7 +580,6 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos)
|
|||||||
|
|
||||||
// If we have a single option with no sidetext just add it directly to the grid sizer
|
// If we have a single option with no sidetext just add it directly to the grid sizer
|
||||||
if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 &&
|
if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 &&
|
||||||
option_set.front().opt.label.empty() &&
|
|
||||||
option_set.front().side_widget == nullptr && og_line.get_extra_widgets().size() == 0)
|
option_set.front().side_widget == nullptr && og_line.get_extra_widgets().size() == 0)
|
||||||
{
|
{
|
||||||
if (field && field->undo_to_sys_bitmap())
|
if (field && field->undo_to_sys_bitmap())
|
||||||
@ -595,11 +593,12 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t bmp_rect_id = 0;
|
size_t bmp_rect_id = 0;
|
||||||
|
bool is_multioption_line = option_set.size() > 1;
|
||||||
for (const Option& opt : option_set) {
|
for (const Option& opt : option_set) {
|
||||||
field = ctrl->opt_group->get_field(opt.opt_id);
|
field = ctrl->opt_group->get_field(opt.opt_id);
|
||||||
ConfigOptionDef option = opt.opt;
|
ConfigOptionDef option = opt.opt;
|
||||||
// add label if any
|
// add label if any
|
||||||
if (!option.label.empty()) {
|
if (is_multioption_line && !option.label.empty()) {
|
||||||
//! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1
|
//! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1
|
||||||
label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ?
|
label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ?
|
||||||
_CTX(option.label, "Layers") : _(option.label);
|
_CTX(option.label, "Layers") : _(option.label);
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
#include "ConfigExceptions.hpp"
|
#include "ConfigExceptions.hpp"
|
||||||
#include "Plater.hpp"
|
#include "Plater.hpp"
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
|
#include "MainFrame.hpp"
|
||||||
#include "OG_CustomCtrl.hpp"
|
#include "OG_CustomCtrl.hpp"
|
||||||
#include "MsgDialog.hpp"
|
#include "MsgDialog.hpp"
|
||||||
#include "format.hpp"
|
#include "format.hpp"
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <wx/bookctrl.h>
|
||||||
#include <wx/numformatter.h>
|
#include <wx/numformatter.h>
|
||||||
#include <boost/algorithm/string/split.hpp>
|
#include <boost/algorithm/string/split.hpp>
|
||||||
#include <boost/algorithm/string/classification.hpp>
|
#include <boost/algorithm/string/classification.hpp>
|
||||||
@ -247,7 +249,6 @@ void OptionsGroup::activate_line(Line& line)
|
|||||||
|
|
||||||
// if we have a single option with no label, no sidetext just add it directly to sizer
|
// if we have a single option with no label, no sidetext just add it directly to sizer
|
||||||
if (option_set.size() == 1 && label_width == 0 && option_set.front().opt.full_width &&
|
if (option_set.size() == 1 && label_width == 0 && option_set.front().opt.full_width &&
|
||||||
option_set.front().opt.label.empty() &&
|
|
||||||
option_set.front().opt.sidetext.size() == 0 && option_set.front().side_widget == nullptr &&
|
option_set.front().opt.sidetext.size() == 0 && option_set.front().side_widget == nullptr &&
|
||||||
line.get_extra_widgets().size() == 0) {
|
line.get_extra_widgets().size() == 0) {
|
||||||
|
|
||||||
@ -326,7 +327,6 @@ void OptionsGroup::activate_line(Line& line)
|
|||||||
grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1);
|
grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1);
|
||||||
// If we have a single option with no sidetext just add it directly to the grid sizer
|
// If we have a single option with no sidetext just add it directly to the grid sizer
|
||||||
if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 &&
|
if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 &&
|
||||||
option_set.front().opt.label.empty() &&
|
|
||||||
option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) {
|
option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) {
|
||||||
const auto& option = option_set.front();
|
const auto& option = option_set.front();
|
||||||
const auto& field = build_field(option);
|
const auto& field = build_field(option);
|
||||||
@ -341,11 +341,12 @@ void OptionsGroup::activate_line(Line& line)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_multioption_line = option_set.size() > 1;
|
||||||
for (auto opt : option_set) {
|
for (auto opt : option_set) {
|
||||||
ConfigOptionDef option = opt.opt;
|
ConfigOptionDef option = opt.opt;
|
||||||
wxSizer* sizer_tmp = sizer;
|
wxSizer* sizer_tmp = sizer;
|
||||||
// add label if any
|
// add label if any
|
||||||
if (!option.label.empty() && !custom_ctrl) {
|
if ((is_multioption_line || line.label.IsEmpty()) && !option.label.empty() && !custom_ctrl) {
|
||||||
//! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1
|
//! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1
|
||||||
wxString str_label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ?
|
wxString str_label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ?
|
||||||
_CTX(option.label, "Layers") :
|
_CTX(option.label, "Layers") :
|
||||||
@ -507,15 +508,13 @@ void OptionsGroup::clear(bool destroy_custom_ctrl)
|
|||||||
m_fields.clear();
|
m_fields.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Line OptionsGroup::create_single_option_line(const Option& option, const std::string& path/* = std::string()*/) const {
|
Line OptionsGroup::create_single_option_line(const Option& option, const std::string& path/* = std::string()*/) const
|
||||||
// Line retval{ _(option.opt.label), _(option.opt.tooltip) };
|
{
|
||||||
wxString tooltip = _(option.opt.tooltip);
|
wxString tooltip = _(option.opt.tooltip);
|
||||||
edit_tooltip(tooltip);
|
edit_tooltip(tooltip);
|
||||||
Line retval{ _(option.opt.label), tooltip };
|
Line retval{ _(option.opt.label), tooltip };
|
||||||
retval.label_path = path;
|
retval.label_path = path;
|
||||||
Option tmp(option);
|
retval.append_option(option);
|
||||||
tmp.opt.label = std::string("");
|
|
||||||
retval.append_option(tmp);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -981,7 +980,8 @@ bool OptionsGroup::launch_browser(const std::string& path_end)
|
|||||||
bool launch = true;
|
bool launch = true;
|
||||||
|
|
||||||
if (get_app_config()->get("suppress_hyperlinks").empty()) {
|
if (get_app_config()->get("suppress_hyperlinks").empty()) {
|
||||||
RichMessageDialog dialog(nullptr, _L("Open hyperlink in default browser?"), _L("PrusaSlicer: Open hyperlink"), wxYES_NO);
|
wxWindow* parent = wxGetApp().mainframe->m_tabpanel;
|
||||||
|
RichMessageDialog dialog(parent, _L("Open hyperlink in default browser?"), _L("PrusaSlicer: Open hyperlink"), wxYES_NO);
|
||||||
dialog.ShowCheckBox(_L("Remember my choice"));
|
dialog.ShowCheckBox(_L("Remember my choice"));
|
||||||
int answer = dialog.ShowModal();
|
int answer = dialog.ShowModal();
|
||||||
|
|
||||||
@ -992,7 +992,7 @@ bool OptionsGroup::launch_browser(const std::string& path_end)
|
|||||||
_L("You will not be asked about it again on label hovering.") + "\n\n" +
|
_L("You will not be asked about it again on label hovering.") + "\n\n" +
|
||||||
format_wxstr(_L("Visit \"Preferences\" and check \"%1%\"\nto changes your choice."), preferences_item);
|
format_wxstr(_L("Visit \"Preferences\" and check \"%1%\"\nto changes your choice."), preferences_item);
|
||||||
|
|
||||||
MessageDialog msg_dlg(nullptr, msg, _L("PrusaSlicer: Don't ask me again"), wxOK | wxCANCEL | wxICON_INFORMATION);
|
MessageDialog msg_dlg(parent, msg, _L("PrusaSlicer: Don't ask me again"), wxOK | wxCANCEL | wxICON_INFORMATION);
|
||||||
if (msg_dlg.ShowModal() == wxID_CANCEL)
|
if (msg_dlg.ShowModal() == wxID_CANCEL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -1032,9 +1032,6 @@ void ogStaticText::SetText(const wxString& value, bool wrap/* = true*/)
|
|||||||
|
|
||||||
void ogStaticText::SetPathEnd(const std::string& link)
|
void ogStaticText::SetPathEnd(const std::string& link)
|
||||||
{
|
{
|
||||||
if (get_app_config()->get("suppress_hyperlinks") != "1")
|
|
||||||
SetToolTip(OptionsGroup::get_url(link));
|
|
||||||
|
|
||||||
Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& event) {
|
Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& event) {
|
||||||
if (HasCapture())
|
if (HasCapture())
|
||||||
return;
|
return;
|
||||||
@ -1048,7 +1045,11 @@ void ogStaticText::SetPathEnd(const std::string& link)
|
|||||||
OptionsGroup::launch_browser(link);
|
OptionsGroup::launch_browser(link);
|
||||||
event.Skip();
|
event.Skip();
|
||||||
} );
|
} );
|
||||||
Bind(wxEVT_ENTER_WINDOW, [this](wxMouseEvent& event) { FocusText(true) ; event.Skip(); });
|
Bind(wxEVT_ENTER_WINDOW, [this, link](wxMouseEvent& event) {
|
||||||
|
SetToolTip(OptionsGroup::get_url(get_app_config()->get("suppress_hyperlinks") != "1" ? link : std::string()));
|
||||||
|
FocusText(true);
|
||||||
|
event.Skip();
|
||||||
|
});
|
||||||
Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& event) { FocusText(false); event.Skip(); });
|
Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& event) { FocusText(false); event.Skip(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1260,7 +1260,11 @@ void Sidebar::show_info_sizer()
|
|||||||
if (selection.is_single_volume()) {
|
if (selection.is_single_volume()) {
|
||||||
std::vector<int> obj_idxs, vol_idxs;
|
std::vector<int> obj_idxs, vol_idxs;
|
||||||
wxGetApp().obj_list()->get_selection_indexes(obj_idxs, vol_idxs);
|
wxGetApp().obj_list()->get_selection_indexes(obj_idxs, vol_idxs);
|
||||||
assert(vol_idxs.size() == 1);
|
if (vol_idxs.size() != 1)
|
||||||
|
// Case when this fuction is called between update selection in ObjectList and on Canvas
|
||||||
|
// Like after try to delete last solid part in object, the object is selected in ObjectLIst when just a part is still selected on Canvas
|
||||||
|
// see https://github.com/prusa3d/PrusaSlicer/issues/7408
|
||||||
|
return;
|
||||||
vol = model_object->volumes[vol_idxs[0]];
|
vol = model_object->volumes[vol_idxs[0]];
|
||||||
t = model_object->instances[inst_idx]->get_matrix() * vol->get_matrix();
|
t = model_object->instances[inst_idx]->get_matrix() * vol->get_matrix();
|
||||||
}
|
}
|
||||||
@ -2347,7 +2351,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto loading = _L("Loading") + dots;
|
const auto loading = _L("Loading") + dots;
|
||||||
wxProgressDialog dlg(loading, "", 100, q, wxPD_AUTO_HIDE);
|
wxProgressDialog dlg(loading, "", 100, find_toplevel_parent(q), wxPD_AUTO_HIDE);
|
||||||
wxBusyCursor busy;
|
wxBusyCursor busy;
|
||||||
|
|
||||||
auto *new_model = (!load_model || one_by_one) ? nullptr : new Slic3r::Model();
|
auto *new_model = (!load_model || one_by_one) ? nullptr : new Slic3r::Model();
|
||||||
@ -6302,15 +6306,6 @@ void Plater::force_print_bed_update()
|
|||||||
|
|
||||||
void Plater::on_activate()
|
void Plater::on_activate()
|
||||||
{
|
{
|
||||||
#if defined(__linux__) || defined(_WIN32)
|
|
||||||
// Activating the main frame, and no window has keyboard focus.
|
|
||||||
// Set the keyboard focus to the visible Canvas3D.
|
|
||||||
if (this->p->view3D->IsShown() && wxWindow::FindFocus() != this->p->view3D->get_wxglcanvas())
|
|
||||||
CallAfter([this]() { this->p->view3D->get_wxglcanvas()->SetFocus(); });
|
|
||||||
else if (this->p->preview->IsShown() && wxWindow::FindFocus() != this->p->view3D->get_wxglcanvas())
|
|
||||||
CallAfter([this]() { this->p->preview->get_wxglcanvas()->SetFocus(); });
|
|
||||||
#endif
|
|
||||||
|
|
||||||
this->p->show_delayed_error_message();
|
this->p->show_delayed_error_message();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6875,7 +6870,6 @@ wxMenu* Plater::instance_menu() { return p->menus.instance_menu();
|
|||||||
wxMenu* Plater::layer_menu() { return p->menus.layer_menu(); }
|
wxMenu* Plater::layer_menu() { return p->menus.layer_menu(); }
|
||||||
wxMenu* Plater::multi_selection_menu() { return p->menus.multi_selection_menu(); }
|
wxMenu* Plater::multi_selection_menu() { return p->menus.multi_selection_menu(); }
|
||||||
|
|
||||||
|
|
||||||
SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() :
|
SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() :
|
||||||
m_was_scheduled(wxGetApp().plater()->is_background_process_update_scheduled())
|
m_was_scheduled(wxGetApp().plater()->is_background_process_update_scheduled())
|
||||||
{
|
{
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include "Notebook.hpp"
|
#include "Notebook.hpp"
|
||||||
#include "ButtonsDescription.hpp"
|
#include "ButtonsDescription.hpp"
|
||||||
#include "OG_CustomCtrl.hpp"
|
#include "OG_CustomCtrl.hpp"
|
||||||
#include <initializer_list>
|
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
@ -466,7 +465,7 @@ void PreferencesDialog::build(size_t selected_tab)
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Add "Dark Mode" tab
|
// Add "Dark Mode" tab
|
||||||
if (is_editor) {
|
{
|
||||||
// Add "Dark Mode" tab
|
// Add "Dark Mode" tab
|
||||||
m_optgroup_dark_mode = create_options_tab(_L("Dark mode (experimental)"), tabs);
|
m_optgroup_dark_mode = create_options_tab(_L("Dark mode (experimental)"), tabs);
|
||||||
m_optgroup_dark_mode->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
m_optgroup_dark_mode->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||||
@ -519,21 +518,29 @@ void PreferencesDialog::build(size_t selected_tab)
|
|||||||
this->CenterOnParent();
|
this->CenterOnParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreferencesDialog::update_ctrls_alignment()
|
std::vector<ConfigOptionsGroup*> PreferencesDialog::optgroups()
|
||||||
{
|
{
|
||||||
int max_ctrl_width{ 0 };
|
std::vector<ConfigOptionsGroup*> out;
|
||||||
std::initializer_list<ConfigOptionsGroup*> og_list = { m_optgroup_general.get(), m_optgroup_camera.get(), m_optgroup_gui.get()
|
out.reserve(4);
|
||||||
|
for (ConfigOptionsGroup* opt : { m_optgroup_general.get(), m_optgroup_camera.get(), m_optgroup_gui.get()
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
, m_optgroup_dark_mode.get()
|
, m_optgroup_dark_mode.get()
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
};
|
})
|
||||||
for (auto og : og_list) {
|
if (opt)
|
||||||
|
out.emplace_back(opt);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PreferencesDialog::update_ctrls_alignment()
|
||||||
|
{
|
||||||
|
int max_ctrl_width{ 0 };
|
||||||
|
for (ConfigOptionsGroup* og : this->optgroups())
|
||||||
if (int max = og->custom_ctrl->get_max_win_width();
|
if (int max = og->custom_ctrl->get_max_win_width();
|
||||||
max_ctrl_width < max)
|
max_ctrl_width < max)
|
||||||
max_ctrl_width = max;
|
max_ctrl_width = max;
|
||||||
}
|
|
||||||
if (max_ctrl_width)
|
if (max_ctrl_width)
|
||||||
for (auto og : og_list)
|
for (ConfigOptionsGroup* og : this->optgroups())
|
||||||
og->custom_ctrl->set_max_win_width(max_ctrl_width);
|
og->custom_ctrl->set_max_win_width(max_ctrl_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -622,9 +629,8 @@ void PreferencesDialog::accept(wxEvent&)
|
|||||||
|
|
||||||
void PreferencesDialog::on_dpi_changed(const wxRect &suggested_rect)
|
void PreferencesDialog::on_dpi_changed(const wxRect &suggested_rect)
|
||||||
{
|
{
|
||||||
m_optgroup_general->msw_rescale();
|
for (ConfigOptionsGroup* og : this->optgroups())
|
||||||
m_optgroup_camera->msw_rescale();
|
og->msw_rescale();
|
||||||
m_optgroup_gui->msw_rescale();
|
|
||||||
|
|
||||||
msw_buttons_rescale(this, em_unit(), { wxID_OK, wxID_CANCEL });
|
msw_buttons_rescale(this, em_unit(), { wxID_OK, wxID_CANCEL });
|
||||||
|
|
||||||
@ -788,7 +794,7 @@ void PreferencesDialog::init_highlighter(const t_config_option_key& opt_key)
|
|||||||
});
|
});
|
||||||
|
|
||||||
std::pair<OG_CustomCtrl*, bool*> ctrl = { nullptr, nullptr };
|
std::pair<OG_CustomCtrl*, bool*> ctrl = { nullptr, nullptr };
|
||||||
for (auto opt_group : { m_optgroup_general, m_optgroup_camera, m_optgroup_gui }) {
|
for (ConfigOptionsGroup* opt_group : this->optgroups()) {
|
||||||
ctrl = opt_group->get_custom_ctrl_with_blinking_ptr(opt_key, -1);
|
ctrl = opt_group->get_custom_ctrl_with_blinking_ptr(opt_key, -1);
|
||||||
if (ctrl.first && ctrl.second) {
|
if (ctrl.first && ctrl.second) {
|
||||||
m_highlighter.init(ctrl);
|
m_highlighter.init(ctrl);
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <wx/dialog.h>
|
#include <wx/dialog.h>
|
||||||
#include <wx/timer.h>
|
#include <wx/timer.h>
|
||||||
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
class wxColourPickerCtrl;
|
class wxColourPickerCtrl;
|
||||||
@ -61,6 +62,7 @@ protected:
|
|||||||
void create_settings_mode_widget();
|
void create_settings_mode_widget();
|
||||||
void create_settings_text_color_widget();
|
void create_settings_text_color_widget();
|
||||||
void init_highlighter(const t_config_option_key& opt_key);
|
void init_highlighter(const t_config_option_key& opt_key);
|
||||||
|
std::vector<ConfigOptionsGroup*> optgroups();
|
||||||
|
|
||||||
struct PreferencesHighlighter
|
struct PreferencesHighlighter
|
||||||
{
|
{
|
||||||
|
@ -98,8 +98,9 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, PrintHostPostUplo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (post_actions.has(PrintHostPostUploadAction::StartSimulation)) {
|
if (post_actions.has(PrintHostPostUploadAction::StartSimulation)) {
|
||||||
auto* btn_print = add_button(wxID_YES, false, _L("Upload and Simulate"));
|
// Using wxID_MORE as a button identifier to be different from the other buttons, wxID_MORE has no other meaning here.
|
||||||
btn_print->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
|
auto* btn_simulate = add_button(wxID_MORE, false, _L("Upload and Simulate"));
|
||||||
|
btn_simulate->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
|
||||||
if (validate_path(txt_filename->GetValue())) {
|
if (validate_path(txt_filename->GetValue())) {
|
||||||
post_upload_action = PrintHostPostUploadAction::StartSimulation;
|
post_upload_action = PrintHostPostUploadAction::StartSimulation;
|
||||||
EndDialog(wxID_OK);
|
EndDialog(wxID_OK);
|
||||||
|
@ -1731,7 +1731,9 @@ void TabPrint::update_description_lines()
|
|||||||
if (m_active_page && m_active_page->title() == "Output options" && m_post_process_explanation) {
|
if (m_active_page && m_active_page->title() == "Output options" && m_post_process_explanation) {
|
||||||
m_post_process_explanation->SetText(
|
m_post_process_explanation->SetText(
|
||||||
_u8L("Post processing scripts shall modify G-code file in place."));
|
_u8L("Post processing scripts shall modify G-code file in place."));
|
||||||
|
#ifndef __linux__
|
||||||
m_post_process_explanation->SetPathEnd("post-processing-scripts_283913");
|
m_post_process_explanation->SetPathEnd("post-processing-scripts_283913");
|
||||||
|
#endif // __linux__
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4479,7 +4481,7 @@ ConfigManipulation Tab::get_config_manipulation()
|
|||||||
return on_value_change(opt_key, value);
|
return on_value_change(opt_key, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
return ConfigManipulation(load_config, cb_toggle_field, cb_value_change);
|
return ConfigManipulation(load_config, cb_toggle_field, cb_value_change, nullptr, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -112,7 +112,17 @@ SCENARIO("2D convex hull of sinking object", "[3mf]") {
|
|||||||
{ -91501496, 4243 }
|
{ -91501496, 4243 }
|
||||||
};
|
};
|
||||||
|
|
||||||
bool res = hull_2d.points == result;
|
// Allow 1um error due to floating point rounding.
|
||||||
|
bool res = hull_2d.points.size() == result.size();
|
||||||
|
if (res)
|
||||||
|
for (size_t i = 0; i < result.size(); ++ i) {
|
||||||
|
const Point &p1 = result[i];
|
||||||
|
const Point &p2 = hull_2d.points[i];
|
||||||
|
if (std::abs(p1.x() - p2.x()) > 1 || std::abs(p1.y() - p2.y()) > 1) {
|
||||||
|
res = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
THEN("2D convex hull should match with reference") {
|
THEN("2D convex hull should match with reference") {
|
||||||
REQUIRE(res);
|
REQUIRE(res);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
set(SLIC3R_APP_NAME "PrusaSlicer")
|
set(SLIC3R_APP_NAME "PrusaSlicer")
|
||||||
set(SLIC3R_APP_KEY "PrusaSlicer")
|
set(SLIC3R_APP_KEY "PrusaSlicer")
|
||||||
set(SLIC3R_VERSION "2.4.0-beta2")
|
set(SLIC3R_VERSION "2.4.0-beta3")
|
||||||
set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN")
|
set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN")
|
||||||
set(SLIC3R_RC_VERSION "2,4,0,0")
|
set(SLIC3R_RC_VERSION "2,4,0,0")
|
||||||
set(SLIC3R_RC_VERSION_DOTS "2.4.0.0")
|
set(SLIC3R_RC_VERSION_DOTS "2.4.0.0")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user