diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp
index d04bc97fa..255afc631 100644
--- a/src/libslic3r/Technologies.hpp
+++ b/src/libslic3r/Technologies.hpp
@@ -59,7 +59,7 @@
 // Enable G-Code viewer
 #define ENABLE_GCODE_VIEWER (1 && ENABLE_2_3_0_ALPHA1)
 #define ENABLE_GCODE_VIEWER_DEBUG_OUTPUT (0 && ENABLE_GCODE_VIEWER)
-#define ENABLE_GCODE_VIEWER_STATISTICS (0 && ENABLE_2_3_0_ALPHA1)
+#define ENABLE_GCODE_VIEWER_STATISTICS (0 && ENABLE_GCODE_VIEWER)
 
 
 #endif // _prusaslicer_technologies_h_
diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp
index 7426eafc9..71053819d 100644
--- a/src/slic3r/GUI/GCodeViewer.cpp
+++ b/src/slic3r/GUI/GCodeViewer.cpp
@@ -271,10 +271,29 @@ void GCodeViewer::set_toolpath_move_type_visible(GCodeProcessor::EMoveType type,
         m_buffers[id].visible = visible;
 }
 
+unsigned int GCodeViewer::get_options_visibility_flags() const
+{
+    auto set_flag = [](unsigned int flags, unsigned int flag, bool active) {
+        return active ? (flags | (1 << flag)) : flags;
+    };
+
+    unsigned int flags = 0;
+    flags = set_flag(flags, 0, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Travel));
+    flags = set_flag(flags, 1, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Retract));
+    flags = set_flag(flags, 2, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Unretract));
+    flags = set_flag(flags, 3, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Tool_change));
+    flags = set_flag(flags, 4, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Color_change));
+    flags = set_flag(flags, 5, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Pause_Print));
+    flags = set_flag(flags, 6, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Custom_GCode));
+    flags = set_flag(flags, 7, m_shells.visible);
+    flags = set_flag(flags, 8, is_legend_enabled());
+    return flags;
+}
+
 void GCodeViewer::set_options_visibility_from_flags(unsigned int flags)
 {
     auto is_flag_set = [flags](unsigned int flag) {
-        return (flags& (1 << flag)) != 0;
+        return (flags & (1 << flag)) != 0;
     };
 
     set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Travel, is_flag_set(0));
@@ -752,7 +771,7 @@ void GCodeViewer::render_legend() const
 
     ImDrawList* draw_list = ImGui::GetWindowDrawList();
 
-    auto add_item = [draw_list, &imgui](const std::array<float, 3>& color, const std::string& label) {
+    auto add_item = [draw_list, &imgui](const std::array<float, 3>& color, const std::string& label, std::function<void()> callback = nullptr) {
         float icon_size = ImGui::GetTextLineHeight();
         ImVec2 pos = ImGui::GetCursorPos();
         draw_list->AddRect({ pos.x, pos.y }, { pos.x + icon_size, pos.y + icon_size }, ICON_BORDER_COLOR, 0.0f, 0);
@@ -762,7 +781,13 @@ void GCodeViewer::render_legend() const
         // draw text
         ImGui::Dummy({ icon_size, icon_size });
         ImGui::SameLine();
-        imgui.text(label);
+        if (callback != nullptr)
+        {
+            if (ImGui::MenuItem(label.c_str()))
+                callback();
+        }
+        else
+            imgui.text(label);
     };
 
     auto add_range = [this, draw_list, &imgui, add_item](const Extrusions::Range& range, unsigned int decimals) {
@@ -811,7 +836,15 @@ void GCodeViewer::render_legend() const
             if (!visible)
                 ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.3333f);
 
-            add_item(Extrusion_Role_Colors[static_cast<unsigned int>(role)], I18N::translate_utf8(ExtrusionEntity::role_to_string(role)));
+            add_item(Extrusion_Role_Colors[static_cast<unsigned int>(role)], I18N::translate_utf8(ExtrusionEntity::role_to_string(role)), [this, role]() {
+                if (role < erCount)
+                {
+                    m_extrusions.role_visibility_flags = is_visible(role) ? m_extrusions.role_visibility_flags & ~(1 << role) : m_extrusions.role_visibility_flags | (1 << role);
+                    wxGetApp().plater()->get_current_canvas3D()->set_as_dirty();
+                    wxGetApp().plater()->update_preview_bottom_toolbar();
+                }
+                });
+
             if (!visible)
                 ImGui::PopStyleVar();
         }
diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp
index be239e20c..a8816f7a1 100644
--- a/src/slic3r/GUI/GCodeViewer.hpp
+++ b/src/slic3r/GUI/GCodeViewer.hpp
@@ -189,7 +189,7 @@ private:
     std::array<double, 2> m_layers_z_range;
     std::vector<ExtrusionRole> m_roles;
     std::vector<unsigned char> m_extruder_ids;
-    Extrusions m_extrusions;
+    mutable Extrusions m_extrusions;
     Shells m_shells;
     EViewType m_view_type{ EViewType::FeatureType };
     bool m_legend_enabled{ true };
@@ -227,7 +227,9 @@ public:
 
     bool is_toolpath_move_type_visible(GCodeProcessor::EMoveType type) const;
     void set_toolpath_move_type_visible(GCodeProcessor::EMoveType type, bool visible);
+    unsigned int get_toolpath_role_visibility_flags() const { return m_extrusions.role_visibility_flags; }
     void set_toolpath_role_visibility_flags(unsigned int flags) { m_extrusions.role_visibility_flags = flags; }
+    unsigned int get_options_visibility_flags() const;
     void set_options_visibility_from_flags(unsigned int flags);
     void set_layers_z_range(const std::array<double, 2>& layers_z_range) { m_layers_z_range = layers_z_range; }
 
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index 152658b13..bbe53c5cd 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -646,8 +646,11 @@ public:
     void ensure_on_bed(unsigned int object_idx);
 
 #if ENABLE_GCODE_VIEWER
+    GCodeViewer::EViewType get_gcode_view_type() const { return m_gcode_viewer.get_view_type(); }
     const std::vector<double>& get_layers_zs() const;
+    unsigned int get_gcode_options_visibility_flags() const { return m_gcode_viewer.get_options_visibility_flags(); }
     void set_gcode_options_visibility_from_flags(unsigned int flags);
+    unsigned int get_toolpath_role_visibility_flags() const { return m_gcode_viewer.get_toolpath_role_visibility_flags(); }
     void set_toolpath_role_visibility_flags(unsigned int flags);
     void set_toolpath_view_type(GCodeViewer::EViewType type);
     void set_toolpaths_z_range(const std::array<double, 2>& range);
diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp
index a66396b27..ebdc51c6b 100644
--- a/src/slic3r/GUI/GUI.cpp
+++ b/src/slic3r/GUI/GUI.cpp
@@ -301,21 +301,33 @@ void create_combochecklist(wxComboCtrl* comboCtrl, const std::string& text, cons
 	}
 }
 
-int combochecklist_get_flags(wxComboCtrl* comboCtrl)
+unsigned int combochecklist_get_flags(wxComboCtrl* comboCtrl)
 {
-    int flags = 0;
+	unsigned int flags = 0;
 
-    wxCheckListBoxComboPopup* popup = wxDynamicCast(comboCtrl->GetPopupControl(), wxCheckListBoxComboPopup);
-    if (popup != nullptr)
-    {
-        for (unsigned int i = 0; i < popup->GetCount(); ++i)
-        {
-            if (popup->IsChecked(i))
-                flags |= 1 << i;
-        }
-    }
+	wxCheckListBoxComboPopup* popup = wxDynamicCast(comboCtrl->GetPopupControl(), wxCheckListBoxComboPopup);
+	if (popup != nullptr)
+	{
+		for (unsigned int i = 0; i < popup->GetCount(); ++i)
+		{
+			if (popup->IsChecked(i))
+				flags |= 1 << i;
+		}
+	}
 
-    return flags;
+	return flags;
+}
+
+void combochecklist_set_flags(wxComboCtrl* comboCtrl, unsigned int flags)
+{
+	wxCheckListBoxComboPopup* popup = wxDynamicCast(comboCtrl->GetPopupControl(), wxCheckListBoxComboPopup);
+	if (popup != nullptr)
+	{
+		for (unsigned int i = 0; i < popup->GetCount(); ++i)
+		{
+			popup->Check(i, (flags & (1 << i)) != 0);
+		}
+	}
 }
 
 AppConfig* get_app_config()
diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp
index 6690b2120..cf133971e 100644
--- a/src/slic3r/GUI/GUI.hpp
+++ b/src/slic3r/GUI/GUI.hpp
@@ -54,8 +54,12 @@ void warning_catcher(wxWindow* parent, const wxString& message);
 void create_combochecklist(wxComboCtrl* comboCtrl, const std::string& text, const std::string& items);
 
 // Returns the current state of the items listed in the wxCheckListBoxComboPopup contained in the given wxComboCtrl,
-// encoded inside an int.
-int combochecklist_get_flags(wxComboCtrl* comboCtrl);
+// encoded inside an unsigned int.
+unsigned int combochecklist_get_flags(wxComboCtrl* comboCtrl);
+
+// Sets the current state of the items listed in the wxCheckListBoxComboPopup contained in the given wxComboCtrl,
+// with the flags encoded in the given unsigned int.
+void combochecklist_set_flags(wxComboCtrl* comboCtrl, unsigned int flags);
 
 // wxString conversions:
 
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index 3e0d5cd5a..e84d1a9d5 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -222,6 +222,9 @@ Preview::Preview(
     : m_canvas_widget(nullptr)
     , m_canvas(nullptr)
     , m_double_slider_sizer(nullptr)
+#if ENABLE_GCODE_VIEWER
+    , m_bottom_toolbar_sizer(nullptr)
+#endif // ENABLE_GCODE_VIEWER
     , m_label_view_type(nullptr)
     , m_choice_view_type(nullptr)
     , m_label_show(nullptr)
@@ -256,7 +259,9 @@ Preview::Preview(
     if (init(parent, bed, camera, view_toolbar, model))
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
     {
+#if !ENABLE_GCODE_VIEWER
         show_hide_ui_elements("none");
+#endif // !ENABLE_GCODE_VIEWER
         load_print();
     }
 }
@@ -358,15 +363,21 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view
     top_sizer->Add(m_canvas_widget, 1, wxALL | wxEXPAND, 0);
     top_sizer->Add(m_double_slider_sizer, 0, wxEXPAND, 0);
 
+#if ENABLE_GCODE_VIEWER
+    m_bottom_toolbar_sizer = new wxBoxSizer(wxHORIZONTAL);
+    m_bottom_toolbar_sizer->Add(m_label_view_type, 0, wxALIGN_CENTER_VERTICAL, 5);
+    m_bottom_toolbar_sizer->Add(m_choice_view_type, 0, wxEXPAND | wxALL, 5);
+    m_bottom_toolbar_sizer->AddSpacer(10);
+    m_bottom_toolbar_sizer->Add(m_label_show, 0, wxALIGN_CENTER_VERTICAL, 5);
+    m_bottom_toolbar_sizer->Add(m_combochecklist_features, 0, wxEXPAND | wxALL, 5);
+    m_bottom_toolbar_sizer->Add(m_combochecklist_options, 0, wxEXPAND | wxALL, 5);
+#else
     wxBoxSizer* bottom_sizer = new wxBoxSizer(wxHORIZONTAL);
     bottom_sizer->Add(m_label_view_type, 0, wxALIGN_CENTER_VERTICAL, 5);
     bottom_sizer->Add(m_choice_view_type, 0, wxEXPAND | wxALL, 5);
     bottom_sizer->AddSpacer(10);
     bottom_sizer->Add(m_label_show, 0, wxALIGN_CENTER_VERTICAL, 5);
     bottom_sizer->Add(m_combochecklist_features, 0, wxEXPAND | wxALL, 5);
-#if ENABLE_GCODE_VIEWER
-    bottom_sizer->Add(m_combochecklist_options, 0, wxEXPAND | wxALL, 5);
-#else
     bottom_sizer->AddSpacer(20);
     bottom_sizer->Add(m_checkbox_travel, 0, wxEXPAND | wxALL, 5);
     bottom_sizer->AddSpacer(10);
@@ -381,8 +392,12 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view
 
     wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
     main_sizer->Add(top_sizer, 1, wxALL | wxEXPAND, 0);
+#if ENABLE_GCODE_VIEWER
+    main_sizer->Add(m_bottom_toolbar_sizer, 0, wxALL | wxEXPAND, 0);
+    main_sizer->Hide(m_bottom_toolbar_sizer);
+#else
     main_sizer->Add(bottom_sizer, 0, wxALL | wxEXPAND, 0);
-
+#endif // ENABLE_GCODE_VIEWER
     SetSizer(main_sizer);
     SetMinSize(GetSize());
     GetSizer()->SetSizeHints(this);
@@ -480,6 +495,9 @@ void Preview::load_print(bool keep_z_range)
     else if (tech == ptSLA)
         load_print_as_sla();
 
+#if ENABLE_GCODE_VIEWER
+    update_bottom_toolbar();
+#endif // ENABLE_GCODE_VIEWER
     Layout();
 }
 
@@ -581,6 +599,7 @@ void Preview::unbind_event_handlers()
 #endif // ENABLE_GCODE_VIEWER
 }
 
+#if !ENABLE_GCODE_VIEWER
 void Preview::show_hide_ui_elements(const std::string& what)
 {
     bool enable = (what == "full");
@@ -615,6 +634,7 @@ void Preview::show_hide_ui_elements(const std::string& what)
     m_label_view_type->Show(visible);
     m_choice_view_type->Show(visible);
 }
+#endif // !ENABLE_GCODE_VIEWER
 
 void Preview::reset_sliders(bool reset_all)
 {
@@ -661,11 +681,11 @@ void Preview::on_choice_view_type(wxCommandEvent& evt)
 
 void Preview::on_combochecklist_features(wxCommandEvent& evt)
 {
-    int flags = Slic3r::GUI::combochecklist_get_flags(m_combochecklist_features);
+    unsigned int flags = Slic3r::GUI::combochecklist_get_flags(m_combochecklist_features);
 #if ENABLE_GCODE_VIEWER
-    m_canvas->set_toolpath_role_visibility_flags(static_cast<unsigned int>(flags));
+    m_canvas->set_toolpath_role_visibility_flags(flags);
 #else
-    m_gcode_preview_data->extrusion.role_flags = (unsigned int)flags;
+    m_gcode_preview_data->extrusion.role_flags = flags;
 #endif // ENABLE_GCODE_VIEWER
     refresh_print();
 }
@@ -673,7 +693,7 @@ void Preview::on_combochecklist_features(wxCommandEvent& evt)
 #if ENABLE_GCODE_VIEWER
 void Preview::on_combochecklist_options(wxCommandEvent& evt)
 {
-    m_canvas->set_gcode_options_visibility_from_flags(static_cast<unsigned int>(Slic3r::GUI::combochecklist_get_flags(m_combochecklist_options)));
+    m_canvas->set_gcode_options_visibility_from_flags(Slic3r::GUI::combochecklist_get_flags(m_combochecklist_options));
     refresh_print();
 }
 #else
@@ -730,6 +750,17 @@ void Preview::update_view_type(bool slice_completed)
     }
 }
 
+#if ENABLE_GCODE_VIEWER
+void Preview::update_bottom_toolbar()
+{
+    combochecklist_set_flags(m_combochecklist_features, m_canvas->get_toolpath_role_visibility_flags());
+    combochecklist_set_flags(m_combochecklist_options, m_canvas->get_gcode_options_visibility_flags());
+
+    m_bottom_toolbar_sizer->Show(m_combochecklist_features, m_canvas->get_gcode_view_type() != GCodeViewer::EViewType::FeatureType);
+    m_bottom_toolbar_sizer->Layout();
+}
+#endif // ENABLE_GCODE_VIEWER
+
 void Preview::create_double_slider()
 {
     m_slider = new DoubleSlider::Control(this, wxID_ANY, 0, 0, 0, 100);
@@ -1039,7 +1070,8 @@ void Preview::load_print_as_fff(bool keep_z_range)
 #if ENABLE_GCODE_VIEWER
             m_canvas->load_gcode_preview(*m_gcode_result);
             m_canvas->refresh_gcode_preview(*m_gcode_result, colors);
-            show_hide_ui_elements(gcode_preview_data_valid ? "full" : "simple");
+            GetSizer()->Show(m_bottom_toolbar_sizer);
+            GetSizer()->Layout();
 #else
             m_canvas->load_gcode_preview(*m_gcode_preview_data, colors);
 #endif // ENABLE_GCODE_VIEWER
@@ -1048,7 +1080,8 @@ void Preview::load_print_as_fff(bool keep_z_range)
             // Load the initial preview based on slices, not the final G-code.
             m_canvas->load_preview(colors, color_print_values);
 #if ENABLE_GCODE_VIEWER
-            show_hide_ui_elements("none");
+            GetSizer()->Hide(m_bottom_toolbar_sizer);
+            GetSizer()->Layout();
 #endif // ENABLE_GCODE_VIEWER
         }
 #if ENABLE_GCODE_VIEWER
@@ -1097,7 +1130,12 @@ void Preview::load_print_as_sla()
     if (IsShown())
     {
         m_canvas->load_sla_preview();
+#if ENABLE_GCODE_VIEWER
+        GetSizer()->Hide(m_bottom_toolbar_sizer);
+        GetSizer()->Layout();
+#else
         show_hide_ui_elements("none");
+#endif // ENABLE_GCODE_VIEWER
 
         if (n_layers > 0)
             update_sliders(zs);
@@ -1132,6 +1170,5 @@ void Preview::on_sliders_scroll_changed(wxCommandEvent& event)
     }
 }
 
-
 } // namespace GUI
 } // namespace Slic3r
diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp
index c4ad4eb79..a7db054bc 100644
--- a/src/slic3r/GUI/GUI_Preview.hpp
+++ b/src/slic3r/GUI/GUI_Preview.hpp
@@ -91,6 +91,9 @@ class Preview : public wxPanel
     wxGLCanvas* m_canvas_widget;
     GLCanvas3D* m_canvas;
     wxBoxSizer* m_double_slider_sizer;
+#if ENABLE_GCODE_VIEWER
+    wxBoxSizer* m_bottom_toolbar_sizer;
+#endif // ENABLE_GCODE_VIEWER
     wxStaticText* m_label_view_type;
     wxChoice* m_choice_view_type;
     wxStaticText* m_label_show;
@@ -172,6 +175,10 @@ public:
 
     bool is_loaded() const { return m_loaded; }
 
+#if ENABLE_GCODE_VIEWER
+    void update_bottom_toolbar();
+#endif // ENABLE_GCODE_VIEWER
+
 private:
 #if ENABLE_NON_STATIC_CANVAS_MANAGER
     bool init(wxWindow* parent, Model* model);
@@ -182,7 +189,9 @@ private:
     void bind_event_handlers();
     void unbind_event_handlers();
 
+#if !ENABLE_GCODE_VIEWER
     void show_hide_ui_elements(const std::string& what);
+#endif // !ENABLE_GCODE_VIEWER
 
     void reset_sliders(bool reset_all);
     void update_sliders(const std::vector<double>& layers_z, bool keep_z_range = false);
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index b64f705dd..861e0e55f 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -1570,6 +1570,9 @@ struct Plater::priv
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
     bool init_view_toolbar();
+#if ENABLE_GCODE_VIEWER
+    void update_preview_bottom_toolbar();
+#endif // ENABLE_GCODE_VIEWER
 
     void reset_all_gizmos();
     void update_ui_from_settings();
@@ -3765,6 +3768,13 @@ bool Plater::priv::init_view_toolbar()
     return true;
 }
 
+#if ENABLE_GCODE_VIEWER
+void Plater::priv::update_preview_bottom_toolbar()
+{
+    preview->update_bottom_toolbar();
+}
+#endif // ENABLE_GCODE_VIEWER
+
 bool Plater::priv::can_set_instance_to_object() const
 {
     const int obj_idx = get_selected_object_idx();
@@ -5313,6 +5323,13 @@ GLToolbar& Plater::get_view_toolbar()
 }
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
+#if ENABLE_GCODE_VIEWER
+void Plater::update_preview_bottom_toolbar()
+{
+    p->update_preview_bottom_toolbar();
+}
+#endif // ENABLE_GCODE_VIEWER
+
 const Mouse3DController& Plater::get_mouse3d_controller() const
 {
     return p->mouse3d_controller;
diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp
index 2ac4f23c1..f4ca22578 100644
--- a/src/slic3r/GUI/Plater.hpp
+++ b/src/slic3r/GUI/Plater.hpp
@@ -310,6 +310,10 @@ public:
     GLToolbar& get_view_toolbar();
 #endif // ENABLE_NON_STATIC_CANVAS_MANAGER
 
+#if ENABLE_GCODE_VIEWER
+    void update_preview_bottom_toolbar();
+#endif // ENABLE_GCODE_VIEWER
+
     const Mouse3DController& get_mouse3d_controller() const;
     Mouse3DController& get_mouse3d_controller();