From bbed47acd0dac80bb7f9f22de29b6e4e1c5fcb48 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 7 Jan 2019 10:32:33 +0100 Subject: [PATCH 01/23] Fixed #1579 --- src/slic3r/GUI/GUI_ObjectList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index dffaf7afc..0b6c38bd8 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -635,7 +635,7 @@ void ObjectList::get_settings_choice(const wxString& category_name) // Add settings item for object const auto item = GetSelection(); if (item) { - const auto settings_item = m_objects_model->GetSettingsItem(item); + const auto settings_item = m_objects_model->IsSettingsItem(item) ? item : m_objects_model->GetSettingsItem(item); select_item(settings_item ? settings_item : m_objects_model->AddSettingsChild(item)); } From c81dbba794e5130f916334d97a8e543d39a158f5 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 7 Jan 2019 10:53:48 +0100 Subject: [PATCH 02/23] Fix of #1590 --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 139 ++++++++++++++++------ src/slic3r/GUI/GUI_ObjectManipulation.hpp | 30 ++++- 2 files changed, 130 insertions(+), 39 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index be421e5d3..1848ddda7 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -17,12 +17,6 @@ namespace GUI ObjectManipulation::ObjectManipulation(wxWindow* parent) : OG_Settings(parent, true) -#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION - , m_cache_position(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX)) - , m_cache_rotation(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX)) - , m_cache_scale(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX)) - , m_cache_size(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX)) -#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION { m_og->set_name(_(L("Object Manipulation"))); m_og->label_width = 100; @@ -80,25 +74,41 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : int axis = opt_key.back() == 'x' ? 0 : opt_key.back() == 'y' ? 1 : 2; +#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION + value = m_cache.position(axis); +#else value = m_cache_position(axis); +#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION } else if (param == "rotation") { int axis = opt_key.back() == 'x' ? 0 : opt_key.back() == 'y' ? 1 : 2; +#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION + value = m_cache.rotation(axis); +#else value = m_cache_rotation(axis); +#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION } else if (param == "scale") { int axis = opt_key.back() == 'x' ? 0 : opt_key.back() == 'y' ? 1 : 2; +#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION + value = m_cache.scale(axis); +#else value = m_cache_scale(axis); +#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION } else if (param == "size") { int axis = opt_key.back() == 'x' ? 0 : opt_key.back() == 'y' ? 1 : 2; +#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION + value = m_cache.size(axis); +#else value = m_cache_size(axis); +#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION } m_og->set_value(opt_key, double_to_string(value)); @@ -229,16 +239,41 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele m_new_rotation = volume->get_instance_rotation(); m_new_scale = volume->get_instance_scaling_factor(); int obj_idx = volume->object_idx(); +#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION + int instance_idx = volume->instance_idx(); + if ((0 <= obj_idx) && (obj_idx < (int)wxGetApp().model_objects()->size())) + { + bool changed_box = false; + if ((m_cache.object_idx != obj_idx) || (m_cache.instance_idx != instance_idx)) + { + m_cache.object_idx = obj_idx; + m_cache.instance_idx = instance_idx; + m_cache.instance_box_size = (*wxGetApp().model_objects())[obj_idx]->raw_mesh().bounding_box().size(); + changed_box = true; + } + if (changed_box || !m_cache.scale.isApprox(100.0 * m_new_scale) || !m_cache.rotation.isApprox(m_new_rotation)) + m_new_size = volume->get_instance_transformation().get_matrix(true, true) * m_cache.instance_box_size; + } + else + // this should never happen + m_new_size = Vec3d::Zero(); +#else if ((0 <= obj_idx) && (obj_idx < (int)wxGetApp().model_objects()->size())) m_new_size = volume->get_instance_transformation().get_matrix(true, true) * (*wxGetApp().model_objects())[obj_idx]->raw_mesh().bounding_box().size(); else // this should never happen m_new_size = Vec3d::Zero(); +#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION m_new_enabled = true; } else if (selection.is_single_full_object()) { +#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION + m_cache.object_idx = -1; + m_cache.instance_idx = -1; +#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION + const BoundingBoxf3& box = selection.get_bounding_box(); m_new_position = box.center(); m_new_rotation = Vec3d::Zero(); @@ -250,6 +285,11 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele } else if (selection.is_single_modifier() || selection.is_single_volume()) { +#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION + m_cache.object_idx = -1; + m_cache.instance_idx = -1; +#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION + // the selection contains a single volume const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); m_new_position = volume->get_volume_offset(); @@ -280,59 +320,68 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele void ObjectManipulation::update_if_dirty() { #if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION - if (_(m_new_move_label_string) != m_move_Label->GetLabel()) - m_move_Label->SetLabel(_(m_new_move_label_string)); + if (m_cache.move_label_string != _(m_new_move_label_string)) + { + m_cache.move_label_string = _(m_new_move_label_string); + m_move_Label->SetLabel(m_cache.move_label_string); + } - if (_(m_new_rotate_label_string) != m_rotate_Label->GetLabel()) - m_rotate_Label->SetLabel(_(m_new_rotate_label_string)); + if (m_cache.rotate_label_string != _(m_new_rotate_label_string)) + { + m_cache.rotate_label_string = _(m_new_rotate_label_string); + m_rotate_Label->SetLabel(m_cache.rotate_label_string); + } - if (_(m_new_scale_label_string) != m_scale_Label->GetLabel()) - m_scale_Label->SetLabel(_(m_new_scale_label_string)); + if (m_cache.scale_label_string != _(m_new_scale_label_string)) + { + m_cache.scale_label_string = _(m_new_scale_label_string); + m_scale_Label->SetLabel(m_cache.scale_label_string); + } - if (m_cache_position(0) != m_new_position(0)) + if (m_cache.position(0) != m_new_position(0)) m_og->set_value("position_x", double_to_string(m_new_position(0), 2)); - if (m_cache_position(1) != m_new_position(1)) + if (m_cache.position(1) != m_new_position(1)) m_og->set_value("position_y", double_to_string(m_new_position(1), 2)); - if (m_cache_position(2) != m_new_position(2)) + if (m_cache.position(2) != m_new_position(2)) m_og->set_value("position_z", double_to_string(m_new_position(2), 2)); - m_cache_position = m_new_position; + m_cache.position = m_new_position; auto scale = m_new_scale * 100.0; - if (m_cache_scale(0) != scale(0)) + if (m_cache.scale(0) != scale(0)) m_og->set_value("scale_x", double_to_string(scale(0), 2)); - if (m_cache_scale(1) != scale(1)) + if (m_cache.scale(1) != scale(1)) m_og->set_value("scale_y", double_to_string(scale(1), 2)); - if (m_cache_scale(2) != scale(2)) + if (m_cache.scale(2) != scale(2)) m_og->set_value("scale_z", double_to_string(scale(2), 2)); - m_cache_scale = scale; + m_cache.scale = scale; - if (m_cache_size(0) != m_new_size(0)) + if (m_cache.size(0) != m_new_size(0)) m_og->set_value("size_x", double_to_string(m_new_size(0), 2)); - if (m_cache_size(1) != m_new_size(1)) + if (m_cache.size(1) != m_new_size(1)) m_og->set_value("size_y", double_to_string(m_new_size(1), 2)); - if (m_cache_size(2) != m_new_size(2)) + if (m_cache.size(2) != m_new_size(2)) m_og->set_value("size_z", double_to_string(m_new_size(2), 2)); - m_cache_size = m_new_size; + m_cache.size = m_new_size; - if (m_cache_rotation(0) != m_new_rotation(0)) + if (m_cache.rotation(0) != m_new_rotation(0)) m_og->set_value("rotation_x", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(0)), 0), 2)); - if (m_cache_rotation(1) != m_new_rotation(1)) + if (m_cache.rotation(1) != m_new_rotation(1)) m_og->set_value("rotation_y", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(1)), 0), 2)); - if (m_cache_rotation(2) != m_new_rotation(2)) + if (m_cache.rotation(2) != m_new_rotation(2)) m_og->set_value("rotation_z", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(2)), 0), 2)); - m_cache_rotation = m_new_rotation; + m_cache.rotation = m_new_rotation; if (m_new_enabled) m_og->enable(); @@ -378,11 +427,15 @@ void ObjectManipulation::update_if_dirty() void ObjectManipulation::reset_settings_value() { - m_new_position = Vec3d::Zero(); - m_new_rotation = Vec3d::Zero(); + m_new_position = Vec3d::Zero(); + m_new_rotation = Vec3d::Zero(); m_new_scale = Vec3d::Ones(); m_new_size = Vec3d::Zero(); - m_new_enabled = false; + m_new_enabled = false; +#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION + m_cache.object_idx = -1; + m_cache.instance_idx = -1; +#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION #if !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION m_dirty = true; #endif // !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION @@ -393,10 +446,18 @@ void ObjectManipulation::change_position_value(const Vec3d& position) auto canvas = wxGetApp().plater()->canvas3D(); GLCanvas3D::Selection& selection = canvas->get_selection(); selection.start_dragging(); +#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION + selection.translate(position - m_cache.position, selection.requires_local_axes()); +#else selection.translate(position - m_cache_position, selection.requires_local_axes()); +#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION canvas->do_move(); +#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION + m_cache.position = position; +#else m_cache_position = position; +#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION } void ObjectManipulation::change_rotation_value(const Vec3d& rotation) @@ -415,7 +476,7 @@ void ObjectManipulation::change_rotation_value(const Vec3d& rotation) canvas->do_rotate(); #if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION - m_cache_rotation = rotation; + m_cache.rotation = rotation; #endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION } @@ -425,7 +486,11 @@ void ObjectManipulation::change_scale_value(const Vec3d& scale) const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); if (selection.requires_uniform_scale()) { +#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION + Vec3d abs_scale_diff = (scale - m_cache.scale).cwiseAbs(); +#else Vec3d abs_scale_diff = (scale - m_cache_scale).cwiseAbs(); +#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION double max_diff = abs_scale_diff(X); Axis max_diff_axis = X; if (max_diff < abs_scale_diff(Y)) @@ -449,7 +514,7 @@ void ObjectManipulation::change_scale_value(const Vec3d& scale) canvas->do_scale(); #if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION - m_cache_scale = scale; + m_cache.scale = scale; #endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION } @@ -457,7 +522,11 @@ void ObjectManipulation::change_size_value(const Vec3d& size) { const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); +#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION + Vec3d ref_size = m_cache.size; +#else Vec3d ref_size = m_cache_size; +#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION if (selection.is_single_full_instance()) { const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); @@ -470,7 +539,7 @@ void ObjectManipulation::change_size_value(const Vec3d& size) if (selection.requires_uniform_scale()) { - Vec3d abs_scale_diff = (scale - m_cache_scale).cwiseAbs(); + Vec3d abs_scale_diff = (scale - m_cache.scale).cwiseAbs(); double max_diff = abs_scale_diff(X); Axis max_diff_axis = X; if (max_diff < abs_scale_diff(Y)) @@ -493,7 +562,7 @@ void ObjectManipulation::change_size_value(const Vec3d& size) canvas->get_selection().scale(scaling_factor, false); canvas->do_scale(); - m_cache_size = size; + m_cache.size = size; #else change_scale_value(100.0 * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2))); #endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index ac80f56b3..ee768510a 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -15,10 +15,32 @@ namespace GUI { class ObjectManipulation : public OG_Settings { #if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION - Vec3d m_cache_position; - Vec3d m_cache_rotation; - Vec3d m_cache_scale; - Vec3d m_cache_size; + struct Cache + { + Vec3d position; + Vec3d rotation; + Vec3d scale; + Vec3d size; + + std::string move_label_string; + std::string rotate_label_string; + std::string scale_label_string; + + int object_idx; + int instance_idx; + + Vec3d instance_box_size; + + Cache() : position(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX)) , rotation(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX)) + , scale(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX)) , size(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX)) + , move_label_string("") , rotate_label_string("") , scale_label_string("") + , object_idx(-1) + , instance_idx(-1) + { + } + }; + + Cache m_cache; #else Vec3d m_cache_position{ 0., 0., 0. }; Vec3d m_cache_rotation{ 0., 0., 0. }; From 2b39babf5fef0e9c5540eb9f940d25c3988989b5 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 7 Jan 2019 12:05:16 +0100 Subject: [PATCH 03/23] Place on bed area limit decreased --- src/slic3r/GUI/GLGizmo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index 5908044f9..7fff44e6f 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -1523,7 +1523,7 @@ void GLGizmoFlatten::update_planes() const Transform3d& inst_matrix = m_model_object->instances.front()->get_matrix(); // Following constants are used for discarding too small polygons. - const float minimal_area = 20.f; // in square mm (world coordinates) + const float minimal_area = 5.f; // in square mm (world coordinates) const float minimal_side = 1.f; // mm // Now we'll go through all the facets and append Points of facets sharing the same normal. From 026bc801e33778ebc5500ad0a3aac9437bca181f Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 7 Jan 2019 12:20:48 +0100 Subject: [PATCH 04/23] Fix of #1505, #1541 Fixed a regression issue in initialization of the "Avoid external perimeters" feature. --- src/libslic3r/GCode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 1134b383f..9225b2bea 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -809,7 +809,7 @@ void GCode::_do_export(Print &print, FILE *file) for (const ExPolygon &expoly : layer->slices.expolygons) for (const Point © : object->copies()) { islands.emplace_back(expoly.contour); - islands.back().translate(- copy); + islands.back().translate(copy); } //FIXME Mege the islands in parallel. m_avoid_crossing_perimeters.init_external_mp(union_ex(islands)); From 0970457a46ca2c32966ef05e323c87fc514365ac Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 7 Jan 2019 14:52:13 +0100 Subject: [PATCH 05/23] Reverted a buggy change done in c0ebcacf1d62d44d247755c9c0d9c681d3579651 --- src/slic3r/GUI/GUI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 0761845b6..df5c1d407 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -148,7 +148,7 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt config.set_key_value(opt_key, new ConfigOptionString(boost::any_cast(value))); break; case coStrings:{ - if (opt_key == "compatible_prints" || opt_key == "compatible_printers" || opt_key == "post_process") { + if (opt_key == "compatible_prints" || opt_key == "compatible_printers") { config.option(opt_key)->values = boost::any_cast>(value); } From 2f4adc1906316158cac81b263150c3372e6ea745 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 7 Jan 2019 15:12:40 +0100 Subject: [PATCH 06/23] Implemented [filament_extruder_id] placeholder #1568 --- src/libslic3r/GCode.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 9225b2bea..bff72a9c0 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -204,7 +204,9 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T if (! start_filament_gcode.empty()) { // Process the start_filament_gcode for the active filament only. gcodegen.placeholder_parser().set("current_extruder", new_extruder_id); - gcode += gcodegen.placeholder_parser_process("start_filament_gcode", start_filament_gcode, new_extruder_id); + DynamicConfig config; + config.set_key_value("filament_extruder_id", new ConfigOptionInt(new_extruder_id)); + gcode += gcodegen.placeholder_parser_process("start_filament_gcode", start_filament_gcode, new_extruder_id, &config); check_add_eol(gcode); } // A phony move to the end position at the wipe tower. @@ -787,11 +789,17 @@ void GCode::_do_export(Print &print, FILE *file) // Wipe tower will control the extruder switching, it will call the start_filament_gcode. } else { // Only initialize the initial extruder. - _writeln(file, this->placeholder_parser_process("start_filament_gcode", print.config().start_filament_gcode.values[initial_extruder_id], initial_extruder_id)); + DynamicConfig config; + config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(initial_extruder_id))); + _writeln(file, this->placeholder_parser_process("start_filament_gcode", print.config().start_filament_gcode.values[initial_extruder_id], initial_extruder_id, &config)); } } else { - for (const std::string &start_gcode : print.config().start_filament_gcode.values) - _writeln(file, this->placeholder_parser_process("start_filament_gcode", start_gcode, (unsigned int)(&start_gcode - &print.config().start_filament_gcode.values.front()))); + DynamicConfig config; + for (const std::string &start_gcode : print.config().start_filament_gcode.values) { + int extruder_id = (unsigned int)(&start_gcode - &print.config().start_filament_gcode.values.front()); + config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id)); + _writeln(file, this->placeholder_parser_process("start_filament_gcode", start_gcode, extruder_id, &config)); + } } this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true); print.throw_if_canceled(); @@ -990,10 +998,15 @@ void GCode::_do_export(Print &print, FILE *file) config.set_key_value("layer_z", new ConfigOptionFloat(m_writer.get_position()(2) - m_config.z_offset.value)); if (print.config().single_extruder_multi_material) { // Process the end_filament_gcode for the active filament only. - _writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config().end_filament_gcode.get_at(m_writer.extruder()->id()), m_writer.extruder()->id(), &config)); + int extruder_id = m_writer.extruder()->id(); + config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id)); + _writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config().end_filament_gcode.get_at(extruder_id), extruder_id, &config)); } else { - for (const std::string &end_gcode : print.config().end_filament_gcode.values) - _writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, (unsigned int)(&end_gcode - &print.config().end_filament_gcode.values.front()), &config)); + for (const std::string &end_gcode : print.config().end_filament_gcode.values) { + int extruder_id = (unsigned int)(&end_gcode - &print.config().end_filament_gcode.values.front()); + config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id)); + _writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, extruder_id, &config)); + } } _writeln(file, this->placeholder_parser_process("end_gcode", print.config().end_gcode, m_writer.extruder()->id(), &config)); } From b66f41f43dd740f17e54951fbaf453bd8069c889 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 7 Jan 2019 16:20:50 +0100 Subject: [PATCH 07/23] Fixed #1543 --- src/slic3r/GUI/Field.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 928a6236e..91052570d 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -474,6 +474,7 @@ void Choice::BUILD() { if (temp->GetWindowStyle() != wxCB_READONLY) { temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { e.Skip(); + if (m_opt.type == coStrings) return; double old_val = !m_value.empty() ? boost::any_cast(m_value) : -99999; if (is_defined_input_value(window, m_opt.type)) { if (fabs(old_val - boost::any_cast(get_value())) <= 0.0001) @@ -692,7 +693,7 @@ boost::any& Choice::get_value() } else if (m_opt.gui_type == "f_enum_open") { const int ret_enum = static_cast(window)->GetSelection(); - if (ret_enum < 0 || m_opt.enum_values.empty()) + if (ret_enum < 0 || m_opt.enum_values.empty() || m_opt.type == coStrings) get_value_by_opt_type(ret_str); else m_value = atof(m_opt.enum_values[ret_enum].c_str()); From 02e1636831378e10653e6f3d08fc19416b127cdf Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 3 Jan 2019 19:33:57 +0100 Subject: [PATCH 08/23] doc: Update Windows build instructions --- doc/How to build - Windows.md | 120 ++++++++++++++++------------------ 1 file changed, 55 insertions(+), 65 deletions(-) diff --git a/doc/How to build - Windows.md b/doc/How to build - Windows.md index 5c8e7ef3c..96fa24cae 100644 --- a/doc/How to build - Windows.md +++ b/doc/How to build - Windows.md @@ -1,99 +1,89 @@ -### NOTE: This document is currently outdated wrt. the new post-Perl Slic3rPE. A new build process and the description thereof is a work in progress and is comming soon. Please stay tuned. - --- - - # Building Slic3r PE on Microsoft Windows -The currently supported way of building Slic3r PE on Windows is with CMake and MS Visual Studio 2013 -using our Perl binary distribution (compiled from official Perl sources). +The currently supported way of building Slic3r PE on Windows is with CMake and MS Visual Studio 2013. You can use the free [Visual Studio 2013 Community Edition](https://www.visualstudio.com/vs/older-downloads/). CMake installer can be downloaded from [the official website](https://cmake.org/download/). -Other setups (such as mingw + Strawberry Perl) _may_ work, but we cannot guarantee this will work -and cannot provide guidance. +Building with newer versions of MSVS (2015, 2017) may work too as reported by some of our users. +### Dependencies -### Geting the dependencies +On Windows Slic3r is built against statically built libraries. +We provide a prebuilt package of all the needed dependencies. +The package comes in a several variants: -First, download and upnack our Perl + wxWidgets binary distribution: + - [64 bit, Release mode only](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-64.7z) (41 MB, 546 MB unpacked) + - [64 bit, Release and Debug mode](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-64-dev.7z) (88 MB, 1200 MB unpacked) + - [32 bit, Release mode only](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-32.7z) (38 MB, 391 MB unpacked) + - [32 bit, Release and Debug mode](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-32-dev.7z) (24 MB, 487 MB unpacked) - - 32 bit, release mode: [wperl32-5.24.0-2018-03-02.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=wperl32-5.24.0-2018-03-02.7z) - - 64 bit, release mode: [wperl64-5.24.0-2018-03-02.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=wperl64-5.24.0-2018-03-02.7z) - - 64 bit, release mode + debug symbols: [wperl64d-5.24.0-2018-03-02.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=wperl64d-5.24.0-2018-03-02.7z) +When unsure, use the _Release mode only_ variant, the _Release and Debug_ variant is only needed for debugging & developement. -It is recommended to unpack this package into `C:\`. +If you're unsure where to unpack the package, unpack it into `C:\local\` (but it can really be anywhere). -Apart from wxWidgets and Perl, you will also need additional dependencies: +Alternatively you can also compile the dependencies yourself, see below. - - Boost - - Intel TBB - - libcurl +### Building Slic3r PE with Visual Studio -We have prepared a binary package of the listed libraries: +First obtain the Slic3 PE sources via either git or by extracting the source archive. - - 32 bit: [slic3r-destdir-32.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=2%2Fslic3r-destdir-32.7z) - - 64 bit: [slic3r-destdir-64.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=2%2Fslic3r-destdir-64.7z) +Then you will need to note down the so-called 'prefix path' to the dependencies, this is the location of the dependencies packages + `\usr\local` appended. +For example on 64 bits this would be `C:\local\destdir-64\usr\local`. The prefix path will need to be passed to CMake. -It is recommended you unpack this package into `C:\local\` as the environment -setup script expects it there. +When ready, open the relevant Visual Studio command line and `cd` into the directory with Slic3r sources. +Use these commands to prepare Visual Studio solution file: -Alternatively you can also compile the additional dependencies yourself. -There is a [powershell script](./deps-build/windows/slic3r-makedeps.ps1) which automates this process. - -### Building Slic3r PE - -Once the dependencies are set up in their respective locations, -go to the `wperl*` directory extracted earlier and launch the `cmdline.lnk` file -which opens a command line prompt with appropriate environment variables set up. - -In this command line, `cd` into the directory with Slic3r sources -and use these commands to build the Slic3r from the command line: - - perl Build.PL - perl Build.PL --gui mkdir build cd build - cmake .. -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release - nmake - cd .. - perl slic3r.pl + cmake .. -G "Visual Studio 12 Win64" -DCMAKE_PREFIX_PATH="" -The above commands use `nmake` Makefiles. -You may also build Slic3r PE with other build tools: +Note that if you're building a 32-bit variant, you will need to change the `"Visual Studio 12 Win64"` to just `"Visual Studio 12"`. +Conversely, if you're using Visual Studio version other than 2013, the version number will need to be changed accordingly. -### Building with Visual Studio +If `cmake` has finished without errors, go to the build directory and open the `Slic3r.sln` solution file in Visual Studio. +Before building, make sure you're building the right project (use one of those starting with `slic3r_app_...`) and that you're building +with the right configuration, ie. _Release_ vs. _Debug_. When unsure, choose _Release_. +Note that you won't be able to build a _Debug_ variant against a _Release_-only dependencies package. -To build and debug Slic3r PE with Visual Studio (64 bits), replace the `cmake` command with: +TODO: Install paragraph from @supermerill (?), also credit - cmake .. -G "Visual Studio 12 Win64" -DCMAKE_CONFIGURATION_TYPES=RelWithDebInfo +### Building from the command line -For the 32-bit variant, use: +There are several options for building from the command line: - cmake .. -G "Visual Studio 12" -DCMAKE_CONFIGURATION_TYPES=RelWithDebInfo +- [msbuild](https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-reference?view=vs-2017&viewFallbackFrom=vs-2013) +- [Ninja](https://ninja-build.org/) +- [nmake](https://docs.microsoft.com/en-us/cpp/build/nmake-reference?view=vs-2017) -After `cmake` has finished, go to the build directory and open the `Slic3r.sln` solution file. -This should open Visual Studio and load the Slic3r solution containing all the projects. -Make sure you use Visual Studio 2013 to open the solution. +To build with msbuild, use the same CMake command as in previous paragraph and then build using -You can then use the usual Visual Studio controls to build Slic3r (Hit `F5` to build and run with debugger). -If you want to run or debug Slic3r from within Visual Studio, make sure the `XS` project is activated. -It should be set as the Startup project by CMake by default, but you might want to check anyway. -There are multiple projects in the Slic3r solution, but only the `XS` project is configured with the right -commands to run and debug Slic3r. + msbuild /P:Configuration=Release ALL_BUILD.vcxproj -The above cmake commands generate Visual Studio project files with the `RelWithDebInfo` configuration only. -If you also want to use the `Release` configuration, you can generate Visual Studio projects with: +To build with Ninja or nmake, replace the `-G` option in the CMake call with `-G Ninja` or `-G "NMake Makefiles"`, respectively. +Then use either `ninja` or `nmake` to start the build. - -DCMAKE_CONFIGURATION_TYPES=Release;RelWithDebInfo +### Building the dependencies package yourself -(The `Debug` configuration is not supported as of now.) +The dependencies package is built using CMake scripts inside the `deps` subdirectory of Slic3r PE sources. +(This is intentionally not interconnected with the CMake scripts in the rest of the sources.) -### Building with ninja +Open the preferred Visual Studio command line and `cd` into the directory with Slic3r sources. +Then `cd` into the `deps` directory and use these commands to build: -To use [Ninja](https://ninja-build.org/), replace the `cmake` and `nmake` commands with: + mkdir build + cd build + cmake .. -G "Visual Studio 12 Win64" -DDESTDIR="C:\local\destdir-custom" + msbuild ALL_BUILD.vcxproj - cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release - ninja +You can also use the Visual Studio GUI or other generators as mentioned above. + +The `DESTDIR` option is the location where the bundle will be installed. +This may be customized. If you leave it empty, the `DESTDIR` will be places inside the same `build` directory. + +Note that the build variant that you may choose using Visual Studio (ie. _Release_ or _Debug_ etc.) when building the dependency package is **not relevant**. +The dependency build will by default build _both_ the _Release_ and _Debug_ variants regardless of what you choose in Visual Studio. +You can disable building of the debug variant by passing the `-DDEP_DEBUG=OFF` option to CMake, this will only produce a _Release_ build. + +Refer to the CMake scripts inside the `deps` directory to see which dependencies are built in what versions and how this is done. From 8bc8dfaba4abdb88e64379bbb4d3527d87a5ac82 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 4 Jan 2019 12:06:25 +0100 Subject: [PATCH 09/23] Build: Fix install targets, add SLIC3R_FHS, check resource dir on GUI_App init Fix #1515 --- CMakeLists.txt | 24 ++++++++++++++++++------ src/CMakeLists.txt | 13 +++++++++++++ src/platform/unix/fhs.hpp.in | 2 ++ src/slic3r.cpp | 6 ++++++ src/slic3r/GUI/GUI_App.cpp | 7 ++++++- 5 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 src/platform/unix/fhs.hpp.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 781dbd01a..fad1af6f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,8 @@ project(Slic3r) cmake_minimum_required(VERSION 3.2) include("version.inc") +include(GNUInstallDirs) + set(SLIC3R_RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/resources") file(TO_NATIVE_PATH "${SLIC3R_RESOURCES_DIR}" SLIC3R_RESOURCES_DIR_WIN) @@ -22,6 +24,7 @@ endif() option(SLIC3R_STATIC "Compile Slic3r with static libraries (Boost, TBB, glew)" ${SLIC3R_STATIC_INITIAL}) option(SLIC3R_GUI "Compile Slic3r with GUI components (OpenGL, wxWidgets)" 1) +option(SLIC3R_FHS "Assume Slic3r is to be installed in a FHS directory structure" 0) option(SLIC3R_PROFILE "Compile Slic3r with an invasive Shiny profiler" 0) option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1) option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1) @@ -61,6 +64,8 @@ foreach (DIR ${PREFIX_PATH_CHECK}) endif () endforeach () +message(STATUS "SLIC3R_FHS: ${SLIC3R_FHS}") + # Add our own cmake module path. list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules/) @@ -146,12 +151,14 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STRE endif() # Where all the bundled libraries reside? -set(LIBDIR ${CMAKE_CURRENT_SOURCE_DIR}/src/) +set(LIBDIR ${CMAKE_CURRENT_SOURCE_DIR}/src) +set(LIBDIR_BIN ${CMAKE_CURRENT_BINARY_DIR}/src) # For the bundled boost libraries (boost::nowide) include_directories(${LIBDIR}) +# For generated header files +include_directories(${LIBDIR_BIN}/platform) # For libslic3r.h include_directories(${LIBDIR}/clipper ${LIBDIR}/polypartition) -#set(CMAKE_INCLUDE_CURRENT_DIR ON) if(WIN32) # BOOST_ALL_NO_LIB: Avoid the automatic linking of Boost libraries on Windows. Rather rely on explicit linking. @@ -215,7 +222,6 @@ endif() # The Intel TBB library will use the std::exception_ptr feature of C++11. add_definitions(-DTBB_USE_CAPTURED_EXCEPTION=0) -#set(CURL_DEBUG 1) find_package(CURL REQUIRED) include_directories(${CURL_INCLUDE_DIRS}) @@ -280,7 +286,6 @@ include_directories(${GLEW_INCLUDE_DIRS}) # l10n set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/localization") add_custom_target(pot - # FIXME: file list stale COMMAND xgettext --keyword=L --from-code=UTF-8 --debug -f "${L10N_DIR}/list.txt" -o "${L10N_DIR}/Slic3rPE.pot" @@ -307,5 +312,12 @@ if(SLIC3R_BUILD_TESTS) add_subdirectory(tests) endif() -file(GLOB MyVar var/*.png) -install(FILES ${MyVar} DESTINATION share/slic3r-prusa3d) + +# Resources install target, configure fhs.hpp on UNIX +if (WIN32) + install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/resources") +else () + set(SLIC3R_FHS_RESOURCES "${CMAKE_INSTALL_FULL_DATAROOTDIR}/slic3r-prusa3d") + install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${SLIC3R_FHS_RESOURCES}") +endif () +configure_file(${LIBDIR}/platform/unix/fhs.hpp.in ${LIBDIR_BIN}/platform/unix/fhs.hpp) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 31c801379..fa043cf9e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,6 +33,7 @@ if(PNG_FOUND AND NOT RASTERIZER_FORCE_BUILTIN_LIBPNG) else() set(ZLIB_LIBRARY "") message(WARNING "Using builtin libpng. This can cause crashes on some platforms.") + set(SKIP_INSTALL_ALL 1) # Prevent png+zlib from creating install targets add_subdirectory(png/zlib) set(ZLIB_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/png/zlib ${CMAKE_CURRENT_BINARY_DIR}/png/zlib) include_directories(${ZLIB_INCLUDE_DIR}) @@ -188,3 +189,15 @@ else () VERBATIM ) endif() + +# Slic3r binary install target +if (WIN32) + install(TARGETS slic3r RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}") + if (MSVC) + install(TARGETS slic3r_app_gui RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}") + install(TARGETS slic3r_app_console RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}") + install(TARGETS slic3r_app_noconsole RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}") + endif () +else () + install(TARGETS slic3r RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") +endif () diff --git a/src/platform/unix/fhs.hpp.in b/src/platform/unix/fhs.hpp.in new file mode 100644 index 000000000..8d03d4107 --- /dev/null +++ b/src/platform/unix/fhs.hpp.in @@ -0,0 +1,2 @@ +#cmakedefine SLIC3R_FHS @SLIC3R_FHS@ +#define SLIC3R_FHS_RESOURCES "@SLIC3R_FHS_RESOURCES@" diff --git a/src/slic3r.cpp b/src/slic3r.cpp index 59b23c133..6cd16889b 100644 --- a/src/slic3r.cpp +++ b/src/slic3r.cpp @@ -22,6 +22,8 @@ #include #include +#include "unix/fhs.hpp" // Generated by CMake from ../platform/unix/fhs.hpp.in + #include "libslic3r/libslic3r.h" #include "libslic3r/Config.hpp" #include "libslic3r/Geometry.hpp" @@ -77,6 +79,10 @@ int main(int argc, char **argv) // The resources are packed to 'resources' // Path from Slic3r binary to resources: boost::filesystem::path path_resources = path_to_binary.parent_path() / "resources"; +#elif defined SLIC3R_FHS + // The application is packaged according to the Linux Filesystem Hierarchy Standard + // Resources are set to the 'Architecture-independent (shared) data', typically /usr/share or /usr/local/share + boost::filesystem::path path_resources = SLIC3R_FHS_RESOURCES; #else // The application is packed in the .tar.bz archive (or in AppImage) as 'bin/slic3r', // The resources are packed to 'resources' diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 091071e16..ce7ea8bac 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include @@ -15,6 +14,7 @@ #include #include #include +#include #include "libslic3r/Utils.hpp" #include "libslic3r/Model.hpp" @@ -83,6 +83,11 @@ GUI_App::GUI_App() bool GUI_App::OnInit() { + // Verify resources path + const wxString resources_dir = from_u8(Slic3r::resources_dir()); + wxCHECK_MSG(wxDirExists(resources_dir), false, + wxString::Format("Resources path does not exist or is not a directory: %s", resources_dir)); + #if ENABLE_IMGUI wxCHECK_MSG(m_imgui->init(), false, "Failed to initialize ImGui"); #endif // ENABLE_IMGUI From 39c0e80ce8ca65beb473f9beee45fd72c95509f6 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 7 Jan 2019 14:00:38 +0100 Subject: [PATCH 10/23] deps: Fix libpng and zlib on Windows --- deps/deps-windows.cmake | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/deps/deps-windows.cmake b/deps/deps-windows.cmake index d49434ecb..17dfae8bd 100644 --- a/deps/deps-windows.cmake +++ b/deps/deps-windows.cmake @@ -121,7 +121,8 @@ ExternalProject_Add(dep_zlib URL_HASH SHA256=4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066 CMAKE_GENERATOR "${DEP_MSVC_GEN}" CMAKE_ARGS - "-DINSTALL_BIN_DIR=${CMAKE_CURRENT_BINARY_DIR}\\fallout" # I found no better way of preventing zlib creating & installing DLLs :-/ + -DSKIP_INSTALL_FILES=ON # Prevent installation of man pages et al. + "-DINSTALL_BIN_DIR=${CMAKE_CURRENT_BINARY_DIR}\\fallout" # I found no better way of preventing zlib from creating & installing DLLs :-/ -DCMAKE_POSITION_INDEPENDENT_CODE=ON "-DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR}\\usr\\local" BUILD_COMMAND msbuild /P:Configuration=Release INSTALL.vcxproj @@ -136,6 +137,19 @@ if (${DEP_DEBUG}) WORKING_DIRECTORY "${BINARY_DIR}" ) endif () +# The following steps are unfortunately needed to remove the _static suffix on libraries +ExternalProject_Add_Step(dep_zlib fix_static + DEPENDEES install + COMMAND "${CMAKE_COMMAND}" -E rename zlibstatic.lib zlib.lib + WORKING_DIRECTORY "${DESTDIR}\\usr\\local\\lib\\" +) +if (${DEP_DEBUG}) + ExternalProject_Add_Step(dep_zlib fix_static_debug + DEPENDEES install + COMMAND "${CMAKE_COMMAND}" -E rename zlibstaticd.lib zlibd.lib + WORKING_DIRECTORY "${DESTDIR}\\usr\\local\\lib\\" + ) +endif () ExternalProject_Add(dep_libpng @@ -147,6 +161,7 @@ ExternalProject_Add(dep_libpng CMAKE_ARGS -DPNG_SHARED=OFF -DPNG_TESTS=OFF + -DSKIP_INSTALL_FILES=ON # Prevent installation of man pages et al. -DCMAKE_POSITION_INDEPENDENT_CODE=ON "-DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR}\\usr\\local" BUILD_COMMAND msbuild /P:Configuration=Release INSTALL.vcxproj @@ -161,6 +176,20 @@ if (${DEP_DEBUG}) WORKING_DIRECTORY "${BINARY_DIR}" ) endif () +# The following steps are unfortunately needed to remove the _static suffix on libraries +# (And also overwrite the dynamic .lib) +ExternalProject_Add_Step(dep_libpng fix_static + DEPENDEES install + COMMAND "${CMAKE_COMMAND}" -E rename libpng16_static.lib libpng16.lib + WORKING_DIRECTORY "${DESTDIR}\\usr\\local\\lib\\" +) +if (${DEP_DEBUG}) + ExternalProject_Add_Step(dep_libpng fix_static_debug + DEPENDEES install + COMMAND "${CMAKE_COMMAND}" -E rename libpng16_staticd.lib libpng16d.lib + WORKING_DIRECTORY "${DESTDIR}\\usr\\local\\lib\\" + ) +endif () if (${DEPS_BITS} EQUAL 32) From 42a4ceaf3eacabce3b1e7d4fdc114f2fb8b62d31 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 7 Jan 2019 15:26:53 +0100 Subject: [PATCH 11/23] doc: Update build doc for Windows --- doc/How to build - Windows.md | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/doc/How to build - Windows.md b/doc/How to build - Windows.md index 96fa24cae..898c830d0 100644 --- a/doc/How to build - Windows.md +++ b/doc/How to build - Windows.md @@ -7,16 +7,18 @@ CMake installer can be downloaded from [the official website](https://cmake.org/ Building with newer versions of MSVS (2015, 2017) may work too as reported by some of our users. +_Note:_ Thanks to **@supermerill** for testing and inspiration on this guide. + ### Dependencies On Windows Slic3r is built against statically built libraries. We provide a prebuilt package of all the needed dependencies. The package comes in a several variants: - - [64 bit, Release mode only](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-64.7z) (41 MB, 546 MB unpacked) - - [64 bit, Release and Debug mode](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-64-dev.7z) (88 MB, 1200 MB unpacked) - - [32 bit, Release mode only](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-32.7z) (38 MB, 391 MB unpacked) - - [32 bit, Release and Debug mode](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-32-dev.7z) (24 MB, 487 MB unpacked) + - [64 bit, Release mode only](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-64.7z) (41 MB, 578 MB unpacked) + - [64 bit, Release and Debug mode](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-64-dev.7z) (88 MB, 1.3 GB unpacked) + - [32 bit, Release mode only](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-32.7z) (38 MB, 520 MB unpacked) + - [32 bit, Release and Debug mode](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-32-dev.7z) (74 MB, 1.1 GB unpacked) When unsure, use the _Release mode only_ variant, the _Release and Debug_ variant is only needed for debugging & developement. @@ -47,7 +49,12 @@ Before building, make sure you're building the right project (use one of those s with the right configuration, ie. _Release_ vs. _Debug_. When unsure, choose _Release_. Note that you won't be able to build a _Debug_ variant against a _Release_-only dependencies package. -TODO: Install paragraph from @supermerill (?), also credit +#### Installing using the `INSTALL` project + +Slic3r PE can be run from the Visual Studio or from Visual Studio's build directory (`src\Release` or `src\Debug`), +but for longer-term usage you migth want to install somewhere using the `INSTALL` project. +By default, this installs into `C:\Program Files\Slic3r`. +To customize the install path, use the `-DCMAKE_INSTALL_PREFIX=` when invoking `cmake`. ### Building from the command line @@ -61,15 +68,17 @@ To build with msbuild, use the same CMake command as in previous paragraph and t msbuild /P:Configuration=Release ALL_BUILD.vcxproj -To build with Ninja or nmake, replace the `-G` option in the CMake call with `-G Ninja` or `-G "NMake Makefiles"`, respectively. +To build with Ninja or nmake, replace the `-G` option in the CMake call with `-G Ninja` or `-G "NMake Makefiles"` , respectively. Then use either `ninja` or `nmake` to start the build. +To install, use `msbuild /P:Configuration=Release INSTALL.vcxproj` , `ninja install` , or `nmake install` . + ### Building the dependencies package yourself The dependencies package is built using CMake scripts inside the `deps` subdirectory of Slic3r PE sources. (This is intentionally not interconnected with the CMake scripts in the rest of the sources.) -Open the preferred Visual Studio command line and `cd` into the directory with Slic3r sources. +Open the preferred Visual Studio command line (64 or 32 bit variant) and `cd` into the directory with Slic3r sources. Then `cd` into the `deps` directory and use these commands to build: mkdir build From 00c9d1f1847e571097c2a79a9ce0de0e458dbc7d Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 7 Jan 2019 15:26:31 +0100 Subject: [PATCH 12/23] doc: Add build tutorial for Mac Fix #1421 Fix #827 Fix #1039 --- doc/How to build - Mac OS.md | 62 ++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 doc/How to build - Mac OS.md diff --git a/doc/How to build - Mac OS.md b/doc/How to build - Mac OS.md new file mode 100644 index 000000000..a2d7cf7fe --- /dev/null +++ b/doc/How to build - Mac OS.md @@ -0,0 +1,62 @@ + +# Building Slic3r PE on Mac OS + +To build Slic3r PE on Mac OS, you will need to install XCode and an appropriate SDK. +You will also need [CMake](https://cmake.org/) installed (available on Brew) and possibly git. + +Currently Slic3r PE is built against the Mac OS X SDK version 10.9. +Building against older SDKs is unsupported. Building against newer SDKs might work, +but there may be subtle issues, such as dark mode not working very well on Mojave or other GUI problems. + +You can obtain the SDK 10.9 for example [in this repository](https://github.com/phracker/MacOSX-SDKs). +If you don't already have the 10.9 version as part of your Mac OS installation, please download it +and place it into a reachable location. + +The default location for Mac OS SDKs is: + + /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ + +Wherever the 10.9 SDK is, please note down its location, it will be required to build Slic3r. + +On my system, for example, the path to the SDK is + + /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk + +### Dependencies + +Slic3r comes with a set of CMake scripts to build its dependencies, it lives in the `deps` directory. +Open a terminal window and navigate to Slic3r sources directory and then to `deps`. +Use the following commands to build the dependencies: + + mkdir build + cd build + cmake .. -DDEPS_OSX_SYSROOT= + +This will create a dependencies bundle inside the `build/destdir` directory. +You can also customize the bundle output path using the `-DDESTDIR=` option passed to `cmake`. + +### Building Slic3r + +If dependencies built without an error, you can proceed to build Slic3r itself. +Go back to top level Slic3r sources directory and use these commands: + + mkdir build + cd build + cmake .. -DCMAKE_PREFIX_PATH="$PWD/../deps/build/destdir/usr/local" -DCMAKE_OSX_SYSROOT= + +The `CMAKE_PREFIX_PATH` is the path to the dependencies bundle but with `/usr/local` appended - if you set a custom path +using the `DESTDIR` option, you will need to change this accordingly. **Warning:** the `CMAKE_PREFIX_PATH` needs to be an absolute path. + +The CMake command above prepares Slic3r for building from the command line. +To start the build, use + + make -jN + +where `N` is the number of CPU cores, so, for example `make -j4` for a 4-core machine. + +Alternatively, if you would like to use XCode GUI, modify the `cmake` command to include the `-GXcode` option: + + cmake .. -GXcode -DCMAKE_PREFIX_PATH="$PWD/../deps/build/destdir/usr/local" -DCMAKE_OSX_SYSROOT= + +and then open the `Slic3r.xcodeproj` file. +This should open up XCode where you can perform build using the GUI or perform other tasks. From f013972d8b2d794cfde39170259d76603b616c76 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 7 Jan 2019 16:28:57 +0100 Subject: [PATCH 13/23] doc: Add build tutorial for Unix/Linux --- deps/CMakeLists.txt | 1 + doc/How to build - Linux et al.md | 66 +++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 doc/How to build - Linux et al.md diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index 8f98e0bda..1b23c5864 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -6,6 +6,7 @@ # All the dependencies are installed in a `destdir` directory in the root of the build directory, # in a traditional Unix-style prefix structure. The destdir can be used directly by CMake # when building Slic3r - to do this, set the CMAKE_PREFIX_PATH to ${destdir}/usr/local. +# Warning: On UNIX/Linux, you also need to set -DSLIC3R_STATIC=1 when building Slic3r. # # For better clarity of console output, it's recommended to _not_ use a parallelized build # for the top-level command, ie. use `make -j 1` or `ninja -j 1` to force single-threaded top-level diff --git a/doc/How to build - Linux et al.md b/doc/How to build - Linux et al.md new file mode 100644 index 000000000..e665cd14c --- /dev/null +++ b/doc/How to build - Linux et al.md @@ -0,0 +1,66 @@ + +# Building Slic3r PE on UNIX/Linux + +Slic3r PE uses the CMake build system and requires several dependencies. +The dependencies can be listed in `deps/deps-linux.cmake`, although they don't necessarily need to be as recent +as the versions listed - generally versions available on conservative Linux distros such as Debian stable or CentOS should suffice. + +Perl is not required any more. + +In a typical situaction, one would open a command line, go to the Slic3r sources, create a directory called `build` or similar, +`cd` into it and call: + + cmake .. + make -jN + +where `N` is the number of CPU cores available. + +Additional CMake flags may be applicable as explained below. + +### Dependenciy resolution + +By default Slic3r looks for dependencies the default way CMake looks for them, ie. in default system locations. +On Linux this will typically make Slic3r depend on dynamically loaded libraries from the system, however, Slic3r can be told +to specifically look for static libraries with the `SLIC3R_STATIC` flag passed to cmake: + + cmake .. -DSLIC3R_STATIC=1 + +Additionally, Slic3r can be built in a static manner mostly independent of the system libraries with a dependencies bundle +created using CMake script in the `deps` directory (these are not interconnected with the rest of the CMake scripts). + +Note: We say _mostly independent_ because it's still expected the system will provide some transitive dependencies, such as GTK for wxWidgets. + +To do this, go to the `deps` directory, create a `build` subdirectory (or the like) and use: + + cmake .. -DDESTDIR= + +where the target destdir is a directory of your choosing where the dependencies will be installed. +You can also omit the `DESTDIR` option to use the default, in that case the `destdir` will be created inside the `build` directory where `cmake` is run. + +To pass the destdir path to the top-level Slic3r CMake script, use the `CMAKE_PREFIX_PATH` option along with turning on `SLIC3R_STATIC`: + + cmake .. -DSLIC3R_STATIC=1 -DCMAKE_PREFIX_PATH=/usr/local + +Note that `/usr/local` needs to be appended to the destdir path and also the prefix path should be absolute. + +**Warning**: Once the dependency bundle is installed in a destdir, the destdir cannot be moved elsewhere. +This is because wxWidgets hardcode the installation path. + +### Build variant + +By default Scli3r builds the release variant. +To create a debug build, use the following CMake flag: + + -DCMAKE_BUILD_TYPE=Debug + +### Installation + +In runtime, Slic3r needs a way to access its resource files. By default, it looks for a `resources` directory relative to its binary. + +If you instead wnat Slic3r installed in a structure according to the Filesystem Hierarchy Standard, use the `SLIC3R_FHS` flag + + cmake .. -DSLIC3R_FHS=1 + +This will make Slic3r look for a fixed-location `share/slic3r-prusa3d` directory instead (note that the location becomes hardcoded). + +You can then use the `make install` target to install Slic3r. From 153c6e7f68633b21486e9fb35bfe07367920f6c0 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 8 Jan 2019 09:10:57 +0100 Subject: [PATCH 14/23] Extended limits in z for camera target movements - Fix of #1589 --- src/slic3r/GUI/GLCanvas3D.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 8cd80ad7d..f2de33bb7 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3979,6 +3979,12 @@ BoundingBoxf3 GLCanvas3D::scene_bounding_box() const { BoundingBoxf3 bb = volumes_bounding_box(); bb.merge(m_bed.get_bounding_box()); + if (m_config != nullptr) + { + double h = m_config->opt_float("max_print_height"); + bb.min(2) = std::min(bb.min(2), -h); + bb.max(2) = std::max(bb.max(2), h); + } return bb; } From 66f9582a20a716883237adb107a6ae0599866e6b Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 8 Jan 2019 09:51:58 +0100 Subject: [PATCH 15/23] Fixed sidebar size fields update (which was broken again) --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 22 ++++++++++------------ src/slic3r/GUI/GUI_ObjectManipulation.hpp | 19 ++++++++++++++----- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 1848ddda7..f763cc5a1 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -244,15 +244,13 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele if ((0 <= obj_idx) && (obj_idx < (int)wxGetApp().model_objects()->size())) { bool changed_box = false; - if ((m_cache.object_idx != obj_idx) || (m_cache.instance_idx != instance_idx)) + if (!m_cache.instance.matches_object(obj_idx)) { - m_cache.object_idx = obj_idx; - m_cache.instance_idx = instance_idx; - m_cache.instance_box_size = (*wxGetApp().model_objects())[obj_idx]->raw_mesh().bounding_box().size(); + m_cache.instance.set(obj_idx, instance_idx, (*wxGetApp().model_objects())[obj_idx]->raw_mesh().bounding_box().size()); changed_box = true; } - if (changed_box || !m_cache.scale.isApprox(100.0 * m_new_scale) || !m_cache.rotation.isApprox(m_new_rotation)) - m_new_size = volume->get_instance_transformation().get_matrix(true, true) * m_cache.instance_box_size; + if (changed_box || !m_cache.instance.matches_instance(instance_idx) || !m_cache.scale.isApprox(100.0 * m_new_scale)) + m_new_size = volume->get_instance_transformation().get_matrix(true, true) * m_cache.instance.box_size; } else // this should never happen @@ -270,8 +268,7 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele else if (selection.is_single_full_object()) { #if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION - m_cache.object_idx = -1; - m_cache.instance_idx = -1; + m_cache.instance.reset(); #endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION const BoundingBoxf3& box = selection.get_bounding_box(); @@ -286,8 +283,7 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele else if (selection.is_single_modifier() || selection.is_single_volume()) { #if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION - m_cache.object_idx = -1; - m_cache.instance_idx = -1; + m_cache.instance.reset(); #endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION // the selection contains a single volume @@ -433,8 +429,7 @@ void ObjectManipulation::reset_settings_value() m_new_size = Vec3d::Zero(); m_new_enabled = false; #if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION - m_cache.object_idx = -1; - m_cache.instance_idx = -1; + m_cache.instance.reset(); #endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION #if !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION m_dirty = true; @@ -514,6 +509,9 @@ void ObjectManipulation::change_scale_value(const Vec3d& scale) canvas->do_scale(); #if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION + if (!m_cache.scale.isApprox(scale)) + m_cache.instance.instance_idx = -1; + m_cache.scale = scale; #endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION } diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index ee768510a..97cd2b639 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -26,16 +26,25 @@ class ObjectManipulation : public OG_Settings std::string rotate_label_string; std::string scale_label_string; - int object_idx; - int instance_idx; + struct Instance + { + int object_idx; + int instance_idx; + Vec3d box_size; - Vec3d instance_box_size; + Instance() { reset(); } + void reset() { this->object_idx = -1; this->instance_idx = -1; this->box_size = Vec3d::Zero(); } + void set(int object_idx, int instance_idx, const Vec3d& box_size) { this->object_idx = object_idx; this->instance_idx = instance_idx; this->box_size = box_size; } + bool matches(int object_idx, int instance_idx) const { return (this->object_idx == object_idx) && (this->instance_idx == instance_idx); } + bool matches_object(int object_idx) const { return (this->object_idx == object_idx); } + bool matches_instance(int instance_idx) const { return (this->instance_idx == instance_idx); } + }; + + Instance instance; Cache() : position(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX)) , rotation(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX)) , scale(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX)) , size(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX)) , move_label_string("") , rotate_label_string("") , scale_label_string("") - , object_idx(-1) - , instance_idx(-1) { } }; From cfff3832dc8982cc8e4964694faeb228c86b8a03 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 8 Jan 2019 10:06:10 +0100 Subject: [PATCH 16/23] Force SetFocus on 3D view when mouse enters it also on Mac --- src/slic3r/GUI/GLCanvas3D.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f2de33bb7..a6d0f4e9d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4945,8 +4945,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (evt.Entering()) { -#if defined(__WXMSW__) || defined(__linux__) - // On Windows and Linux needs focus in order to catch key events +//#if defined(__WXMSW__) || defined(__linux__) +// // On Windows and Linux needs focus in order to catch key events + // Set focus in order to remove it from sidebar fields if (m_canvas != nullptr) { // Only set focus, if the top level window of this canvas is active. auto p = dynamic_cast(evt.GetEventObject()); @@ -4958,7 +4959,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } m_mouse.set_start_position_2D_as_invalid(); -#endif +//#endif } else if (evt.Leaving()) { From 591d42fd762d9d22e6b139d8fc043b60949e43c2 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 8 Jan 2019 10:15:15 +0100 Subject: [PATCH 17/23] Fixed editing of the extruder's settings (SPE-735) --- src/libslic3r/Config.hpp | 4 ++-- src/slic3r/GUI/GUI.cpp | 16 +++++++++------- src/slic3r/GUI/Preset.cpp | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 7f826109a..e0544b153 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -218,7 +218,7 @@ public: const T& get_at(size_t i) const { return const_cast*>(this)->get_at(i); } - // Resize this vector by duplicating the last value. + // Resize this vector by duplicating the /*last*/first value. // If the current vector is empty, the default value is used instead. void resize(size_t n, const ConfigOption *opt_default = nullptr) override { @@ -238,7 +238,7 @@ public: this->values.resize(n, static_cast*>(opt_default)->values.front()); } else { // Resize by duplicating the last value. - this->values.resize(n, this->values.back()); + this->values.resize(n, this->values./*back*/front()); } } } diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index df5c1d407..0a27af9fa 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -154,13 +154,15 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt } else if (config.def()->get(opt_key)->gui_flags.compare("serialized") == 0) { std::string str = boost::any_cast(value); - if (str.back() == ';') str.pop_back(); - // Split a string to multiple strings by a semi - colon.This is the old way of storing multi - string values. - // Currently used for the post_process config value only. - std::vector values; - boost::split(values, str, boost::is_any_of(";")); - if (values.size() == 1 && values[0] == "") - values.resize(0);//break; + std::vector values {}; + if (!str.empty()) { + if (str.back() == ';') str.pop_back(); + // Split a string to multiple strings by a semi - colon.This is the old way of storing multi - string values. + // Currently used for the post_process config value only. + boost::split(values, str, boost::is_any_of(";")); + if (values.size() == 1 && values[0] == "") + values.resize(0); + } config.option(opt_key)->values = values; } else{ diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index fd2b26458..112a579b0 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -1053,7 +1053,7 @@ std::vector PresetCollection::dirty_options(const Preset *edited, c std::vector changed; if (edited != nullptr && reference != nullptr) { changed = deep_compare ? - deep_diff(reference->config, edited->config) : + deep_diff(edited->config, reference->config) : reference->config.diff(edited->config); // The "compatible_printers" option key is handled differently from the others: // It is not mandatory. If the key is missing, it means it is compatible with any printer. From 42e8d8140341153dca83d8d01b3bd09794214987 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 8 Jan 2019 10:52:11 +0100 Subject: [PATCH 18/23] Fix of "Build plate missing in view #1580" Fixed import of the user config bundle to maintain the "inherits" references to system profiles. --- src/slic3r/GUI/Preset.cpp | 15 +++++++++++ src/slic3r/GUI/Preset.hpp | 3 +++ src/slic3r/GUI/PresetBundle.cpp | 48 ++++++++++++++++++++++----------- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index fd2b26458..0a2f98414 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -1161,6 +1161,21 @@ std::string PresetCollection::name() const } } +std::vector PresetCollection::system_preset_names() const +{ + size_t num = 0; + for (const Preset &preset : m_presets) + if (preset.is_system) + ++ num; + std::vector out; + out.reserve(num); + for (const Preset &preset : m_presets) + if (preset.is_system) + out.emplace_back(preset.name); + std::sort(out.begin(), out.end()); + return out; +} + // Generate a file path from a profile name. Add the ".ini" suffix if it is missing. std::string PresetCollection::path_from_name(const std::string &new_name) const { diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index 96230ad2b..24112cf10 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -365,6 +365,9 @@ public: std::vector current_different_from_parent_options(const bool deep_compare = false) const { return dirty_options(&this->get_edited_preset(), this->get_selected_preset_parent(), deep_compare); } + // Return a sorted list of system preset names. + std::vector system_preset_names() const; + // Update the choice UI from the list of presets. // If show_incompatible, all presets are shown, otherwise only the compatible presets are shown. // If an incompatible preset is selected, it is shown as well. diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 274f2a7ef..0021ce307 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -876,7 +876,8 @@ void PresetBundle::load_config_file_config_bundle(const std::string &path, const // The presets starting with '*' are considered non-terminal and they are // removed through the flattening process by this function. // This function will never fail, but it will produce error messages through boost::log. -static void flatten_configbundle_hierarchy(boost::property_tree::ptree &tree, const std::string &group_name) +// system_profiles will not be flattened, and they will be kept inside the "inherits" field +static void flatten_configbundle_hierarchy(boost::property_tree::ptree &tree, const std::string &group_name, const std::vector &system_profiles) { namespace pt = boost::property_tree; @@ -911,23 +912,38 @@ static void flatten_configbundle_hierarchy(boost::property_tree::ptree &tree, co for (const Prst &prst : presets) { // Parse the list of comma separated values, possibly enclosed in quotes. std::vector inherits_names; + std::vector inherits_system; if (Slic3r::unescape_strings_cstyle(prst.node->get("inherits", ""), inherits_names)) { // Resolve the inheritance by name. std::vector &inherits_nodes = const_cast(prst).inherits; for (const std::string &node_name : inherits_names) { - auto it = presets.find(Prst(node_name, nullptr)); - if (it == presets.end()) - BOOST_LOG_TRIVIAL(error) << "flatten_configbundle_hierarchy: The preset " << prst.name << " inherits an unknown preset \"" << node_name << "\""; - else { - inherits_nodes.emplace_back(const_cast(&(*it))); - inherits_nodes.back()->parent_of.emplace_back(const_cast(&prst)); + auto it_system = std::lower_bound(system_profiles.begin(), system_profiles.end(), node_name); + if (it_system != system_profiles.end() && *it_system == node_name) { + // Loading a user config budnle, this preset is derived from a system profile. + inherits_system.emplace_back(node_name); + } else { + auto it = presets.find(Prst(node_name, nullptr)); + if (it == presets.end()) + BOOST_LOG_TRIVIAL(error) << "flatten_configbundle_hierarchy: The preset " << prst.name << " inherits an unknown preset \"" << node_name << "\""; + else { + inherits_nodes.emplace_back(const_cast(&(*it))); + inherits_nodes.back()->parent_of.emplace_back(const_cast(&prst)); + } } } } else { BOOST_LOG_TRIVIAL(error) << "flatten_configbundle_hierarchy: The preset " << prst.name << " has an invalid \"inherits\" field"; } - // Remove the "inherits" key, it has no meaning outside the config bundle. + // Remove the "inherits" key, it has no meaning outside of the config bundle. const_cast(prst.node)->erase("inherits"); + if (! inherits_system.empty()) { + // Loaded a user config bundle, where a profile inherits a system profile. + // User profile should be derived from a single system profile only. + assert(inherits_system.size() == 1); + if (inherits_system.size() > 1) + BOOST_LOG_TRIVIAL(error) << "flatten_configbundle_hierarchy: The preset " << prst.name << " inherits from more than single system preset"; + prst.node->put("inherits", Slic3r::escape_string_cstyle(inherits_system.front())); + } } // 2) Create a linear ordering for the directed acyclic graph of preset inheritance. @@ -983,13 +999,14 @@ static void flatten_configbundle_hierarchy(boost::property_tree::ptree &tree, co } } -static void flatten_configbundle_hierarchy(boost::property_tree::ptree &tree) +// preset_bundle is set when loading user config bundles, which must not overwrite the system profiles. +static void flatten_configbundle_hierarchy(boost::property_tree::ptree &tree, const PresetBundle *preset_bundle) { - flatten_configbundle_hierarchy(tree, "print"); - flatten_configbundle_hierarchy(tree, "filament"); - flatten_configbundle_hierarchy(tree, "sla_print"); - flatten_configbundle_hierarchy(tree, "sla_material"); - flatten_configbundle_hierarchy(tree, "printer"); + flatten_configbundle_hierarchy(tree, "print", preset_bundle ? preset_bundle->prints.system_preset_names() : std::vector()); + flatten_configbundle_hierarchy(tree, "filament", preset_bundle ? preset_bundle->filaments.system_preset_names() : std::vector()); + flatten_configbundle_hierarchy(tree, "sla_print", preset_bundle ? preset_bundle->sla_prints.system_preset_names() : std::vector()); + flatten_configbundle_hierarchy(tree, "sla_material", preset_bundle ? preset_bundle->sla_materials.system_preset_names() : std::vector()); + flatten_configbundle_hierarchy(tree, "printer", preset_bundle ? preset_bundle->printers.system_preset_names() : std::vector()); } // Load a config bundle file, into presets and store the loaded presets into separate files @@ -1019,7 +1036,8 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla } // 1.5) Flatten the config bundle by applying the inheritance rules. Internal profiles (with names starting with '*') are removed. - flatten_configbundle_hierarchy(tree); + // If loading a user config bundle, do not flatten with the system profiles, but keep the "inherits" flag intact. + flatten_configbundle_hierarchy(tree, ((flags & LOAD_CFGBNDLE_SYSTEM) == 0) ? this : nullptr); // 2) Parse the property_tree, extract the active preset names and the profiles, save them into local config files. // Parse the obsolete preset names, to be deleted when upgrading from the old configuration structure. From 4d0c0ac7483eac299fea266d9a35e8e10e3cd5de Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 8 Jan 2019 11:47:05 +0100 Subject: [PATCH 19/23] Fix of Cyrillic named files inside the object list (part of the #1622) --- src/slic3r/GUI/GUI_ObjectList.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 0b6c38bd8..729946dbf 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -849,7 +849,7 @@ void ObjectList::load_part( ModelObject* model_object, new_volume->set_type(static_cast(type)); new_volume->name = boost::filesystem::path(input_file).filename().string(); - part_names.Add(new_volume->name); + part_names.Add(from_u8(new_volume->name)); // set a default extruder value, since user can't add it manually new_volume->config.set_key_value("extruder", new ConfigOptionInt(0)); @@ -903,7 +903,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const int m_parts_changed = true; parts_changed(obj_idx); - select_item(m_objects_model->AddVolumeChild(GetSelection(), name, type)); + select_item(m_objects_model->AddVolumeChild(GetSelection(), from_u8(name), type)); #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME selection_changed(); #endif //no __WXOSX__ //__WXMSW__ @@ -1031,7 +1031,7 @@ void ObjectList::split() parent = item; for (auto id = 0; id < model_object->volumes.size(); id++) { - const auto vol_item = m_objects_model->AddVolumeChild(parent, model_object->volumes[id]->name, + const auto vol_item = m_objects_model->AddVolumeChild(parent, from_u8(model_object->volumes[id]->name), model_object->volumes[id]->is_modifier() ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART, model_object->volumes[id]->config.has("extruder") ? @@ -1188,7 +1188,7 @@ void ObjectList::part_selection_changed() void ObjectList::add_object_to_list(size_t obj_idx) { auto model_object = (*m_objects)[obj_idx]; - wxString item_name = model_object->name; + wxString item_name = from_u8(model_object->name); const auto item = m_objects_model->Add(item_name, !model_object->config.has("extruder") ? 0 : model_object->config.option("extruder")->value); @@ -1207,8 +1207,8 @@ void ObjectList::add_object_to_list(size_t obj_idx) if (model_object->volumes.size() > 1) { for (auto id = 0; id < model_object->volumes.size(); id++) { auto vol_item = m_objects_model->AddVolumeChild(item, - model_object->volumes[id]->name, - model_object->volumes[id]->type()/*ModelVolume::MODEL_PART*/, + from_u8(model_object->volumes[id]->name), + model_object->volumes[id]->type(), !model_object->volumes[id]->config.has("extruder") ? 0 : model_object->volumes[id]->config.option("extruder")->value, false); From 24e0c9b79e7faca2a3cf5a07c216648b385daf1a Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 8 Jan 2019 13:34:47 +0100 Subject: [PATCH 20/23] Added "uniform scaling" button --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 24 +++++++++++++++++++++-- src/slic3r/GUI/GUI_ObjectManipulation.hpp | 4 ++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index f763cc5a1..1cdf87be2 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -19,7 +19,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : OG_Settings(parent, true) { m_og->set_name(_(L("Object Manipulation"))); - m_og->label_width = 100; + m_og->label_width = 125; m_og->set_grid_vgap(5); m_og->m_on_change = [this](const std::string& opt_key, const boost::any& value) { @@ -150,7 +150,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : m_og->append_line(line); - auto add_og_to_object_settings = [](const std::string& option_name, const std::string& sidetext) + auto add_og_to_object_settings = [this](const std::string& option_name, const std::string& sidetext) { Line line = { _(option_name), "" }; ConfigOptionDef def; @@ -164,6 +164,26 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : def.max = 360; } + // Add "uniform scaling" button in front of "Scale" option + else if (option_name == "Scale") { + line.near_label_widget = [this](wxWindow* parent) { + auto btn = new PrusaLockButton(parent, wxID_ANY); + btn->Bind(wxEVT_BUTTON, [btn, this](wxCommandEvent &event){ + event.Skip(); + wxTheApp->CallAfter([btn, this]() { set_uniform_scaling(btn->IsLocked()); }); + }); + return btn; + }; + } + + // Add empty bmp (Its size have to be equal to PrusaLockButton) in front of "Size" option to label alignment + else if (option_name == "Size") { + line.near_label_widget = [this](wxWindow* parent) { + return new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, + wxBitmap(from_u8(var("one_layer_lock_on.png")), wxBITMAP_TYPE_PNG).GetSize()); + }; + } + const std::string lower_name = boost::algorithm::to_lower_copy(option_name); std::vector axes{ "x", "y", "z" }; diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index 97cd2b639..57eb93b71 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -74,6 +74,7 @@ class ObjectManipulation : public OG_Settings Vec3d m_new_scale; Vec3d m_new_size; bool m_new_enabled; + bool m_uniform_scale {false}; public: ObjectManipulation(wxWindow* parent); @@ -88,6 +89,9 @@ public: // Called from the App to update the UI if dirty. void update_if_dirty(); + void set_uniform_scaling(const bool uniform_scale) { m_uniform_scale = uniform_scale;} + bool get_uniform_scaling() const { return m_uniform_scale; } + private: void reset_settings_value(); From 7cf67db3321fa4bcae03405be6d6938777b5efa4 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 8 Jan 2019 15:16:40 +0100 Subject: [PATCH 21/23] Uniform scale is sidebar --- src/slic3r/GUI/GLCanvas3D.cpp | 10 ++++++---- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 5 ++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a6d0f4e9d..c8bd71754 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2513,7 +2513,9 @@ void GLCanvas3D::Selection::_render_sidebar_rotation_hints(const std::string& si void GLCanvas3D::Selection::_render_sidebar_scale_hints(const std::string& sidebar_field) const { - if (boost::ends_with(sidebar_field, "x") || requires_uniform_scale()) + bool uniform_scale = requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling(); + + if (boost::ends_with(sidebar_field, "x") || uniform_scale) { ::glPushMatrix(); ::glRotated(-90.0, 0.0, 0.0, 1.0); @@ -2521,14 +2523,14 @@ void GLCanvas3D::Selection::_render_sidebar_scale_hints(const std::string& sideb ::glPopMatrix(); } - if (boost::ends_with(sidebar_field, "y") || requires_uniform_scale()) + if (boost::ends_with(sidebar_field, "y") || uniform_scale) { ::glPushMatrix(); _render_sidebar_scale_hint(Y); ::glPopMatrix(); } - if (boost::ends_with(sidebar_field, "z") || requires_uniform_scale()) + if (boost::ends_with(sidebar_field, "z") || uniform_scale) { ::glPushMatrix(); ::glRotated(90.0, 1.0, 0.0, 0.0); @@ -2559,7 +2561,7 @@ void GLCanvas3D::Selection::_render_sidebar_rotation_hint(Axis axis) const void GLCanvas3D::Selection::_render_sidebar_scale_hint(Axis axis) const { - m_arrow.set_color((requires_uniform_scale() ? UNIFORM_SCALE_COLOR : AXES_COLOR[axis]), 3); + m_arrow.set_color(((requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling()) ? UNIFORM_SCALE_COLOR : AXES_COLOR[axis]), 3); ::glTranslated(0.0, 5.0, 0.0); m_arrow.render(); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 1cdf87be2..84025bae0 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -399,6 +399,9 @@ void ObjectManipulation::update_if_dirty() m_cache.rotation = m_new_rotation; +// if (wxGetApp().plater()->canvas3D()->get_selection().requires_uniform_scale()) +// m_uniform_scale = true; + if (m_new_enabled) m_og->enable(); else @@ -499,7 +502,7 @@ void ObjectManipulation::change_scale_value(const Vec3d& scale) { Vec3d scaling_factor = scale; const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); - if (selection.requires_uniform_scale()) + if (m_uniform_scale || selection.requires_uniform_scale()) { #if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION Vec3d abs_scale_diff = (scale - m_cache.scale).cwiseAbs(); From 2ccdfe68531265a51f6f5a7a8788cdbdf765b74f Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 8 Jan 2019 15:26:27 +0100 Subject: [PATCH 22/23] Fixed typo --- src/libslic3r/Geometry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index ba9c7b00e..fc5b158c7 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -1194,7 +1194,7 @@ Vec3d extract_euler_angles(const Eigen::Matrix& } else { - angles(1) = 0.0; + angles(0) = 0.0; angles(1) = ::atan2(-rotation_matrix(2, 0), sy); angles(2) = (angles(1) >-0.0) ? ::atan2(rotation_matrix(1, 2), rotation_matrix(1, 1)) : ::atan2(-rotation_matrix(1, 2), rotation_matrix(1, 1)); } From 6efcdd1ddf5bd57b110370cc314f275cded3fb2d Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 8 Jan 2019 16:05:49 +0100 Subject: [PATCH 23/23] Added wxEVT_TEXT_ENTER handling for TextCtrl, SpinCtrl & PointCtrl (but it doesn't work under OSX) (fix of #1518) --- src/slic3r/GUI/Field.cpp | 97 ++++++++++++++++++++++++++-------------- src/slic3r/GUI/Field.hpp | 12 +++-- 2 files changed, 72 insertions(+), 37 deletions(-) diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 91052570d..2c7bce613 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -66,12 +66,8 @@ void Field::PostInitialize() BUILD(); } -void Field::on_kill_focus(wxEvent& event) +void Field::on_kill_focus() { - // Without this, there will be nasty focus bugs on Windows. - // Also, docs for wxEvent::Skip() say "In general, it is recommended to skip all - // non-command events to allow the default handling to take place." - event.Skip(); // call the registered function if it is available if (m_on_kill_focus!=nullptr) m_on_kill_focus(m_opt_id); @@ -250,11 +246,23 @@ void TextCtrl::BUILD() { break; } - const long style = m_opt.multiline ? wxTE_MULTILINE : 0; + const long style = m_opt.multiline ? wxTE_MULTILINE : wxTE_PROCESS_ENTER/*0*/; auto temp = new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, style); temp->SetToolTip(get_tooltip_text(text_value)); + if (style == wxTE_PROCESS_ENTER) { + temp->Bind(wxEVT_TEXT_ENTER, ([this, temp](wxEvent& e) + { +#if !defined(__WXGTK__) + e.Skip(); + temp->GetToolTip()->Enable(true); +#endif // __WXGTK__ + propagate_value(); + bEnterPressed = true; + }), temp->GetId()); + } + temp->Bind(wxEVT_SET_FOCUS, ([this](wxEvent& e) { on_set_focus(e); }), temp->GetId()); temp->Bind(wxEVT_LEFT_DOWN, ([temp](wxEvent& event) @@ -272,14 +280,15 @@ void TextCtrl::BUILD() { temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent& e) { -#if !defined(__WXGTK__) e.Skip(); +#if !defined(__WXGTK__) temp->GetToolTip()->Enable(true); #endif // __WXGTK__ - if (is_defined_input_value(window, m_opt.type)) - on_change_field(); - else - on_kill_focus(e); + if (bEnterPressed) { + bEnterPressed = false; + return; + } + propagate_value(); }), temp->GetId()); /* temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent& evt) @@ -311,6 +320,14 @@ void TextCtrl::BUILD() { window = dynamic_cast(temp); } +void TextCtrl::propagate_value() +{ + if (is_defined_input_value(window, m_opt.type)) + on_change_field(); + else + on_kill_focus(); +} + boost::any& TextCtrl::get_value() { wxString ret_str = static_cast(window)->GetValue(); @@ -398,7 +415,7 @@ void SpinCtrl::BUILD() { const int max_val = m_opt.max < 2147483647 ? m_opt.max : 2147483647; auto temp = new wxSpinCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, - 0, min_val, max_val, default_value); + 0|wxTE_PROCESS_ENTER, min_val, max_val, default_value); #ifndef __WXOSX__ // #ys_FIXME_KILL_FOCUS @@ -407,15 +424,23 @@ void SpinCtrl::BUILD() { // and on TEXT event under OSX temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { - if (tmp_value < 0) - on_kill_focus(e); - else { - e.Skip(); - on_change_field(); + e.Skip(); + if (bEnterPressed) { + bEnterPressed = false; + return; } + + propagate_value(); }), temp->GetId()); - temp->Bind(wxEVT_SPINCTRL, ([this](wxCommandEvent e) { on_change_field(); }), temp->GetId()); + temp->Bind(wxEVT_SPINCTRL, ([this](wxCommandEvent e) { on_change_field(); }), temp->GetId()); + + temp->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent e) + { + e.Skip(); + propagate_value(); + bEnterPressed = true; + }), temp->GetId()); #endif temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) @@ -430,12 +455,7 @@ void SpinCtrl::BUILD() { tmp_value = std::stoi(value); else tmp_value = -9999; #ifdef __WXOSX__ - if (tmp_value < 0) { - if (m_on_kill_focus != nullptr) - m_on_kill_focus(m_opt_id); - } - else - on_change_field(); + propagate_value(); #endif }), temp->GetId()); @@ -445,6 +465,14 @@ void SpinCtrl::BUILD() { window = dynamic_cast(temp); } +void SpinCtrl::propagate_value() +{ + if (tmp_value < 0) + on_kill_focus(); + else + on_change_field(); +} + void Choice::BUILD() { auto size = wxSize(wxDefaultSize); if (m_opt.height >= 0) size.SetHeight(m_opt.height); @@ -483,7 +511,7 @@ void Choice::BUILD() { on_change_field(); } else - on_kill_focus(e); + on_kill_focus(); }), temp->GetId()); } @@ -755,8 +783,8 @@ void PointCtrl::BUILD() val = default_pt(1); wxString Y = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None); - x_textctrl = new wxTextCtrl(m_parent, wxID_ANY, X, wxDefaultPosition, field_size); - y_textctrl = new wxTextCtrl(m_parent, wxID_ANY, Y, wxDefaultPosition, field_size); + x_textctrl = new wxTextCtrl(m_parent, wxID_ANY, X, wxDefaultPosition, field_size, wxEVT_TEXT_ENTER); + y_textctrl = new wxTextCtrl(m_parent, wxID_ANY, Y, wxDefaultPosition, field_size, wxEVT_TEXT_ENTER); temp->Add(new wxStaticText(m_parent, wxID_ANY, "x : "), 0, wxALIGN_CENTER_VERTICAL, 0); temp->Add(x_textctrl); @@ -766,8 +794,11 @@ void PointCtrl::BUILD() // x_textctrl->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), x_textctrl->GetId()); // y_textctrl->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), y_textctrl->GetId()); - x_textctrl->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { OnKillFocus(e, x_textctrl); }), x_textctrl->GetId()); - y_textctrl->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { OnKillFocus(e, x_textctrl); }), y_textctrl->GetId()); + x_textctrl->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent e) { propagate_value(x_textctrl); }), x_textctrl->GetId()); + y_textctrl->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent e) { propagate_value(y_textctrl); }), y_textctrl->GetId()); + + x_textctrl->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { e.Skip(); propagate_value(x_textctrl); }), x_textctrl->GetId()); + y_textctrl->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { e.Skip(); propagate_value(y_textctrl); }), y_textctrl->GetId()); // // recast as a wxWindow to fit the calling convention sizer = dynamic_cast(temp); @@ -776,14 +807,12 @@ void PointCtrl::BUILD() y_textctrl->SetToolTip(get_tooltip_text(X+", "+Y)); } -void PointCtrl::OnKillFocus(wxEvent& e, wxTextCtrl* win) +void PointCtrl::propagate_value(wxTextCtrl* win) { - e.Skip(); - if (!win->GetValue().empty()) { + if (!win->GetValue().empty()) on_change_field(); - } else - on_kill_focus(e); + on_kill_focus(); } void PointCtrl::set_value(const Vec2d& value, bool change_event) diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index 4a19b6103..bcc94c7ba 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -74,7 +74,7 @@ protected: /// Call the attached on_kill_focus method. //! It's important to use wxEvent instead of wxFocusEvent, //! in another case we can't unfocused control at all - void on_kill_focus(wxEvent& event); + void on_kill_focus(); /// Call the attached on_change method. void on_set_focus(wxEvent& event); /// Call the attached on_change method. @@ -226,6 +226,8 @@ protected: // current value boost::any m_value; + + bool bEnterPressed = false; friend class OptionsGroup; }; @@ -252,6 +254,8 @@ public: ~TextCtrl() {} void BUILD(); + // Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER + void propagate_value(); wxWindow* window {nullptr}; virtual void set_value(const std::string& value, bool change_event = false) { @@ -310,6 +314,8 @@ public: wxWindow* window{ nullptr }; void BUILD() override; + /// Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER + void propagate_value() ; void set_value(const std::string& value, bool change_event = false) { m_disable_change_event = !change_event; @@ -393,8 +399,8 @@ public: wxTextCtrl* y_textctrl{ nullptr }; void BUILD() override; - - void OnKillFocus(wxEvent& e, wxTextCtrl* win); + // Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER + void propagate_value(wxTextCtrl* win); void set_value(const Vec2d& value, bool change_event = false); void set_value(const boost::any& value, bool change_event = false); boost::any& get_value() override;