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/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, &current_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<Vec3crd> 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 62fd8730e..22b80d627 100644
--- a/src/slic3r/GUI/3DScene.hpp
+++ b/src/slic3r/GUI/3DScene.hpp
@@ -582,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/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index e01e1dbbe..7facc3623 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;
@@ -2055,6 +2074,50 @@ 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
+
 void GLCanvas3D::Selection::_update_valid()
 {
     m_valid = (m_volumes != nullptr) && (m_model != nullptr);
@@ -2457,6 +2520,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<unsigned int> done;  // prevent processing volumes twice
@@ -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<int>);
 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<int>());
 
+#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<int>(EVT_GLCANVAS_INCREASE_INSTANCES, +1)); break; }
                 // key -
                 case 45: { post_event(Event<int>(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 7dd8c54a0..54e546c78 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -106,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<int>); // data: +1 => increase, -1 => decrease
 wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent);
 wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent);
@@ -368,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<unsigned int> IndicesList;
 
@@ -495,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();
@@ -503,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);
@@ -580,6 +593,9 @@ 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
 
     private:
         void _update_valid();
@@ -595,6 +611,16 @@ 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
@@ -1055,6 +1081,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/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index e4db9b6e1..88c77c193 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<void()> cb,
     //                       wxMessageDialog* message_dialog,
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<void()> cb,
diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp
new file mode 100644
index 000000000..87010f081
--- /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 <wx/scrolwin.h>
+
+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);
+    const 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 <wx/wx.h>
+#include <map>
+
+namespace Slic3r { 
+namespace GUI {
+
+class KBShortcutsDialog : public wxDialog
+{
+    typedef std::pair<std::string, std::string> Shortcut;
+    typedef std::vector< Shortcut >             Shortcuts;
+    typedef std::map<wxString, Shortcuts>       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 c3f0565c8..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<int> &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(); });