Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_gcode_viewer

This commit is contained in:
enricoturri1966 2020-05-13 12:34:50 +02:00
commit 2bd514614b
23 changed files with 476 additions and 161 deletions

View file

@ -3,3 +3,8 @@
For more information go to https://github.com/ocornut/imgui
THIS DIRECTORY CONTAINS THE imgui-1.75 58b3e02 SOURCE DISTRIBUTION.
Customized with the following commits:
042880ba2df913916b2cc77f7bb677e07bfd2c58
67c55c74901f1d337ef08f2090a87cfb4263bb0f
a94c952b40d36b1505fb77b87c0dd739e1034659

View file

@ -411,6 +411,11 @@ public:
return timestamp == other.get_timestamp();
}
template<class Archive> void serialize(Archive &ar)
{
ar(m_data);
}
private:
std::map<int, FacetSupportType> m_data;
@ -613,7 +618,8 @@ private:
}
template<class Archive> void load(Archive &ar) {
bool has_convex_hull;
ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull);
ar(name, source, m_mesh, m_type, m_material_id, m_transformation,
m_is_splittable, has_convex_hull, m_supported_facets);
cereal::load_by_value(ar, config);
assert(m_mesh);
if (has_convex_hull) {
@ -626,7 +632,8 @@ private:
}
template<class Archive> void save(Archive &ar) const {
bool has_convex_hull = m_convex_hull.get() != nullptr;
ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull);
ar(name, source, m_mesh, m_type, m_material_id, m_transformation,
m_is_splittable, has_convex_hull, m_supported_facets);
cereal::save_by_value(ar, config);
if (has_convex_hull)
cereal::save_optional(ar, m_convex_hull);

View file

@ -84,6 +84,9 @@ void AppConfig::set_defaults()
if (get("custom_toolbar_size").empty())
set("custom_toolbar_size", "100");
if (get("auto_toolbar_size").empty())
set("auto_toolbar_size", "100");
if (get("use_perspective_camera").empty())
set("use_perspective_camera", "1");

View file

@ -9,6 +9,7 @@
#include <regex>
#include <wx/numformatter.h>
#include <wx/tooltip.h>
#include <wx/notebook.h>
#include <boost/algorithm/string/predicate.hpp>
#ifdef __WXOSX__
@ -79,6 +80,29 @@ void Field::PostInitialize()
m_em_unit = em_unit(m_parent);
BUILD();
// For the mode, when settings are in non-modal dialog, neither dialog nor tabpanel doesn't receive wxEVT_KEY_UP event, when some field is selected.
// So, like a workaround check wxEVT_KEY_UP event for the Filed and switch between tabs if Ctrl+(1-4) was pressed
if (getWindow())
getWindow()->Bind(wxEVT_KEY_UP, [](wxKeyEvent& evt) {
if ((evt.GetModifiers() & wxMOD_CONTROL) != 0) {
int tab_id = -1;
switch (evt.GetKeyCode()) {
case '1': { tab_id = 0; break; }
case '2': { tab_id = 1; break; }
case '3': { tab_id = 2; break; }
case '4': { tab_id = 3; break; }
default: break;
}
if (tab_id >= 0)
wxGetApp().mainframe->select_tab(tab_id);
if (tab_id > 0)
// tab panel should be focused for correct navigation between tabs
wxGetApp().tab_panel()->SetFocus();
}
evt.Skip();
});
}
// Values of width to alignments of fields
@ -397,7 +421,7 @@ void TextCtrl::BUILD() {
bKilledFocus = false;
#endif // __WXOSX__
}), temp->GetId());
/*
// select all text using Ctrl+A
temp->Bind(wxEVT_CHAR, ([temp](wxKeyEvent& event)
{
@ -405,7 +429,7 @@ void TextCtrl::BUILD() {
temp->SetSelection(-1, -1); //select all
event.Skip();
}));
*/
// recast as a wxWindow to fit the calling convention
window = dynamic_cast<wxWindow*>(temp);
}

View file

@ -1438,7 +1438,7 @@ void GLCanvas3D::Tooltip::render(const Vec2d& mouse_position, GLCanvas3D& canvas
#if ENABLE_SLOPE_RENDERING
void GLCanvas3D::Slope::render() const
{
if (is_shown())
if (m_dialog_shown)
{
const std::array<float, 2>& z_range = m_volumes.get_slope_z_range();
std::array<float, 2> angle_range = { Geometry::rad2deg(::acos(z_range[0])) - 90.0f, Geometry::rad2deg(::acos(z_range[1])) - 90.0f };
@ -1449,29 +1449,41 @@ void GLCanvas3D::Slope::render() const
imgui.set_next_window_pos((float)cnv_size.get_width(), (float)cnv_size.get_height(), ImGuiCond_Always, 1.0f, 1.0f);
imgui.begin(_(L("Slope visualization")), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
imgui.text(_(L("Facets' normal angle range (degrees)")) + ":");
imgui.text(_(L("Facets' slope range (degrees)")) + ":");
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.75f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 1.0f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.85f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.25f, 0.0f, 1.0f));
if (ImGui::SliderFloat("##yellow", &angle_range[0], 0.0f, 90.0f, "%.1f"))
{
modified = true;
if (angle_range[1] < angle_range[0])
angle_range[1] = angle_range[0];
}
ImGui::PopStyleColor(4);
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.0f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 0.0f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.0f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.0f, 0.0f, 1.0f));
if (ImGui::SliderFloat("##red", &angle_range[1], 0.0f, 90.0f, "%.1f"))
// angle_range is range of normal angle, GUI should
// show facet slope angle
float slope_bound = 90.f - angle_range[1];
bool mod = ImGui::SliderFloat("##red", &slope_bound, 0.0f, 90.0f, "%.1f");
angle_range[1] = 90.f - slope_bound;
if (mod)
{
modified = true;
if (angle_range[0] > angle_range[1])
angle_range[0] = angle_range[1];
}
ImGui::PopStyleColor(4);
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.75f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 1.0f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.85f, 0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.25f, 0.0f, 1.0f));
slope_bound = 90.f - angle_range[0];
mod = ImGui::SliderFloat("##yellow", &slope_bound, 0.0f, 90.0f, "%.1f");
angle_range[0] = 90.f - slope_bound;
if (mod)
{
modified = true;
if (angle_range[1] < angle_range[0])
angle_range[1] = angle_range[0];
}
ImGui::PopStyleColor(4);
ImGui::Separator();
@ -1486,7 +1498,7 @@ void GLCanvas3D::Slope::render() const
imgui.end();
if (modified)
m_volumes.set_slope_z_range({ -::cos(Geometry::deg2rad(90.0f - angle_range[0])), -::cos(Geometry::deg2rad(90.0f - angle_range[1])) });
set_range(angle_range);
}
}
#endif // ENABLE_SLOPE_RENDERING
@ -1868,8 +1880,8 @@ bool GLCanvas3D::is_reload_delayed() const
void GLCanvas3D::enable_layers_editing(bool enable)
{
#if ENABLE_SLOPE_RENDERING
if (enable && m_slope.is_shown())
m_slope.show(false);
if (enable && m_slope.is_dialog_shown())
m_slope.show_dialog(false);
#endif // ENABLE_SLOPE_RENDERING
m_layers_editing.set_enabled(enable);
@ -3098,7 +3110,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
case 'd': {
if (!is_layers_editing_enabled())
{
m_slope.show(!m_slope.is_shown());
m_slope.show_dialog(!m_slope.is_dialog_shown());
m_dirty = true;
}
break;
@ -3697,7 +3709,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
else if (evt.LeftDown() && (evt.ShiftDown() || evt.AltDown()) && m_picking_enabled)
{
if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)
if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports
&& m_gizmos.get_current_type() != GLGizmosManager::FdmSupports)
{
m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect);
m_dirty = true;
@ -4492,7 +4505,7 @@ bool GLCanvas3D::_render_search_list(float pos_x) const
bool action_taken = false;
ImGuiWrapper* imgui = wxGetApp().imgui();
const float x = pos_x * (float)wxGetApp().plater()->get_camera().get_zoom() + 0.5f * (float)get_canvas_size().get_width();
const float x = /*pos_x * (float)wxGetApp().plater()->get_camera().get_zoom() + */0.5f * (float)get_canvas_size().get_width();
imgui->set_next_window_pos(x, m_main_toolbar.get_height(), ImGuiCond_Always, 0.5f, 0.0f);
std::string title = L("Search");
imgui->begin(_(title), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
@ -5630,6 +5643,44 @@ void GLCanvas3D::_render_selection_center() const
}
#endif // ENABLE_RENDER_SELECTION_CENTER
void GLCanvas3D::_check_and_update_toolbar_icon_scale() const
{
float scale = wxGetApp().toolbar_icon_scale();
Size cnv_size = get_canvas_size();
float size = GLToolbar::Default_Icons_Size * scale;
// Set current size for all top toolbars. It will be used for next calculations
#if ENABLE_RETINA_GL
const float sc = m_retina_helper->get_scale_factor() * scale;
m_main_toolbar.set_scale(sc);
m_undoredo_toolbar.set_scale(sc);
m_collapse_toolbar.set_scale(sc);
#else
m_main_toolbar.set_icons_size(size);
m_undoredo_toolbar.set_icons_size(size);
m_collapse_toolbar.set_icons_size(size);
#endif // ENABLE_RETINA_GL
float top_tb_width = m_main_toolbar.get_width() + m_undoredo_toolbar.get_width() + m_collapse_toolbar.get_width();
int items_cnt = m_main_toolbar.get_visible_items_cnt() + m_undoredo_toolbar.get_visible_items_cnt() + m_collapse_toolbar.get_visible_items_cnt();
float noitems_width = top_tb_width - size * items_cnt; // width of separators and borders in top toolbars
// calculate scale needed for items in all top toolbars
float new_h_scale = (cnv_size.get_width() - noitems_width) / (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);
// set minimum scale as a auto scale for the toolbars
float new_scale = std::min(new_h_scale, new_v_scale);
if (fabs(new_scale - scale) > EPSILON)
wxGetApp().set_auto_toolbar_icon_scale(new_scale);
}
void GLCanvas3D::_render_overlays() const
{
glsafe(::glDisable(GL_DEPTH_TEST));
@ -5642,6 +5693,8 @@ void GLCanvas3D::_render_overlays() const
double gui_scale = camera.get_gui_scale();
glsafe(::glScaled(gui_scale, gui_scale, 1.0));
_check_and_update_toolbar_icon_scale();
_render_gizmos_overlay();
_render_warning_texture();
#if !ENABLE_GCODE_VIEWER
@ -5651,12 +5704,12 @@ void GLCanvas3D::_render_overlays() const
// 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);
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);
m_collapse_toolbar.set_scale(scale);
#else
const float size = int(GLToolbar::Default_Icons_Size * wxGetApp().toolbar_icon_scale(true));
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);
m_collapse_toolbar.set_icons_size(size);
@ -5765,7 +5818,8 @@ void GLCanvas3D::_render_main_toolbar() const
float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
float top = 0.5f * (float)cnv_size.get_height() * inv_zoom;
float left = -0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width()) * inv_zoom;
float collapse_toolbar_width = m_collapse_toolbar.is_enabled() ? m_collapse_toolbar.get_width() : 0.0f;
float left = -0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width() + collapse_toolbar_width) * inv_zoom;
m_main_toolbar.set_position(top, left);
m_main_toolbar.render(*this);
@ -5780,7 +5834,8 @@ void GLCanvas3D::_render_undoredo_toolbar() const
float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
float top = 0.5f * (float)cnv_size.get_height() * inv_zoom;
float left = (m_main_toolbar.get_width() - 0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width())) * inv_zoom;
float collapse_toolbar_width = m_collapse_toolbar.is_enabled() ? m_collapse_toolbar.get_width() : 0.0f;
float left = (m_main_toolbar.get_width() - 0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width() + collapse_toolbar_width)) * inv_zoom;
m_undoredo_toolbar.set_position(top, left);
m_undoredo_toolbar.render(*this);
}
@ -7338,9 +7393,14 @@ bool GLCanvas3D::_deactivate_undo_redo_toolbar_items()
return false;
}
bool GLCanvas3D::is_search_pressed() const
{
return m_main_toolbar.is_item_pressed("search");
}
bool GLCanvas3D::_deactivate_search_toolbar_item()
{
if (m_main_toolbar.is_item_pressed("search"))
if (is_search_pressed())
{
m_main_toolbar.force_left_action(m_main_toolbar.get_item_id("search"), *this);
return true;

View file

@ -415,6 +415,7 @@ private:
class Slope
{
bool m_enabled{ false };
bool m_dialog_shown{ false };
GLCanvas3D& m_canvas;
GLVolumeCollection& m_volumes;
@ -423,9 +424,14 @@ private:
void enable(bool enable) { m_enabled = enable; }
bool is_enabled() const { return m_enabled; }
void show(bool show) { m_volumes.set_slope_active(m_enabled ? show : false); }
bool is_shown() const { return m_volumes.is_slope_active(); }
void use(bool use) { m_volumes.set_slope_active(m_enabled ? use : false); }
bool is_used() const { return m_volumes.is_slope_active(); }
void show_dialog(bool show) { if (show && is_used()) return; use(show); m_dialog_shown = show; }
bool is_dialog_shown() const { return m_dialog_shown; }
void render() const;
void set_range(const std::array<float, 2>& range) const {
m_volumes.set_slope_z_range({ -::cos(Geometry::deg2rad(90.0f - range[0])), -::cos(Geometry::deg2rad(90.0f - range[1])) });
}
};
#endif // ENABLE_SLOPE_RENDERING
@ -586,6 +592,7 @@ public:
bool is_layers_editing_enabled() const;
bool is_layers_editing_allowed() const;
bool is_search_pressed() const;
void reset_layer_height_profile();
void adaptive_layer_height_profile(float quality_factor);
@ -753,8 +760,10 @@ public:
void show_labels(bool show) { m_labels.show(show); }
#if ENABLE_SLOPE_RENDERING
bool is_slope_shown() const { return m_slope.is_shown(); }
void show_slope(bool show) { m_slope.show(show); }
bool is_slope_shown() const { return m_slope.is_dialog_shown(); }
void use_slope(bool use) { m_slope.use(use); }
void show_slope(bool show) { m_slope.show_dialog(show); }
void set_slope_range(const std::array<float, 2>& range) { m_slope.set_range(range); }
#endif // ENABLE_SLOPE_RENDERING
private:
@ -788,6 +797,7 @@ private:
#if ENABLE_RENDER_SELECTION_CENTER
void _render_selection_center() const;
#endif // ENABLE_RENDER_SELECTION_CENTER
void _check_and_update_toolbar_icon_scale() const;
void _render_overlays() const;
void _render_warning_texture() const;
#if !ENABLE_GCODE_VIEWER

View file

@ -532,7 +532,12 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
m_mouse_capture.left = true;
m_mouse_capture.parent = &parent;
processed = true;
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if ((item_id != -2) && !m_items[item_id]->is_separator() && !m_items[item_id]->is_disabled() &&
((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Left)))
#else
if ((item_id != -2) && !m_items[item_id]->is_separator() && ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Left)))
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
{
// mouse is inside an icon
do_action(GLToolbarItem::Left, item_id, parent, true);
@ -549,7 +554,12 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
m_mouse_capture.right = true;
m_mouse_capture.parent = &parent;
processed = true;
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if ((item_id != -2) && !m_items[item_id]->is_separator() && !m_items[item_id]->is_disabled() &&
((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Right)))
#else
if ((item_id != -2) && !m_items[item_id]->is_separator() && ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Right)))
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
{
// mouse is inside an icon
do_action(GLToolbarItem::Right, item_id, parent, true);
@ -627,6 +637,16 @@ float GLToolbar::get_main_size() const
return size * m_layout.scale;
}
int GLToolbar::get_visible_items_cnt() const
{
int cnt = 0;
for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i)
if (m_items[i]->is_visible() && !m_items[i]->is_separator())
cnt++;
return cnt;
}
void GLToolbar::do_action(GLToolbarItem::EActionType type, int item_id, GLCanvas3D& parent, bool check_hover)
{
if ((m_pressed_toggable_id == -1) || (m_pressed_toggable_id == item_id))
@ -634,7 +654,11 @@ void GLToolbar::do_action(GLToolbarItem::EActionType type, int item_id, GLCanvas
if ((0 <= item_id) && (item_id < (int)m_items.size()))
{
GLToolbarItem* item = m_items[item_id];
#if ENABLE_CANVAS_TOOLTIP_USING_IMGUI
if ((item != nullptr) && !item->is_separator() && !item->is_disabled() && (!check_hover || item->is_hovered()))
#else
if ((item != nullptr) && !item->is_separator() && (!check_hover || item->is_hovered()))
#endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI
{
if (((type == GLToolbarItem::Right) && item->is_right_toggable()) ||
((type == GLToolbarItem::Left) && item->is_left_toggable()))

View file

@ -319,6 +319,7 @@ public:
void get_additional_tooltip(int item_id, std::string& text);
void set_additional_tooltip(int item_id, const std::string& text);
void set_tooltip(int item_id, const std::string& text);
int get_visible_items_cnt() const;
// returns true if any item changed its state
bool update_items_state();

View file

@ -580,17 +580,35 @@ float GUI_App::toolbar_icon_scale(const bool is_limited/* = false*/) const
const std::string& use_val = app_config->get("use_custom_toolbar_size");
const std::string& val = app_config->get("custom_toolbar_size");
const std::string& auto_val = app_config->get("auto_toolbar_size");
if (val.empty() || use_val.empty() || use_val == "0")
if (val.empty() || auto_val.empty() || use_val.empty())
return icon_sc;
int int_val = atoi(val.c_str());
int int_val = use_val == "0" ? 100 : atoi(val.c_str());
// correct value in respect to auto_toolbar_size
int_val = std::min(atoi(auto_val.c_str()), int_val);
if (is_limited && int_val < 50)
int_val = 50;
return 0.01f * int_val * icon_sc;
}
void GUI_App::set_auto_toolbar_icon_scale(float scale) const
{
#ifdef __APPLE__
const float icon_sc = 1.0f; // for Retina display will be used its own scale
#else
const float icon_sc = m_em_unit * 0.1f;
#endif // __APPLE__
int int_val = std::min(int(scale / icon_sc * 100), 100);
std::string val = std::to_string(int_val);
app_config->set("auto_toolbar_size", val);
}
void GUI_App::recreate_GUI(const wxString& msg_name)
{
mainframe->shutdown();

View file

@ -135,6 +135,7 @@ public:
const wxFont& normal_font() { return m_normal_font; }
int em_unit() const { return m_em_unit; }
float toolbar_icon_scale(const bool is_limited = false) const;
void set_auto_toolbar_icon_scale(float scale) const;
void recreate_GUI(const wxString& message);
void system_info();

View file

@ -2771,6 +2771,7 @@ void ObjectList::delete_all_objects_from_list()
void ObjectList::increase_object_instances(const size_t obj_idx, const size_t num)
{
select_item(m_objects_model->AddInstanceChild(m_objects_model->GetItemById(obj_idx), num));
selection_changed();
}
void ObjectList::decrease_object_instances(const size_t obj_idx, const size_t num)

View file

@ -58,10 +58,10 @@ void GLGizmoFdmSupports::set_fdm_support_data(ModelObject* model_object, const S
return;
if (mo && selection.is_from_single_instance()
&& (mo != m_old_mo || mo->volumes.size() != m_old_volumes_size))
&& (mo->id() != m_old_mo_id || mo->volumes.size() != m_old_volumes_size))
{
update_mesh();
m_old_mo = mo;
update_from_model_object();
m_old_mo_id = mo->id();
m_old_volumes_size = mo->volumes.size();
}
}
@ -84,12 +84,29 @@ void GLGizmoFdmSupports::on_render() const
void GLGizmoFdmSupports::render_triangles(const Selection& selection) const
{
if (m_setting_angle)
return;
const ModelObject* mo = m_c->selection_info()->model_object();
glsafe(::glEnable(GL_POLYGON_OFFSET_FILL));
ScopeGuard offset_fill_guard([]() { glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); } );
glsafe(::glPolygonOffset(-1.0, 1.0));
// Take care of the clipping plane. The normal of the clipping plane is
// saved with opposite sign than we need to pass to OpenGL (FIXME)
bool clipping_plane_active = m_c->object_clipper()->get_position() != 0.;
if (clipping_plane_active) {
const ClippingPlane* clp = m_c->object_clipper()->get_clipping_plane();
double clp_data[4];
memcpy(clp_data, clp->get_data(), 4 * sizeof(double));
for (int i=0; i<3; ++i)
clp_data[i] = -1. * clp_data[i];
glsafe(::glClipPlane(GL_CLIP_PLANE0, (GLdouble*)clp_data));
glsafe(::glEnable(GL_CLIP_PLANE0));
}
int mesh_id = -1;
for (const ModelVolume* mv : mo->volumes) {
if (! mv->is_model_part())
@ -113,6 +130,8 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const
}
glsafe(::glPopMatrix());
}
if (clipping_plane_active)
glsafe(::glDisable(GL_CLIP_PLANE0));
}
@ -161,14 +180,21 @@ void GLGizmoFdmSupports::render_cursor_circle() const
}
void GLGizmoFdmSupports::on_render_for_picking() const
void GLGizmoFdmSupports::update_model_object() const
{
ModelObject* mo = m_c->selection_info()->model_object();
int idx = -1;
for (ModelVolume* mv : mo->volumes) {
++idx;
if (! mv->is_model_part())
continue;
for (int i=0; i<int(m_selected_facets[idx].size()); ++i)
mv->m_supported_facets.set_facet(i, m_selected_facets[idx][i]);
}
}
void GLGizmoFdmSupports::update_mesh()
void GLGizmoFdmSupports::update_from_model_object()
{
wxBusyCursor wait;
@ -177,7 +203,6 @@ void GLGizmoFdmSupports::update_mesh()
for (const ModelVolume* mv : mo->volumes)
if (mv->is_model_part())
++num_of_volumes;
m_selected_facets.resize(num_of_volumes);
m_neighbors.resize(num_of_volumes);
m_ivas.clear();
@ -218,6 +243,21 @@ void GLGizmoFdmSupports::update_mesh()
bool GLGizmoFdmSupports::is_mesh_point_clipped(const Vec3d& point) const
{
if (m_c->object_clipper()->get_position() == 0.)
return false;
auto sel_info = m_c->selection_info();
int active_inst = m_c->selection_info()->get_active_instance();
const ModelInstance* mi = sel_info->model_object()->instances[active_inst];
const Transform3d& trafo = mi->get_transformation().get_matrix();
Vec3d transformed_point = trafo * point;
transformed_point(2) += sel_info->get_sla_shift();
return m_c->object_clipper()->get_clipping_plane()->is_point_clipped(transformed_point);
}
bool operator<(const GLGizmoFdmSupports::NeighborData& a, const GLGizmoFdmSupports::NeighborData& b) {
return a.first < b.first;
@ -310,6 +350,12 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
m_clipping_plane.get(),
&facet))
{
// In case this hit is clipped, skip it.
if (is_mesh_point_clipped(hit.cast<double>())) {
some_mesh_was_hit = true;
continue;
}
// Is this hit the closest to the camera so far?
double hit_squared_distance = (camera.get_position()-trafo_matrices[mesh_id]*hit.cast<double>()).squaredNorm();
if (hit_squared_distance < closest_hit_squared_distance) {
@ -430,19 +476,16 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::RightUp)
&& m_button_down != Button::None) {
// Take snapshot and update ModelVolume data.
wxString action_name = shift_down
? _L("Remove selection")
: (m_button_down == Button::Left
? _L("Add supports")
: _L("Block supports"));
Plater::TakeSnapshot(wxGetApp().plater(), action_name);
update_model_object();
m_button_down = Button::None;
// Synchronize gizmo with ModelVolume data.
ModelObject* mo = m_c->selection_info()->model_object();
int idx = -1;
for (ModelVolume* mv : mo->volumes) {
++idx;
if (! mv->is_model_part())
continue;
for (int i=0; i<int(m_selected_facets[idx].size()); ++i)
mv->m_supported_facets.set_facet(i, m_selected_facets[idx][i]);
}
return true;
}
@ -481,6 +524,46 @@ void GLGizmoFdmSupports::update_vertex_buffers(const ModelVolume* mv,
}
void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool overwrite, bool block)
{
float threshold = (M_PI/180.)*threshold_deg;
const Selection& selection = m_parent.get_selection();
const ModelObject* mo = m_c->selection_info()->model_object();
const ModelInstance* mi = mo->instances[selection.get_instance_idx()];
int mesh_id = -1;
for (const ModelVolume* mv : mo->volumes) {
if (! mv->is_model_part())
continue;
++mesh_id;
const Transform3d trafo_matrix = mi->get_matrix(true) * mv->get_matrix(true);
Vec3f down = (trafo_matrix.inverse() * (-Vec3d::UnitZ())).cast<float>().normalized();
Vec3f limit = (trafo_matrix.inverse() * Vec3d(std::sin(threshold), 0, -std::cos(threshold))).cast<float>().normalized();
float dot_limit = limit.dot(down);
// Now calculate dot product of vert_direction and facets' normals.
int idx = -1;
for (const stl_facet& facet : mv->mesh().stl.facet_start) {
++idx;
if (facet.normal.dot(down) > dot_limit && (overwrite || m_selected_facets[mesh_id][idx] == FacetSupportType::NONE))
m_selected_facets[mesh_id][idx] = block
? FacetSupportType::BLOCKER
: FacetSupportType::ENFORCER;
}
update_vertex_buffers(mv, mesh_id, true, true);
}
Plater::TakeSnapshot(wxGetApp().plater(), block ? _L("Block supports by angle")
: _L("Add supports by angle"));
update_model_object();
m_parent.set_as_dirty();
m_setting_angle = false;
}
void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit)
{
if (! m_c->selection_info()->model_object())
@ -489,96 +572,131 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
const float approx_height = m_imgui->scaled(18.0f);
y = std::min(y, bottom_limit - approx_height);
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f);
const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f);
const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f);
const float minimal_slider_width = m_imgui->scaled(4.f);
if (! m_setting_angle) {
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
float caption_max = 0.f;
float total_text_max = 0.;
for (const std::string& t : {"enforce", "block", "remove"}) {
caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t+"_caption")).x);
total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x);
}
caption_max += m_imgui->scaled(1.f);
total_text_max += m_imgui->scaled(1.f);
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f);
const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f);
const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f);
const float minimal_slider_width = m_imgui->scaled(4.f);
float window_width = minimal_slider_width + std::max(cursor_slider_left, clipping_slider_left);
window_width = std::max(window_width, total_text_max);
window_width = std::max(window_width, button_width);
float caption_max = 0.f;
float total_text_max = 0.;
for (const std::string& t : {"enforce", "block", "remove"}) {
caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t+"_caption")).x);
total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x);
}
caption_max += m_imgui->scaled(1.f);
total_text_max += m_imgui->scaled(1.f);
auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) {
static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f);
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
m_imgui->text(caption);
ImGui::PopStyleColor();
ImGui::SameLine(caption_max);
m_imgui->text(text);
};
float window_width = minimal_slider_width + std::max(cursor_slider_left, clipping_slider_left);
window_width = std::max(window_width, total_text_max);
window_width = std::max(window_width, button_width);
for (const std::string& t : {"enforce", "block", "remove"})
draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t));
auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) {
static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f);
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
m_imgui->text(caption);
ImGui::PopStyleColor();
ImGui::SameLine(caption_max);
m_imgui->text(text);
};
m_imgui->text("");
for (const std::string& t : {"enforce", "block", "remove"})
draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t));
if (m_imgui->button(m_desc.at("remove_all"))) {
ModelObject* mo = m_c->selection_info()->model_object();
int idx = -1;
for (ModelVolume* mv : mo->volumes) {
++idx;
if (mv->is_model_part()) {
m_selected_facets[idx].assign(m_selected_facets[idx].size(), FacetSupportType::NONE);
mv->m_supported_facets.clear();
update_vertex_buffers(mv, idx, true, true);
m_parent.set_as_dirty();
m_imgui->text("");
if (m_imgui->button("Autoset by angle...")) {
m_setting_angle = true;
}
ImGui::SameLine();
if (m_imgui->button(m_desc.at("remove_all"))) {
ModelObject* mo = m_c->selection_info()->model_object();
int idx = -1;
for (ModelVolume* mv : mo->volumes) {
++idx;
if (mv->is_model_part()) {
m_selected_facets[idx].assign(m_selected_facets[idx].size(), FacetSupportType::NONE);
mv->m_supported_facets.clear();
update_vertex_buffers(mv, idx, true, true);
m_parent.set_as_dirty();
}
}
}
}
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
m_imgui->text(m_desc.at("cursor_size"));
ImGui::SameLine(clipping_slider_left);
ImGui::PushItemWidth(window_width - clipping_slider_left);
ImGui::SliderFloat(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Alt + Mouse wheel").ToUTF8().data());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
m_imgui->text(m_desc.at("cursor_size"));
ImGui::SameLine(clipping_slider_left);
ImGui::PushItemWidth(window_width - clipping_slider_left);
ImGui::SliderFloat(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Alt + Mouse wheel").ToUTF8().data());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
ImGui::Separator();
if (m_c->object_clipper()->get_position() == 0.f)
m_imgui->text(m_desc.at("clipping_of_view"));
else {
if (m_imgui->button(m_desc.at("reset_direction"))) {
wxGetApp().CallAfter([this](){
m_c->object_clipper()->set_position(-1., false);
});
ImGui::Separator();
if (m_c->object_clipper()->get_position() == 0.f)
m_imgui->text(m_desc.at("clipping_of_view"));
else {
if (m_imgui->button(m_desc.at("reset_direction"))) {
wxGetApp().CallAfter([this](){
m_c->object_clipper()->set_position(-1., false);
});
}
}
ImGui::SameLine(clipping_slider_left);
ImGui::PushItemWidth(window_width - clipping_slider_left);
float clp_dist = m_c->object_clipper()->get_position();
if (ImGui::SliderFloat(" ", &clp_dist, 0.f, 1.f, "%.2f"))
m_c->object_clipper()->set_position(clp_dist, true);
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Ctrl + Mouse wheel").ToUTF8().data());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
m_imgui->end();
if (m_setting_angle) {
m_parent.show_slope(false);
m_parent.set_slope_range({90.f - m_angle_threshold_deg, 90.f - m_angle_threshold_deg});
m_parent.use_slope(true);
m_parent.set_as_dirty();
}
}
ImGui::SameLine(clipping_slider_left);
ImGui::PushItemWidth(window_width - clipping_slider_left);
float clp_dist = m_c->object_clipper()->get_position();
if (ImGui::SliderFloat(" ", &clp_dist, 0.f, 1.f, "%.2f"))
m_c->object_clipper()->set_position(clp_dist, true);
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Ctrl + Mouse wheel").ToUTF8().data());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
else {
std::string name = "Autoset custom supports";
m_imgui->begin(wxString(name), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
m_imgui->text("Threshold:");
ImGui::SameLine();
if (m_imgui->slider_float("", &m_angle_threshold_deg, 0.f, 90.f, "%.f"))
m_parent.set_slope_range({90.f - m_angle_threshold_deg, 90.f - m_angle_threshold_deg});
m_imgui->checkbox(wxString("Overwrite already selected facets"), m_overwrite_selected);
if (m_imgui->button("Enforce"))
select_facets_by_angle(m_angle_threshold_deg, m_overwrite_selected, false);
ImGui::SameLine();
if (m_imgui->button("Block"))
select_facets_by_angle(m_angle_threshold_deg, m_overwrite_selected, true);
ImGui::SameLine();
if (m_imgui->button("Cancel"))
m_setting_angle = false;
m_imgui->end();
if (! m_setting_angle) {
m_parent.use_slope(false);
m_parent.set_as_dirty();
}
}
m_imgui->end();
}
bool GLGizmoFdmSupports::on_is_activable() const
@ -627,12 +745,24 @@ void GLGizmoFdmSupports::on_set_state()
return;
if (m_state == On && m_old_state != On) { // the gizmo was just turned on
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned on")));
{
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned on")));
}
if (! m_parent.get_gizmos_manager().is_serializing()) {
wxGetApp().CallAfter([]() {
wxGetApp().plater()->enter_gizmos_stack();
});
}
}
if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off
// we are actually shutting down
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned off")));
m_old_mo = nullptr;
m_setting_angle = false;
m_parent.use_slope(false);
wxGetApp().plater()->leave_gizmos_stack();
{
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned off")));
}
m_old_mo_id = -1;
m_ivas.clear();
m_neighbors.clear();
m_selected_facets.clear();
@ -657,7 +787,7 @@ void GLGizmoFdmSupports::on_stop_dragging()
void GLGizmoFdmSupports::on_load(cereal::BinaryInputArchive& ar)
{
update_from_model_object();
}

View file

@ -19,7 +19,7 @@ enum class SLAGizmoEventType : unsigned char;
class GLGizmoFdmSupports : public GLGizmoBase
{
private:
const ModelObject* m_old_mo = nullptr;
ObjectID m_old_mo_id;
size_t m_old_volumes_size = 0;
GLUquadricObj* m_quadric;
@ -53,14 +53,23 @@ public:
private:
bool on_init() override;
void on_render() const override;
void on_render_for_picking() const override;
void on_render_for_picking() const override {}
void render_triangles(const Selection& selection) const;
void render_cursor_circle() const;
void update_mesh();
void update_model_object() const;
void update_from_model_object();
void select_facets_by_angle(float threshold, bool overwrite, bool block);
bool m_overwrite_selected = false;
float m_angle_threshold_deg = 45.f;
bool is_mesh_point_clipped(const Vec3d& point) const;
float m_clipping_plane_distance = 0.f;
std::unique_ptr<ClippingPlane> m_clipping_plane;
bool m_setting_angle = false;
// This map holds all translated description texts, so they can be easily referenced during layout calculations
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.

View file

@ -58,7 +58,10 @@ void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&)
const ModelObject* mo = m_c->selection_info()->model_object();
if (mo) {
reload_cache();
if (m_old_mo_id != mo->id()) {
reload_cache();
m_old_mo_id = mo->id();
}
if (m_c->hollowed_mesh() && m_c->hollowed_mesh()->get_hollowed_mesh())
m_holes_in_drilled_mesh = mo->sla_drain_holes;
}

View file

@ -43,6 +43,8 @@ private:
void hollow_mesh(bool postpone_error_messages = false);
bool unsaved_changes() const;
ObjectID m_old_mo_id = -1;
// bool m_show_supports = true;
float m_new_hole_radius = 2.f; // Size of a new hole.
float m_new_hole_height = 6.f;

View file

@ -66,11 +66,10 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S
ModelObject* mo = m_c->selection_info()->model_object();
if (mo != m_old_mo) {
if (mo && mo->id() != m_old_mo_id) {
disable_editing_mode();
if (mo)
reload_cache();
m_old_mo = mo;
reload_cache();
m_old_mo_id = mo->id();
}
// If we triggered autogeneration before, check backend and fetch results if they are there

View file

@ -83,7 +83,7 @@ private:
float m_density_stash = 0.f; // and again
mutable std::vector<CacheEntry> m_editing_cache; // a support point and whether it is currently selected
std::vector<sla::SupportPoint> m_normal_cache; // to restore after discarding changes or undo/redo
const ModelObject* m_old_mo = nullptr;
ObjectID m_old_mo_id;
// This map holds all translated description texts, so they can be easily referenced during layout calculations
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.

View file

@ -369,15 +369,6 @@ void GLGizmosManager::set_sla_support_data(ModelObject* model_object)
|| wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
return;
/*m_common_gizmos_data->update_from_backend(m_parent, model_object);
auto* gizmo_supports = dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get());
// note: sla support gizmo takes care of updating the common data.
// following lines are thus dependent
//gizmo_supports->set_sla_support_data(model_object, m_parent.get_selection());
*/
auto* gizmo_hollow = dynamic_cast<GLGizmoHollow*>(m_gizmos[Hollow].get());
auto* gizmo_supports = dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get());
gizmo_hollow->set_sla_support_data(model_object, m_parent.get_selection());

View file

@ -139,6 +139,11 @@ public:
EType new_current = m_current;
m_current = old_current;
// Update common data. They should be updated when activate_gizmo is
// called, so it can be used in on_set_state which is called from there.
if (new_current != Undefined)
m_common_gizmos_data->update(m_gizmos[new_current]->get_requirements());
// activate_gizmo call sets m_current and calls set_state for the gizmo
// it does nothing in case the gizmo is already activated
// it can safely be called for Undefined gizmo
@ -167,6 +172,7 @@ public:
void refresh_on_off_state();
void reset_all_states();
bool is_serializing() const { return m_serializing; }
void set_hover_id(int id);
void enable_grabber(EType type, unsigned int id, bool enable);
@ -220,6 +226,8 @@ public:
void update_after_undo_redo(const UndoRedo::Snapshot& snapshot);
int get_selectable_icons_cnt() const { return get_selectable_idxs().size(); }
private:
void render_background(float left, float top, float right, float bottom, float border) const;
void do_render_overlay() const;

View file

@ -7,7 +7,7 @@
#include <wx/menu.h>
#include <wx/progdlg.h>
#include <wx/tooltip.h>
#include <wx/glcanvas.h>
//#include <wx/glcanvas.h>
#include <wx/debug.h>
#include <boost/algorithm/string/predicate.hpp>
@ -28,6 +28,7 @@
#include "RemovableDriveManager.hpp"
#include "InstanceCheck.hpp"
#include "I18N.hpp"
#include "GLCanvas3D.hpp"
#include <fstream>
#include "GUI_App.hpp"
@ -1263,6 +1264,9 @@ void MainFrame::select_tab(size_t tab/* = size_t(-1)*/)
if (tab==0) {
if (m_settings_dialog->IsShown())
this->SetFocus();
// plater should be focused for correct navigation inside search window
if (m_plater->canvas3D()->is_search_pressed())
m_plater->SetFocus();
return;
}
// Show/Activate Settings Dialog
@ -1278,6 +1282,10 @@ void MainFrame::select_tab(size_t tab/* = size_t(-1)*/)
else if (m_layout == slNew) {
m_plater->Show(tab == 0);
m_tabpanel->Show(tab != 0);
// plater should be focused for correct navigation inside search window
if (tab == 0 && m_plater->canvas3D()->is_search_pressed())
m_plater->SetFocus();
Layout();
}

View file

@ -4474,8 +4474,6 @@ void Plater::increase_instances(size_t num)
// p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec));
}
sidebar().obj_list()->increase_object_instances(obj_idx, was_one_instance ? num + 1 : num);
if (p->get_config("autocenter") == "1")
arrange();
@ -4483,8 +4481,9 @@ void Plater::increase_instances(size_t num)
p->get_selection().add_instance(obj_idx, (int)model_object->instances.size() - 1);
p->selection_changed();
sidebar().obj_list()->increase_object_instances(obj_idx, was_one_instance ? num + 1 : num);
p->selection_changed();
this->p->schedule_background_process();
}
@ -5389,6 +5388,9 @@ void Plater::paste_from_clipboard()
void Plater::search(bool plater_is_active)
{
if (plater_is_active) {
// plater should be focused for correct navigation inside search window
this->SetFocus();
wxKeyEvent evt;
#ifdef __APPLE__
evt.m_keyCode = 'f';

View file

@ -190,9 +190,17 @@ void PreferencesDialog::accept()
auto app_config = get_app_config();
m_settings_layout_changed = m_values.find("old_settings_layout_mode") != m_values.end() ||
m_values.find("new_settings_layout_mode") != m_values.end() ||
m_values.find("dlg_settings_layout_mode") != m_values.end();
m_settings_layout_changed = false;
for (const std::string& key : {"old_settings_layout_mode",
"new_settings_layout_mode",
"dlg_settings_layout_mode" })
{
auto it = m_values.find(key);
if (it != m_values.end() && app_config->get(key) != it->second) {
m_settings_layout_changed = true;
break;
}
}
if (m_settings_layout_changed) {
// the dialog needs to be destroyed before the call to recreate_gui()

View file

@ -262,13 +262,14 @@ bool OptionsSearcher::search(const std::string& search, bool force/* = false*/)
append(matches, matches2);
score = score2;
}
if (fuzzy_match(wsearch, label_english, score2, matches2) && score2 > score) {
if (view_params.english && fuzzy_match(wsearch, label_english, score2, matches2) && score2 > score) {
label = std::move(label_english);
matches = std::move(matches2);
score = score2;
}
if (score > std::numeric_limits<int>::min()) {
label = mark_string(label, matches);
label = mark_string(label, matches);
label += L" [" + std::to_wstring(score) + L"]";// add score value
std::string label_u8 = into_u8(label);
std::string label_plain = label_u8;
boost::erase_all(label_plain, std::string(1, char(ImGui::ColorMarkerStart)));