diff --git a/resources/icons/overlay/cut_hover.png b/resources/icons/overlay/cut_hover.png index eccce0243..5efdefc5e 100644 Binary files a/resources/icons/overlay/cut_hover.png and b/resources/icons/overlay/cut_hover.png differ diff --git a/resources/icons/overlay/cut_off.png b/resources/icons/overlay/cut_off.png index 4d0f8c93f..3e442101c 100644 Binary files a/resources/icons/overlay/cut_off.png and b/resources/icons/overlay/cut_off.png differ diff --git a/resources/icons/overlay/cut_on.png b/resources/icons/overlay/cut_on.png index 967d15458..c1f7bf62d 100644 Binary files a/resources/icons/overlay/cut_on.png and b/resources/icons/overlay/cut_on.png differ diff --git a/resources/icons/overlay/layflat_hover.png b/resources/icons/overlay/layflat_hover.png index 31ee91f46..4db9d63d9 100644 Binary files a/resources/icons/overlay/layflat_hover.png and b/resources/icons/overlay/layflat_hover.png differ diff --git a/resources/icons/overlay/layflat_off.png b/resources/icons/overlay/layflat_off.png index 4feadbaf4..393dfb37f 100644 Binary files a/resources/icons/overlay/layflat_off.png and b/resources/icons/overlay/layflat_off.png differ diff --git a/resources/icons/overlay/layflat_on.png b/resources/icons/overlay/layflat_on.png index 93a186957..adb04e6e0 100644 Binary files a/resources/icons/overlay/layflat_on.png and b/resources/icons/overlay/layflat_on.png differ diff --git a/resources/icons/overlay/move_hover.png b/resources/icons/overlay/move_hover.png index 8cd66cab9..322736553 100644 Binary files a/resources/icons/overlay/move_hover.png and b/resources/icons/overlay/move_hover.png differ diff --git a/resources/icons/overlay/move_off.png b/resources/icons/overlay/move_off.png index 9e44690df..9a4dbea6b 100644 Binary files a/resources/icons/overlay/move_off.png and b/resources/icons/overlay/move_off.png differ diff --git a/resources/icons/overlay/move_on.png b/resources/icons/overlay/move_on.png index c19be461d..11f46fff3 100644 Binary files a/resources/icons/overlay/move_on.png and b/resources/icons/overlay/move_on.png differ diff --git a/resources/icons/overlay/rotate_hover.png b/resources/icons/overlay/rotate_hover.png index 818abcbdc..696b70c6b 100644 Binary files a/resources/icons/overlay/rotate_hover.png and b/resources/icons/overlay/rotate_hover.png differ diff --git a/resources/icons/overlay/rotate_off.png b/resources/icons/overlay/rotate_off.png index d8037d773..65ca5c843 100644 Binary files a/resources/icons/overlay/rotate_off.png and b/resources/icons/overlay/rotate_off.png differ diff --git a/resources/icons/overlay/rotate_on.png b/resources/icons/overlay/rotate_on.png index f40f28d4b..e32c13f3f 100644 Binary files a/resources/icons/overlay/rotate_on.png and b/resources/icons/overlay/rotate_on.png differ diff --git a/resources/icons/overlay/scale_hover.png b/resources/icons/overlay/scale_hover.png index 394cb4b20..46a4b5d89 100644 Binary files a/resources/icons/overlay/scale_hover.png and b/resources/icons/overlay/scale_hover.png differ diff --git a/resources/icons/overlay/scale_off.png b/resources/icons/overlay/scale_off.png index fac035099..81bacddfe 100644 Binary files a/resources/icons/overlay/scale_off.png and b/resources/icons/overlay/scale_off.png differ diff --git a/resources/icons/overlay/scale_on.png b/resources/icons/overlay/scale_on.png index 4d4c075f3..271116858 100644 Binary files a/resources/icons/overlay/scale_on.png and b/resources/icons/overlay/scale_on.png differ diff --git a/resources/icons/toolbar.png b/resources/icons/toolbar.png index 75faea658..e5eabd536 100644 Binary files a/resources/icons/toolbar.png and b/resources/icons/toolbar.png differ diff --git a/resources/icons/toolbar141.png b/resources/icons/toolbar141.png new file mode 100644 index 000000000..888b7b1f9 Binary files /dev/null and b/resources/icons/toolbar141.png differ diff --git a/resources/icons/view_toolbar.png b/resources/icons/view_toolbar.png index dd1f5aca4..6d842c5c3 100644 Binary files a/resources/icons/view_toolbar.png and b/resources/icons/view_toolbar.png differ diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index 88e0c7664..2f61cc008 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -483,8 +483,9 @@ bool DynamicConfig::operator==(const DynamicConfig &rhs) const t_options_map::const_iterator it2 = rhs.options.begin(); t_options_map::const_iterator it2_end = rhs.options.end(); for (; it1 != it1_end && it2 != it2_end; ++ it1, ++ it2) - if (*it1->second != *it2->second) - return false; + if (it1->first != it2->first || *it1->second != *it2->second) + // key or value differ + return false; return it1 == it1_end && it2 == it2_end; } diff --git a/src/libslic3r/GCode/Analyzer.cpp b/src/libslic3r/GCode/Analyzer.cpp index 8212b1703..c32acd4e9 100644 --- a/src/libslic3r/GCode/Analyzer.cpp +++ b/src/libslic3r/GCode/Analyzer.cpp @@ -668,6 +668,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ { static GCodePreviewData::Extrusion::Layer& get_layer_at_z(GCodePreviewData::Extrusion::LayersList& layers, float z) { + //FIXME this has a terrible time complexity for (GCodePreviewData::Extrusion::Layer& layer : layers) { // if layer found, return it @@ -863,20 +864,4 @@ size_t GCodeAnalyzer::memory_used() const return out; } -GCodePreviewData::Color operator + (const GCodePreviewData::Color& c1, const GCodePreviewData::Color& c2) -{ - return GCodePreviewData::Color(clamp(0.0f, 1.0f, c1.rgba[0] + c2.rgba[0]), - clamp(0.0f, 1.0f, c1.rgba[1] + c2.rgba[1]), - clamp(0.0f, 1.0f, c1.rgba[2] + c2.rgba[2]), - clamp(0.0f, 1.0f, c1.rgba[3] + c2.rgba[3])); -} - -GCodePreviewData::Color operator * (float f, const GCodePreviewData::Color& color) -{ - return GCodePreviewData::Color(clamp(0.0f, 1.0f, f * color.rgba[0]), - clamp(0.0f, 1.0f, f * color.rgba[1]), - clamp(0.0f, 1.0f, f * color.rgba[2]), - clamp(0.0f, 1.0f, f * color.rgba[3])); -} - } // namespace Slic3r diff --git a/src/libslic3r/GCode/PreviewData.cpp b/src/libslic3r/GCode/PreviewData.cpp index d4aa9bc02..e99eeac02 100644 --- a/src/libslic3r/GCode/PreviewData.cpp +++ b/src/libslic3r/GCode/PreviewData.cpp @@ -521,4 +521,20 @@ size_t GCodePreviewData::memory_used() const sizeof(shell) + sizeof(ranges); } +GCodePreviewData::Color operator + (const GCodePreviewData::Color& c1, const GCodePreviewData::Color& c2) +{ + return GCodePreviewData::Color(clamp(0.0f, 1.0f, c1.rgba[0] + c2.rgba[0]), + clamp(0.0f, 1.0f, c1.rgba[1] + c2.rgba[1]), + clamp(0.0f, 1.0f, c1.rgba[2] + c2.rgba[2]), + clamp(0.0f, 1.0f, c1.rgba[3] + c2.rgba[3])); +} + +GCodePreviewData::Color operator * (float f, const GCodePreviewData::Color& color) +{ + return GCodePreviewData::Color(clamp(0.0f, 1.0f, f * color.rgba[0]), + clamp(0.0f, 1.0f, f * color.rgba[1]), + clamp(0.0f, 1.0f, f * color.rgba[2]), + clamp(0.0f, 1.0f, f * color.rgba[3])); +} + } // namespace Slic3r diff --git a/src/libslic3r/GCode/PreviewData.hpp b/src/libslic3r/GCode/PreviewData.hpp index 8ed5e91c7..4ca579d9a 100644 --- a/src/libslic3r/GCode/PreviewData.hpp +++ b/src/libslic3r/GCode/PreviewData.hpp @@ -22,6 +22,7 @@ public: static const Color Dummy; }; + // Color mapping from a range into a smooth rainbow of 10 colors. struct Range { static const unsigned int Colors_Count = 10; @@ -45,9 +46,13 @@ public: struct Ranges { + // Color mapping by layer height. Range height; + // Color mapping by extrusion width. Range width; + // Color mapping by feedrate. Range feedrate; + // Color mapping by volumetric extrusion rate. Range volumetric_rate; }; diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 0f0ae974b..797272223 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -42,6 +42,8 @@ #define ENABLE_TOOLBAR_BACKGROUND_TEXTURE (1 && ENABLE_1_42_0) // Renders a small sphere in the center of the bounding box of the current selection when no gizmo is active #define ENABLE_RENDER_SELECTION_CENTER (0 && ENABLE_1_42_0) +// Show visual hints in the 3D scene when sidebar matrix fields have focus +#define ENABLE_SIDEBAR_VISUAL_HINTS (0 && ENABLE_1_42_0) #endif // _technologies_h_ diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 3b6bad16d..d79421439 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -10,6 +10,8 @@ add_library(libslic3r_gui STATIC GUI/AboutDialog.hpp GUI/SysInfoDialog.cpp GUI/SysInfoDialog.hpp + GUI/KBShortcutsDialog.cpp + GUI/KBShortcutsDialog.hpp GUI/AppConfig.cpp GUI/AppConfig.hpp GUI/BackgroundSlicingProcess.cpp diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 09c3443c3..012203450 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1868,6 +1868,130 @@ void _3DScene::point3_to_verts(const Vec3crd& point, double width, double height GUI::GLCanvas3DManager _3DScene::s_canvas_mgr; +#if ENABLE_SIDEBAR_VISUAL_HINTS +GLModel::GLModel() + : m_useVBOs(false) +{ +} + +GLModel::~GLModel() +{ + m_volume.release_geometry(); +} + +void GLModel::set_color(float* color, unsigned int size) +{ + m_volume.set_render_color(color, size); +} + +void GLModel::set_scale(const Vec3d& scale) +{ + m_volume.set_volume_scaling_factor(scale); +} + +void GLModel::render() const +{ + if (m_useVBOs) + render_VBOs(); + else + { + } +} + +void GLModel::render_VBOs() const +{ + ::glEnable(GL_BLEND); + ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + ::glCullFace(GL_BACK); + ::glEnableClientState(GL_VERTEX_ARRAY); + ::glEnableClientState(GL_NORMAL_ARRAY); + + GLint current_program_id; + ::glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_id); + GLint color_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "uniform_color") : -1; + + m_volume.render_VBOs(color_id, -1, -1); + + ::glBindBuffer(GL_ARRAY_BUFFER, 0); + ::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + ::glDisableClientState(GL_VERTEX_ARRAY); + ::glDisableClientState(GL_NORMAL_ARRAY); + + ::glDisable(GL_BLEND); +} + +GLArrow::GLArrow() + : GLModel() +{ +} + +bool GLArrow::on_init(bool useVBOs) +{ + Pointf3s vertices; + std::vector triangles; + + // top face + vertices.emplace_back(0.5, 0.0, -0.1); + vertices.emplace_back(0.5, 2.0, -0.1); + vertices.emplace_back(1.0, 2.0, -0.1); + vertices.emplace_back(0.0, 3.0, -0.1); + vertices.emplace_back(-1.0, 2.0, -0.1); + vertices.emplace_back(-0.5, 2.0, -0.1); + vertices.emplace_back(-0.5, 0.0, -0.1); + + // bottom face + vertices.emplace_back(0.5, 0.0, 0.1); + vertices.emplace_back(0.5, 2.0, 0.1); + vertices.emplace_back(1.0, 2.0, 0.1); + vertices.emplace_back(0.0, 3.0, 0.1); + vertices.emplace_back(-1.0, 2.0, 0.1); + vertices.emplace_back(-0.5, 2.0, 0.1); + vertices.emplace_back(-0.5, 0.0, 0.1); + + // bottom face + triangles.emplace_back(0, 6, 1); + triangles.emplace_back(6, 5, 1); + triangles.emplace_back(5, 4, 3); + triangles.emplace_back(5, 3, 1); + triangles.emplace_back(1, 3, 2); + + // top face + triangles.emplace_back(7, 8, 13); + triangles.emplace_back(13, 8, 12); + triangles.emplace_back(12, 10, 11); + triangles.emplace_back(8, 10, 12); + triangles.emplace_back(8, 9, 10); + + // side face + triangles.emplace_back(0, 1, 8); + triangles.emplace_back(8, 7, 0); + triangles.emplace_back(1, 2, 9); + triangles.emplace_back(9, 8, 1); + triangles.emplace_back(2, 3, 10); + triangles.emplace_back(10, 9, 2); + triangles.emplace_back(3, 4, 11); + triangles.emplace_back(11, 10, 3); + triangles.emplace_back(4, 5, 12); + triangles.emplace_back(12, 11, 4); + triangles.emplace_back(5, 6, 13); + triangles.emplace_back(13, 12, 5); + triangles.emplace_back(6, 0, 7); + triangles.emplace_back(7, 13, 6); + + m_useVBOs = useVBOs; + + if (m_useVBOs) + m_volume.indexed_vertex_array.load_mesh_full_shading(TriangleMesh(vertices, triangles)); + else + m_volume.indexed_vertex_array.load_mesh_flat_shading(TriangleMesh(vertices, triangles)); + + m_volume.finalize_geometry(m_useVBOs); + return true; +} +#endif // ENABLE_SIDEBAR_VISUAL_HINTS + std::string _3DScene::get_gl_info(bool format_as_html, bool extensions) { return s_canvas_mgr.get_gl_info(format_as_html, extensions); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 97b0310e5..22b80d627 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -18,7 +18,6 @@ class SLAPrintObject; enum SLAPrintObjectStep : unsigned int; class Model; class ModelObject; -class GCodePreviewData; class DynamicPrintConfig; class ExtrusionPath; class ExtrusionMultiPath; @@ -583,6 +582,41 @@ private: GLVolumeCollection& operator=(const GLVolumeCollection &); }; +#if ENABLE_SIDEBAR_VISUAL_HINTS +class GLModel +{ +protected: + GLVolume m_volume; + bool m_useVBOs; + +public: + GLModel(); + virtual ~GLModel(); + + bool init(bool useVBOs) { return on_init(useVBOs); } + + void set_color(float* color, unsigned int size); + void set_scale(const Vec3d& scale); + + void render() const; + +protected: + virtual bool on_init(bool useVBOs) = 0; + +private: + void render_VBOs() const; +}; + +class GLArrow : public GLModel +{ +public: + GLArrow(); + +protected: + virtual bool on_init(bool useVBOs); +}; +#endif // ENABLE_SIDEBAR_VISUAL_HINTS + class _3DScene { static GUI::GLCanvas3DManager s_canvas_mgr; diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index d748919c9..66a0884a4 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -15,8 +15,8 @@ #include "libslic3r/SLAPrint.hpp" #include "libslic3r/Utils.hpp" #include "libslic3r/GCode/PostProcessor.hpp" +#include "libslic3r/GCode/PreviewData.hpp" -//#undef NDEBUG #include #include #include @@ -367,6 +367,13 @@ Print::ApplyStatus BackgroundSlicingProcess::apply(const Model &model, const Dyn assert(m_print != nullptr); assert(config.opt_enum("printer_technology") == m_print->technology()); Print::ApplyStatus invalidated = m_print->apply(model, config); + if ((invalidated & PrintBase::APPLY_STATUS_INVALIDATED) != 0 && m_print->technology() == ptFFF && + m_gcode_preview_data != nullptr && ! this->m_fff_print->is_step_done(psGCodeExport)) { + // Some FFF status was invalidated, and the G-code was not exported yet. + // Let the G-code preview UI know that the final G-code preview is not valid. + // In addition, this early memory deallocation reduces memory footprint. + m_gcode_preview_data->reset(); + } return invalidated; } @@ -392,7 +399,7 @@ void BackgroundSlicingProcess::schedule_upload(Slic3r::PrintHostJob upload_job) // Guard against entering the export step before changing the export path. tbb::mutex::scoped_lock lock(m_print->state_mutex()); this->invalidate_step(bspsGCodeFinalize); - m_export_path = std::string(); + m_export_path.clear(); m_upload_job = std::move(upload_job); } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index e01e1dbbe..3c4debba0 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1154,6 +1154,12 @@ GLCanvas3D::Selection::VolumeCache::VolumeCache(const Vec3d& position, const Vec } #endif // ENABLE_MODELVOLUME_TRANSFORM +#if ENABLE_SIDEBAR_VISUAL_HINTS +const float GLCanvas3D::Selection::RED[3] = { 1.0f, 0.0f, 0.0f }; +const float GLCanvas3D::Selection::GREEN[3] = { 0.0f, 1.0f, 0.0f }; +const float GLCanvas3D::Selection::BLUE[3] = { 0.0f, 0.0f, 1.0f }; +#endif // ENABLE_SIDEBAR_VISUAL_HINTS + GLCanvas3D::Selection::Selection() : m_volumes(nullptr) , m_model(nullptr) @@ -1183,6 +1189,19 @@ void GLCanvas3D::Selection::set_volumes(GLVolumePtrs* volumes) _update_valid(); } +#if ENABLE_SIDEBAR_VISUAL_HINTS +bool GLCanvas3D::Selection::init(bool useVBOs) +{ + if (m_arrow.init(useVBOs)) + { + m_arrow.set_scale(5.0 * Vec3d::Ones()); + return true; + } + + return false; +} +#endif // ENABLE_SIDEBAR_VISUAL_HINTS + void GLCanvas3D::Selection::set_model(Model* model) { m_model = model; @@ -1530,7 +1549,7 @@ void GLCanvas3D::Selection::start_dragging() _set_caches(); } -void GLCanvas3D::Selection::translate(const Vec3d& displacement) +void GLCanvas3D::Selection::translate(const Vec3d& displacement, bool local) { if (!m_valid) return; @@ -1540,7 +1559,7 @@ void GLCanvas3D::Selection::translate(const Vec3d& displacement) #if ENABLE_MODELVOLUME_TRANSFORM if ((m_mode == Volume) || (*m_volumes)[i]->is_wipe_tower) { - if (_requires_local_axes()) + if (local) (*m_volumes)[i]->set_volume_offset(m_cache.volumes_data[i].get_volume_position() + displacement); else { @@ -1595,7 +1614,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) else if (is_single_volume() || is_single_modifier()) #if ENABLE_WORLD_ROTATIONS { - if (_requires_local_axes()) + if (requires_local_axes()) (*m_volumes)[i]->set_volume_rotation(rotation); else { @@ -2055,6 +2074,55 @@ void GLCanvas3D::Selection::render_center() const } #endif // ENABLE_RENDER_SELECTION_CENTER +#if ENABLE_SIDEBAR_VISUAL_HINTS +void GLCanvas3D::Selection::render_sidebar_hints(const std::string& sidebar_field) const +{ + if (sidebar_field.empty()) + return; + + ::glClear(GL_DEPTH_BUFFER_BIT); + ::glEnable(GL_DEPTH_TEST); + + ::glEnable(GL_LIGHTING); + + ::glPushMatrix(); + + const Vec3d& center = get_bounding_box().center(); + + if (is_single_full_instance()) + ::glTranslated(center(0), center(1), center(2)); + else if (is_single_volume() || is_single_modifier()) + { + const GLVolume* volume = (*m_volumes)[*m_list.begin()]; + Transform3d orient_matrix = volume->get_instance_transformation().get_matrix(true, false, true, true) * volume->get_volume_transformation().get_matrix(true, false, true, true); + const Vec3d& offset = get_bounding_box().center(); + + ::glTranslated(offset(0), offset(1), offset(2)); + ::glMultMatrixd(orient_matrix.data()); + } + else + ::glTranslated(center(0), center(1), center(2)); + + if (boost::starts_with(sidebar_field, "position")) + _render_sidebar_position_hints(sidebar_field); + else if (boost::starts_with(sidebar_field, "rotation")) + _render_sidebar_rotation_hints(sidebar_field); + else if (boost::starts_with(sidebar_field, "scale")) + _render_sidebar_scale_hints(sidebar_field); + else if (boost::starts_with(sidebar_field, "size")) + _render_sidebar_size_hints(sidebar_field); + + ::glPopMatrix(); + + ::glDisable(GL_LIGHTING); +} +#endif // ENABLE_SIDEBAR_VISUAL_HINTS + +bool GLCanvas3D::Selection::requires_local_axes() const +{ + return (m_mode == Volume) && is_from_single_instance(); +} + void GLCanvas3D::Selection::_update_valid() { m_valid = (m_volumes != nullptr) && (m_model != nullptr); @@ -2457,6 +2525,101 @@ void GLCanvas3D::Selection::_render_bounding_box(const BoundingBoxf3& box, float ::glEnd(); } +#if ENABLE_SIDEBAR_VISUAL_HINTS +void GLCanvas3D::Selection::_render_sidebar_position_hints(const std::string& sidebar_field) const +{ + if (boost::ends_with(sidebar_field, "x")) + { + ::glRotated(-90.0, 0.0, 0.0, 1.0); + _render_sidebar_position_hint(X); + } + else if (boost::ends_with(sidebar_field, "y")) + _render_sidebar_position_hint(Y); + else if (boost::ends_with(sidebar_field, "z")) + { + ::glRotated(90.0, 1.0, 0.0, 0.0); + _render_sidebar_position_hint(Z); + } +} + +void GLCanvas3D::Selection::_render_sidebar_rotation_hints(const std::string& sidebar_field) const +{ +} + +void GLCanvas3D::Selection::_render_sidebar_scale_hints(const std::string& sidebar_field) const +{ + if (boost::ends_with(sidebar_field, "x") || requires_uniform_scale()) + { + ::glPushMatrix(); + ::glRotated(-90.0, 0.0, 0.0, 1.0); + _render_sidebar_scale_hint(X); + ::glPopMatrix(); + } + + if (boost::ends_with(sidebar_field, "y") || requires_uniform_scale()) + { + ::glPushMatrix(); + _render_sidebar_scale_hint(Y); + ::glPopMatrix(); + } + + if (boost::ends_with(sidebar_field, "z") || requires_uniform_scale()) + { + ::glPushMatrix(); + ::glRotated(90.0, 1.0, 0.0, 0.0); + _render_sidebar_scale_hint(Z); + ::glPopMatrix(); + } +} + +void GLCanvas3D::Selection::_render_sidebar_size_hints(const std::string& sidebar_field) const +{ + _render_sidebar_scale_hints(sidebar_field); +} + +void GLCanvas3D::Selection::_render_sidebar_position_hint(Axis axis) const +{ + float color[3]; + switch (axis) + { + case X: { ::memcpy((void*)color, (const void*)RED, 3 * sizeof(float)); break; } + case Y: { ::memcpy((void*)color, (const void*)GREEN, 3 * sizeof(float)); break; } + case Z: { ::memcpy((void*)color, (const void*)BLUE, 3 * sizeof(float)); break; } + } + + m_arrow.set_color(color, 3); + m_arrow.render(); +} + +void GLCanvas3D::Selection::_render_sidebar_rotation_hint(Axis axis, double length) const +{ +} + +void GLCanvas3D::Selection::_render_sidebar_scale_hint(Axis axis) const +{ + float color[3]; + switch (axis) + { + case X: { ::memcpy((void*)color, (const void*)RED, 3 * sizeof(float)); break; } + case Y: { ::memcpy((void*)color, (const void*)GREEN, 3 * sizeof(float)); break; } + case Z: { ::memcpy((void*)color, (const void*)BLUE, 3 * sizeof(float)); break; } + } + + m_arrow.set_color(color, 3); + + ::glTranslated(0.0, 5.0, 0.0); + m_arrow.render(); + + ::glTranslated(0.0, -10.0, 0.0); + ::glRotated(180.0, 0.0, 0.0, 1.0); + m_arrow.render(); +} + +void GLCanvas3D::Selection::_render_sidebar_size_hint(Axis axis, double length) const +{ +} +#endif // ENABLE_SIDEBAR_VISUAL_HINTS + void GLCanvas3D::Selection::_synchronize_unselected_instances() { std::set done; // prevent processing volumes twice @@ -2588,11 +2751,6 @@ void GLCanvas3D::Selection::_ensure_on_bed() } #endif // ENABLE_ENSURE_ON_BED_WHILE_SCALING -bool GLCanvas3D::Selection::_requires_local_axes() const -{ - return (m_mode == Volume) && is_from_single_instance(); -} - const float GLCanvas3D::Gizmos::OverlayIconsScale = 1.0f; const float GLCanvas3D::Gizmos::OverlayBorder = 5.0f; const float GLCanvas3D::Gizmos::OverlayGapY = 5.0f * OverlayIconsScale; @@ -3624,6 +3782,7 @@ wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent); wxDEFINE_EVENT(EVT_GLCANVAS_MODEL_UPDATE, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent); +wxDEFINE_EVENT(EVT_GLCANVAS_QUESTION_MARK, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event); wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); @@ -3787,6 +3946,11 @@ bool GLCanvas3D::init(bool useVBOs, bool use_legacy_opengl) if (!_init_toolbar()) return false; +#if ENABLE_SIDEBAR_VISUAL_HINTS + if (!m_selection.init(m_use_VBOs)) + return false; +#endif // ENABLE_SIDEBAR_VISUAL_HINTS + #if ENABLE_REMOVE_TABS_FROM_PLATER post_event(SimpleEvent(EVT_GLCANVAS_INIT)); #endif // ENABLE_REMOVE_TABS_FROM_PLATER @@ -4164,6 +4328,10 @@ void GLCanvas3D::render() // this position is used later into on_mouse() to drag the objects m_mouse.scene_position = _mouse_to_3d(m_mouse.position.cast()); +#if ENABLE_SIDEBAR_VISUAL_HINTS + _render_selection_sidebar_hints(); +#endif // ENABLE_SIDEBAR_VISUAL_HINTS + _render_current_gizmo(); #if ENABLE_SHOW_CAMERA_TARGET _render_camera_target(); @@ -4777,6 +4945,8 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case 43: { post_event(Event(EVT_GLCANVAS_INCREASE_INSTANCES, +1)); break; } // key - case 45: { post_event(Event(EVT_GLCANVAS_INCREASE_INSTANCES, -1)); break; } + // key ? + case 63: { post_event(SimpleEvent(EVT_GLCANVAS_QUESTION_MARK)); break; } // key A/a case 65: case 97: { post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); break; } @@ -5668,6 +5838,11 @@ bool GLCanvas3D::_init_toolbar() icons_data.icon_border_size = 1; icons_data.icon_gap_size = 1; +// icons_data.filename = "toolbar141.png"; +// icons_data.icon_size = 52; +// icons_data.icon_border_size = 0; +// icons_data.icon_gap_size = 0; + BackgroundTexture::Metadata background_data; background_data.filename = "toolbar_background.png"; background_data.left = 16; @@ -6574,6 +6749,19 @@ void GLCanvas3D::_render_sla_slices() const } } +#if ENABLE_SIDEBAR_VISUAL_HINTS +void GLCanvas3D::_render_selection_sidebar_hints() const +{ + if (m_use_VBOs) + m_shader.start_using(); + + m_selection.render_sidebar_hints(m_sidebar_field); + + if (m_use_VBOs) + m_shader.stop_using(); +} +#endif // ENABLE_SIDEBAR_VISUAL_HINTS + void GLCanvas3D::_update_volumes_hover_state() const { for (GLVolume* v : m_volumes.volumes) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 08368a131..413d625f1 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -28,6 +28,7 @@ namespace Slic3r { class GLShader; class ExPolygon; class BackgroundSlicingProcess; +class GCodePreviewData; namespace GUI { @@ -105,6 +106,7 @@ wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent); wxDECLARE_EVENT(EVT_GLCANVAS_MODEL_UPDATE, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent); +wxDECLARE_EVENT(EVT_GLCANVAS_QUESTION_MARK, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event); // data: +1 => increase, -1 => decrease wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); @@ -367,6 +369,12 @@ class GLCanvas3D public: class Selection { +#if ENABLE_SIDEBAR_VISUAL_HINTS + static const float RED[3]; + static const float GREEN[3]; + static const float BLUE[3]; +#endif // ENABLE_SIDEBAR_VISUAL_HINTS + public: typedef std::set IndicesList; @@ -494,6 +502,9 @@ public: #if ENABLE_RENDER_SELECTION_CENTER GLUquadricObj* m_quadric; #endif // ENABLE_RENDER_SELECTION_CENTER +#if ENABLE_SIDEBAR_VISUAL_HINTS + mutable GLArrow m_arrow; +#endif // ENABLE_SIDEBAR_VISUAL_HINTS public: Selection(); @@ -502,6 +513,9 @@ public: #endif // ENABLE_RENDER_SELECTION_CENTER void set_volumes(GLVolumePtrs* volumes); +#if ENABLE_SIDEBAR_VISUAL_HINTS + bool init(bool useVBOs); +#endif // ENABLE_SIDEBAR_VISUAL_HINTS Model* get_model() const { return m_model; } void set_model(Model* model); @@ -564,7 +578,7 @@ public: void start_dragging(); - void translate(const Vec3d& displacement); + void translate(const Vec3d& displacement, bool local = false); void rotate(const Vec3d& rotation, bool local); void flattening_rotate(const Vec3d& normal); void scale(const Vec3d& scale, bool local); @@ -579,6 +593,11 @@ public: #if ENABLE_RENDER_SELECTION_CENTER void render_center() const; #endif // ENABLE_RENDER_SELECTION_CENTER +#if ENABLE_SIDEBAR_VISUAL_HINTS + void render_sidebar_hints(const std::string& sidebar_field) const; +#endif // ENABLE_SIDEBAR_VISUAL_HINTS + + bool requires_local_axes() const; private: void _update_valid(); @@ -594,12 +613,21 @@ public: void _render_selected_volumes() const; void _render_synchronized_volumes() const; void _render_bounding_box(const BoundingBoxf3& box, float* color) const; +#if ENABLE_SIDEBAR_VISUAL_HINTS + void _render_sidebar_position_hints(const std::string& sidebar_field) const; + void _render_sidebar_rotation_hints(const std::string& sidebar_field) const; + void _render_sidebar_scale_hints(const std::string& sidebar_field) const; + void _render_sidebar_size_hints(const std::string& sidebar_field) const; + void _render_sidebar_position_hint(Axis axis) const; + void _render_sidebar_rotation_hint(Axis axis, double length) const; + void _render_sidebar_scale_hint(Axis axis) const; + void _render_sidebar_size_hint(Axis axis, double length) const; +#endif // ENABLE_SIDEBAR_VISUAL_HINTS void _synchronize_unselected_instances(); void _synchronize_unselected_volumes(); #if ENABLE_ENSURE_ON_BED_WHILE_SCALING void _ensure_on_bed(); #endif // ENABLE_ENSURE_ON_BED_WHILE_SCALING - bool _requires_local_axes() const; }; class ClippingPlane @@ -1054,6 +1082,9 @@ private: void _render_camera_target() const; #endif // ENABLE_SHOW_CAMERA_TARGET void _render_sla_slices() const; +#if ENABLE_SIDEBAR_VISUAL_HINTS + void _render_selection_sidebar_hints() const; +#endif // ENABLE_SIDEBAR_VISUAL_HINTS void _update_volumes_hover_state() const; void _update_gizmos_data(); diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp index 1ed4a8251..64301c73d 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -19,7 +19,6 @@ class ExPolygon; typedef std::vector ExPolygons; class ModelObject; class PrintObject; -class GCodePreviewData; namespace GUI { diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp index e7ab0443d..3ca4292a9 100644 --- a/src/slic3r/GUI/GUI.hpp +++ b/src/slic3r/GUI/GUI.hpp @@ -16,7 +16,6 @@ namespace Slic3r { class AppConfig; class DynamicPrintConfig; class Print; -class GCodePreviewData; namespace GUI { diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index e4db9b6e1..2998ea7f3 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -35,6 +35,7 @@ #include "Preferences.hpp" #include "Tab.hpp" #include "SysInfoDialog.hpp" +#include "KBShortcutsDialog.hpp" namespace Slic3r { namespace GUI { @@ -301,6 +302,13 @@ void GUI_App::system_info() dlg.Destroy(); } +void GUI_App::keyboard_shortcuts() +{ + KBShortcutsDialog dlg; + dlg.ShowModal(); + dlg.Destroy(); +} + // static method accepting a wxWindow object as first parameter bool GUI_App::catch_error(std::function cb, // wxMessageDialog* message_dialog, @@ -426,7 +434,7 @@ bool GUI_App::select_language( wxArrayString & names, m_wxLocale = new wxLocale; m_wxLocale->Init(identifiers[index]); m_wxLocale->AddCatalogLookupPathPrefix(localization_dir()); - m_wxLocale->AddCatalog(GetAppName()); + m_wxLocale->AddCatalog(/*GetAppName()*/"Slic3rPE"); wxSetlocale(LC_NUMERIC, "C"); Preset::update_suffix_modified(); return true; @@ -453,7 +461,7 @@ bool GUI_App::load_language() m_wxLocale = new wxLocale; m_wxLocale->Init(identifiers[i]); m_wxLocale->AddCatalogLookupPathPrefix(localization_dir()); - m_wxLocale->AddCatalog(GetAppName()); + m_wxLocale->AddCatalog(/*GetAppName()*/"Slic3rPE"); wxSetlocale(LC_NUMERIC, "C"); Preset::update_suffix_modified(); return true; @@ -496,7 +504,8 @@ void GUI_App::get_installed_languages(wxArrayString & names, wxArrayLong & ident { auto full_file_name = dir.GetName() + wxFileName::GetPathSeparator() + filename + wxFileName::GetPathSeparator() + - GetAppName() + wxT(".mo"); + /*GetAppName()*/"Slic3rPE" + + wxT(".mo"); if (wxFileExists(full_file_name)) { names.Add(langinfo->Description); diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 3c2b4a21f..81175b7ca 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -115,6 +115,7 @@ public: void recreate_GUI(); void system_info(); + void keyboard_shortcuts(); void load_project(wxWindow *parent, wxString& input_file); void import_model(wxWindow *parent, wxArrayString& input_files); static bool catch_error(std::function cb, diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index ddf699c2c..8cc2362e8 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -361,8 +361,9 @@ void ObjectManipulation::update_rotation_value(const Vec3d& rotation) void ObjectManipulation::change_position_value(const Vec3d& position) { auto canvas = wxGetApp().plater()->canvas3D(); - canvas->get_selection().start_dragging(); - canvas->get_selection().translate(position - cache_position); + GLCanvas3D::Selection& selection = canvas->get_selection(); + selection.start_dragging(); + selection.translate(position - cache_position, selection.requires_local_axes()); canvas->do_move(); cache_position = position; diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 71c92f2d1..735b55125 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -395,12 +395,6 @@ void Preview::set_number_extruders(unsigned int number_extruders) } } -void Preview::reset_gcode_preview_data() -{ - m_gcode_preview_data->reset(); - m_canvas->reset_legend_texture(); -} - void Preview::set_canvas_as_dirty() { m_canvas->set_as_dirty(); @@ -451,6 +445,7 @@ void Preview::load_print() void Preview::reload_print(bool force) { m_canvas->reset_volumes(); + m_canvas->reset_legend_texture(); m_loaded = false; if (!IsShown() && !force) @@ -759,7 +754,8 @@ void Preview::load_print_as_fff() // Collect colors per extruder. std::vector colors; - if (!m_gcode_preview_data->empty() || (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::Tool)) + bool gcode_preview_data_valid = print->is_step_done(psGCodeExport) && ! m_gcode_preview_data->empty(); + if (gcode_preview_data_valid || (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::Tool)) { const ConfigOptionStrings* extruders_opt = dynamic_cast(m_config->option("extruder_colour")); const ConfigOptionStrings* filamemts_opt = dynamic_cast(m_config->option("filament_colour")); @@ -785,13 +781,7 @@ void Preview::load_print_as_fff() // used to set the sliders to the extremes of the current zs range m_force_sliders_full_range = false; - if (m_gcode_preview_data->empty()) - { - // load skirt and brim - m_canvas->load_preview(colors); - show_hide_ui_elements("simple"); - } - else + if (gcode_preview_data_valid) { m_force_sliders_full_range = (m_canvas->get_volumes_count() == 0); m_canvas->load_gcode_preview(*m_gcode_preview_data, colors); @@ -805,8 +795,15 @@ void Preview::load_print_as_fff() reset_sliders(); m_canvas_widget->Refresh(); } + } + else + { + // load skirt and brim + m_canvas->load_preview(colors); + show_hide_ui_elements("simple"); } + if (n_layers > 0) update_sliders(m_canvas->get_current_print_zs(true)); diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 23e6a682f..534191633 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -140,7 +140,6 @@ public: #endif // ENABLE_REMOVE_TABS_FROM_PLATER void set_number_extruders(unsigned int number_extruders); - void reset_gcode_preview_data(); void set_canvas_as_dirty(); void set_enabled(bool enabled); void set_bed_shape(const Pointfs& shape); diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp new file mode 100644 index 000000000..b3edbc9a8 --- /dev/null +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -0,0 +1,153 @@ +#include "KBShortcutsDialog.hpp" +#include "I18N.hpp" +#include "libslic3r/Utils.hpp" +#include "GUI.hpp" +#include + +namespace Slic3r { +namespace GUI { + +KBShortcutsDialog::KBShortcutsDialog() + : wxDialog(NULL, wxID_ANY, _(L("Slic3r Prusa Edition - Keyboard Shortcuts")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) +{ + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + + auto main_sizer = new wxBoxSizer(wxVERTICAL); + + // logo + wxBitmap logo_bmp = wxBitmap(from_u8(Slic3r::var("Slic3r_32px.png")), wxBITMAP_TYPE_PNG); + + // fonts + wxFont head_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold(); + head_font.SetPointSize(19); + + wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + font.SetPointSize(10); + wxFont bold_font = font.Bold(); +#ifdef __WXOSX__ + font.SetPointSize(12); + bold_font.SetPointSize(14); +#endif /*__WXOSX__*/ + + fill_shortcuts(); + + auto panel = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(500, 600)); + panel->SetScrollbars(0, 20, 1, 2); + auto sizer = new wxBoxSizer(wxVERTICAL); + panel->SetSizer(sizer); + main_sizer->Add(panel, 1, wxEXPAND | wxALL, 0); + + for (auto& sc : m_full_shortcuts) + { + wxBoxSizer* hsizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(hsizer, 0, wxEXPAND | wxTOP, 25); + + // logo + auto *logo = new wxStaticBitmap(panel, wxID_ANY, logo_bmp); + hsizer->Add(logo, 0, wxEXPAND | wxLEFT | wxRIGHT, 15); + + // head + wxStaticText* head = new wxStaticText(panel, wxID_ANY, sc.first, wxDefaultPosition, wxSize(400,-1)); + head->SetFont(head_font); + hsizer->Add(head, 0, wxALIGN_CENTER_VERTICAL); + + // Shortcuts list + auto grid_sizer = new wxFlexGridSizer(2, 10, 25); + sizer->Add(grid_sizer, 0, wxEXPAND | wxLEFT | wxTOP, 10); + + for (auto pair : sc.second) + { + auto shortcut = new wxStaticText(panel, wxID_ANY, _(pair.first)); + shortcut->SetFont(bold_font); + grid_sizer->Add(shortcut, -1, wxALIGN_CENTRE_VERTICAL); + + auto description = new wxStaticText(panel, wxID_ANY, _(pair.second)); + description->SetFont(font); + grid_sizer->Add(description, -1, wxALIGN_CENTRE_VERTICAL); + } + } + + wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxOK); + + this->SetEscapeId(wxID_CLOSE); + this->Bind(wxEVT_BUTTON, &KBShortcutsDialog::onCloseDialog, this, wxID_OK); + main_sizer->Add(buttons, 0, wxEXPAND | wxALL, 15); + + this->Bind(wxEVT_LEFT_DOWN, &KBShortcutsDialog::onCloseDialog, this); + + SetSizer(main_sizer); + main_sizer->SetSizeHints(this); +} + +void KBShortcutsDialog::fill_shortcuts() +{ + Shortcuts main_shortcuts; + main_shortcuts.reserve(25); + + main_shortcuts.push_back(Shortcut("Ctrl+O", L("Open project STL/OBJ/AMF/3MF with config, delete bed"))); + main_shortcuts.push_back(Shortcut("Ctrl+I", L("Import STL//OBJ/AMF/3MF without config, keep bed"))); + main_shortcuts.push_back(Shortcut("Ctrl+L", L("Load Config from .ini/amf/3mf/gcode"))); + main_shortcuts.push_back(Shortcut("Ctrl+Alt+L", L("Load Config from .ini/amf/3mf/gcode and merge"))); + main_shortcuts.push_back(Shortcut("Ctrl+G", L("Export Gcode"))); + main_shortcuts.push_back(Shortcut("Ctrl+S", L("Save project (3MF)"))); + main_shortcuts.push_back(Shortcut("Ctrl+R", L("(Re)slice"))); + main_shortcuts.push_back(Shortcut("Ctrl+U", L("Quick slice"))); + main_shortcuts.push_back(Shortcut("Ctrl+Alt+U", L("Quick slice and Save as"))); + main_shortcuts.push_back(Shortcut("Ctrl+Shift+U", L("Repeat last quick slice"))); + main_shortcuts.push_back(Shortcut("Ctrl+1", L("Select Plater Tab"))); + main_shortcuts.push_back(Shortcut("Ctrl+2", L("Select Print Settings Tab"))); + main_shortcuts.push_back(Shortcut("Ctrl+3", L("Select Filament Setting Tab"))); + main_shortcuts.push_back(Shortcut("Ctrl+4", L("Select Printer Setting Tab"))); + main_shortcuts.push_back(Shortcut("Ctrl+5", L("Switch to 3D"))); + main_shortcuts.push_back(Shortcut("Ctrl+6", L("Switch to Preview"))); + main_shortcuts.push_back(Shortcut("Ctrl+P", L("Preferences"))); + main_shortcuts.push_back(Shortcut("0-6", L("Camera view "))); + main_shortcuts.push_back(Shortcut("+", L("Add Instance to selected object "))); + main_shortcuts.push_back(Shortcut("-", L("Remove Instance from selected object"))); + main_shortcuts.push_back(Shortcut("?", L("Show keyboard shortcuts list"))); + main_shortcuts.push_back(Shortcut("PgUp/PgDn", L("Switch between 3D and Preview"))); + main_shortcuts.push_back(Shortcut("Shift+LeftMouse",L("Select multiple object/Move multiple object"))); + + m_full_shortcuts.emplace(_(L("Main Shortcuts")), main_shortcuts); + + + Shortcuts plater_shortcuts; + plater_shortcuts.reserve(20); + + plater_shortcuts.push_back(Shortcut("A", L("Arrange"))); + plater_shortcuts.push_back(Shortcut("Ctrl+A", L("Select All objects"))); + plater_shortcuts.push_back(Shortcut("Del", L("Delete selected"))); + plater_shortcuts.push_back(Shortcut("Ctrl+Del", L("Delete all"))); + plater_shortcuts.push_back(Shortcut("M", L("Gizmo move"))); + plater_shortcuts.push_back(Shortcut("S", L("Gizmo scale"))); + plater_shortcuts.push_back(Shortcut("R", L("Gizmo rotate"))); + plater_shortcuts.push_back(Shortcut("C", L("Gizmo cut"))); + plater_shortcuts.push_back(Shortcut("F", L("Gizmo Place face on bed"))); + plater_shortcuts.push_back(Shortcut("L", L("Gizmo SLA support points"))); + plater_shortcuts.push_back(Shortcut("B", L("Zoom to Bed"))); + plater_shortcuts.push_back(Shortcut("Z", L("Zoom to all objects in scene, if none selected"))); + plater_shortcuts.push_back(Shortcut("Z", L("Zoom to selected object"))); + plater_shortcuts.push_back(Shortcut("I", L("Zoom in"))); + plater_shortcuts.push_back(Shortcut("O", L("Zoom out"))); + plater_shortcuts.push_back(Shortcut("ESC", L("Unselect gizmo, keep object selection"))); + + m_full_shortcuts.emplace(_(L("Plater Shortcuts")), plater_shortcuts); + + + Shortcuts preview_shortcuts; + preview_shortcuts.reserve(2); + + preview_shortcuts.push_back(Shortcut(L("Arrow Up"), L("Upper Layer"))); + preview_shortcuts.push_back(Shortcut(L("Arrow Down"), L("Lower Layer"))); + + m_full_shortcuts.emplace(_(L("Preview Shortcuts")), preview_shortcuts); +} + +void KBShortcutsDialog::onCloseDialog(wxEvent &) +{ + this->EndModal(wxID_CLOSE); + this->Close(); +} + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/KBShortcutsDialog.hpp b/src/slic3r/GUI/KBShortcutsDialog.hpp new file mode 100644 index 000000000..8517544b5 --- /dev/null +++ b/src/slic3r/GUI/KBShortcutsDialog.hpp @@ -0,0 +1,32 @@ +#ifndef slic3r_GUI_KBShortcutsDialog_hpp_ +#define slic3r_GUI_KBShortcutsDialog_hpp_ + +#include +#include + +namespace Slic3r { +namespace GUI { + +class KBShortcutsDialog : public wxDialog +{ + typedef std::pair Shortcut; + typedef std::vector< Shortcut > Shortcuts; + typedef std::map ShortcutsMap; + + wxString text_info {wxEmptyString}; + + ShortcutsMap m_full_shortcuts; + +public: + KBShortcutsDialog(); + + void fill_shortcuts(); + +private: + void onCloseDialog(wxEvent &); +}; + +} // namespace GUI +} // namespace Slic3r + +#endif diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 4d4ee17ae..2211023f0 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -432,6 +432,9 @@ void MainFrame::init_menubar() [this](wxCommandEvent&) { wxLaunchDefaultBrowser("http://github.com/prusa3d/slic3r/issues/new"); }); append_menu_item(helpMenu, wxID_ANY, _(L("About Slic3r")), _(L("Show about dialog")), [this](wxCommandEvent&) { Slic3r::GUI::about(); }); + helpMenu->AppendSeparator(); + append_menu_item(helpMenu, wxID_ANY, _(L("Keyboard Shortcuts")) + "\t?", _(L("Show the list of the keyboard shortcuts")), + [this](wxCommandEvent&) { wxGetApp().keyboard_shortcuts(); }); } // menubar diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ea8a83871..cba53cf17 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1186,6 +1186,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) view3D_canvas->Bind(EVT_GLCANVAS_MODEL_UPDATE, [this](SimpleEvent&) { this->schedule_background_process(); }); view3D_canvas->Bind(EVT_GLCANVAS_REMOVE_OBJECT, [q](SimpleEvent&) { q->remove_selected(); }); view3D_canvas->Bind(EVT_GLCANVAS_ARRANGE, [this](SimpleEvent&) { arrange(); }); + view3D_canvas->Bind(EVT_GLCANVAS_QUESTION_MARK, [this](SimpleEvent&) { wxGetApp().keyboard_shortcuts(); }); view3D_canvas->Bind(EVT_GLCANVAS_INCREASE_INSTANCES, [this](Event &evt) { if (evt.data == 1) this->q->increase_instances(); else if (this->can_decrease_instances()) this->q->decrease_instances(); }); view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_MOVED, [this](SimpleEvent&) { update(); }); @@ -1273,7 +1274,6 @@ void Plater::priv::update(bool force_full_scene_refresh) #else this->canvas3D->reload_scene(false, force_full_scene_refresh); #endif // ENABLE_REMOVE_TABS_FROM_PLATER - preview->reset_gcode_preview_data(); preview->reload_print(); this->schedule_background_process(); @@ -2010,7 +2010,6 @@ unsigned int Plater::priv::update_background_process() this->sidebar->show_sliced_info_sizer(false); // Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared. // Otherwise they will be just refreshed. - this->gcode_preview_data.reset(); switch (this->printer_technology) { case ptFFF: if (this->preview != nullptr) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 0b59a21ab..5a212d4ee 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1551,7 +1551,7 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup) auto printhost_browse = [this, optgroup] (wxWindow* parent) { - // TODO: SLA + // TODO: SLA Bonjour auto btn = m_printhost_browse_btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT); btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("zoom.png")), wxBITMAP_TYPE_PNG)); @@ -1562,6 +1562,7 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup) BonjourDialog dialog(parent); if (dialog.show_and_lookup()) { optgroup->set_value("print_host", std::move(dialog.get_selected()), true); + // FIXME: emit killfocus on the edit widget } }); diff --git a/src/slic3r/Utils/Duet.hpp b/src/slic3r/Utils/Duet.hpp index 0608f85a5..d0f5b3009 100644 --- a/src/slic3r/Utils/Duet.hpp +++ b/src/slic3r/Utils/Duet.hpp @@ -19,12 +19,12 @@ public: Duet(DynamicPrintConfig *config); virtual ~Duet(); - bool test(wxString &curl_msg) const; - wxString get_test_ok_msg () const; - wxString get_test_failed_msg (wxString &msg) const; - bool upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn, Http::ErrorFn error_fn) const; - bool has_auto_discovery() const; - bool can_test() const; + virtual bool test(wxString &curl_msg) const; + virtual wxString get_test_ok_msg () const; + virtual wxString get_test_failed_msg (wxString &msg) const; + virtual bool upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn, Http::ErrorFn error_fn) const; + virtual bool has_auto_discovery() const; + virtual bool can_test() const; virtual std::string get_host() const { return host; } private: std::string host; diff --git a/src/slic3r/Utils/OctoPrint.cpp b/src/slic3r/Utils/OctoPrint.cpp index cbb81c54f..cf5fc2f54 100644 --- a/src/slic3r/Utils/OctoPrint.cpp +++ b/src/slic3r/Utils/OctoPrint.cpp @@ -1,8 +1,12 @@ #include "OctoPrint.hpp" #include +#include #include #include +#include +#include +#include #include @@ -12,6 +16,7 @@ namespace fs = boost::filesystem; +namespace pt = boost::property_tree; namespace Slic3r { @@ -41,11 +46,29 @@ bool OctoPrint::test(wxString &msg) const res = false; msg = format_error(body, error, status); }) - .on_complete([&](std::string body, unsigned) { + .on_complete([&, this](std::string body, unsigned) { BOOST_LOG_TRIVIAL(debug) << boost::format("Octoprint: Got version: %1%") % body; - // TODO: parse body, call validate_version_text + try { + std::stringstream ss(body); + pt::ptree ptree; + pt::read_json(ss, ptree); + if (! ptree.get_optional("api")) { + res = false; + return; + } + + const auto text = ptree.get_optional("text"); + res = validate_version_text(text); + if (! res) { + msg = wxString::Format("Mismatched type of print host: %s", text ? *text : "OctoPrint"); + } + } + catch (...) { + res = false; + msg = "Could not parse server response"; + } }) .perform_sync(); @@ -71,7 +94,7 @@ bool OctoPrint::upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn wxString test_msg; if (! test(test_msg)) { - // TODO: + // FIXME: // auto errormsg = wxString::Format("%s: %s", errortitle, test_msg); // GUI::show_error(&progress_dialog, std::move(errormsg)); @@ -125,10 +148,9 @@ bool OctoPrint::can_test() const return true; } -bool OctoPrint::validate_version_text(const std::string &version_text) +bool OctoPrint::validate_version_text(const boost::optional &version_text) const { - // FIXME - return true; + return version_text ? boost::starts_with(*version_text, "OctoPrint") : true; } void OctoPrint::set_auth(Http &http) const @@ -164,14 +186,23 @@ wxString OctoPrint::format_error(const std::string &body, const std::string &err } -// SL1 +// SLAHost -SL1Host::~SL1Host() {} +SLAHost::~SLAHost() {} -bool SL1Host::validate_version_text(const std::string &version_text) +wxString SLAHost::get_test_ok_msg () const { - // FIXME - return true; + return wxString::Format("%s", _(L("Connection to Prusa SLA works correctly."))); +} + +wxString SLAHost::get_test_failed_msg (wxString &msg) const +{ + return wxString::Format("%s: %s", _(L("Could not connect to Prusa SLA")), msg); +} + +bool SLAHost::validate_version_text(const boost::optional &version_text) const +{ + return version_text ? boost::starts_with(*version_text, "Prusa SLA") : false; } diff --git a/src/slic3r/Utils/OctoPrint.hpp b/src/slic3r/Utils/OctoPrint.hpp index 4d6555e13..57aae672a 100644 --- a/src/slic3r/Utils/OctoPrint.hpp +++ b/src/slic3r/Utils/OctoPrint.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "PrintHost.hpp" @@ -19,16 +20,16 @@ public: OctoPrint(DynamicPrintConfig *config); virtual ~OctoPrint(); - bool test(wxString &curl_msg) const; - wxString get_test_ok_msg () const; - wxString get_test_failed_msg (wxString &msg) const; - bool upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn, Http::ErrorFn error_fn) const; - bool has_auto_discovery() const; - bool can_test() const; + virtual bool test(wxString &curl_msg) const; + virtual wxString get_test_ok_msg () const; + virtual wxString get_test_failed_msg (wxString &msg) const; + virtual bool upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn, Http::ErrorFn error_fn) const; + virtual bool has_auto_discovery() const; + virtual bool can_test() const; virtual std::string get_host() const { return host; } protected: - virtual bool validate_version_text(const std::string &version_text); + virtual bool validate_version_text(const boost::optional &version_text) const; private: std::string host; @@ -41,14 +42,16 @@ private: }; -class SL1Host: public OctoPrint +class SLAHost: public OctoPrint { public: - SL1Host(DynamicPrintConfig *config) : OctoPrint(config) {} - virtual ~SL1Host(); + SLAHost(DynamicPrintConfig *config) : OctoPrint(config) {} + virtual ~SLAHost(); + virtual wxString get_test_ok_msg () const; + virtual wxString get_test_failed_msg (wxString &msg) const; protected: - virtual bool validate_version_text(const std::string &version_text); + virtual bool validate_version_text(const boost::optional &version_text) const; }; diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index cdd0c107e..5c4507816 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -30,8 +30,8 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config) switch (opt->value) { case htOctoPrint: return new OctoPrint(config); - case htSL1: return new SL1Host(config); case htDuet: return new Duet(config); + case htSL1: return new SLAHost(config); default: return nullptr; } }