From b037e5f024d1c6e7dea90daf4f8e31b95117d5ae Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 5 Dec 2022 22:10:33 +0100 Subject: [PATCH 1/6] Optimization: do not regenerate toolbar texture in each frame --- src/slic3r/GUI/GLCanvas3D.cpp | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 79370022b..b7988ea7c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5653,9 +5653,9 @@ void GLCanvas3D::_check_and_update_toolbar_icon_scale() collapse_toolbar.set_scale(sc); size *= m_retina_helper->get_scale_factor(); #else - m_main_toolbar.set_icons_size(size); - m_undoredo_toolbar.set_icons_size(size); - collapse_toolbar.set_icons_size(size); + m_main_toolbar.set_icons_size(int(size)); + m_undoredo_toolbar.set_icons_size(int(size)); + collapse_toolbar.set_icons_size(int(size)); #endif // ENABLE_RETINA_GL float top_tb_width = m_main_toolbar.get_width() + m_undoredo_toolbar.get_width() + collapse_toolbar.get_width(); @@ -5687,24 +5687,12 @@ void GLCanvas3D::_render_overlays() { glsafe(::glDisable(GL_DEPTH_TEST)); + // main toolbar and undoredo toolbar need to be both updated before rendering because both their sizes are needed + // to correctly place them _check_and_update_toolbar_icon_scale(); _render_gizmos_overlay(); - // main toolbar and undoredo toolbar need to be both updated before rendering because both their sizes are needed - // to correctly place them -#if ENABLE_RETINA_GL - const float scale = m_retina_helper->get_scale_factor() * wxGetApp().toolbar_icon_scale(/*true*/); - m_main_toolbar.set_scale(scale); - m_undoredo_toolbar.set_scale(scale); - wxGetApp().plater()->get_collapse_toolbar().set_scale(scale); -#else - const float size = int(GLToolbar::Default_Icons_Size * wxGetApp().toolbar_icon_scale(/*true*/)); - m_main_toolbar.set_icons_size(size); - m_undoredo_toolbar.set_icons_size(size); - wxGetApp().plater()->get_collapse_toolbar().set_icons_size(size); -#endif // ENABLE_RETINA_GL - _render_main_toolbar(); _render_undoredo_toolbar(); _render_collapse_toolbar(); From fe3a15942bae16e7d8bf70ac66a7625c983f5963 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 7 Dec 2022 14:50:20 +0100 Subject: [PATCH 2/6] Follow-up of 6d737f7081883071a547e0c9960813342e8388e3 - Ensure icon size is a whole number wherever is used --- src/slic3r/GUI/GLCanvas3D.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index b7988ea7c..d93a76cc1 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5639,10 +5639,10 @@ void GLCanvas3D::_check_and_update_toolbar_icon_scale() if (wxGetApp().plater()->is_preview_shown()) return; - float scale = wxGetApp().toolbar_icon_scale(); - Size cnv_size = get_canvas_size(); + const float scale = wxGetApp().toolbar_icon_scale(); + const Size cnv_size = get_canvas_size(); - float size = GLToolbar::Default_Icons_Size * scale; + int size = int(GLToolbar::Default_Icons_Size * scale); // Set current size for all top toolbars. It will be used for next calculations GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar(); @@ -5651,28 +5651,28 @@ void GLCanvas3D::_check_and_update_toolbar_icon_scale() m_main_toolbar.set_scale(sc); m_undoredo_toolbar.set_scale(sc); collapse_toolbar.set_scale(sc); - size *= m_retina_helper->get_scale_factor(); + size *= int(m_retina_helper->get_scale_factor()); #else - m_main_toolbar.set_icons_size(int(size)); - m_undoredo_toolbar.set_icons_size(int(size)); - collapse_toolbar.set_icons_size(int(size)); + m_main_toolbar.set_icons_size(size); + m_undoredo_toolbar.set_icons_size(size); + collapse_toolbar.set_icons_size(size); #endif // ENABLE_RETINA_GL - float top_tb_width = m_main_toolbar.get_width() + m_undoredo_toolbar.get_width() + collapse_toolbar.get_width(); + const float top_tb_width = m_main_toolbar.get_width() + m_undoredo_toolbar.get_width() + collapse_toolbar.get_width(); int items_cnt = m_main_toolbar.get_visible_items_cnt() + m_undoredo_toolbar.get_visible_items_cnt() + collapse_toolbar.get_visible_items_cnt(); - float noitems_width = top_tb_width - size * items_cnt; // width of separators and borders in top toolbars + const float noitems_width = top_tb_width - float(size) * items_cnt; // width of separators and borders in top toolbars // calculate scale needed for items in all top toolbars // the std::max() is there because on some Linux dialects/virtual machines this code is called when the canvas has not been properly initialized yet, // leading to negative values for the scale. // See: https://github.com/prusa3d/PrusaSlicer/issues/8563 // https://github.com/supermerill/SuperSlicer/issues/854 - float new_h_scale = std::max((cnv_size.get_width() - noitems_width), 1.0f) / (items_cnt * GLToolbar::Default_Icons_Size); + const float new_h_scale = std::max((cnv_size.get_width() - noitems_width), 1.0f) / (items_cnt * GLToolbar::Default_Icons_Size); items_cnt = m_gizmos.get_selectable_icons_cnt() + 3; // +3 means a place for top and view toolbars and separators in gizmos toolbar // calculate scale needed for items in the gizmos toolbar - float new_v_scale = cnv_size.get_height() / (items_cnt * GLGizmosManager::Default_Icons_Size); + const float new_v_scale = cnv_size.get_height() / (items_cnt * GLGizmosManager::Default_Icons_Size); // set minimum scale as a auto scale for the toolbars float new_scale = std::min(new_h_scale, new_v_scale); From 85ad56b43bedf882097255e643b8ab974943f7b0 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 6 Dec 2022 12:18:05 +0100 Subject: [PATCH 3/6] Optimization: std::vector can be quite slow to access --- src/libslic3r/TriangleMesh.cpp | 2 +- src/libslic3r/TriangleMesh.hpp | 2 +- src/libslic3r/TriangleMeshSlicer.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 6e17daa56..d5fe83c26 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -622,7 +622,7 @@ std::vector its_face_edge_ids(const indexed_triangle_set &its, std::funct return its_face_edge_ids_impl(its, [](const uint32_t){ return true; }, throw_on_cancel_callback); } -std::vector its_face_edge_ids(const indexed_triangle_set &its, const std::vector &face_mask) +std::vector its_face_edge_ids(const indexed_triangle_set &its, const std::vector &face_mask) { return its_face_edge_ids_impl(its, [&face_mask](const uint32_t idx){ return face_mask[idx]; }, [](){}); } diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index d8096eae2..26701bdf5 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -188,7 +188,7 @@ private: // Used for chaining slice lines into polygons. std::vector its_face_edge_ids(const indexed_triangle_set &its); std::vector its_face_edge_ids(const indexed_triangle_set &its, std::function throw_on_cancel_callback); -std::vector its_face_edge_ids(const indexed_triangle_set &its, const std::vector &face_mask); +std::vector its_face_edge_ids(const indexed_triangle_set &its, const std::vector &face_mask); // Having the face neighbors available, assign unique edge IDs to face edges for chaining of polygons over slices. std::vector its_face_edge_ids(const indexed_triangle_set &its, std::vector &face_neighbors, bool assign_unbound_edges = false, int *num_edges = nullptr); diff --git a/src/libslic3r/TriangleMeshSlicer.cpp b/src/libslic3r/TriangleMeshSlicer.cpp index 63802961b..461d8c22e 100644 --- a/src/libslic3r/TriangleMeshSlicer.cpp +++ b/src/libslic3r/TriangleMeshSlicer.cpp @@ -1805,7 +1805,7 @@ Polygons slice_mesh( { bool trafo_identity = is_identity(params.trafo); Transform3f tf; - std::vector face_mask(mesh.indices.size(), false); + std::vector face_mask(mesh.indices.size(), 0); { // 1) Mark vertices as below or above the slicing plane. From 595ef873ad0fb3c52ce3705bc80569326c089ec3 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 7 Dec 2022 15:23:38 +0100 Subject: [PATCH 4/6] Change the way how cut gizmo detects hits on cut plane: it did not work well on meshes with overlapping surfaces --- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 73 +++++++++++++--------------- src/slic3r/GUI/Gizmos/GLGizmoCut.hpp | 2 +- src/slic3r/GUI/MeshUtils.cpp | 45 ++--------------- src/slic3r/GUI/MeshUtils.hpp | 8 +-- 4 files changed, 40 insertions(+), 88 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 29d578fba..3cd661ba3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -1144,11 +1144,11 @@ void GLGizmoCut3D::dragging_grabber_xy(const GLGizmoBase::UpdateData &data) void GLGizmoCut3D::dragging_connector(const GLGizmoBase::UpdateData &data) { CutConnectors& connectors = m_c->selection_info()->model_object()->cut_connectors; - std::pair pos_and_normal; + Vec3d pos; Vec3d pos_world; - if (unproject_on_cut_plane(data.mouse_pos.cast(), pos_and_normal, pos_world)) { - connectors[m_hover_id - m_connectors_group_id].pos = pos_and_normal.first; + if (unproject_on_cut_plane(data.mouse_pos.cast(), pos, pos_world)) { + connectors[m_hover_id - m_connectors_group_id].pos = pos; update_raycasters_for_picking_transform(); } } @@ -2006,44 +2006,41 @@ void GLGizmoCut3D::perform_cut(const Selection& selection) // Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal // Return false if no intersection was found, true otherwise. -bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, std::pair& pos_and_normal, Vec3d& pos_world) +bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, Vec3d& pos, Vec3d& pos_world) { const float sla_shift = m_c->selection_info()->get_sla_shift(); const ModelObject* mo = m_c->selection_info()->model_object(); const ModelInstance* mi = mo->instances[m_c->selection_info()->get_active_instance()]; - const Transform3d instance_trafo = sla_shift > 0.f ? - translation_transform(sla_shift * Vec3d::UnitZ()) * mi->get_transformation().get_matrix() : mi->get_transformation().get_matrix(); const Camera& camera = wxGetApp().plater()->get_camera(); - int mesh_id = -1; - for (const ModelVolume* mv : mo->volumes) { - ++mesh_id; - if (!mv->is_model_part()) - continue; - Vec3f normal; - Vec3f hit; - bool clipping_plane_was_hit = false; + // Calculate intersection with the clipping plane. + const ClippingPlane* cp = m_c->object_clipper()->get_clipping_plane(true); + Vec3d point; + Vec3d direction; + Vec3d hit; + MeshRaycaster::line_from_mouse_pos(mouse_position, Transform3d::Identity(), camera, point, direction); + Vec3d normal = -cp->get_normal().cast(); + double den = normal.dot(direction); + if (den != 0.) { + double t = (-cp->get_offset() - normal.dot(point))/den; + hit = (point + t * direction); + } else + return false; + + if (! m_c->object_clipper()->is_projection_inside_cut(hit)) + return false; -// const Transform3d volume_trafo = get_volume_transformation(mv); - const Transform3d volume_trafo = mv->get_transformation().get_matrix(); + // recalculate hit to object's local position + Vec3d hit_d = hit; + hit_d -= mi->get_offset(); + hit_d[Z] -= sla_shift; - m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh(mouse_position, instance_trafo * volume_trafo, - camera, hit, normal, m_c->object_clipper()->get_clipping_plane(true), - nullptr, &clipping_plane_was_hit); - if (clipping_plane_was_hit) { - // recalculate hit to object's local position - Vec3d hit_d = hit.cast(); - hit_d -= mi->get_offset(); - hit_d[Z] -= sla_shift; + // Return both the point and the facet normal. + pos = hit_d; + pos_world = hit; - // Return both the point and the facet normal. - pos_and_normal = std::make_pair(hit_d, normal.cast()); - pos_world = hit.cast(); - return true; - } - } - return false; + return true; } void GLGizmoCut3D::clear_selection() @@ -2139,17 +2136,13 @@ bool GLGizmoCut3D::add_connector(CutConnectors& connectors, const Vec2d& mouse_p if (!m_connectors_editing) return false; - std::pair pos_and_normal; + Vec3d pos; Vec3d pos_world; - if (unproject_on_cut_plane(mouse_position.cast(), pos_and_normal, pos_world)) { - // check if pos is out of enabled clipping plane - if (m_c->object_clipper() && !m_c->object_clipper()->is_projection_inside_cut(pos_world)) - return true; - + if (unproject_on_cut_plane(mouse_position.cast(), pos, pos_world)) { Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Add connector"), UndoRedo::SnapshotType::GizmoAction); unselect_all_connectors(); - connectors.emplace_back(pos_and_normal.first, m_rotation_m, + connectors.emplace_back(pos, m_rotation_m, m_connector_size * 0.5f, m_connector_depth_ratio, m_connector_size_tolerance, m_connector_depth_ratio_tolerance, CutConnectorAttributes( CutConnectorType(m_connector_type), @@ -2247,9 +2240,9 @@ bool GLGizmoCut3D::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_posi if (!m_connectors_editing) { if (0 && action == SLAGizmoEventType::LeftDown) { // disable / enable current contour - std::pair pos_and_normal; + Vec3d pos; Vec3d pos_world; - if (unproject_on_cut_plane(mouse_position.cast(), pos_and_normal, pos_world)) { + if (unproject_on_cut_plane(mouse_position.cast(), pos, pos_world)) { // Following would inform the clipper about the mouse click, so it can // toggle the respective contour as disabled. m_c->object_clipper()->pass_mouse_click(pos_world); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index 8a3ee6d07..e9412357d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -155,7 +155,7 @@ public: GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); std::string get_tooltip() const override; - bool unproject_on_cut_plane(const Vec2d& mouse_pos, std::pair& pos_and_normal, Vec3d& pos_world); + bool unproject_on_cut_plane(const Vec2d& mouse_pos, Vec3d& pos, Vec3d& pos_world); bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); bool is_in_editing_mode() const override { return m_connectors_editing; } diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 39e463a19..a58191528 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -365,11 +365,8 @@ void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3 bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane, - size_t* facet_idx, bool* was_clipping_plane_hit) const + size_t* facet_idx) const { - if (was_clipping_plane_hit) - *was_clipping_plane_hit = false; - Vec3d point; Vec3d direction; line_from_mouse_pos(mouse_pos, trafo, camera, point, direction); @@ -390,26 +387,9 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& break; } - if (i==hits.size()) { - // All hits are clipped. - return false; - } - if (clipping_plane && (hits.size()-i) % 2 != 0) { - // There is an odd number of unclipped hits - meaning the nearest must be from inside the mesh. - // In that case, calculate intersection with the clipping place. - if (was_clipping_plane_hit) { - direction = direction + point; - point = trafo * point; // transform to world coords - direction = trafo * direction - point; - - Vec3d normal = -clipping_plane->get_normal().cast(); - double den = normal.dot(direction); - if (den != 0.) { - double t = (-clipping_plane->get_offset() - normal.dot(point))/den; - position = (point + t * direction).cast(); - *was_clipping_plane_hit = true; - } - } + if (i==hits.size() || (hits.size()-i) % 2 != 0) { + // All hits are either clipped, or there is an odd number of unclipped + // hits - meaning the nearest must be from inside the mesh. return false; } @@ -423,24 +403,7 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& return true; } -bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, - Vec3d& position, Vec3d& normal) const -{ - Vec3d point; - Vec3d direction; - line_from_mouse_pos(mouse_pos, trafo, camera, point, direction); - std::vector hits = m_emesh.query_ray_hits(point, direction); - - if (hits.empty()) - return false; // no intersection found - - // Now stuff the points in the provided vector and calculate normals if asked about them: - position = hits[0].position(); - normal = hits[0].normal(); - - return true; -} bool MeshRaycaster::is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const { diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index 441532fdb..401ba22f1 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -153,16 +153,12 @@ public: const Vec2d& mouse_pos, const Transform3d& trafo, // how to get the mesh into world coords const Camera& camera, // current camera position - Vec3f& position, // where to save the positibon of the hit (mesh coords if mesh, world coords if clipping plane) + Vec3f& position, // where to save the positibon of the hit (mesh coords) Vec3f& normal, // normal of the triangle that was hit const ClippingPlane* clipping_plane = nullptr, // clipping plane (if active) - size_t* facet_idx = nullptr, // index of the facet hit - bool* was_clipping_plane_hit = nullptr // is the hit on the clipping place cross section? + size_t* facet_idx = nullptr // index of the facet hit ) const; - // Given a mouse position, this returns true in case it is on the mesh. - bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, Vec3d& position, Vec3d& normal) const; - bool is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const; // Given a vector of points in woorld coordinates, this returns vector From d2c8d628b96f8e3e0b4fe8ac6a9879c33521c037 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 7 Dec 2022 16:06:43 +0100 Subject: [PATCH 5/6] Fixed a bug in Cut gizmo - contour width was not updating correctly --- src/slic3r/GUI/MeshUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index a58191528..9246c4cdf 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -22,7 +22,7 @@ namespace GUI { void MeshClipper::set_behaviour(bool fill_cut, double contour_width) { - if (fill_cut != m_fill_cut || is_approx(contour_width, m_contour_width)) + if (fill_cut != m_fill_cut || ! is_approx(contour_width, m_contour_width)) m_result.reset(); m_fill_cut = fill_cut; m_contour_width = contour_width; From 71a0b626a9d15a61dbd9a87f25c28001cb631292 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 7 Dec 2022 16:52:52 +0100 Subject: [PATCH 6/6] Fixed memory leaks on switch between parameter pages --- src/slic3r/GUI/Field.cpp | 9 +++ src/slic3r/GUI/Field.hpp | 2 +- src/slic3r/GUI/OptionsGroup.cpp | 130 ++++++++++++++++---------------- src/slic3r/GUI/OptionsGroup.hpp | 1 + src/slic3r/GUI/Tab.cpp | 2 + 5 files changed, 78 insertions(+), 66 deletions(-) diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index d3fef44d3..40cd7f889 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -1416,6 +1416,15 @@ void ColourPicker::sys_color_changed() #endif } +PointCtrl::~PointCtrl() +{ + if (sizer) { + sizer->Clear(); + delete sizer; + sizer = nullptr; + } +} + void PointCtrl::BUILD() { auto temp = new wxBoxSizer(wxHORIZONTAL); diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index 60a06427d..eaa4fe481 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -425,7 +425,7 @@ class PointCtrl : public Field { public: PointCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {} PointCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} - ~PointCtrl() {} + ~PointCtrl(); wxSizer* sizer{ nullptr }; wxTextCtrl* x_textctrl{ nullptr }; diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index cfa2ef15a..0534446f0 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -118,6 +118,24 @@ OptionsGroup::OptionsGroup( wxWindow* _parent, const wxString& title, { } +void Line::clear() +{ + if (near_label_widget_win) + near_label_widget_win = nullptr; + + if (widget_sizer) { + widget_sizer->Clear(true); + delete widget_sizer; + widget_sizer = nullptr; + } + + if (extra_widget_sizer) { + extra_widget_sizer->Clear(true); + delete extra_widget_sizer; + extra_widget_sizer = nullptr; + } +} + wxWindow* OptionsGroup::ctrl_parent() const { return this->custom_ctrl && m_use_custom_ctrl_as_parent ? static_cast(this->custom_ctrl) : (this->stb ? static_cast(this->stb) : this->parent()); @@ -231,7 +249,7 @@ void OptionsGroup::activate_line(Line& line) } } - auto option_set = line.get_options(); + const std::vector