Fixed conflicts after merge with master

This commit is contained in:
Enrico Turri 2020-03-02 11:35:03 +01:00
commit 2f8970de86
60 changed files with 15028 additions and 13576 deletions

View file

@ -42,6 +42,15 @@
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG (0 && ENABLE_THUMBNAIL_GENERATOR)
//==================
// 2.2.0.rc1 techs
//==================
#define ENABLE_2_2_0_RC1 1
// Enable hack to remove crash when closing on OSX 10.9.5
#define ENABLE_HACK_CLOSING_ON_OSX_10_9_5 (1 && ENABLE_2_2_0_RC1)
//==================
// 2.2.0.final techs
//==================

View file

@ -64,15 +64,23 @@ extern std::string normalize_utf8_nfc(const char *src);
// for a short while, so the file may not be movable. Retry while we see recoverable errors.
extern std::error_code rename_file(const std::string &from, const std::string &to);
enum CopyFileResult {
SUCCESS = 0,
FAIL_COPY_FILE,
FAIL_FILES_DIFFERENT,
FAIL_RENAMING,
FAIL_CHECK_ORIGIN_NOT_OPENED,
FAIL_CHECK_TARGET_NOT_OPENED
};
// Copy a file, adjust the access attributes, so that the target is writable.
int copy_file_inner(const std::string &from, const std::string &to);
CopyFileResult copy_file_inner(const std::string &from, const std::string &to);
// Copy file to a temp file first, then rename it to the final file name.
// If with_check is true, then the content of the copied file is compared to the content
// of the source file before renaming.
extern int copy_file(const std::string &from, const std::string &to, const bool with_check = false);
extern CopyFileResult copy_file(const std::string &from, const std::string &to, const bool with_check = false);
// Compares two files, returns 0 if identical, -1 if different.
extern int check_copy(const std::string& origin, const std::string& copy);
// Compares two files if identical.
extern CopyFileResult check_copy(const std::string& origin, const std::string& copy);
// Ignore system and hidden files, which may be created by the DropBox synchronisation process.
// https://github.com/prusa3d/PrusaSlicer/issues/1298

View file

@ -417,7 +417,7 @@ std::error_code rename_file(const std::string &from, const std::string &to)
#endif
}
int copy_file_inner(const std::string& from, const std::string& to)
CopyFileResult copy_file_inner(const std::string& from, const std::string& to)
{
const boost::filesystem::path source(from);
const boost::filesystem::path target(to);
@ -433,40 +433,40 @@ int copy_file_inner(const std::string& from, const std::string& to)
boost::filesystem::permissions(target, perms, ec);
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
if (ec) {
return -1;
return FAIL_COPY_FILE;
}
boost::filesystem::permissions(target, perms, ec);
return 0;
return SUCCESS;
}
int copy_file(const std::string &from, const std::string &to, const bool with_check)
CopyFileResult copy_file(const std::string &from, const std::string &to, const bool with_check)
{
std::string to_temp = to + ".tmp";
int ret_val = copy_file_inner(from,to_temp);
if(ret_val == 0)
CopyFileResult ret_val = copy_file_inner(from,to_temp);
if(ret_val == SUCCESS)
{
if (with_check)
ret_val = check_copy(from, to_temp);
if (ret_val == 0 && rename_file(to_temp, to))
ret_val = -3;
ret_val = FAIL_RENAMING;
}
return ret_val;
}
int check_copy(const std::string &origin, const std::string &copy)
CopyFileResult check_copy(const std::string &origin, const std::string &copy)
{
boost::nowide::ifstream f1(origin, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
boost::nowide::ifstream f2(copy, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
if (f1.fail())
return -4;
return FAIL_CHECK_ORIGIN_NOT_OPENED;
if (f2.fail())
return -5;
return FAIL_CHECK_TARGET_NOT_OPENED;
std::streampos fsize = f1.tellg();
if (fsize != f2.tellg())
return -2;
return FAIL_FILES_DIFFERENT;
f1.seekg(0, std::ifstream::beg);
f2.seekg(0, std::ifstream::beg);
@ -483,12 +483,12 @@ int check_copy(const std::string &origin, const std::string &copy)
if (origin_cnt != copy_cnt ||
(origin_cnt > 0 && std::memcmp(buffer_origin.data(), buffer_copy.data(), origin_cnt) != 0))
// Files are different.
return -2;
return FAIL_FILES_DIFFERENT;
fsize -= origin_cnt;
} while (f1.good() && f2.good());
// All data has been read and compared equal.
return (f1.eof() && f2.eof() && fsize == 0) ? 0 : -2;
return (f1.eof() && f2.eof() && fsize == 0) ? SUCCESS : FAIL_FILES_DIFFERENT;
}
// Ignore system and hidden files, which may be created by the DropBox synchronisation process.

View file

@ -104,21 +104,24 @@ void BackgroundSlicingProcess::process_fff()
bool with_check = GUI::RemovableDriveManager::get_instance().is_path_on_removable_drive(export_path);
int copy_ret_val = copy_file(m_temp_output_path, export_path, with_check);
switch (copy_ret_val){
case 0: break; // no error
case -2:
case SUCCESS: break; // no error
case FAIL_COPY_FILE:
throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?")));
break;
case FAIL_FILES_DIFFERENT:
throw std::runtime_error((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str());
break;
case -3:
case FAIL_RENAMING:
throw std::runtime_error((boost::format(_utf8(L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."))) % export_path).str());
break;
case -4:
case FAIL_CHECK_ORIGIN_NOT_OPENED:
throw std::runtime_error((boost::format(_utf8(L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."))) % m_temp_output_path % export_path).str());
break;
case -5:
case FAIL_CHECK_TARGET_NOT_OPENED:
throw std::runtime_error((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str());
break;
default:
throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?")));
BOOST_LOG_TRIVIAL(warning) << "Unexpected fail code(" << (int)copy_ret_val << ") durring copy_file() to " << export_path << ".";
break;
}
@ -473,7 +476,7 @@ void BackgroundSlicingProcess::prepare_upload()
if (m_print == m_fff_print) {
m_print->set_status(95, _utf8(L("Running post-processing scripts")));
if (copy_file(m_temp_output_path, source_path.string()) != 0) {
if (copy_file(m_temp_output_path, source_path.string()) != SUCCESS) {
throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed")));
}
run_post_process_scripts(source_path.string(), m_fff_print->config());

View file

@ -220,7 +220,7 @@ wxPanel* BedShapePanel::init_texture_panel()
if (m_custom_texture != NONE)
{
if (!exists)
tooltip_text += _(L("Not found: "));
tooltip_text += _(L("Not found:")) + " ";
tooltip_text += _(m_custom_texture);
}
@ -299,7 +299,7 @@ wxPanel* BedShapePanel::init_model_panel()
if (m_custom_model != NONE)
{
if (!exists)
tooltip_text += _(L("Not found: "));
tooltip_text += _(L("Not found:")) + " ";
tooltip_text += _(m_custom_model);
}

View file

@ -43,6 +43,7 @@ Camera::Camera()
, m_distance(DefaultDistance)
, m_gui_scale(1.0)
, m_view_matrix(Transform3d::Identity())
, m_view_rotation(1., 0., 0., 0.)
, m_projection_matrix(Transform3d::Identity())
{
set_default_orientation();
@ -85,7 +86,13 @@ void Camera::select_next_type()
void Camera::set_target(const Vec3d& target)
{
translate_world(target - m_target);
Vec3d new_target = validate_target(target);
Vec3d new_displacement = new_target - m_target;
if (!new_displacement.isApprox(Vec3d::Zero()))
{
m_target = new_target;
m_view_matrix.translate(-new_displacement);
}
}
void Camera::update_zoom(double delta_zoom)
@ -299,17 +306,6 @@ void Camera::debug_render() const
}
#endif // ENABLE_CAMERA_STATISTICS
void Camera::translate_world(const Vec3d& displacement)
{
Vec3d new_target = validate_target(m_target + displacement);
Vec3d new_displacement = new_target - m_target;
if (!new_displacement.isApprox(Vec3d::Zero()))
{
m_target += new_displacement;
m_view_matrix.translate(-new_displacement);
}
}
void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, bool apply_limits)
{
m_zenit += Geometry::rad2deg(delta_zenit_rad);
@ -324,50 +320,23 @@ void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, b
}
}
// FIXME -> The following is a HACK !!!
// When the value of the zenit rotation is large enough, the following call to rotate() shows
// numerical instability introducing some scaling into m_view_matrix (verified by checking
// that the camera space unit vectors are no more unit).
// See also https://dev.prusa3d.com/browse/SPE-1082
// We split the zenit rotation into a set of smaller rotations which are then applied.
static const double MAX_ALLOWED = Geometry::deg2rad(0.1);
unsigned int zenit_steps_count = 1 + (unsigned int)(std::abs(delta_zenit_rad) / MAX_ALLOWED);
double zenit_step = delta_zenit_rad / (double)zenit_steps_count;
Vec3d target = m_target;
translate_world(-target);
if (zenit_step != 0.0)
{
Vec3d right = get_dir_right();
for (unsigned int i = 0; i < zenit_steps_count; ++i)
{
m_view_matrix.rotate(Eigen::AngleAxisd(zenit_step, right));
}
}
if (delta_azimut_rad != 0.0)
m_view_matrix.rotate(Eigen::AngleAxisd(delta_azimut_rad, Vec3d::UnitZ()));
translate_world(target);
Vec3d translation = m_view_matrix.translation() + m_view_rotation * m_target;
auto rot_z = Eigen::AngleAxisd(delta_azimut_rad, Vec3d::UnitZ());
m_view_rotation *= rot_z * Eigen::AngleAxisd(delta_zenit_rad, rot_z.inverse() * get_dir_right());
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (- m_target) + translation, m_view_rotation, Vec3d(1., 1., 1.));
}
// Virtual trackball, rotate around an axis, where the eucledian norm of the axis gives the rotation angle in radians.
void Camera::rotate_local_around_target(const Vec3d& rotation_rad)
{
rotate_local_around_pivot(rotation_rad, m_target);
}
void Camera::rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& pivot)
{
// we use a copy of the pivot because a reference to the current m_target may be passed in (see i.e. rotate_local_around_target())
// and m_target is modified by the translate_world() calls
Vec3d center = pivot;
translate_world(-center);
m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(0), get_dir_right()));
m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(1), get_dir_up()));
m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(2), get_dir_forward()));
translate_world(center);
update_zenit();
double angle = rotation_rad.norm();
if (std::abs(angle) > EPSILON) {
Vec3d translation = m_view_matrix.translation() + m_view_rotation * m_target;
Vec3d axis = m_view_rotation.conjugate() * rotation_rad.normalized();
m_view_rotation *= Eigen::Quaterniond(Eigen::AngleAxisd(angle, axis));
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (-m_target) + translation, m_view_rotation, Vec3d(1., 1., 1.));
update_zenit();
}
}
double Camera::min_zoom() const
@ -588,6 +557,9 @@ void Camera::look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up
m_view_matrix(3, 2) = 0.0;
m_view_matrix(3, 3) = 1.0;
// Initialize the rotation quaternion from the rotation submatrix of of m_view_matrix.
m_view_rotation = Eigen::Quaterniond(m_view_matrix.matrix().template block<3, 3>(0, 0));
update_zenit();
}
@ -598,8 +570,8 @@ void Camera::set_default_orientation()
double phi_rad = Geometry::deg2rad(45.0);
double sin_theta = ::sin(theta_rad);
Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad));
m_view_matrix = Transform3d::Identity();
m_view_matrix.rotate(Eigen::AngleAxisd(theta_rad, Vec3d::UnitX())).rotate(Eigen::AngleAxisd(phi_rad, Vec3d::UnitZ())).translate(-camera_pos);
m_view_rotation = Eigen::AngleAxisd(theta_rad, Vec3d::UnitX()) * Eigen::AngleAxisd(phi_rad, Vec3d::UnitZ());
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (- camera_pos), m_view_rotation, Vec3d(1., 1., 1.));
}
Vec3d Camera::validate_target(const Vec3d& target) const

View file

@ -43,6 +43,8 @@ private:
mutable std::array<int, 4> m_viewport;
mutable Transform3d m_view_matrix;
// We are calculating the rotation part of the m_view_matrix from m_view_rotation.
mutable Eigen::Quaterniond m_view_rotation;
mutable Transform3d m_projection_matrix;
mutable std::pair<double, double> m_frustrum_zs;
@ -107,7 +109,7 @@ public:
#endif // ENABLE_CAMERA_STATISTICS
// translate the camera in world space
void translate_world(const Vec3d& displacement);
void translate_world(const Vec3d& displacement) { this->set_target(m_target + displacement); }
// rotate the camera on a sphere having center == m_target and radius == m_distance
// using the given variations of spherical coordinates
@ -117,9 +119,6 @@ public:
// rotate the camera around three axes parallel to the camera local axes and passing through m_target
void rotate_local_around_target(const Vec3d& rotation_rad);
// rotate the camera around three axes parallel to the camera local axes and passing through the given pivot point
void rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& pivot);
// returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis
bool is_looking_downward() const { return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; }

View file

@ -1916,7 +1916,7 @@ bool Control::check_ticks_changed_event(const std::string& gcode)
_(L("The last color change data was saved for a multi extruder printing.")) + "\n\n" +
_(L("Select YES if you want to delete all saved tool changes, \n\t"
"NO if you want all tool changes switch to color changes, \n\t"
"or CANCEL to leave it unchanged")) + "\n\n\t" +
"or CANCEL to leave it unchanged.")) + "\n\n\t" +
_(L("Do you want to delete all saved tool changes?"))
) : ( // t_mode::MultiExtruder
_(L("The last color change data was saved for a multi extruder printing with tool changes for whole print.")) + "\n\n" +

View file

@ -742,7 +742,7 @@ static void msw_disable_cleartype(wxFont &font)
++ startpos_weight;
size_t endpos_weight = font_desc.find(sep, startpos_weight);
// Parse the weight field.
unsigned int weight = atoi(font_desc(startpos_weight, endpos_weight - startpos_weight));
unsigned int weight = wxAtoi(font_desc(startpos_weight, endpos_weight - startpos_weight));
size_t startpos = endpos_weight;
for (size_t i = 0; i < 6; ++ i)
startpos = font_desc.find(sep, startpos + 1);
@ -3601,19 +3601,19 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
// if dragging over blank area with left button, rotate
if (m_hover_volume_idxs.empty() && m_mouse.is_start_position_3D_defined())
{
const Vec3d& orig = m_mouse.drag.start_position_3D;
double x = Geometry::deg2rad(pos(0) - orig(0)) * (double)TRACKBALLSIZE;
double y = Geometry::deg2rad(pos(1) - orig(1)) * (double)TRACKBALLSIZE;
const Vec3d rot = (Vec3d(pos.x(), pos.y(), 0.) - m_mouse.drag.start_position_3D) * (PI * TRACKBALLSIZE / 180.);
#if ENABLE_NON_STATIC_CANVAS_MANAGER
if (wxGetApp().plater()->get_mouse3d_controller().is_running() || (wxGetApp().app_config->get("use_free_camera") == "1"))
wxGetApp().plater()->get_camera().rotate_local_around_target(Vec3d(y, x, 0.0));
// Virtual track ball (similar to the 3DConnexion mouse).
wxGetApp().plater()->get_camera().rotate_local_around_target(Vec3d(rot.y(), rot.x(), 0.));
else
wxGetApp().plater()->get_camera().rotate_on_sphere(x, y, wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
wxGetApp().plater()->get_camera().rotate_on_sphere(rot.x(), rot.y(), wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
#else
if (wxGetApp().plater()->get_mouse3d_controller().is_running() || (wxGetApp().app_config->get("use_free_camera") == "1"))
m_camera.rotate_local_around_target(Vec3d(y, x, 0.0));
// Virtual track ball (similar to the 3DConnexion mouse).
m_camera.rotate_local_around_target(Vec3d(rot.y(), rot.x(), 0.));
else
m_camera.rotate_on_sphere(x, y, wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
m_camera.rotate_on_sphere(rot.x(), rot.y(), wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
m_dirty = true;

View file

@ -17,6 +17,11 @@
#include <string>
#include <iostream>
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
// Part of temporary hack to remove crash when closing on OSX 10.9.5
#include <wx/platinfo.h>
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
#include "../Utils/MacDarkMode.hpp"
#endif // __APPLE__
@ -114,6 +119,9 @@ void GLCanvas3DManager::GLInfo::detect() const
m_max_tex_size /= 2;
if (Slic3r::total_physical_memory() / (1024 * 1024 * 1024) < 6)
m_max_tex_size /= 2;
if (GLEW_EXT_texture_filter_anisotropic)
glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &m_max_anisotropy));
@ -201,6 +209,12 @@ GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas
GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::FB_None;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
GLCanvas3DManager::OSInfo GLCanvas3DManager::s_os_info;
#endif // __APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
GLCanvas3DManager::GLCanvas3DManager()
: m_context(nullptr)
@ -239,6 +253,15 @@ bool GLCanvas3DManager::add(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLTo
m_context = new wxGLContext(canvas);
if (m_context == nullptr)
return false;
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
// Part of temporary hack to remove crash when closing on OSX 10.9.5
s_os_info.major = wxPlatformInfo::Get().GetOSMajorVersion();
s_os_info.minor = wxPlatformInfo::Get().GetOSMinorVersion();
s_os_info.micro = wxPlatformInfo::Get().GetOSMicroVersion();
#endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
}
canvas3D->set_context(m_context);
@ -358,6 +381,15 @@ void GLCanvas3DManager::destroy()
{
if (m_context != nullptr)
{
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
// this is a temporary ugly hack to solve the crash happening when closing the application on OSX 10.9.5
// the crash is inside wxGLContext destructor
if (s_os_info.major == 10 && s_os_info.minor == 9 && s_os_info.micro == 5)
return;
#endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
delete m_context;
m_context = nullptr;
}

View file

@ -94,6 +94,17 @@ public:
void detect() const;
};
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
struct OSInfo
{
int major{ 0 };
int minor{ 0 };
int micro{ 0 };
};
#endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
private:
#if ENABLE_NON_STATIC_CANVAS_MANAGER
enum class EMultisampleState : unsigned char
@ -118,6 +129,15 @@ private:
wxGLContext* m_context{ nullptr };
#else
wxGLContext* m_context;
<<<<<<< HEAD
=======
static GLInfo s_gl_info;
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
static OSInfo s_os_info;
#endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
>>>>>>> 11bd62a3e6887741701eb908e0fd0cc0b6afb576
bool m_gl_initialized;
CanvasesMap m_canvases;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER

View file

@ -231,6 +231,7 @@ void show_error(wxWindow* parent, const wxString& message)
void show_error(wxWindow* parent, const char* message)
{
assert(message);
show_error(parent, wxString::FromUTF8(message));
}
@ -242,10 +243,16 @@ void show_error_id(int id, const std::string& message)
void show_info(wxWindow* parent, const wxString& message, const wxString& title)
{
wxMessageDialog msg_wingow(parent, message, title.empty() ? _(L("Notice")) : title, wxOK | wxICON_INFORMATION);
wxMessageDialog msg_wingow(parent, message, wxString(SLIC3R_APP_NAME " - ") + (title.empty() ? _(L("Notice")) : title), wxOK | wxICON_INFORMATION);
msg_wingow.ShowModal();
}
void show_info(wxWindow* parent, const char* message, const char* title)
{
assert(message);
show_info(parent, wxString::FromUTF8(message), title ? wxString::FromUTF8(title) : wxString());
}
void warning_catcher(wxWindow* parent, const wxString& message)
{
wxMessageDialog msg(parent, message, _(L("Warning")), wxOK | wxICON_WARNING);

View file

@ -42,7 +42,9 @@ void show_error(wxWindow* parent, const wxString& message);
void show_error(wxWindow* parent, const char* message);
inline void show_error(wxWindow* parent, const std::string& message) { show_error(parent, message.c_str()); }
void show_error_id(int id, const std::string& message); // For Perl
void show_info(wxWindow* parent, const wxString& message, const wxString& title);
void show_info(wxWindow* parent, const wxString& message, const wxString& title = wxString());
void show_info(wxWindow* parent, const char* message, const char* title = nullptr);
inline void show_info(wxWindow* parent, const std::string& message,const std::string& title = std::string()) { show_info(parent, message.c_str(), title.c_str()); }
void warning_catcher(wxWindow* parent, const wxString& message);
// Creates a wxCheckListBoxComboPopup inside the given wxComboCtrl, filled with the given text and items.

View file

@ -204,8 +204,8 @@ bool GUI_App::on_init_inner()
wxString::Format("Resources path does not exist or is not a directory: %s", resources_dir));
// Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release.
// SetAppName(SLIC3R_APP_KEY);
SetAppName(SLIC3R_APP_KEY "-beta");
SetAppName(SLIC3R_APP_KEY);
// SetAppName(SLIC3R_APP_KEY "-beta");
SetAppDisplayName(SLIC3R_APP_NAME);
// Enable this to get the default Win32 COMCTRL32 behavior of static boxes.
@ -349,7 +349,11 @@ unsigned GUI_App::get_colour_approx_luma(const wxColour &colour)
bool GUI_App::dark_mode()
{
#if __APPLE__
return mac_dark_mode();
// The check for dark mode returns false positive on 10.12 and 10.13,
// which allowed setting dark menu bar and dock area, which is
// is detected as dark mode. We must run on at least 10.14 where the
// proper dark mode was first introduced.
return wxPlatformInfo::Get().CheckOSVersion(10, 14) && mac_dark_mode();
#else
const unsigned luma = get_colour_approx_luma(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
return luma < 128;
@ -773,7 +777,7 @@ Tab* GUI_App::get_tab(Preset::Type type)
{
for (Tab* tab: tabs_list)
if (tab->type() == type)
return tab->complited() ? tab : nullptr; // To avoid actions with no-completed Tab
return tab->completed() ? tab : nullptr; // To avoid actions with no-completed Tab
return nullptr;
}

View file

@ -3413,7 +3413,7 @@ bool ObjectList::check_last_selection(wxString& msg_str)
(type & itInstance && !(m_selection_mode & smInstance))
)
{
// Inform user why selection isn't complited
// Inform user why selection isn't completed
const wxString item_type = m_selection_mode & smInstance ? _(L("Object or Instance")) :
m_selection_mode & smVolume ? _(L("Part")) : _(L("Layer"));

View file

@ -5,10 +5,6 @@
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "slic3r/GUI/MeshUtils.hpp"
@ -138,7 +134,7 @@ void GLGizmoBase::Grabber::render_face(float half_size) const
}
GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* common_data_ptr)
GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: m_parent(parent)
, m_group_id(-1)
, m_state(Off)
@ -149,7 +145,6 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, u
, m_dragging(false)
, m_imgui(wxGetApp().imgui())
, m_first_input_window_render(true)
, m_c(common_data_ptr)
{
::memcpy((void*)m_base_color, (const void*)DEFAULT_BASE_COLOR, 4 * sizeof(float));
::memcpy((void*)m_drag_color, (const void*)DEFAULT_DRAG_COLOR, 4 * sizeof(float));
@ -306,113 +301,5 @@ unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char gr
}
bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas, ModelObject* model_object)
{
recent_update = false;
bool object_changed = false;
if (m_model_object != model_object
|| (model_object && m_model_object_id != model_object->id())) {
m_model_object = model_object;
m_print_object_idx = -1;
m_mesh_raycaster.reset();
m_object_clipper.reset();
m_supports_clipper.reset();
m_old_mesh = nullptr;
m_mesh = nullptr;
m_backend_mesh_transformed.clear();
if (m_model_object) {
m_active_instance = canvas.get_selection().get_instance_idx();
m_active_instance_bb_radius = m_model_object->instance_bounding_box(m_active_instance).radius();
}
object_changed = true;
recent_update = true;
}
if (! m_model_object || ! canvas.get_selection().is_from_single_instance())
return false;
int old_po_idx = m_print_object_idx;
// First we need a pointer to the respective SLAPrintObject. The index into objects vector is
// cached so we don't have todo it on each render. We only search for the po if needed:
if (m_print_object_idx < 0 || (int)canvas.sla_print()->objects().size() != m_print_objects_count) {
m_print_objects_count = canvas.sla_print()->objects().size();
m_print_object_idx = -1;
for (const SLAPrintObject* po : canvas.sla_print()->objects()) {
++m_print_object_idx;
if (po->model_object()->id() == m_model_object->id())
break;
}
}
bool mesh_exchanged = false;
m_mesh = nullptr;
// Load either the model_object mesh, or one provided by the backend
// This mesh does not account for the possible Z up SLA offset.
// The backend mesh needs to be transformed and because a pointer to it is
// saved, a copy is stored as a member (FIXME)
if (m_print_object_idx >=0) {
const SLAPrintObject* po = canvas.sla_print()->objects()[m_print_object_idx];
if (po->is_step_done(slaposDrillHoles)) {
m_backend_mesh_transformed = po->get_mesh_to_print();
m_backend_mesh_transformed.transform(canvas.sla_print()->sla_trafo(*m_model_object).inverse());
m_mesh = &m_backend_mesh_transformed;
m_has_drilled_mesh = true;
mesh_exchanged = true;
}
}
if (! m_mesh) {
m_mesh = &m_model_object->volumes.front()->mesh();
m_backend_mesh_transformed.clear();
m_has_drilled_mesh = false;
}
m_model_object_id = m_model_object->id();
if (m_mesh != m_old_mesh) {
// Update clipping plane position.
float new_clp_pos = m_clipping_plane_distance;
if (object_changed) {
new_clp_pos = 0.f;
m_clipping_plane_was_moved = false;
} else {
// After we got a drilled mesh, move the cp to 25% (if not used already)
if (m_clipping_plane_distance == 0.f && mesh_exchanged && m_has_drilled_mesh) {
new_clp_pos = 0.25f;
m_clipping_plane_was_moved = false; // so it uses current camera direction
}
}
m_clipping_plane_distance = new_clp_pos;
m_clipping_plane_distance_stash = new_clp_pos;
m_schedule_aabb_calculation = true;
recent_update = true;
return true;
}
if (! recent_update)
recent_update = m_print_object_idx < 0 && old_po_idx >= 0;
return recent_update;
}
void CommonGizmosData::build_AABB_if_needed()
{
if (! m_schedule_aabb_calculation)
return;
wxBusyCursor wait;
m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh));
m_object_clipper.reset();
m_supports_clipper.reset();
m_old_mesh = m_mesh;
m_schedule_aabb_calculation = false;
}
} // namespace GUI
} // namespace Slic3r

View file

@ -30,7 +30,6 @@ static const float CONSTRAINED_COLOR[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
class ImGuiWrapper;
class CommonGizmosData;
class GLCanvas3D;
class ClippingPlane;
@ -101,13 +100,11 @@ protected:
mutable std::vector<Grabber> m_grabbers;
ImGuiWrapper* m_imgui;
bool m_first_input_window_render;
CommonGizmosData* m_c = nullptr;
public:
GLGizmoBase(GLCanvas3D& parent,
const std::string& icon_filename,
unsigned int sprite_id,
CommonGizmosData* common_data = nullptr);
unsigned int sprite_id);
virtual ~GLGizmoBase() {}
bool init() { return on_init(); }
@ -185,63 +182,6 @@ protected:
// were not interpolated by alpha blending or multi sampling.
extern unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char green, unsigned char blue);
class MeshRaycaster;
class MeshClipper;
class CommonGizmosData {
public:
const TriangleMesh* mesh() const {
return (! m_mesh ? nullptr : m_mesh); //(m_cavity_mesh ? m_cavity_mesh.get() : m_mesh));
}
bool update_from_backend(GLCanvas3D& canvas, ModelObject* model_object);
bool recent_update = false;
static constexpr float HoleStickOutLength = 1.f;
ModelObject* m_model_object = nullptr;
const TriangleMesh* m_mesh;
std::unique_ptr<MeshRaycaster> m_mesh_raycaster;
std::unique_ptr<MeshClipper> m_object_clipper;
std::unique_ptr<MeshClipper> m_supports_clipper;
//std::unique_ptr<TriangleMesh> m_cavity_mesh;
//std::unique_ptr<GLVolume> m_volume_with_cavity;
int m_active_instance = -1;
float m_active_instance_bb_radius = 0;
ObjectID m_model_object_id = 0;
int m_print_object_idx = -1;
int m_print_objects_count = -1;
int m_old_timestamp = -1;
float m_clipping_plane_distance = 0.f;
std::unique_ptr<ClippingPlane> m_clipping_plane;
bool m_clipping_plane_was_moved = false;
void stash_clipping_plane() {
m_clipping_plane_distance_stash = m_clipping_plane_distance;
}
void unstash_clipping_plane() {
m_clipping_plane_distance = m_clipping_plane_distance_stash;
}
bool has_drilled_mesh() const { return m_has_drilled_mesh; }
void build_AABB_if_needed();
private:
const TriangleMesh* m_old_mesh;
TriangleMesh m_backend_mesh_transformed;
float m_clipping_plane_distance_stash = 0.f;
bool m_has_drilled_mesh = false;
bool m_schedule_aabb_calculation = false;
};
} // namespace GUI
} // namespace Slic3r

View file

@ -20,11 +20,10 @@
namespace Slic3r {
namespace GUI {
GLGizmoHollow::GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* cd)
: GLGizmoBase(parent, icon_filename, sprite_id, cd)
GLGizmoHollow::GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: GLGizmoBase(parent, icon_filename, sprite_id)
, m_quadric(nullptr)
{
m_c->m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.));
m_quadric = ::gluNewQuadric();
if (m_quadric != nullptr)
// using GLU_FILL does not work when the instance's transformation
@ -66,22 +65,25 @@ void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&)
update_clipping_plane(m_c->m_clipping_plane_was_moved);
// This is a temporary and not very nice hack, to make sure that
// if the cp was moved by the data returned by backend, it will
// remember its direction. FIXME: Refactor this mess and make
// the clipping plane itself part of the shared data.
if (! m_c->m_clipping_plane_was_moved && m_c->m_clipping_plane_distance == 0.25f)
m_c->m_clipping_plane_was_moved = true;
if (m_c->m_model_object) {
reload_cache();
if (m_c->has_drilled_mesh())
m_holes_in_drilled_mesh = m_c->m_model_object->sla_drain_holes;
}
}
if (m_state == On) {
m_parent.toggle_model_objects_visibility(false);
m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance);
}
// following was removed so that it does not show the object when it should
// be hidden because the supports gizmo is active. on_set_state takes care
// of showing the object.
//else
// m_parent.toggle_model_objects_visibility(true, nullptr, -1);
if (m_state == On) {
m_parent.toggle_model_objects_visibility(false);
m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance);
}
}
@ -1163,6 +1165,13 @@ void GLGizmoHollow::update_clipping_plane(bool keep_normal) const
}
void GLGizmoHollow::on_set_hover_id()
{
if (int(m_c->m_model_object->sla_drain_holes.size()) <= m_hover_id)
m_hover_id = -1;
}
} // namespace GUI

View file

@ -16,6 +16,7 @@ namespace GUI {
class ClippingPlane;
class MeshClipper;
class MeshRaycaster;
class CommonGizmosData;
enum class SLAGizmoEventType : unsigned char;
class GLGizmoHollow : public GLGizmoBase
@ -28,7 +29,7 @@ private:
public:
GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* cd);
GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
~GLGizmoHollow() override;
void set_sla_support_data(ModelObject* model_object, const Selection& selection);
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
@ -42,6 +43,7 @@ public:
bool is_selection_rectangle_dragging() const { return m_selection_rectangle.is_dragging(); }
void update_clipping_plane(bool keep_normal = false) const;
void set_common_data_ptr(CommonGizmosData* ptr) { m_c = ptr; }
private:
bool on_init() override;
@ -72,6 +74,8 @@ private:
sla::DrainHoles m_holes_stash;
CommonGizmosData* m_c = nullptr;
//std::unique_ptr<ClippingPlane> m_clipping_plane;
// This map holds all translated description texts, so they can be easily referenced during layout calculations
@ -99,12 +103,7 @@ private:
protected:
void on_set_state() override;
void on_set_hover_id() override
{
if (int(m_c->m_model_object->sla_drain_holes.size()) <= m_hover_id)
m_hover_id = -1;
}
void on_set_hover_id() override;
void on_start_dragging() override;
void on_stop_dragging() override;
void on_render_input_window(float x, float y, float bottom_limit) override;

View file

@ -25,12 +25,11 @@
namespace Slic3r {
namespace GUI {
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* cd)
: GLGizmoBase(parent, icon_filename, sprite_id, cd)
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: GLGizmoBase(parent, icon_filename, sprite_id)
, m_quadric(nullptr)
, m_its(nullptr)
{
m_c->m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.));
{
m_quadric = ::gluNewQuadric();
if (m_quadric != nullptr)
// using GLU_FILL does not work when the instance's transformation
@ -66,32 +65,23 @@ bool GLGizmoSlaSupports::on_init()
void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const Selection& selection)
{
// Update common data for hollowing and sla support gizmos.
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA)
m_c->update_from_backend(m_parent, model_object);
if (m_c->recent_update) {
if (m_state == On)
m_c->build_AABB_if_needed();
update_clipping_plane(m_c->m_clipping_plane_was_moved);
if (m_state == On) {
m_parent.toggle_model_objects_visibility(false);
m_parent.toggle_model_objects_visibility(/*! m_c->m_cavity_mesh*/ true, m_c->m_model_object, m_c->m_active_instance);
m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance);
}
// following was removed so that it does not show the object when it should
// be hidden because the supports gizmo is active. on_set_state takes care
// of showing the object.
//else
// m_parent.toggle_model_objects_visibility(true, nullptr, -1);
disable_editing_mode();
if (m_c->m_model_object)
reload_cache();
}
if (m_state == On) {
m_parent.toggle_model_objects_visibility(false);
m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance);
}
// If we triggered autogeneration before, check backend and fetch results if they are there
if (m_c->m_model_object) {
if (m_c->m_model_object->sla_points_status == sla::PointsStatus::Generating)

View file

@ -16,6 +16,7 @@ namespace GUI {
class ClippingPlane;
class MeshClipper;
class MeshRaycaster;
class CommonGizmosData;
enum class SLAGizmoEventType : unsigned char;
class GLGizmoSlaSupports : public GLGizmoBase
@ -69,7 +70,7 @@ private:
};
public:
GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* cd);
GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
~GLGizmoSlaSupports() override;
void set_sla_support_data(ModelObject* model_object, const Selection& selection);
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
@ -81,6 +82,7 @@ public:
bool has_backend_supports() const;
void reslice_SLA_supports(bool postpone_error_messages = false) const;
void update_clipping_plane(bool keep_normal = false) const;
void set_common_data_ptr(CommonGizmosData* ptr) { m_c = ptr; }
private:
bool on_init() override;
@ -116,6 +118,8 @@ private:
bool m_selection_empty = true;
EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state)
CommonGizmosData* m_c = nullptr;
//mutable std::unique_ptr<MeshClipper> m_object_clipper;
//mutable std::unique_ptr<MeshClipper> m_supports_clipper;

View file

@ -9,6 +9,8 @@
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
#include "slic3r/GUI/PresetBundle.hpp"
#include "slic3r/Utils/UndoRedo.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "slic3r/GUI/MeshUtils.hpp"
#include <GL/glew.h>
#include <wx/glcanvas.h>
@ -86,16 +88,18 @@ bool GLGizmosManager::init()
return false;
}
m_common_gizmos_data.reset(new CommonGizmosData());
// Order of gizmos in the vector must match order in EType!
m_gizmos.emplace_back(new GLGizmoMove3D(m_parent, "move.svg", 0));
m_gizmos.emplace_back(new GLGizmoScale3D(m_parent, "scale.svg", 1));
m_gizmos.emplace_back(new GLGizmoRotate3D(m_parent, "rotate.svg", 2));
m_gizmos.emplace_back(new GLGizmoFlatten(m_parent, "place.svg", 3));
m_gizmos.emplace_back(new GLGizmoCut(m_parent, "cut.svg", 4));
m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", 5, m_common_gizmos_data.get()));
m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6, m_common_gizmos_data.get()));
m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", 5));
m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6));
m_common_gizmos_data.reset(new CommonGizmosData());
dynamic_cast<GLGizmoHollow*>(m_gizmos[Hollow].get())->set_common_data_ptr(m_common_gizmos_data.get());
dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get())->set_common_data_ptr(m_common_gizmos_data.get());
for (auto& gizmo : m_gizmos) {
if (! gizmo->init()) {
@ -348,9 +352,13 @@ void GLGizmosManager::set_flattening_data(const ModelObject* model_object)
void GLGizmosManager::set_sla_support_data(ModelObject* model_object)
{
if (!m_enabled || m_gizmos.empty())
if (! m_enabled
|| m_gizmos.empty()
|| wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
return;
m_common_gizmos_data->update_from_backend(m_parent, model_object);
auto* gizmo_supports = dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get());
auto* gizmo_hollow = dynamic_cast<GLGizmoHollow*>(m_gizmos[Hollow].get());
@ -1059,5 +1067,135 @@ bool GLGizmosManager::grabber_contains_mouse() const
return (curr != nullptr) ? (curr->get_hover_id() != -1) : false;
}
CommonGizmosData::CommonGizmosData()
{
m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.));
}
bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas, ModelObject* model_object)
{
recent_update = false;
bool object_changed = false;
if (m_model_object != model_object
|| (model_object && m_model_object_id != model_object->id())) {
m_model_object = model_object;
m_print_object_idx = -1;
m_mesh_raycaster.reset();
m_object_clipper.reset();
m_supports_clipper.reset();
m_old_mesh = nullptr;
m_mesh = nullptr;
m_backend_mesh_transformed.clear();
object_changed = true;
recent_update = true;
}
if (m_model_object) {
int active_inst = canvas.get_selection().get_instance_idx();
if (m_active_instance != active_inst) {
m_active_instance = active_inst;
m_active_instance_bb_radius = m_model_object->instance_bounding_box(m_active_instance).radius();
recent_update = true;
}
}
if (! m_model_object || ! canvas.get_selection().is_from_single_instance())
return false;
int old_po_idx = m_print_object_idx;
// First we need a pointer to the respective SLAPrintObject. The index into objects vector is
// cached so we don't have todo it on each render. We only search for the po if needed:
if (m_print_object_idx < 0 || (int)canvas.sla_print()->objects().size() != m_print_objects_count) {
m_print_objects_count = canvas.sla_print()->objects().size();
m_print_object_idx = -1;
for (const SLAPrintObject* po : canvas.sla_print()->objects()) {
++m_print_object_idx;
if (po->model_object()->id() == m_model_object->id())
break;
}
}
bool mesh_exchanged = false;
m_mesh = nullptr;
// Load either the model_object mesh, or one provided by the backend
// This mesh does not account for the possible Z up SLA offset.
// The backend mesh needs to be transformed and because a pointer to it is
// saved, a copy is stored as a member (FIXME)
if (m_print_object_idx >=0) {
const SLAPrintObject* po = canvas.sla_print()->objects()[m_print_object_idx];
if (po->is_step_done(slaposDrillHoles)) {
m_backend_mesh_transformed = po->get_mesh_to_print();
m_backend_mesh_transformed.transform(canvas.sla_print()->sla_trafo(*m_model_object).inverse());
m_mesh = &m_backend_mesh_transformed;
m_has_drilled_mesh = true;
mesh_exchanged = true;
}
}
if (! m_mesh) {
m_mesh = &m_model_object->volumes.front()->mesh();
m_backend_mesh_transformed.clear();
m_has_drilled_mesh = false;
}
m_model_object_id = m_model_object->id();
if (m_mesh != m_old_mesh) {
// Update clipping plane position.
float new_clp_pos = m_clipping_plane_distance;
if (object_changed) {
new_clp_pos = 0.f;
m_clipping_plane_was_moved = false;
} else {
// After we got a drilled mesh, move the cp to 25%. This only applies when
// the hollowing gizmo is active and hollowing is enabled
if (m_clipping_plane_distance == 0.f && mesh_exchanged && m_has_drilled_mesh) {
const DynamicPrintConfig& cfg =
(m_model_object && m_model_object->config.has("hollowing_enable"))
? m_model_object->config
: wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
if (cfg.has("hollowing_enable") && cfg.opt_bool("hollowing_enable")
&& canvas.get_gizmos_manager().get_current_type() == GLGizmosManager::Hollow) {
new_clp_pos = 0.25f;
m_clipping_plane_was_moved = false; // so it uses current camera direction
}
}
}
m_clipping_plane_distance = new_clp_pos;
m_clipping_plane_distance_stash = new_clp_pos;
m_schedule_aabb_calculation = true;
recent_update = true;
return true;
}
if (! recent_update)
recent_update = m_print_object_idx < 0 && old_po_idx >= 0;
return recent_update;
}
void CommonGizmosData::build_AABB_if_needed()
{
if (! m_schedule_aabb_calculation)
return;
wxBusyCursor wait;
m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh));
m_object_clipper.reset();
m_supports_clipper.reset();
m_old_mesh = m_mesh;
m_schedule_aabb_calculation = false;
}
} // namespace GUI
} // namespace Slic3r

View file

@ -227,6 +227,65 @@ private:
bool grabber_contains_mouse() const;
};
class MeshRaycaster;
class MeshClipper;
// This class is only for sharing SLA related data between SLA gizmos
// and its synchronization with backend data. It should not be misused
// for anything else.
class CommonGizmosData {
public:
CommonGizmosData();
const TriangleMesh* mesh() const {
return (! m_mesh ? nullptr : m_mesh); //(m_cavity_mesh ? m_cavity_mesh.get() : m_mesh));
}
bool update_from_backend(GLCanvas3D& canvas, ModelObject* model_object);
bool recent_update = false;
static constexpr float HoleStickOutLength = 1.f;
ModelObject* m_model_object = nullptr;
const TriangleMesh* m_mesh;
std::unique_ptr<MeshRaycaster> m_mesh_raycaster;
std::unique_ptr<MeshClipper> m_object_clipper;
std::unique_ptr<MeshClipper> m_supports_clipper;
//std::unique_ptr<TriangleMesh> m_cavity_mesh;
//std::unique_ptr<GLVolume> m_volume_with_cavity;
int m_active_instance = -1;
float m_active_instance_bb_radius = 0;
ObjectID m_model_object_id = 0;
int m_print_object_idx = -1;
int m_print_objects_count = -1;
int m_old_timestamp = -1;
float m_clipping_plane_distance = 0.f;
std::unique_ptr<ClippingPlane> m_clipping_plane;
bool m_clipping_plane_was_moved = false;
void stash_clipping_plane() {
m_clipping_plane_distance_stash = m_clipping_plane_distance;
}
void unstash_clipping_plane() {
m_clipping_plane_distance = m_clipping_plane_distance_stash;
}
bool has_drilled_mesh() const { return m_has_drilled_mesh; }
void build_AABB_if_needed();
private:
const TriangleMesh* m_old_mesh;
TriangleMesh m_backend_mesh_transformed;
float m_clipping_plane_distance_stash = 0.f;
bool m_has_drilled_mesh = false;
bool m_schedule_aabb_calculation = false;
};
} // namespace GUI
} // namespace Slic3r

View file

@ -145,6 +145,9 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
wxGetApp().persist_window_geometry(this, true);
update_ui_from_settings(); // FIXME (?)
if (m_plater != nullptr)
m_plater->show_action_buttons(true);
}
void MainFrame::update_title()

View file

@ -162,8 +162,8 @@ bool Mouse3DController::State::apply(Camera& camera)
if (has_rotation())
{
Vec3d rotation = (m_rotation_params.scale * m_rotation.queue.front()).cast<double>();
camera.rotate_local_around_target(Vec3d(Geometry::deg2rad(rotation(0)), Geometry::deg2rad(-rotation(2)), Geometry::deg2rad(-rotation(1))));
Vec3d rot = (m_rotation_params.scale * m_rotation.queue.front()).cast<double>() * (PI / 180.);
camera.rotate_local_around_target(Vec3d(rot.x(), - rot.z(), rot.y()));
m_rotation.queue.pop();
ret = true;
}

View file

@ -262,6 +262,11 @@ PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)),
m_em_unit(wxGetApp().em_unit())
{
SetFont(wxGetApp().normal_font());
#ifdef _WIN32
// Workaround for ignoring CBN_EDITCHANGE events, which are processed after the content of the combo box changes, so that
// the index of the item inside CBN_EDITCHANGE may no more be valid.
EnableTextChangedEvents(false);
#endif /* _WIN32 */
Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &evt) {
auto selected_item = this->GetSelection();
@ -871,7 +876,7 @@ Sidebar::Sidebar(Plater *parent)
};
init_scalable_btn(&p->btn_send_gcode , "export_gcode", _(L("Send to printer")) + "\tCtrl+Shift+G");
init_scalable_btn(&p->btn_remove_device, "cross" , _(L("Remove device")));
init_scalable_btn(&p->btn_remove_device, "eject_sd" , _(L("Remove device")));
init_scalable_btn(&p->btn_export_gcode_removable, "export_to_sd", _(L("Export to SD card / Flash drive")));
// regular buttons "Slice now" and "Export G-code"
@ -3338,7 +3343,7 @@ void Plater::priv::reload_from_disk()
const auto& path = input_paths[i].string();
wxBusyCursor wait;
wxBusyInfo info(_(L("Reload from: ")) + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas());
wxBusyInfo info(_(L("Reload from:")) + " " + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas());
Model new_model;
try
@ -5202,11 +5207,10 @@ void Plater::drive_ejected_callback()
if (RemovableDriveManager::get_instance().get_did_eject())
{
RemovableDriveManager::get_instance().set_did_eject(false);
wxString message = wxString::Format(
_(L("Unmounting successful. The device %s(%s) can now be safely removed from the computer.")),
RemovableDriveManager::get_instance().get_ejected_name(),
RemovableDriveManager::get_instance().get_ejected_path());
wxMessageBox(message);
show_info(this,
(boost::format(_utf8(L("Unmounting successful. The device %s(%s) can now be safely removed from the computer.")))
% RemovableDriveManager::get_instance().get_ejected_name()
% RemovableDriveManager::get_instance().get_ejected_path()).str());
}
p->show_action_buttons(false);
}
@ -5594,6 +5598,7 @@ void Plater::suppress_background_process(const bool stop_background_process)
void Plater::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) { p->fix_through_netfabb(obj_idx, vol_idx); }
void Plater::update_object_menu() { p->update_object_menu(); }
void Plater::show_action_buttons(const bool is_ready_to_slice) const { p->show_action_buttons(is_ready_to_slice); }
void Plater::copy_selection_to_clipboard()
{

View file

@ -239,6 +239,7 @@ public:
std::vector<std::string> get_colors_for_color_print() const;
void update_object_menu();
void show_action_buttons(const bool is_ready_to_slice) const;
wxString get_project_filename(const wxString& extension = wxEmptyString) const;
void set_project_filename(const wxString& filename);

View file

@ -313,9 +313,9 @@ std::string Preset::label() const
return this->name + (this->is_dirty ? g_suffix_modified : "");
}
bool is_compatible_with_print(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print)
bool is_compatible_with_print(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print, const PresetWithVendorProfile &active_printer)
{
if (preset.vendor != nullptr && preset.vendor != active_print.vendor)
if (preset.vendor != nullptr && preset.vendor != active_printer.vendor)
// The current profile has a vendor assigned and it is different from the active print's vendor.
return false;
auto &condition = preset.preset.compatible_prints_condition();
@ -1042,7 +1042,7 @@ void PresetCollection::set_default_suppressed(bool default_suppressed)
}
}
size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool unselect_if_incompatible)
size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType unselect_if_incompatible)
{
DynamicPrintConfig config;
config.set_key_value("printer_preset", new ConfigOptionString(active_printer.preset.name));
@ -1054,10 +1054,12 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil
Preset &preset_selected = m_presets[idx_preset];
Preset &preset_edited = selected ? m_edited_preset : preset_selected;
const PresetWithVendorProfile this_preset_with_vendor_profile = this->get_preset_with_vendor_profile(preset_edited);
bool was_compatible = preset_edited.is_compatible;
preset_edited.is_compatible = is_compatible_with_printer(this_preset_with_vendor_profile, active_printer, &config);
if (active_print != nullptr)
preset_edited.is_compatible &= is_compatible_with_print(this_preset_with_vendor_profile, *active_print);
if (! preset_edited.is_compatible && selected && unselect_if_incompatible)
preset_edited.is_compatible &= is_compatible_with_print(this_preset_with_vendor_profile, *active_print, active_printer);
if (! preset_edited.is_compatible && selected &&
(unselect_if_incompatible == PresetSelectCompatibleType::Always || (unselect_if_incompatible == PresetSelectCompatibleType::OnlyIfWasCompatible && was_compatible)))
m_idx_selected = -1;
if (selected)
preset_selected.is_compatible = preset_edited.is_compatible;

View file

@ -247,10 +247,19 @@ protected:
static std::string remove_suffix_modified(const std::string &name);
};
bool is_compatible_with_print (const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print);
bool is_compatible_with_print (const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print, const PresetWithVendorProfile &active_printer);
bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer, const DynamicPrintConfig *extra_config);
bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer);
enum class PresetSelectCompatibleType {
// Never select a compatible preset if the newly selected profile is not compatible.
Never,
// Only select a compatible preset if the active profile used to be compatible, but it is no more.
OnlyIfWasCompatible,
// Always select a compatible preset if the active profile is no more compatible.
Always
};
// Collections of presets of the same type (one of the Print, Filament or Printer type).
class PresetCollection
{
@ -412,13 +421,13 @@ public:
// For Print / Filament presets, disable those, which are not compatible with the printer.
template<typename PreferedCondition>
void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool select_other_if_incompatible, PreferedCondition prefered_condition)
void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType select_other_if_incompatible, PreferedCondition prefered_condition)
{
if (this->update_compatible_internal(active_printer, active_print, select_other_if_incompatible) == (size_t)-1)
// Find some other compatible preset, or the "-- default --" preset.
this->select_preset(this->first_compatible_idx(prefered_condition));
}
void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool select_other_if_incompatible)
void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType select_other_if_incompatible)
{ this->update_compatible(active_printer, active_print, select_other_if_incompatible, [](const std::string&){return true;}); }
size_t num_visible() const { return std::count_if(m_presets.begin(), m_presets.end(), [](const Preset &preset){return preset.is_visible;}); }
@ -515,7 +524,7 @@ private:
std::deque<Preset>::const_iterator find_preset_renamed(const std::string &name) const
{ return const_cast<PresetCollection*>(this)->find_preset_renamed(name); }
size_t update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool unselect_if_incompatible);
size_t update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType unselect_if_incompatible);
static std::vector<std::string> dirty_options(const Preset *edited, const Preset *reference, const bool is_printer_type = false);

View file

@ -238,7 +238,7 @@ void PresetBundle::load_presets(AppConfig &config, const std::string &preferred_
errors_cummulative += err.what();
}
this->update_multi_material_filament_presets();
this->update_compatible(false);
this->update_compatible(PresetSelectCompatibleType::Never);
if (! errors_cummulative.empty())
throw std::runtime_error(errors_cummulative);
@ -424,7 +424,7 @@ void PresetBundle::load_selections(AppConfig &config, const std::string &preferr
// or from the preferred_model_id suggestion passed in by ConfigWizard.
// If the printer profile enumerated by the config are not visible, select an alternate preset.
// Do not select alternate profiles for the print / filament profiles as those presets
// will be selected by the following call of this->update_compatible(true).
// will be selected by the following call of this->update_compatible(PresetSelectCompatibleType::Always).
const Preset *initial_printer = printers.find_preset(initial_printer_profile_name);
const Preset *preferred_printer = printers.find_by_model_id(preferred_model_id);
@ -457,7 +457,7 @@ void PresetBundle::load_selections(AppConfig &config, const std::string &preferr
// Always try to select a compatible print and filament preset to the current printer preset,
// as the application may have been closed with an active "external" preset, which does not
// exist.
this->update_compatible(true);
this->update_compatible(PresetSelectCompatibleType::Always);
this->update_multi_material_filament_presets();
}
@ -889,7 +889,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
default: break;
}
this->update_compatible(false);
this->update_compatible(PresetSelectCompatibleType::Never);
}
// Load the active configuration of a config bundle from a boost property_tree. This is a private method called from load_config_file.
@ -951,7 +951,7 @@ void PresetBundle::load_config_file_config_bundle(const std::string &path, const
for (size_t i = 1; i < std::min(tmp_bundle.filament_presets.size(), this->filament_presets.size()); ++ i)
this->filament_presets[i] = load_one(this->filaments, tmp_bundle.filaments, tmp_bundle.filament_presets[i], false);
this->update_compatible(false);
this->update_compatible(PresetSelectCompatibleType::Never);
}
// Process the Config Bundle loaded as a Boost property tree.
@ -1351,7 +1351,7 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla
this->update_multi_material_filament_presets();
for (size_t i = 0; i < std::min(this->filament_presets.size(), active_filaments.size()); ++ i)
this->filament_presets[i] = filaments.find_preset(active_filaments[i], true)->name;
this->update_compatible(false);
this->update_compatible(PresetSelectCompatibleType::Never);
}
return presets_loaded;
@ -1399,7 +1399,7 @@ void PresetBundle::update_multi_material_filament_presets()
}
}
void PresetBundle::update_compatible(bool select_other_if_incompatible)
void PresetBundle::update_compatible(PresetSelectCompatibleType select_other_print_if_incompatible, PresetSelectCompatibleType select_other_filament_if_incompatible)
{
const Preset &printer_preset = this->printers.get_edited_preset();
const PresetWithVendorProfile printer_preset_with_vendor_profile = this->printers.get_preset_with_vendor_profile(printer_preset);
@ -1412,25 +1412,32 @@ void PresetBundle::update_compatible(bool select_other_if_incompatible)
const std::string &prefered_print_profile = printer_preset.config.opt_string("default_print_profile");
const std::vector<std::string> &prefered_filament_profiles = printer_preset.config.option<ConfigOptionStrings>("default_filament_profile")->values;
prefered_print_profile.empty() ?
this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_if_incompatible) :
this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_if_incompatible,
this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible) :
this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible,
[&prefered_print_profile](const std::string& profile_name) { return profile_name == prefered_print_profile; });
const PresetWithVendorProfile print_preset_with_vendor_profile = this->prints.get_edited_preset_with_vendor_profile();
// Remember whether the filament profiles were compatible before updating the filament compatibility.
std::vector<char> filament_preset_was_compatible(this->filament_presets.size(), false);
for (size_t idx = 0; idx < this->filament_presets.size(); ++ idx) {
std::string &filament_name = this->filament_presets[idx];
Preset *preset = this->filaments.find_preset(filament_name, false);
filament_preset_was_compatible[idx] = preset != nullptr && preset->is_compatible;
}
prefered_filament_profiles.empty() ?
this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_if_incompatible) :
this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_if_incompatible,
this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_filament_if_incompatible) :
this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_filament_if_incompatible,
[&prefered_filament_profiles](const std::string& profile_name)
{ return std::find(prefered_filament_profiles.begin(), prefered_filament_profiles.end(), profile_name) != prefered_filament_profiles.end(); });
if (select_other_if_incompatible) {
if (select_other_filament_if_incompatible != PresetSelectCompatibleType::Never) {
// Verify validity of the current filament presets.
if (this->filament_presets.size() == 1)
this->filament_presets.front() = this->filaments.get_edited_preset().name;
else
{
for (size_t idx = 0; idx < this->filament_presets.size(); ++idx) {
if (this->filament_presets.size() == 1) {
if (select_other_filament_if_incompatible == PresetSelectCompatibleType::Always || filament_preset_was_compatible.front())
this->filament_presets.front() = this->filaments.get_edited_preset().name;
} else {
for (size_t idx = 0; idx < this->filament_presets.size(); ++ idx) {
std::string &filament_name = this->filament_presets[idx];
Preset *preset = this->filaments.find_preset(filament_name, false);
if (preset == nullptr || !preset->is_compatible) {
if (preset == nullptr || (! preset->is_compatible && (select_other_filament_if_incompatible == PresetSelectCompatibleType::Always || filament_preset_was_compatible[idx]))) {
// Pick a compatible profile. If there are prefered_filament_profiles, use them.
if (prefered_filament_profiles.empty())
filament_name = this->filaments.first_compatible().name;
@ -1453,13 +1460,13 @@ void PresetBundle::update_compatible(bool select_other_if_incompatible)
const PresetWithVendorProfile sla_print_preset_with_vendor_profile = this->sla_prints.get_edited_preset_with_vendor_profile();
const std::string &prefered_sla_print_profile = printer_preset.config.opt_string("default_sla_print_profile");
(prefered_sla_print_profile.empty()) ?
this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_if_incompatible) :
this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_if_incompatible,
this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible) :
this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible,
[&prefered_sla_print_profile](const std::string& profile_name){ return profile_name == prefered_sla_print_profile; });
const std::string &prefered_sla_material_profile = printer_preset.config.opt_string("default_sla_material_profile");
prefered_sla_material_profile.empty() ?
this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_if_incompatible) :
this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_if_incompatible,
this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_filament_if_incompatible) :
this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_filament_if_incompatible,
[&prefered_sla_material_profile](const std::string& profile_name){ return profile_name == prefered_sla_material_profile; });
break;
}

View file

@ -127,7 +127,8 @@ public:
// Also updates the is_visible flag of each preset.
// If select_other_if_incompatible is true, then the print or filament preset is switched to some compatible
// preset if the current print or filament preset is not compatible.
void update_compatible(bool select_other_if_incompatible);
void update_compatible(PresetSelectCompatibleType select_other_print_if_incompatible, PresetSelectCompatibleType select_other_filament_if_incompatible);
void update_compatible(PresetSelectCompatibleType select_other_if_incompatible) { this->update_compatible(select_other_if_incompatible, select_other_if_incompatible); }
void load_default_preset_bitmaps();

View file

@ -38,8 +38,6 @@ namespace GUI {
wxDEFINE_EVENT(EVT_TAB_VALUE_CHANGED, wxCommandEvent);
wxDEFINE_EVENT(EVT_TAB_PRESETS_CHANGED, SimpleEvent);
// Tab::Tab(wxNotebook* parent, const wxString& title, const char* name) :
// m_parent(parent), m_title(title), m_name(name)
Tab::Tab(wxNotebook* parent, const wxString& title, Preset::Type type) :
m_parent(parent), m_title(title), m_type(type)
{
@ -264,7 +262,7 @@ void Tab::create_preset_tab()
// Initialize the DynamicPrintConfig by default keys/values.
build();
rebuild_page_tree();
m_complited = true;
m_completed = true;
}
void Tab::add_scaled_button(wxWindow* parent,
@ -833,7 +831,7 @@ void Tab::load_key_value(const std::string& opt_key, const boost::any& value, bo
// Mark the print & filament enabled if they are compatible with the currently selected preset.
if (opt_key == "compatible_printers" || opt_key == "compatible_prints") {
// Don't select another profile if this profile happens to become incompatible.
m_preset_bundle->update_compatible(false);
m_preset_bundle->update_compatible(PresetSelectCompatibleType::Never);
}
m_presets->update_dirty_ui(m_presets_choice);
on_presets_changed();
@ -2778,6 +2776,7 @@ void Tab::select_preset(std::string preset_name, bool delete_current)
bool print_tab = m_presets->type() == Preset::TYPE_PRINT || m_presets->type() == Preset::TYPE_SLA_PRINT;
bool printer_tab = m_presets->type() == Preset::TYPE_PRINTER;
bool canceled = false;
bool technology_changed = false;
m_dependent_tabs = {};
if (current_dirty && ! may_discard_current_dirty_preset()) {
canceled = true;
@ -2786,10 +2785,12 @@ void Tab::select_preset(std::string preset_name, bool delete_current)
// are compatible with the new print.
// If it is not compatible and the current filament or SLA material are dirty, let user decide
// whether to discard the changes or keep the current print selection.
PrinterTechnology printer_technology = m_preset_bundle->printers.get_edited_preset().printer_technology();
PresetWithVendorProfile printer_profile = m_preset_bundle->printers.get_edited_preset_with_vendor_profile();
PrinterTechnology printer_technology = printer_profile.preset.printer_technology();
PresetCollection &dependent = (printer_technology == ptFFF) ? m_preset_bundle->filaments : m_preset_bundle->sla_materials;
bool old_preset_dirty = dependent.current_is_dirty();
bool new_preset_compatible = is_compatible_with_print(dependent.get_edited_preset_with_vendor_profile(), m_presets->get_preset_with_vendor_profile(*m_presets->find_preset(preset_name, true)));
bool new_preset_compatible = is_compatible_with_print(dependent.get_edited_preset_with_vendor_profile(),
m_presets->get_preset_with_vendor_profile(*m_presets->find_preset(preset_name, true)), printer_profile);
if (! canceled)
canceled = old_preset_dirty && ! new_preset_compatible && ! may_discard_current_dirty_preset(&dependent, preset_name);
if (! canceled) {
@ -2842,6 +2843,8 @@ void Tab::select_preset(std::string preset_name, bool delete_current)
}
}
}
if (! canceled)
technology_changed = old_printer_technology != new_printer_technology;
}
if (! canceled && delete_current) {
@ -2870,8 +2873,15 @@ void Tab::select_preset(std::string preset_name, bool delete_current)
// Mark the print & filament enabled if they are compatible with the currently selected preset.
// The following method should not discard changes of current print or filament presets on change of a printer profile,
// if they are compatible with the current printer.
auto update_compatible_type = [](bool technology_changed, bool on_page, bool show_incompatible_presets) {
return technology_changed ? PresetSelectCompatibleType::Always :
on_page ? PresetSelectCompatibleType::Never :
(show_incompatible_presets ? PresetSelectCompatibleType::OnlyIfWasCompatible : PresetSelectCompatibleType::Always);
};
if (current_dirty || delete_current || print_tab || printer_tab)
m_preset_bundle->update_compatible(true);
m_preset_bundle->update_compatible(
update_compatible_type(technology_changed, print_tab, (print_tab ? this : wxGetApp().get_tab(Preset::TYPE_PRINT))->m_show_incompatible_presets),
update_compatible_type(technology_changed, false, wxGetApp().get_tab(Preset::TYPE_FILAMENT)->m_show_incompatible_presets));
// Initialize the UI from the current preset.
if (printer_tab)
static_cast<TabPrinter*>(this)->update_pages();
@ -3084,7 +3094,7 @@ void Tab::save_preset(std::string name /*= ""*/)
// Save the preset into Slic3r::data_dir / presets / section_name / preset_name.ini
m_presets->save_current_preset(name);
// Mark the print & filament enabled if they are compatible with the currently selected preset.
m_preset_bundle->update_compatible(false);
m_preset_bundle->update_compatible(PresetSelectCompatibleType::Never);
// Add the new item into the UI component, remove dirty flags and activate the saved item.
update_tab_ui();
// Update the selection boxes at the plater.

View file

@ -218,7 +218,7 @@ protected:
int m_em_unit;
// To avoid actions with no-completed Tab
bool m_complited { false };
bool m_completed { false };
ConfigOptionMode m_mode = comExpert; // to correct first Tab update_visibility() set mode to Expert
public:
@ -244,7 +244,8 @@ public:
// std::string name() const { return m_name; }
std::string name() const { return m_presets->name(); }
Preset::Type type() const { return m_type; }
bool complited() const { return m_complited; }
// The tab is already constructed.
bool completed() const { return m_completed; }
virtual bool supports_printer_technology(const PrinterTechnology tech) = 0;
void create_preset_tab();

View file

@ -145,7 +145,7 @@ MsgUpdateConfig::~MsgUpdateConfig() {}
//MsgUpdateForced
MsgUpdateForced::MsgUpdateForced(const std::vector<Update>& updates) :
MsgDialog(nullptr, wxString::Format(_(L("%s incompatibility")), SLIC3R_APP_NAME), _(L("Is necessary to install a configuration update. ")), wxID_NONE)
MsgDialog(nullptr, wxString::Format(_(L("%s incompatibility")), SLIC3R_APP_NAME), _(L("You must install a configuration update.")) + " ", wxID_NONE)
{
auto* text = new wxStaticText(this, wxID_ANY, wxString::Format(_(L(
"%s will now start updates. Otherwise it won't be able to start.\n\n"