Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSpencer Owen <owenspencer@gmail.com>2021-12-08 19:04:20 +0300
committerGitHub <noreply@github.com>2021-12-08 19:04:20 +0300
commit7e453380d69ee47770e526681ac81c62cda0d30b (patch)
tree419648ec54ee6060b731d0d117f33679423fb333
parentb81964be0f2ae122738e5fae9fe22ef9711aaaf4 (diff)
parentf697ede19ac93b9dee50c76aa01c9d17a69def19 (diff)
Merge branch 'prusa3d:master' into ender2-pro
-rw-r--r--build_win.bat42
-rw-r--r--deps/wxWidgets/wxWidgets.cmake2
-rw-r--r--src/libslic3r/GCode/SeamPlacer.cpp2
-rw-r--r--src/libslic3r/Layer.cpp21
-rw-r--r--src/libslic3r/Layer.hpp2
-rw-r--r--src/libslic3r/LayerRegion.cpp3
-rw-r--r--src/libslic3r/PrintConfig.cpp3
-rw-r--r--src/libslic3r/PrintObject.cpp29
-rw-r--r--src/slic3r/GUI/ConfigManipulation.cpp26
-rw-r--r--src/slic3r/GUI/ConfigManipulation.hpp5
-rw-r--r--src/slic3r/GUI/Field.cpp10
-rw-r--r--src/slic3r/GUI/GCodeViewer.cpp119
-rw-r--r--src/slic3r/GUI/GCodeViewer.hpp12
-rw-r--r--src/slic3r/GUI/GLShader.cpp30
-rw-r--r--src/slic3r/GUI/GLShader.hpp2
-rw-r--r--src/slic3r/GUI/GUI_App.cpp6
-rw-r--r--src/slic3r/GUI/GUI_App.hpp1
-rw-r--r--src/slic3r/GUI/GUI_ObjectList.cpp6
-rw-r--r--src/slic3r/GUI/GUI_ObjectSettings.cpp15
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp36
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp6
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp18
-rw-r--r--src/slic3r/GUI/ImGuiWrapper.cpp6
-rw-r--r--src/slic3r/GUI/ImGuiWrapper.hpp10
-rw-r--r--src/slic3r/GUI/MainFrame.cpp15
-rw-r--r--src/slic3r/GUI/MainFrame.hpp11
-rw-r--r--src/slic3r/GUI/MsgDialog.cpp5
-rw-r--r--src/slic3r/GUI/OG_CustomCtrl.cpp9
-rw-r--r--src/slic3r/GUI/OptionsGroup.cpp20
-rw-r--r--src/slic3r/GUI/Plater.cpp29
-rw-r--r--src/slic3r/GUI/Plater.hpp10
-rw-r--r--src/slic3r/GUI/Preferences.cpp32
-rw-r--r--src/slic3r/GUI/Preferences.hpp2
-rw-r--r--src/slic3r/GUI/PrintHostDialogs.cpp5
-rw-r--r--src/slic3r/GUI/Tab.cpp13
-rw-r--r--tests/libslic3r/test_3mf.cpp12
36 files changed, 334 insertions, 241 deletions
diff --git a/build_win.bat b/build_win.bat
index a5af27609..1a735d7cd 100644
--- a/build_win.bat
+++ b/build_win.bat
@@ -6,7 +6,8 @@
@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.
-@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 [-RUN ^<console^|custom^|none^|viewer^|window^>]
@ECHO.
@@ -14,6 +15,10 @@
@ECHO Default: %PS_ARCH_HOST%
@ECHO -c -CONFIG MSVC project config
@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 all - clean and build deps and app
@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_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
pushd %~dp0
SET PS_CONFIG=RelWithDebInfo
@@ -62,6 +84,8 @@ SET PS_ARCH=%PROCESSOR_ARCHITECTURE:amd64=x64%
CALL :TOLOWER PS_ARCH
SET PS_RUN=none
SET PS_DESTDIR=
+SET PS_VERSION=
+SET PS_PRODUCT=%PS_PRODUCT_DEFAULT%
CALL :RESOLVE_DESTDIR_CACHE
REM Set up parameters used by help menu
@@ -75,7 +99,7 @@ SET EXIT_STATUS=1
SET PS_CURRENT_STEP=arguments
SET PARSER_STATE=
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 "" (
@ECHO ERROR: Invalid switch: %PARSER_FAIL% 1>&2
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"
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.
IF "%PS_ASK_TO_CONTINUE%" EQU "" GOTO :BUILD_ENV
@ECHO.
@@ -142,9 +175,6 @@ SET PS_CURRENT_STEP=environment
@ECHO ** Run App: %PS_RUN%
@ECHO ** Deps path: %PS_DESTDIR%
@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%
CALL "%MSVC_DIR%\Common7\Tools\vsdevcmd.bat" -arch=%PS_ARCH% -host_arch=%PS_ARCH_HOST% -app_platform=Desktop
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%
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.
-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
IF EXIST "%PS_DEPS_PATH_FILE_FOR_CONFIG%" (
FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE_FOR_CONFIG%") DO (
diff --git a/deps/wxWidgets/wxWidgets.cmake b/deps/wxWidgets/wxWidgets.cmake
index 73d841014..62222f812 100644
--- a/deps/wxWidgets/wxWidgets.cmake
+++ b/deps/wxWidgets/wxWidgets.cmake
@@ -13,7 +13,7 @@ prusaslicer_add_cmake_project(wxWidgets
# GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets"
# GIT_TAG tm_cross_compile #${_wx_git_tag}
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
CMAKE_ARGS
-DwxBUILD_PRECOMP=ON
diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp
index 6d082a431..f74775a9a 100644
--- a/src/libslic3r/GCode/SeamPlacer.cpp
+++ b/src/libslic3r/GCode/SeamPlacer.cpp
@@ -498,7 +498,7 @@ Point SeamPlacer::calculate_seam(const Layer& layer, const SeamPosition seam_pos
else if (seam_position == spRear) {
// Object is centered around (0,0) in its current coordinate system.
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;
} if (seam_position == spNearest) {
// last_pos already contains current nozzle position
diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp
index 5c661ed68..d273fde96 100644
--- a/src/libslic3r/Layer.cpp
+++ b/src/libslic3r/Layer.cpp
@@ -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
{
assert(offset_scaled >= 0.f);
@@ -179,7 +198,7 @@ void Layer::make_perimeters()
// group slices (surfaces) according to number of extra perimeters
std::map<unsigned short, Surfaces> slices; // extra_perimeters => [ surface, surface... ]
for (LayerRegion *layerm : layerms) {
- for (Surface &surface : layerm->slices.surfaces)
+ for (const Surface &surface : layerm->slices.surfaces)
slices[surface.extra_perimeters].emplace_back(surface);
if (layerm->region().config().fill_density > layerm_config->region().config().fill_density)
layerm_config = layerm;
diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp
index 516b6da9b..0071c7f6e 100644
--- a/src/libslic3r/Layer.hpp
+++ b/src/libslic3r/Layer.hpp
@@ -137,6 +137,8 @@ public:
//FIXME Review whether not to simplify the code by keeping the raw_slices all the time.
void backup_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.
ExPolygons merged(float offset) const;
template <class T> bool any_internal_region_slice_contains(const T &item) const {
diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp
index 4dbffe7b0..fd29d6d54 100644
--- a/src/libslic3r/LayerRegion.cpp
+++ b/src/libslic3r/LayerRegion.cpp
@@ -51,8 +51,7 @@ void LayerRegion::slices_to_fill_surfaces_clipped()
// so we're safe. This guarantees idempotence of prepare_infill() also in case
// that combine_infill() turns some fill_surface into VOID surfaces.
// Collect polygons per surface type.
- std::vector<SurfacesPtr> by_surface;
- by_surface.assign(size_t(stCount), SurfacesPtr());
+ std::array<SurfacesPtr, size_t(stCount)> by_surface;
for (Surface &surface : this->slices.surfaces)
by_surface[size_t(surface.surface_type)].emplace_back(&surface);
// Trim surfaces by the fill_boundaries.
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index 011539aa4..b2e645714 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -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 "
"bottom layer to improve adhesion and tolerance for non perfect build plates.");
def->sidetext = L("mm");
+ def->min = 0;
def->ratio_over = "layer_height";
def->set_default_value(new ConfigOptionFloatOrPercent(0.35, false));
@@ -3772,7 +3773,7 @@ void PrintConfigDef::init_sla_params()
def->enum_labels.push_back(L("Slow"));
def->enum_labels.push_back(L("Fast"));
def->mode = comAdvanced;
- def->set_default_value(new ConfigOptionEnum<SLAMaterialSpeed>(slamsSlow));
+ def->set_default_value(new ConfigOptionEnum<SLAMaterialSpeed>(slamsFast));
}
void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value)
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index eee0c2aba..05b8c9eb6 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -6,6 +6,7 @@
#include "Geometry.hpp"
#include "I18N.hpp"
#include "Layer.hpp"
+#include "MutablePolygon.hpp"
#include "SupportMaterial.hpp"
#include "Surface.hpp"
#include "Slicing.hpp"
@@ -226,6 +227,17 @@ void PrintObject::prepare_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.
// Then the classifcation of $layerm->slices is transfered onto
// 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 *lower_layer = m_layers[layer_id - 1];
// Detect things that we need to support.
- // Cummulative slices.
- Polygons slices;
- polygons_append(slices, layer->lslices);
// Cummulative fill surfaces.
Polygons fill_surfaces;
// 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
// 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.
//FIXME Offset2 eats out from both sides, while the perimeters are create outside in.
//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
polygons_append(overhangs, opening(perimeters, pw));
}
- // Find new internal infill.
- polygons_append(overhangs, std::move(upper_internal));
- upper_internal = intersection(overhangs, lower_layer_internal_surfaces);
+ // Merge the new overhangs, find new internal infill.
+ polygons_append(upper_internal, std::move(overhangs));
+ 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.
for (LayerRegion *layerm : lower_layer->m_regions) {
if (layerm->region().config().fill_density.value == 0)
diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp
index 0b2af37b8..fe108b1a6 100644
--- a/src/slic3r/GUI/ConfigManipulation.cpp
+++ b/src/slic3r/GUI/ConfigManipulation.cpp
@@ -47,8 +47,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
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."));
- //wxMessageDialog dialog(nullptr, msg_text, _(L("Layer height")), wxICON_WARNING | wxOK);
- MessageDialog dialog(nullptr, msg_text, _(L("Layer height")), wxICON_WARNING | wxOK);
+ MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Layer height")), wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
dialog.ShowModal();
@@ -60,8 +59,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
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."));
- //wxMessageDialog dialog(nullptr, msg_text, _(L("First layer height")), wxICON_WARNING | wxOK);
- MessageDialog 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);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
dialog.ShowModal();
@@ -90,8 +88,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
"- Detect thin walls disabled"));
if (is_global_config)
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(nullptr, msg_text, _(L("Spiral Vase")),
+ MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Spiral Vase")),
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
DynamicPrintConfig new_conf = *config;
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)."));
if (is_global_config)
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 (nullptr, msg_text, _(L("Wipe Tower")),
+ MessageDialog dialog (m_msg_dlg_parent, msg_text, _(L("Wipe Tower")),
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
DynamicPrintConfig new_conf = *config;
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."));
if (is_global_config)
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(nullptr, msg_text, _(L("Wipe Tower")),
+ MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Wipe Tower")),
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
DynamicPrintConfig new_conf = *config;
auto answer = dialog.ShowModal();
@@ -169,7 +164,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
"- Detect bridging perimeters"));
if (is_global_config)
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;
auto answer = dialog.ShowModal();
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()]));
if (is_global_config)
msg_text += "\n\n" + _L("Shall I switch to rectilinear fill pattern?");
- //wxMessageDialog dialog(nullptr, msg_text, _L("Infill"),
- MessageDialog dialog(nullptr, msg_text, _L("Infill"),
+ MessageDialog dialog(m_msg_dlg_parent, msg_text, _L("Infill"),
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK) );
DynamicPrintConfig new_conf = *config;
auto answer = dialog.ShowModal();
@@ -331,8 +325,7 @@ void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, con
if (head_penetration > 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(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);
DynamicPrintConfig new_conf = *config;
if (dialog.ShowModal() == wxID_OK) {
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) {
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(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);
DynamicPrintConfig new_conf = *config;
if (dialog.ShowModal() == wxID_OK) {
diff --git a/src/slic3r/GUI/ConfigManipulation.hpp b/src/slic3r/GUI/ConfigManipulation.hpp
index 0e6815753..32ddb52a9 100644
--- a/src/slic3r/GUI/ConfigManipulation.hpp
+++ b/src/slic3r/GUI/ConfigManipulation.hpp
@@ -30,15 +30,18 @@ class ConfigManipulation
// callback to propagation of changed value, if needed
std::function<void(const std::string&, const boost::any&)> cb_value_change = nullptr;
ModelConfig* local_config = nullptr;
+ wxWindow* m_msg_dlg_parent {nullptr};
public:
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&, const boost::any&)> cb_value_change,
- ModelConfig* local_config = nullptr) :
+ ModelConfig* local_config = nullptr,
+ wxWindow* msg_dlg_parent = nullptr) :
load_config(load_config),
cb_toggle_field(cb_toggle_field),
cb_value_change(cb_value_change),
+ m_msg_dlg_parent(msg_dlg_parent),
local_config(local_config) {}
ConfigManipulation() {}
diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp
index 67f78d26e..5ec622b87 100644
--- a/src/slic3r/GUI/Field.cpp
+++ b/src/slic3r/GUI/Field.cpp
@@ -291,6 +291,16 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
case coString:
case coStrings:
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() != '%')
{
double val = 0.;
diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp
index cdc9c33a4..574ba6ec5 100644
--- a/src/slic3r/GUI/GCodeViewer.cpp
+++ b/src/slic3r/GUI/GCodeViewer.cpp
@@ -977,8 +977,7 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const
for (const RenderPath& path : t_buffer.render_paths) {
colors.push_back(path.color);
}
- std::sort(colors.begin(), colors.end());
- colors.erase(std::unique(colors.begin(), colors.end()), colors.end());
+ sort_remove_duplicates(colors);
// save materials file
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;
wxProgressDialog* progress_dialog = wxGetApp().is_gcode_viewer() ?
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;
@@ -2020,13 +2019,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
}
// roles -> remove duplicates
- std::sort(m_roles.begin(), m_roles.end());
- m_roles.erase(std::unique(m_roles.begin(), m_roles.end()), m_roles.end());
+ sort_remove_duplicates(m_roles);
m_roles.shrink_to_fit();
// extruder ids -> remove duplicates
- std::sort(m_extruder_ids.begin(), m_extruder_ids.end());
- m_extruder_ids.erase(std::unique(m_extruder_ids.begin(), m_extruder_ids.end()), m_extruder_ids.end());
+ sort_remove_duplicates(m_extruder_ids);
m_extruder_ids.shrink_to_fit();
// 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 };
- if (render_path == nullptr || !RenderPathPropertyEqual()(*render_path, key))
- render_path = const_cast<RenderPath*>(&(*buffer.render_paths.emplace(key).first));
+ if (render_path == nullptr || !RenderPathPropertyEqual()(*render_path, key)) {
+ buffer.render_paths.emplace_back(key);
+ render_path = const_cast<RenderPath*>(&buffer.render_paths.back());
+ }
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)
@@ -2433,6 +2432,14 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
#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
for (size_t b = 0; b < m_buffers.size(); ++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())))) :
static_cast<float>(viewport[3]) * 0.0005;
-#if ENABLE_GCODE_VIEWER_STATISTICS
- 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) {
+ auto shader_init_as_points = [zoom, point_size, near_plane_height](GLShaderProgram& shader) {
#if ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS
shader.set_uniform("use_fixed_screen_size", 1);
#else
@@ -2640,65 +2642,67 @@ void GCodeViewer::render_toolpaths()
shader.set_uniform("percent_center_radius", 0.33f);
shader.set_uniform("point_size", point_size);
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_POINT_SPRITE));
- for (const RenderPath& path : buffer.render_paths) {
- if (path.ibuffer_id == ibuffer_id) {
- shader.set_uniform("uniform_color", path.color);
- glsafe(::glMultiDrawElements(GL_POINTS, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
+ 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_POINTS, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
#if ENABLE_GCODE_VIEWER_STATISTICS
- ++m_statistics.gl_multi_points_calls_count;
+ ++m_statistics.gl_multi_points_calls_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
- }
}
glsafe(::glDisable(GL_POINT_SPRITE));
glsafe(::glDisable(GL_VERTEX_PROGRAM_POINT_SIZE));
};
+ auto shader_init_as_lines = [light_intensity](GLShaderProgram &shader) {
+ shader.set_uniform("light_intensity", light_intensity);
+ };
+ auto render_as_lines = [
#if ENABLE_GCODE_VIEWER_STATISTICS
- auto render_as_lines = [this, light_intensity]
-#else
- auto render_as_lines = [light_intensity]
+ this
#endif // ENABLE_GCODE_VIEWER_STATISTICS
- (const TBuffer& buffer, unsigned int ibuffer_id, GLShaderProgram& shader) {
- shader.set_uniform("light_intensity", light_intensity);
- for (const RenderPath& path : buffer.render_paths) {
- if (path.ibuffer_id == ibuffer_id) {
- shader.set_uniform("uniform_color", path.color);
- glsafe(::glMultiDrawElements(GL_LINES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
+ ](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()));
#if ENABLE_GCODE_VIEWER_STATISTICS
- ++m_statistics.gl_multi_lines_calls_count;
+ ++m_statistics.gl_multi_lines_calls_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
- }
}
};
+ auto render_as_triangles = [
#if ENABLE_GCODE_VIEWER_STATISTICS
- auto render_as_triangles = [this]
-#else
- auto render_as_triangles = []
+ this
#endif // ENABLE_GCODE_VIEWER_STATISTICS
- (const TBuffer& buffer, unsigned int ibuffer_id, GLShaderProgram& shader) {
- for (const RenderPath& path : buffer.render_paths) {
- if (path.ibuffer_id == ibuffer_id) {
- shader.set_uniform("uniform_color", path.color);
- glsafe(::glMultiDrawElements(GL_TRIANGLES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
+ ](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_TRIANGLES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
#if ENABLE_GCODE_VIEWER_STATISTICS
- ++m_statistics.gl_multi_triangles_calls_count;
+ ++m_statistics.gl_multi_triangles_calls_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
- }
}
};
+ auto render_as_instanced_model = [
#if ENABLE_GCODE_VIEWER_STATISTICS
- auto render_as_instanced_model = [this]
-#else
- auto render_as_instanced_model = []
+ this
#endif // ENABLE_GCODE_VIEWER_STATISTICS
- (TBuffer& buffer, GLShaderProgram & shader) {
+ ](TBuffer& buffer, GLShaderProgram & shader) {
for (auto& range : buffer.model.instances.render_ranges.ranges) {
if (range.vbo == 0 && range.count > 0) {
glsafe(::glGenBuffers(1, &range.vbo));
@@ -2803,8 +2807,20 @@ void GCodeViewer::render_toolpaths()
shader->set_uniform("emission_factor", 0.0f);
}
else {
- for (size_t j = 0; j < buffer.indices.size(); ++j) {
- const IBuffer& i_buffer = buffer.indices[j];
+ switch (buffer.render_primitive_type) {
+ 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(::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));
+ // Render all elements with it_path->ibuffer_id == ibuffer_id, possible with varying colors.
switch (buffer.render_primitive_type)
{
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;
}
case TBuffer::ERenderPrimitiveType::Line: {
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;
}
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;
}
default: { break; }
diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp
index 9147eec84..c56e88c88 100644
--- a/src/slic3r/GUI/GCodeViewer.hpp
+++ b/src/slic3r/GUI/GCodeViewer.hpp
@@ -259,14 +259,6 @@ class GCodeViewer
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 {
bool operator() (const RenderPath &l, const RenderPath &r) const {
if (l.tbuffer_id < r.tbuffer_id)
@@ -319,9 +311,7 @@ class GCodeViewer
std::string shader;
std::vector<Path> paths;
- // std::set seems to perform significantly better, at least on Windows.
-// std::unordered_set<RenderPath, RenderPathPropertyHash, RenderPathPropertyEqual> render_paths;
- std::set<RenderPath, RenderPathPropertyLower> render_paths;
+ std::vector<RenderPath> render_paths;
bool visible{ false };
void reset();
diff --git a/src/slic3r/GUI/GLShader.cpp b/src/slic3r/GUI/GLShader.cpp
index 0473e5344..9c1e93652 100644
--- a/src/slic3r/GUI/GLShader.cpp
+++ b/src/slic3r/GUI/GLShader.cpp
@@ -358,12 +358,38 @@ bool GLShaderProgram::set_uniform(const char* name, const Vec3d& value) 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
{
- 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
diff --git a/src/slic3r/GUI/GLShader.hpp b/src/slic3r/GUI/GLShader.hpp
index c92ea274a..d7b92000d 100644
--- a/src/slic3r/GUI/GLShader.hpp
+++ b/src/slic3r/GUI/GLShader.hpp
@@ -29,6 +29,8 @@ public:
private:
std::string m_name;
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:
~GLShaderProgram();
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index c7654fcd6..bda7394ed 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -883,6 +883,8 @@ void GUI_App::init_app_config()
dir = wxFileName::GetHomeDir() + wxS("/.config");
set_data_dir((dir + "/" + GetAppName()).ToUTF8().data());
#endif
+ } else {
+ m_datadir_redefined = true;
}
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
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)
std::string config_path = app_config->config_path();
boost::filesystem::path parent_file_path(config_path);
diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp
index 82feb3282..b1b0a7786 100644
--- a/src/slic3r/GUI/GUI_App.hpp
+++ b/src/slic3r/GUI/GUI_App.hpp
@@ -352,6 +352,7 @@ private:
void check_updates(const bool verbose);
bool m_init_app_config_from_older { false };
+ bool m_datadir_redefined { false };
std::string m_older_data_dir_path;
boost::optional<Semver> m_last_config_version;
};
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 7d689ff6a..f4d27b0b2 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1446,7 +1446,7 @@ void ObjectList::load_part(ModelObject& model_object, std::vector<ModelVolume*>&
else
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;
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
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;
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"));
// 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);
int model_idx{ 0 };
if (vol_idxs.empty()) {
diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp
index c92ddd3b5..c9a7cd330 100644
--- a/src/slic3r/GUI/GUI_ObjectSettings.cpp
+++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp
@@ -110,12 +110,6 @@ bool ObjectSettings::update_settings_list()
update_settings_list();
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;
};
@@ -227,11 +221,12 @@ void ObjectSettings::update_config_values(ModelConfig* config)
update_config_values(config);
if (is_added) {
- wxTheApp->CallAfter([this]() {
+// #ysFIXME - Delete after testing! Very likely this CallAfret is no needed
+// wxTheApp->CallAfter([this]() {
wxWindowUpdateLocker noUpdates(m_parent);
update_settings_list();
m_parent->Layout();
- });
+// });
}
};
@@ -253,9 +248,9 @@ void ObjectSettings::update_config_values(ModelConfig* config)
{
const int obj_idx = objects_model->GetObjectIdByItem(item);
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);
- printer_technology == ptFFF ? config_manipulation.update_print_fff_config(&main_config) :
- config_manipulation.update_print_sla_config(&main_config) ;
+ // and then from its own config
}
main_config.apply(config->get(), true);
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
index 614e83811..691a86706 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
@@ -550,24 +550,24 @@ RENDER_AGAIN:
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
ImGui::PushItemWidth(window_width - settings_sliders_left);
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);
- bool slider_clicked = ImGui::IsItemClicked(); // someone clicked the slider
- bool slider_edited = ImGui::IsItemEdited(); // someone is dragging the slider
- bool slider_released = ImGui::IsItemDeactivatedAfterEdit(); // someone has just released the slider
+ bool slider_clicked = m_imgui->get_last_slider_status().clicked; // someone clicked the slider
+ bool slider_edited =m_imgui->get_last_slider_status().edited; // someone is dragging 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) {
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("quality"));
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
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);
- slider_clicked |= ImGui::IsItemClicked();
- slider_edited |= ImGui::IsItemEdited();
- slider_released |= ImGui::IsItemDeactivatedAfterEdit();
+ slider_clicked |= m_imgui->get_last_slider_status().clicked;
+ slider_edited |= m_imgui->get_last_slider_status().edited;
+ slider_released |= m_imgui->get_last_slider_status().deactivated_after_edit;
}
if (current_mode >= closing_d_mode) {
@@ -575,12 +575,12 @@ RENDER_AGAIN:
m_imgui->text(m_desc.at("closing_distance"));
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");
- if (ImGui::IsItemHovered())
+ if (m_imgui->get_last_slider_status().hovered)
m_imgui->tooltip((_utf8(opts[2].second->tooltip)).c_str(), max_tooltip_width);
- slider_clicked |= ImGui::IsItemClicked();
- slider_edited |= ImGui::IsItemEdited();
- slider_released |= ImGui::IsItemDeactivatedAfterEdit();
+ slider_clicked |= m_imgui->get_last_slider_status().clicked;
+ slider_edited |= m_imgui->get_last_slider_status().edited;
+ slider_released |= m_imgui->get_last_slider_status().deactivated_after_edit;
}
if (slider_clicked) {
@@ -627,9 +627,9 @@ RENDER_AGAIN:
//complete non-sense.
diam = std::clamp(diam, 0.1f, diameter_upper_cap);
m_new_hole_radius = diam / 2.f;
- bool clicked = ImGui::IsItemClicked();
- bool edited = ImGui::IsItemEdited();
- bool deactivated = ImGui::IsItemDeactivatedAfterEdit();
+ bool clicked = m_imgui->get_last_slider_status().clicked;
+ bool edited = m_imgui->get_last_slider_status().edited;
+ bool deactivated = m_imgui->get_last_slider_status().deactivated_after_edit;
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc["hole_depth"]);
@@ -638,9 +638,9 @@ RENDER_AGAIN:
// Same as above:
m_new_hole_height = std::clamp(m_new_hole_height, 0.f, 100.f);
- clicked |= ImGui::IsItemClicked();
- edited |= ImGui::IsItemEdited();
- deactivated |= ImGui::IsItemDeactivatedAfterEdit();
+ clicked |= m_imgui->get_last_slider_status().clicked;
+ edited |= m_imgui->get_last_slider_status().edited;
+ deactivated |= m_imgui->get_last_slider_status().deactivated_after_edit;;
// Following is a nasty way to:
// - save the initial value of the slider before one starts messing with it
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp
index e164caee6..8b866c7c9 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp
@@ -859,9 +859,9 @@ void GLPaintContour::finalize_geometry()
if (!this->contour_indices.empty()) {
glsafe(::glGenBuffers(1, &this->m_contour_EBO_id));
- glsafe(::glBindBuffer(GL_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(::glBindBuffer(GL_ARRAY_BUFFER, 0));
+ glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->m_contour_EBO_id));
+ glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->contour_indices.size() * sizeof(unsigned int), this->contour_indices.data(), GL_STATIC_DRAW));
+ glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
this->contour_indices.clear();
}
}
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index 9170db603..29e1fd2f3 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -687,16 +687,16 @@ RENDER_AGAIN:
// - take correct undo/redo snapshot after the user is done with moving the slider
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");
- if (ImGui::IsItemClicked()) {
+ if (m_imgui->get_last_slider_status().clicked) {
if (m_old_point_head_diameter == 0.f)
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)
if (cache_entry.selected)
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
for (auto& cache_entry : m_editing_cache)
if (cache_entry.selected)
@@ -747,18 +747,18 @@ RENDER_AGAIN:
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");
- bool slider_clicked = ImGui::IsItemClicked(); // someone clicked the slider
- bool slider_edited = ImGui::IsItemEdited(); // someone is dragging the slider
- bool slider_released = ImGui::IsItemDeactivatedAfterEdit(); // someone has just released the slider
+ bool slider_clicked = m_imgui->get_last_slider_status().clicked; // someone clicked the slider
+ bool slider_edited = m_imgui->get_last_slider_status().edited; // someone is dragging the slider
+ bool slider_released = m_imgui->get_last_slider_status().deactivated_after_edit; // someone has just released the slider
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("points_density"));
ImGui::SameLine(settings_sliders_left);
m_imgui->slider_float("##points_density", &density, 0.f, 200.f, "%.f %%");
- slider_clicked |= ImGui::IsItemClicked();
- slider_edited |= ImGui::IsItemEdited();
- slider_released |= ImGui::IsItemDeactivatedAfterEdit();
+ slider_clicked |= m_imgui->get_last_slider_status().clicked;
+ slider_edited |= m_imgui->get_last_slider_status().edited;
+ 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
m_minimal_point_distance_stash = minimal_point_distance;
diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp
index 325067aea..a01e2ed69 100644
--- a/src/slic3r/GUI/ImGuiWrapper.cpp
+++ b/src/slic3r/GUI/ImGuiWrapper.cpp
@@ -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);
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())
this->tooltip(into_u8(tooltip).c_str(), max_tooltip_width);
diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp
index 590ef95b0..255c4171b 100644
--- a/src/slic3r/GUI/ImGuiWrapper.hpp
+++ b/src/slic3r/GUI/ImGuiWrapper.hpp
@@ -39,6 +39,13 @@ class ImGuiWrapper
std::string m_clipboard_text;
public:
+ struct LastSliderStatus {
+ bool hovered { false };
+ bool edited { false };
+ bool clicked { false };
+ bool deactivated_after_edit { false };
+ };
+
ImGuiWrapper();
~ImGuiWrapper();
@@ -63,6 +70,7 @@ public:
ImVec2 get_item_spacing() 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_bg_alpha(float alpha);
@@ -146,6 +154,8 @@ private:
static const char* clipboard_get(void* user_data);
static void clipboard_set(void* user_data, const char* text);
+
+ LastSliderStatus m_last_slider_status;
};
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index 32061fd32..8a9702c40 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -2101,21 +2101,6 @@ void MainFrame::technology_changed()
}
-#if defined(__linux__) || defined(_WIN32)
-// wxWidgets callback to enable / disable window and all its children windows.
-// called by wxWindowDisabler when entering / leaving modal dialog loop.
-// Unfortunately the wxWindowDisabler calls Enable(true) after the wxEVT_ACTIVATE event is processed
-// while MainFrame is not yet enabled, thus restoring focus in OnActivate() handler fails
-// and we need to do it now.
-bool MainFrame::Enable(bool enable)
-{
- bool retval = DPIFrame::Enable(enable);
- if (enable && retval)
- this->plater()->restore_keyboard_focus();
- return retval;
-}
-#endif
-
//
// Called after the Preferences dialog is closed and the program settings are saved.
// Update the UI based on the current preferences.
diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp
index 9e09bf088..951ed70a1 100644
--- a/src/slic3r/GUI/MainFrame.hpp
+++ b/src/slic3r/GUI/MainFrame.hpp
@@ -148,15 +148,6 @@ public:
void update_title();
-#if defined(__linux__) || defined(_WIN32)
- // wxWidgets callback to enable / disable window and all its children windows.
- // called by wxWindowDisabler when entering / leaving modal dialog loop.
- // Unfortunately the wxWindowDisabler calls Enable(true) after the wxEVT_ACTIVATE event is processed
- // while MainFrame is not yet enabled, thus restoring focus in OnActivate() handler fails
- // and we need to do it now.
- bool Enable(bool enable = true) override;
-#endif
-
void init_tabpanel();
void create_preset_tabs();
void add_created_tab(Tab* panel, const std::string& bmp_name = "");
@@ -211,7 +202,7 @@ public:
SettingsDialog m_settings_dialog;
DiffPresetDialog diff_dialog;
wxWindow* m_plater_page{ nullptr };
- wxProgressDialog* m_progress_dialog { nullptr };
+// wxProgressDialog* m_progress_dialog { nullptr };
PrintHostQueueDialog* m_printhost_queue_dlg;
// std::shared_ptr<ProgressStatusBar> m_statusbar;
diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp
index a505c2507..56e990577 100644
--- a/src/slic3r/GUI/MsgDialog.cpp
+++ b/src/slic3r/GUI/MsgDialog.cpp
@@ -136,7 +136,8 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin
int em = wxGetApp().em_unit();
// 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 pos = 0;
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);
- 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, "\n", "<br>");
if (monospaced_font)
diff --git a/src/slic3r/GUI/OG_CustomCtrl.cpp b/src/slic3r/GUI/OG_CustomCtrl.cpp
index e9153c70f..ee19e5da5 100644
--- a/src/slic3r/GUI/OG_CustomCtrl.cpp
+++ b/src/slic3r/GUI/OG_CustomCtrl.cpp
@@ -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 (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 &&
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
const std::vector<Option>& option_set = line.get_options();
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)
{
h_pos += 3 * blinking_button_width;
@@ -167,13 +165,14 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/)
break;
}
+ bool is_multioption_line = option_set.size() > 1;
for (auto opt : option_set) {
Field* field = opt_group->get_field(opt.opt_id);
correct_line_height(ctrl_line.height, field->getWindow());
ConfigOptionDef option = opt.opt;
// 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
label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ?
_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 (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)
{
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;
+ bool is_multioption_line = option_set.size() > 1;
for (const Option& opt : option_set) {
field = ctrl->opt_group->get_field(opt.opt_id);
ConfigOptionDef option = opt.opt;
// 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
label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ?
_CTX(option.label, "Layers") : _(option.label);
diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp
index 23c9051be..6039dcbcb 100644
--- a/src/slic3r/GUI/OptionsGroup.cpp
+++ b/src/slic3r/GUI/OptionsGroup.cpp
@@ -2,11 +2,13 @@
#include "ConfigExceptions.hpp"
#include "Plater.hpp"
#include "GUI_App.hpp"
+#include "MainFrame.hpp"
#include "OG_CustomCtrl.hpp"
#include "MsgDialog.hpp"
#include "format.hpp"
#include <utility>
+#include <wx/bookctrl.h>
#include <wx/numformatter.h>
#include <boost/algorithm/string/split.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 (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 &&
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);
// 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 &&
- option_set.front().opt.label.empty() &&
option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) {
const auto& option = option_set.front();
const auto& field = build_field(option);
@@ -341,11 +341,12 @@ void OptionsGroup::activate_line(Line& line)
return;
}
+ bool is_multioption_line = option_set.size() > 1;
for (auto opt : option_set) {
ConfigOptionDef option = opt.opt;
wxSizer* sizer_tmp = sizer;
// 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
wxString str_label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ?
_CTX(option.label, "Layers") :
@@ -507,15 +508,13 @@ void OptionsGroup::clear(bool destroy_custom_ctrl)
m_fields.clear();
}
-Line OptionsGroup::create_single_option_line(const Option& option, const std::string& path/* = std::string()*/) const {
-// Line retval{ _(option.opt.label), _(option.opt.tooltip) };
+Line OptionsGroup::create_single_option_line(const Option& option, const std::string& path/* = std::string()*/) const
+{
wxString tooltip = _(option.opt.tooltip);
edit_tooltip(tooltip);
Line retval{ _(option.opt.label), tooltip };
retval.label_path = path;
- Option tmp(option);
- tmp.opt.label = std::string("");
- retval.append_option(tmp);
+ retval.append_option(option);
return retval;
}
@@ -981,7 +980,8 @@ bool OptionsGroup::launch_browser(const std::string& path_end)
bool launch = true;
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"));
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" +
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)
return false;
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index dd1ccb91f..0485b0075 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -2351,7 +2351,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
}
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;
auto *new_model = (!load_model || one_by_one) ? nullptr : new Slic3r::Model();
@@ -6306,36 +6306,9 @@ void Plater::force_print_bed_update()
void Plater::on_activate()
{
-#if defined(__linux__) || defined(_WIN32)
- this->restore_keyboard_focus();
-#endif
this->p->show_delayed_error_message();
}
-#if defined(__linux__) || defined(_WIN32)
-// wxWidgets callback to enable / disable window and all its children windows.
-// called by wxProgressDialog when entering / leaving modal dialog loop.
-// Unfortunately the wxProgressDialog calls Enable(true) after the wxEVT_ACTIVATE event is processed
-// while MainFrame is not yet enabled, thus restoring focus in OnActivate() handler fails
-// and we need to do it now.
-bool Plater::Enable(bool enable)
-{
- bool retval = wxPanel::Enable(enable);
- if (enable && retval)
- this->restore_keyboard_focus();
- return retval;
-}
-void Plater::restore_keyboard_focus()
-{
- // 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())
- this->p->view3D->get_wxglcanvas()->SetFocus();
- else if (this->p->preview->IsShown() && wxWindow::FindFocus() != this->p->view3D->get_wxglcanvas())
- this->p->preview->get_wxglcanvas()->SetFocus();
-}
-#endif // Linux or Windows
-
// Get vector of extruder colors considering filament color, if extruder color is undefined.
std::vector<std::string> Plater::get_extruder_colors_from_plater_config(const GCodeProcessorResult* const result) const
{
diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp
index 6d742a832..d3eead4ed 100644
--- a/src/slic3r/GUI/Plater.hpp
+++ b/src/slic3r/GUI/Plater.hpp
@@ -149,16 +149,6 @@ public:
void render_project_state_debug_window() const;
#endif // ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW
-#if defined(__linux__) || defined(_WIN32)
- // wxWidgets callback to enable / disable window and all its children windows.
- // called by wxProgressDialog when entering / leaving modal dialog loop.
- // Unfortunately the wxProgressDialog calls Enable(true) after the wxEVT_ACTIVATE event is processed
- // while MainFrame is not yet enabled, thus restoring focus in OnActivate() handler fails
- // and we need to do it now.
- bool Enable(bool enable) override;
- void restore_keyboard_focus();
-#endif
-
Sidebar& sidebar();
const Model& model() const;
Model& model();
diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp
index 40ae0cb8c..5bc7c981e 100644
--- a/src/slic3r/GUI/Preferences.cpp
+++ b/src/slic3r/GUI/Preferences.cpp
@@ -9,7 +9,6 @@
#include "Notebook.hpp"
#include "ButtonsDescription.hpp"
#include "OG_CustomCtrl.hpp"
-#include <initializer_list>
namespace Slic3r {
@@ -466,7 +465,7 @@ void PreferencesDialog::build(size_t selected_tab)
#ifdef _WIN32
// Add "Dark Mode" tab
- if (is_editor) {
+ {
// Add "Dark Mode" tab
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) {
@@ -519,21 +518,29 @@ void PreferencesDialog::build(size_t selected_tab)
this->CenterOnParent();
}
-void PreferencesDialog::update_ctrls_alignment()
+std::vector<ConfigOptionsGroup*> PreferencesDialog::optgroups()
{
- int max_ctrl_width{ 0 };
- std::initializer_list<ConfigOptionsGroup*> og_list = { m_optgroup_general.get(), m_optgroup_camera.get(), m_optgroup_gui.get()
+ std::vector<ConfigOptionsGroup*> out;
+ out.reserve(4);
+ for (ConfigOptionsGroup* opt : { m_optgroup_general.get(), m_optgroup_camera.get(), m_optgroup_gui.get()
#ifdef _WIN32
, m_optgroup_dark_mode.get()
#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();
max_ctrl_width < max)
max_ctrl_width = max;
- }
if (max_ctrl_width)
- for (auto og : og_list)
+ for (ConfigOptionsGroup* og : this->optgroups())
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)
{
- m_optgroup_general->msw_rescale();
- m_optgroup_camera->msw_rescale();
- m_optgroup_gui->msw_rescale();
+ for (ConfigOptionsGroup* og : this->optgroups())
+ og->msw_rescale();
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 };
- 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);
if (ctrl.first && ctrl.second) {
m_highlighter.init(ctrl);
diff --git a/src/slic3r/GUI/Preferences.hpp b/src/slic3r/GUI/Preferences.hpp
index 210b04d4f..6c8012195 100644
--- a/src/slic3r/GUI/Preferences.hpp
+++ b/src/slic3r/GUI/Preferences.hpp
@@ -6,6 +6,7 @@
#include <wx/dialog.h>
#include <wx/timer.h>
+#include <vector>
#include <map>
class wxColourPickerCtrl;
@@ -61,6 +62,7 @@ protected:
void create_settings_mode_widget();
void create_settings_text_color_widget();
void init_highlighter(const t_config_option_key& opt_key);
+ std::vector<ConfigOptionsGroup*> optgroups();
struct PreferencesHighlighter
{
diff --git a/src/slic3r/GUI/PrintHostDialogs.cpp b/src/slic3r/GUI/PrintHostDialogs.cpp
index 2cea580be..09ba48b58 100644
--- a/src/slic3r/GUI/PrintHostDialogs.cpp
+++ b/src/slic3r/GUI/PrintHostDialogs.cpp
@@ -98,8 +98,9 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, PrintHostPostUplo
}
if (post_actions.has(PrintHostPostUploadAction::StartSimulation)) {
- auto* btn_print = add_button(wxID_YES, false, _L("Upload and Simulate"));
- btn_print->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
+ // Using wxID_MORE as a button identifier to be different from the other buttons, wxID_MORE has no other meaning here.
+ 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())) {
post_upload_action = PrintHostPostUploadAction::StartSimulation;
EndDialog(wxID_OK);
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index 41794d294..335dd6619 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -885,6 +885,10 @@ void Tab::on_roll_back_value(const bool to_sys /*= true*/)
}
m_postpone_update_ui = false;
+
+ // When all values are rolled, then we hane to update whole tab in respect to the reverted values
+ update();
+
update_changed_ui();
}
@@ -1148,6 +1152,13 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
if (opt_key == "extruders_count")
wxGetApp().plater()->on_extruders_change(boost::any_cast<size_t>(value));
+ if (m_postpone_update_ui) {
+ // It means that not all values are rolled to the system/last saved values jet.
+ // And call of the update() can causes a redundant check of the config values,
+ // see https://github.com/prusa3d/PrusaSlicer/issues/7146
+ return;
+ }
+
update();
}
@@ -4481,7 +4492,7 @@ ConfigManipulation Tab::get_config_manipulation()
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);
}
diff --git a/tests/libslic3r/test_3mf.cpp b/tests/libslic3r/test_3mf.cpp
index 0ebe47a07..3602d6972 100644
--- a/tests/libslic3r/test_3mf.cpp
+++ b/tests/libslic3r/test_3mf.cpp
@@ -112,7 +112,17 @@ SCENARIO("2D convex hull of sinking object", "[3mf]") {
{ -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") {
REQUIRE(res);