diff --git a/resources/icons/Pmetal_001.png b/resources/icons/Pmetal_001.png new file mode 100644 index 000000000..c848f839c Binary files /dev/null and b/resources/icons/Pmetal_001.png differ diff --git a/resources/shaders/gouraud.fs b/resources/shaders/gouraud.fs index 853a5512c..45175acc2 100644 --- a/resources/shaders/gouraud.fs +++ b/resources/shaders/gouraud.fs @@ -17,6 +17,9 @@ struct SlopeDetection uniform vec4 uniform_color; uniform SlopeDetection slope; +uniform sampler2D environment_tex; +uniform bool use_environment_tex; + varying vec3 clipping_planes_dots; // x = tainted, y = specular; @@ -26,6 +29,7 @@ varying vec3 delta_box_min; varying vec3 delta_box_max; varying float world_normal_z; +varying vec3 eye_normal; vec3 slope_color() { @@ -40,5 +44,8 @@ void main() vec3 color = slope.actived ? slope_color() : uniform_color.rgb; // if the fragment is outside the print volume -> use darker color color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; - gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + color * intensity.x, uniform_color.a); + if (use_environment_tex) + gl_FragColor = vec4(0.45 * texture2D(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity.x, uniform_color.a); + else + gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, uniform_color.a); } diff --git a/resources/shaders/gouraud.vs b/resources/shaders/gouraud.vs index 2644d48e4..d60f6eae8 100644 --- a/resources/shaders/gouraud.vs +++ b/resources/shaders/gouraud.vs @@ -51,22 +51,23 @@ varying vec3 delta_box_max; varying vec3 clipping_planes_dots; varying float world_normal_z; +varying vec3 eye_normal; void main() { // First transform the normal into camera space and normalize the result. - vec3 normal = normalize(gl_NormalMatrix * gl_Normal); + eye_normal = normalize(gl_NormalMatrix * gl_Normal); // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. - float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0); + float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; vec3 position = (gl_ModelViewMatrix * gl_Vertex).xyz; - intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS); + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); // Perform the same lighting calculation for the 2nd light source (no specular applied). - NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0); + NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; // compute deltas for out of print volume detection (world coordinates) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 04c886963..9684bc672 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -85,6 +85,8 @@ void PrintConfigDef::init_common_params() def->label = L("Max print height"); def->tooltip = L("Set this to the maximum height that can be reached by your extruder while printing."); def->sidetext = L("mm"); + def->min = 0; + def->max = 1200; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(200.0)); diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 984373ea4..327af9d75 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -42,6 +42,9 @@ // Enable rendering of objects colored by facets' slope #define ENABLE_SLOPE_RENDERING (1 && ENABLE_2_3_0_ALPHA1) +// Enable rendering of objects using environment map +#define ENABLE_ENVIRONMENT_MAP (1 && ENABLE_2_3_0_ALPHA1) + // Enable G-Code viewer #define ENABLE_GCODE_VIEWER (1 && ENABLE_2_3_0_ALPHA1) #define ENABLE_GCODE_VIEWER_STATISTICS (0 && ENABLE_GCODE_VIEWER) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 7b588540b..462cdcf8f 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -3,6 +3,10 @@ #include "3DScene.hpp" #include "GLShader.hpp" #include "GUI_App.hpp" +#if ENABLE_ENVIRONMENT_MAP +#include "Plater.hpp" +#include "AppConfig.hpp" +#endif // ENABLE_ENVIRONMENT_MAP #include "libslic3r/ExtrusionEntity.hpp" #include "libslic3r/ExtrusionEntityCollection.hpp" @@ -664,6 +668,15 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab shader->set_uniform("slope.z_range", m_slope.z_range); #endif // ENABLE_SLOPE_RENDERING +#if ENABLE_ENVIRONMENT_MAP + unsigned int environment_texture_id = GUI::wxGetApp().plater()->get_environment_texture_id(); + bool use_environment_texture = environment_texture_id > 0 && GUI::wxGetApp().app_config->get("use_environment_map") == "1"; + shader->set_uniform("use_environment_tex", use_environment_texture); + if (use_environment_texture) + glsafe(::glBindTexture(GL_TEXTURE_2D, environment_texture_id)); +#endif // ENABLE_ENVIRONMENT_MAP + glcheck(); + GLVolumeWithIdAndZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func); for (GLVolumeWithIdAndZ& volume : to_render) { volume.first->set_render_color(); @@ -680,6 +693,11 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab #endif // ENABLE_SLOPE_RENDERING } +#if ENABLE_ENVIRONMENT_MAP + if (use_environment_texture) + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); +#endif // ENABLE_ENVIRONMENT_MAP + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index ba13a25d8..c9d4c026f 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -93,6 +93,11 @@ void AppConfig::set_defaults() if (get("use_free_camera").empty()) set("use_free_camera", "0"); +#if ENABLE_ENVIRONMENT_MAP + if (get("use_environment_map").empty()) + set("use_environment_map", "0"); +#endif // ENABLE_ENVIRONMENT_MAP + // Remove legacy window positions/sizes erase("", "main_frame_maximized"); erase("", "main_frame_pos"); diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 2cf2bb705..ed98996b4 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -770,7 +770,6 @@ void GCodeViewer::render_toolpaths() const double zoom = camera.get_zoom(); const std::array& viewport = camera.get_viewport(); std::array viewport_sizes = { viewport[2], viewport[3] }; - const std::pair& camera_z_range = camera.get_z_range(); Transform3d inv_proj = camera.get_projection_matrix().inverse(); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index e5dcdd776..824e22f01 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1983,6 +1983,10 @@ void GLCanvas3D::render() return; } +#if ENABLE_ENVIRONMENT_MAP + wxGetApp().plater()->init_environment_texture(); +#endif // ENABLE_ENVIRONMENT_MAP + const Size& cnv_size = get_canvas_size(); // Probably due to different order of events on Linux/GTK2, when one switched from 3D scene // to preview, this was called before canvas had its final size. It reported zero width diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 3c000f62e..9dfb4b422 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -715,16 +715,24 @@ void GUI_App::update_ui_from_settings() void GUI_App::persist_window_geometry(wxTopLevelWindow *window, bool default_maximized) { const std::string name = into_u8(window->GetName()); + wxTopLevelWindow* settings_dlg = dynamic_cast(window)->m_settings_dialog; + const std::string settings_dlg_name = "settings_dialog"; window->Bind(wxEVT_CLOSE_WINDOW, [=](wxCloseEvent &event) { window_pos_save(window, name); + if (settings_dlg) + window_pos_save(settings_dlg, settings_dlg_name); event.Skip(); }); window_pos_restore(window, name, default_maximized); + if (settings_dlg) + window_pos_restore(settings_dlg, settings_dlg_name, default_maximized); on_window_geometry(window, [=]() { window_pos_sanitize(window); + if (settings_dlg) + window_pos_sanitize(settings_dlg); }); } diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index a468c9f93..441f30816 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2390,40 +2390,120 @@ void ObjectList::merge(bool to_multipart_object) // merge selected objects to the multipart object if (to_multipart_object) { + auto get_object_idxs = [this](std::vector& obj_idxs, wxDataViewItemArray& sels) + { + // check selections and split instances to the separated objects... + bool instance_selection = false; + for (wxDataViewItem item : sels) + if (m_objects_model->GetItemType(item) & itInstance) { + instance_selection = true; + break; + } + + if (!instance_selection) + { + for (wxDataViewItem item : sels) { + assert(m_objects_model->GetItemType(item) & itObject); + obj_idxs.emplace_back(m_objects_model->GetIdByItem(item)); + } + return; + } + + // map of obj_idx -> set of selected instance_idxs + std::map> sel_map; + std::set empty_set; + for (wxDataViewItem item : sels) { + if (m_objects_model->GetItemType(item) & itObject) + { + int obj_idx = m_objects_model->GetIdByItem(item); + int inst_cnt = (*m_objects)[obj_idx]->instances.size(); + if (inst_cnt == 1) + sel_map.emplace(obj_idx, empty_set); + else + for (int i = 0; i < inst_cnt; i++) + sel_map[obj_idx].emplace(i); + continue; + } + int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)); + sel_map[obj_idx].emplace(m_objects_model->GetInstanceIdByItem(item)); + } + + // all objects, created from the instances will be added to the end of list + int new_objects_cnt = 0; // count of this new objects +// std::vector obj_idxs; + + for (auto map_item : sel_map) + { + int obj_idx = map_item.first; + // object with just 1 instance + if (map_item.second.empty()) { + obj_idxs.emplace_back(obj_idx); + continue; + } + + // object with selected all instances + if ((*m_objects)[map_item.first]->instances.size() == map_item.second.size()) { + instances_to_separated_objects(obj_idx); + // first instance stay on its own place and another all add to the end of list : + obj_idxs.emplace_back(obj_idx); + new_objects_cnt += map_item.second.size() - 1; + continue; + } + + // object with selected some of instances + instances_to_separated_object(obj_idx, map_item.second); + + if (map_item.second.size() == 1) + new_objects_cnt += 1; + else {// we should split to separate instances last object + instances_to_separated_objects(m_objects->size() - 1); + // all instances will stay at the end of list : + new_objects_cnt += map_item.second.size(); + } + } + + // all instatnces are extracted to the separate objects and should be selected + m_prevent_list_events = true; + sels.Clear(); + for (int obj_idx : obj_idxs) + sels.Add(m_objects_model->GetItemById(obj_idx)); + int obj_cnt = m_objects->size(); + for (int obj_idx = obj_cnt - new_objects_cnt; obj_idx < obj_cnt; obj_idx++) { + sels.Add(m_objects_model->GetItemById(obj_idx)); + obj_idxs.emplace_back(obj_idx); + } + UnselectAll(); + SetSelections(sels); + assert(!sels.IsEmpty()); + m_prevent_list_events = false; + }; + std::vector obj_idxs; wxDataViewItemArray sels; GetSelections(sels); assert(!sels.IsEmpty()); - for (wxDataViewItem item : sels) { - const ItemType type = m_objects_model->GetItemType(item); - assert(type & (itObject/* | itInstance*/)); - obj_idxs.emplace_back(type & itObject ? m_objects_model->GetIdByItem(item) : - m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item))); - } - std::sort(obj_idxs.begin(), obj_idxs.end()); - obj_idxs.erase(std::unique(obj_idxs.begin(), obj_idxs.end()), obj_idxs.end()); - - if (obj_idxs.size() <= 1) - return; - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Merge")); + get_object_idxs(obj_idxs, sels); + + // resulted objects merge to the one Model* model = (*m_objects)[0]->get_model(); ModelObject* new_object = model->add_object(); new_object->name = _u8L("Merged"); - DynamicPrintConfig* new_config = &new_object->config; + DynamicPrintConfig* config = &new_object->config; - const Vec3d& main_offset = (*m_objects)[0]->instances[0]->get_offset(); + int frst_obj_idx = obj_idxs.front(); + const Vec3d& main_offset = (*m_objects)[frst_obj_idx]->instances[0]->get_offset(); for (int obj_idx : obj_idxs) { ModelObject* object = (*m_objects)[obj_idx]; Vec3d offset = object->instances[0]->get_offset(); - if (object->id() == (*m_objects)[0]->id()) + if (object->id() == (*m_objects)[frst_obj_idx]->id()) new_object->add_instance(*object->instances[0]); - auto new_opt_keys = new_config->keys(); + auto new_opt_keys = config->keys(); const DynamicPrintConfig& from_config = object->config; auto opt_keys = from_config.keys(); @@ -2437,7 +2517,7 @@ void ObjectList::merge(bool to_multipart_object) // get it from default config values option = DynamicPrintConfig::new_from_defaults_keys({ opt_key })->option(opt_key); } - new_config->set_key_value(opt_key, option->clone()); + config->set_key_value(opt_key, option->clone()); } } @@ -2461,8 +2541,11 @@ void ObjectList::merge(bool to_multipart_object) } // remove selected objects remove(); + // Add new object(merged) to the object_list add_object_to_list(m_objects->size() - 1); + select_item(m_objects_model->GetItemById(m_objects->size() - 1)); + update_selections_on_canvas(); } // merge all parts to the one single object // all part's settings will be lost @@ -2613,6 +2696,9 @@ bool ObjectList::can_split_instances() bool ObjectList::can_merge_to_multipart_object() const { + if (printer_technology() == ptSLA) + return false; + wxDataViewItemArray sels; GetSelections(sels); if (sels.IsEmpty()) @@ -2620,7 +2706,7 @@ bool ObjectList::can_merge_to_multipart_object() const // should be selected just objects for (wxDataViewItem item : sels) - if (!(m_objects_model->GetItemType(item) & (itObject/* | itInstance*/))) + if (!(m_objects_model->GetItemType(item) & (itObject | itInstance))) return false; return true; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 97e2ffed2..da5695397 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -365,13 +365,23 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } } + bool dragging_while_painting = (action == SLAGizmoEventType::Dragging && m_button_down != Button::None); + + // The mouse button click detection is enabled when there is a valid hit + // or when the user clicks the clipping plane. Missing the object entirely + // shall not capture the mouse. + if (closest_hit_mesh_id != -1 || clipped_mesh_was_hit) { + if (m_button_down == Button::None) + m_button_down = ((action == SLAGizmoEventType::LeftDown) ? Button::Left : Button::Right); + } + if (closest_hit_mesh_id == -1) { // In case we have no valid hit, we can return. The event will // be stopped in following two cases: // 1. clicking the clipping plane // 2. dragging while painting (to prevent scene rotations and moving the object) return clipped_mesh_was_hit - || (action == SLAGizmoEventType::Dragging && m_button_down != Button::None); + || dragging_while_painting; } // Now propagate the hits @@ -472,10 +482,6 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } } - - if (m_button_down == Button::None) - m_button_down = ((action == SLAGizmoEventType::LeftDown) ? Button::Left : Button::Right); - return true; } diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index d8a799eb2..d35b397a6 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -204,29 +204,6 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S event.Skip(); }); - /* - Bind(wxEVT_SYS_COLOUR_CHANGED, [this](wxSysColourChangedEvent& event) - { - bool recreate_gui = false; - { - // the dialog needs to be destroyed before the call to recreate_gui() - // or sometimes the application crashes into wxDialogBase() destructor - // so we put it into an inner scope - wxMessageDialog dialog(nullptr, - _L("System color mode was changed. " - "It is possible to update the Slicer in respect to the system mode.") + "\n" + - _L("You will lose content of the plater.") + "\n\n" + - _L("Do you want to proceed?"), - wxString(SLIC3R_APP_NAME) + " - " + _L("Switching system color mode"), - wxICON_QUESTION | wxOK | wxCANCEL); - recreate_gui = dialog.ShowModal() == wxID_OK; - } - if (recreate_gui) - wxGetApp().recreate_GUI(_L("Changing of an application in respect to the system mode") + dots); - event.Skip(); - }); - */ - wxGetApp().persist_window_geometry(this, true); update_ui_from_settings(); // FIXME (?) @@ -350,7 +327,8 @@ void MainFrame::init_tabpanel() m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, [this](wxEvent&) { auto panel = m_tabpanel->GetCurrentPage(); - if (panel == nullptr) + // There shouldn't be a case, when we try to select a tab, which doesn't support a printer technology + if (panel == nullptr || !static_cast(panel)->supports_printer_technology(m_plater->printer_technology())) return; auto& tabs_list = wxGetApp().tabs_list; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index a7e029636..90e691a89 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1589,6 +1589,9 @@ struct Plater::priv Sidebar *sidebar; Bed3D bed; Camera camera; +#if ENABLE_ENVIRONMENT_MAP + GLTexture environment_texture; +#endif // ENABLE_ENVIRONMENT_MAP Mouse3DController mouse3d_controller; View3D* view3D; GLToolbar view_toolbar; @@ -2101,7 +2104,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) }); wxGetApp().other_instance_message_handler()->init(this->q); - // collapse sidebar according to saved value bool is_collapsed = wxGetApp().app_config->get("collapsed_sidebar") == "1"; sidebar->collapse(is_collapsed); @@ -5570,6 +5572,19 @@ Camera& Plater::get_camera() return p->camera; } +#if ENABLE_ENVIRONMENT_MAP +void Plater::init_environment_texture() +{ + if (p->environment_texture.get_id() == 0) + p->environment_texture.load_from_file(resources_dir() + "/icons/Pmetal_001.png", false, GLTexture::SingleThreaded, false); +} + +unsigned int Plater::get_environment_texture_id() const +{ + return p->environment_texture.get_id(); +} +#endif // ENABLE_ENVIRONMENT_MAP + const Bed3D& Plater::get_bed() const { return p->bed; diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index d17afa697..56420a624 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -319,6 +319,11 @@ public: const Camera& get_camera() const; Camera& get_camera(); +#if ENABLE_ENVIRONMENT_MAP + void init_environment_texture(); + unsigned int get_environment_texture_id() const; +#endif // ENABLE_ENVIRONMENT_MAP + const Bed3D& get_bed() const; Bed3D& get_bed(); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 35f2ee429..50abfb7e6 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -180,10 +180,28 @@ void PreferencesDialog::build() create_settings_mode_widget(); +#if ENABLE_ENVIRONMENT_MAP + m_optgroup_render = std::make_shared(this, _(L("Render"))); + m_optgroup_render->label_width = 40; + m_optgroup_render->m_on_change = [this](t_config_option_key opt_key, boost::any value) { + m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; + }; + + def.label = L("Use environment map"); + def.type = coBool; + def.tooltip = L("If enabled, renders object using the environment map."); + def.set_default_value(new ConfigOptionBool{ app_config->get("use_environment_map") == "1" }); + option = Option(def, "use_environment_map"); + m_optgroup_render->append_single_option_line(option); +#endif // ENABLE_ENVIRONMENT_MAP + auto sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(m_optgroup_general->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); sizer->Add(m_optgroup_camera->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); sizer->Add(m_optgroup_gui->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); +#if ENABLE_ENVIRONMENT_MAP + sizer->Add(m_optgroup_render->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); +#endif // ENABLE_ENVIRONMENT_MAP SetFont(wxGetApp().normal_font()); diff --git a/src/slic3r/GUI/Preferences.hpp b/src/slic3r/GUI/Preferences.hpp index d90f01e2b..f61c4d932 100644 --- a/src/slic3r/GUI/Preferences.hpp +++ b/src/slic3r/GUI/Preferences.hpp @@ -20,6 +20,9 @@ class PreferencesDialog : public DPIDialog std::shared_ptr m_optgroup_general; std::shared_ptr m_optgroup_camera; std::shared_ptr m_optgroup_gui; +#if ENABLE_ENVIRONMENT_MAP + std::shared_ptr m_optgroup_render; +#endif // ENABLE_ENVIRONMENT_MAP wxSizer* m_icon_size_sizer; wxRadioBox* m_layout_mode_box; bool isOSX {false}; diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index 968589985..b8a7af339 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -28,6 +28,12 @@ using GUI::into_u8; namespace Search { +// Does our wxWidgets version support markup? +// https://github.com/prusa3d/PrusaSlicer/issues/4282#issuecomment-634676371 +#if wxUSE_MARKUP && wxCHECK_VERSION(3, 1, 1) + #define SEARCH_SUPPORTS_MARKUP +#endif + static const std::vector& NameByType() { static std::vector data; @@ -271,8 +277,14 @@ bool OptionsSearcher::search(const std::string& search, bool force/* = false*/) label += L" [" + std::to_wstring(score) + L"]";// add score value std::string label_u8 = into_u8(label); std::string label_plain = label_u8; - boost::replace_all(label_plain, std::string(1, char(ImGui::ColorMarkerStart)), ""); - boost::replace_all(label_plain, std::string(1, char(ImGui::ColorMarkerEnd)), ""); + +#ifdef SEARCH_SUPPORTS_MARKUP + boost::replace_all(label_plain, std::string(1, char(ImGui::ColorMarkerStart)), ""); + boost::replace_all(label_plain, std::string(1, char(ImGui::ColorMarkerEnd)), ""); +#else + boost::erase_all(label_plain, std::string(1, char(ImGui::ColorMarkerStart))); + boost::erase_all(label_plain, std::string(1, char(ImGui::ColorMarkerEnd))); +#endif found.emplace_back(FoundOption{ label_plain, label_u8, boost::nowide::narrow(get_tooltip(opt)), i, score }); } } @@ -443,9 +455,11 @@ SearchDialog::SearchDialog(OptionsSearcher* searcher) search_list->AppendBitmapColumn("", SearchListModel::colIcon); wxDataViewTextRenderer* const markupRenderer = new wxDataViewTextRenderer(); -#if wxUSE_MARKUP + +#ifdef SEARCH_SUPPORTS_MARKUP markupRenderer->EnableMarkup(); -#endif // wxUSE_MARKUP +#endif + search_list->AppendColumn(new wxDataViewColumn("", markupRenderer, SearchListModel::colMarkedText, wxCOL_WIDTH_AUTOSIZE, wxALIGN_LEFT)); search_list->GetColumn(SearchListModel::colIcon )->SetWidth(3 * em_unit());