diff --git a/resources/icons/attention.svg b/resources/icons/attention.svg
new file mode 100644
index 000000000..934bd3b41
--- /dev/null
+++ b/resources/icons/attention.svg
@@ -0,0 +1,12 @@
+
+
+
diff --git a/resources/icons/collapse.svg b/resources/icons/collapse.svg
new file mode 100644
index 000000000..c0d6f43d5
--- /dev/null
+++ b/resources/icons/collapse.svg
@@ -0,0 +1,16 @@
+
+
+
diff --git a/resources/icons/search.svg b/resources/icons/search.svg
new file mode 100644
index 000000000..6421c7e05
--- /dev/null
+++ b/resources/icons/search.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/resources/icons/search_.svg b/resources/icons/search_.svg
new file mode 100644
index 000000000..679bb30f7
--- /dev/null
+++ b/resources/icons/search_.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/resources/icons/search_gray.svg b/resources/icons/search_gray.svg
new file mode 100644
index 000000000..043c2e3b2
--- /dev/null
+++ b/resources/icons/search_gray.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h
index 09bfd16c9..c425bbef2 100644
--- a/src/imgui/imconfig.h
+++ b/src/imgui/imconfig.h
@@ -97,9 +97,17 @@
//#define IMGUI_DEBUG_PARANOID
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
-/*
+
namespace ImGui
{
- void MyFunction(const char* name, const MyMatrix44& v);
+ // Special ASCII character is used here as markup symbols for tokens to be highlighted as a for hovered item
+ const char ColorMarkerHovered = 0x1; // STX
+
+ // Special ASCII characters STX and ETX are used here as markup symbols for tokens to be highlighted.
+ const char ColorMarkerStart = 0x2; // STX
+ const char ColorMarkerEnd = 0x3; // ETX
+
+// void MyFunction(const char* name, const MyMatrix44& v);
+
}
-*/
+
diff --git a/src/imgui/imgui_draw.cpp b/src/imgui/imgui_draw.cpp
index 4bb91ccfe..4e6f1374b 100644
--- a/src/imgui/imgui_draw.cpp
+++ b/src/imgui/imgui_draw.cpp
@@ -33,6 +33,7 @@ Index of this file:
#define IMGUI_DEFINE_MATH_OPERATORS
#endif
#include "imgui_internal.h"
+#include "imconfig.h"
#include // vsnprintf, sscanf, printf
#if !defined(alloca)
@@ -2991,6 +2992,15 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx;
+ ImU32 defaultCol = col;
+ ImU32 highlighCol = ImGui::GetColorU32(ImGuiCol_ButtonHovered);
+
+ // if text is started with ColorMarkerHovered symbol, we should use another color for a highlighting
+ if (*s == ImGui::ColorMarkerHovered) {
+ highlighCol = ImGui::GetColorU32(ImGuiCol_FrameBg);
+ s += 1;
+ }
+
while (s < text_end)
{
if (word_wrap_enabled)
@@ -3019,6 +3029,17 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
}
}
+ if (*s == ImGui::ColorMarkerStart) {
+ col = highlighCol;
+ s += 1;
+ }
+ else if (*s == ImGui::ColorMarkerEnd) {
+ col = defaultCol;
+ s += 1;
+ if (s == text_end)
+ break;
+ }
+
// Decode and advance source
unsigned int c = (unsigned int)*s;
if (c < 0x80)
diff --git a/src/libslic3r/Arrange.hpp b/src/libslic3r/Arrange.hpp
index 352e9e1cf..8ff1e37a9 100644
--- a/src/libslic3r/Arrange.hpp
+++ b/src/libslic3r/Arrange.hpp
@@ -67,7 +67,7 @@ struct ArrangeParams {
/// The minimum distance which is allowed for any
/// pair of items on the print bed in any direction.
- coord_t min_obj_distance = 0.;
+ coord_t min_obj_distance = 0;
/// The accuracy of optimization.
/// Goes from 0.0 to 1.0 and scales performance as well
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index 43c83fe2b..1f0a6c3ae 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -149,6 +149,7 @@ void PrintConfigDef::init_fff_params()
def->label = L("Other layers");
def->tooltip = L("Bed temperature for layers after the first one. "
"Set this to zero to disable bed temperature control commands in the output.");
+ def->sidetext = L("°C");
def->full_label = L("Bed temperature");
def->min = 0;
def->max = 300;
@@ -873,8 +874,10 @@ void PrintConfigDef::init_fff_params()
def = this->add("first_layer_bed_temperature", coInts);
def->label = L("First layer");
+ def->full_label = L("First layer bed temperature");
def->tooltip = L("Heated build plate temperature for the first layer. Set this to zero to disable "
"bed temperature control commands in the output.");
+ def->sidetext = L("°C");
def->max = 0;
def->max = 300;
def->set_default_value(new ConfigOptionInts { 0 });
@@ -915,8 +918,10 @@ void PrintConfigDef::init_fff_params()
def = this->add("first_layer_temperature", coInts);
def->label = L("First layer");
+ def->full_label = L("First layer extruder temperature");
def->tooltip = L("Extruder temperature for first layer. If you want to control temperature manually "
"during print, set this to zero to disable temperature control commands in the output file.");
+ def->sidetext = L("°C");
def->min = 0;
def->max = max_temp;
def->set_default_value(new ConfigOptionInts { 200 });
@@ -2125,7 +2130,8 @@ void PrintConfigDef::init_fff_params()
def->label = L("Other layers");
def->tooltip = L("Extruder temperature for layers after the first one. Set this to zero to disable "
"temperature control commands in the output.");
- def->full_label = L("Temperature");
+ def->sidetext = L("°C");
+ def->full_label = L("Extruder temperature");
def->min = 0;
def->max = max_temp;
def->set_default_value(new ConfigOptionInts { 200 });
diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt
index 1ace0902c..c33a0af59 100644
--- a/src/slic3r/CMakeLists.txt
+++ b/src/slic3r/CMakeLists.txt
@@ -165,6 +165,8 @@ set(SLIC3R_GUI_SOURCES
GUI/ObjectDataViewModel.hpp
GUI/InstanceCheck.cpp
GUI/InstanceCheck.hpp
+ GUI/Search.cpp
+ GUI/Search.hpp
Utils/Http.cpp
Utils/Http.hpp
Utils/FixModelByWin10.cpp
diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp
index 505c2eb2a..92f8d1fdb 100644
--- a/src/slic3r/GUI/AboutDialog.cpp
+++ b/src/slic3r/GUI/AboutDialog.cpp
@@ -115,7 +115,9 @@ void CopyrightsDialog::fill_entries()
{ "Icons for STL and GCODE files."
, "Akira Yasuda" , "http://3dp0.com/icons-for-stl-and-gcode/" },
{ "AppImage packaging for Linux using AppImageKit"
- , "2004-2019 Simon Peter and contributors" , "https://appimage.org/" }
+ , "2004-2019 Simon Peter and contributors" , "https://appimage.org/" },
+ { "lib_fts"
+ , "Forrest Smith" , "https://www.forrestthewoods.com/" }
};
}
diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp
index 68193f84d..16d3f4123 100644
--- a/src/slic3r/GUI/Field.cpp
+++ b/src/slic3r/GUI/Field.cpp
@@ -57,6 +57,8 @@ void Field::PostInitialize()
m_Undo_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent) { on_back_to_initial_value(); }));
m_Undo_to_sys_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent) { on_back_to_sys_value(); }));
+ m_blinking_bmp = new BlinkingBitmap(m_parent);
+
switch (m_opt.type)
{
case coPercents:
diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp
index 5bdbfadc8..f41e3c7b0 100644
--- a/src/slic3r/GUI/Field.hpp
+++ b/src/slic3r/GUI/Field.hpp
@@ -230,6 +230,8 @@ public:
static int def_width_wider() ;
static int def_width_thinner() ;
+ BlinkingBitmap* blinking_bitmap() const { return m_blinking_bmp;}
+
protected:
RevertButton* m_Undo_btn = nullptr;
// Bitmap and Tooltip text for m_Undo_btn. The wxButton will be updated only if the new wxBitmap pointer differs from the currently rendered one.
@@ -240,6 +242,8 @@ protected:
const ScalableBitmap* m_undo_to_sys_bitmap = nullptr;
const wxString* m_undo_to_sys_tooltip = nullptr;
+ BlinkingBitmap* m_blinking_bmp{ nullptr };
+
wxStaticText* m_Label = nullptr;
// Color for Label. The wxColour will be updated only if the new wxColour pointer differs from the currently rendered one.
const wxColour* m_label_color = nullptr;
@@ -461,6 +465,7 @@ public:
x_textctrl->Disable();
y_textctrl->Disable(); }
wxSizer* getSizer() override { return sizer; }
+ wxWindow* getWindow() override { return dynamic_cast(x_textctrl); }
};
class StaticText : public Field {
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 647994717..6881e86fd 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -1537,6 +1537,7 @@ wxDEFINE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
+wxDEFINE_EVENT(EVT_GLCANVAS_COLLAPSE_SIDEBAR, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event);
wxDEFINE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent);
@@ -1562,6 +1563,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
, m_main_toolbar(GLToolbar::Normal, "Top")
, m_undoredo_toolbar(GLToolbar::Normal, "Top")
+ , m_collapse_toolbar(GLToolbar::Normal, "Top")
, m_gizmos(*this)
, m_use_clipping_planes(false)
, m_sidebar_field("")
@@ -1981,6 +1983,11 @@ void GLCanvas3D::enable_undoredo_toolbar(bool enable)
m_undoredo_toolbar.set_enabled(enable);
}
+void GLCanvas3D::enable_collapse_toolbar(bool enable)
+{
+ m_collapse_toolbar.set_enabled(enable);
+}
+
void GLCanvas3D::enable_dynamic_background(bool enable)
{
m_dynamic_background_enabled = enable;
@@ -2213,6 +2220,9 @@ void GLCanvas3D::render()
tooltip = m_undoredo_toolbar.get_tooltip();
if (tooltip.empty())
+ tooltip = m_collapse_toolbar.get_tooltip();
+
+ if (tooltip.empty())
#if ENABLE_NON_STATIC_CANVAS_MANAGER
tooltip = wxGetApp().plater()->get_view_toolbar().get_tooltip();
#else
@@ -2251,6 +2261,9 @@ void GLCanvas3D::render()
if (tooltip.empty())
tooltip = m_undoredo_toolbar.get_tooltip();
+ if (tooltip.empty())
+ tooltip = m_collapse_toolbar.get_tooltip();
+
if (tooltip.empty())
tooltip = m_view_toolbar.get_tooltip();
@@ -3046,6 +3059,7 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
m_dirty |= m_main_toolbar.update_items_state();
m_dirty |= m_undoredo_toolbar.update_items_state();
+ m_dirty |= m_collapse_toolbar.update_items_state();
#if ENABLE_NON_STATIC_CANVAS_MANAGER
m_dirty |= wxGetApp().plater()->get_view_toolbar().update_items_state();
bool mouse3d_controller_applied = wxGetApp().plater()->get_mouse3d_controller().apply(wxGetApp().plater()->get_camera());
@@ -3085,7 +3099,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
return;
}
- if ((keyCode == WXK_ESCAPE) && _deactivate_undo_redo_toolbar_items())
+ if ((keyCode == WXK_ESCAPE) && (_deactivate_undo_redo_toolbar_items() || _deactivate_search_toolbar_item()))
return;
if (m_gizmos.on_char(evt))
@@ -3133,6 +3147,16 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
break;
+#ifdef __APPLE__
+ case 'f':
+ case 'F':
+#else /* __APPLE__ */
+ case WXK_CONTROL_F:
+#endif /* __APPLE__ */
+ _activate_search_toolbar_item();
+ break;
+
+
#ifdef __APPLE__
case 'y':
case 'Y':
@@ -3544,6 +3568,15 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt)
}
}
+ // If the Search window or Undo/Redo list is opened,
+ // update them according to the event
+ if (m_main_toolbar.is_item_pressed("search") ||
+ m_undoredo_toolbar.is_item_pressed("undo") ||
+ m_undoredo_toolbar.is_item_pressed("redo")) {
+ m_mouse_wheel = int((double)evt.GetWheelRotation() / (double)evt.GetWheelDelta());
+ return;
+ }
+
// Inform gizmos about the event so they have the opportunity to react.
if (m_gizmos.on_mouse_wheel(evt))
return;
@@ -3679,6 +3712,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
return;
}
+ if (m_collapse_toolbar.on_mouse(evt, *this))
+ {
+ if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
+ mouse_up_cleanup();
+ m_mouse.set_start_position_3D_as_invalid();
+ return;
+ }
+
#if ENABLE_NON_STATIC_CANVAS_MANAGER
if (wxGetApp().plater()->get_view_toolbar().on_mouse(evt, *this))
#else
@@ -3744,6 +3785,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
else if (evt.Leaving())
{
_deactivate_undo_redo_toolbar_items();
+ _deactivate_search_toolbar_item();
// to remove hover on objects when the mouse goes out of this canvas
m_mouse.position = Vec2d(-1.0, -1.0);
@@ -3751,7 +3793,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
else if (evt.LeftDown() || evt.RightDown() || evt.MiddleDown())
{
- if (_deactivate_undo_redo_toolbar_items())
+ if (_deactivate_undo_redo_toolbar_items() || _deactivate_search_toolbar_item())
return;
// If user pressed left or right button we first check whether this happened
@@ -4548,7 +4590,7 @@ bool GLCanvas3D::_render_undo_redo_stack(const bool is_undo, float pos_x) const
em *= m_retina_helper->get_scale_factor();
#endif
- if (imgui->undo_redo_list(ImVec2(18 * em, 26 * em), is_undo, &string_getter, hovered, selected))
+ if (imgui->undo_redo_list(ImVec2(18 * em, 26 * em), is_undo, &string_getter, hovered, selected, m_mouse_wheel))
m_imgui_undo_redo_hovered_pos = hovered;
else
m_imgui_undo_redo_hovered_pos = -1;
@@ -4566,6 +4608,64 @@ bool GLCanvas3D::_render_undo_redo_stack(const bool is_undo, float pos_x) const
return action_taken;
}
+// Getter for the const char*[] for the search list
+static bool search_string_getter(int idx, const char** label, const char** tooltip)
+{
+ return wxGetApp().plater()->search_string_getter(idx, label, tooltip);
+}
+
+bool GLCanvas3D::_render_search_list(float pos_x) const
+{
+ bool action_taken = false;
+ ImGuiWrapper* imgui = wxGetApp().imgui();
+
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+ const float x = pos_x * (float)wxGetApp().plater()->get_camera().get_zoom() + 0.5f * (float)get_canvas_size().get_width();
+#else
+ const float x = pos_x * (float)get_camera().get_zoom() + 0.5f * (float)get_canvas_size().get_width();
+#endif
+ imgui->set_next_window_pos(x, m_main_toolbar.get_height(), ImGuiCond_Always, 0.5f, 0.0f);
+ std::string title = L("Search");
+ imgui->begin(_(title), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
+
+ int selected = -1;
+ bool edited = false;
+ bool check_changed = false;
+ float em = static_cast(wxGetApp().em_unit());
+#if ENABLE_RETINA_GL
+ em *= m_retina_helper->get_scale_factor();
+#endif
+
+ Sidebar& sidebar = wxGetApp().sidebar();
+
+ std::string& search_line = sidebar.get_search_line();
+ char *s = new char[255];
+ strcpy(s, search_line.empty() ? _u8L("Type here to search").c_str() : search_line.c_str());
+
+ imgui->search_list(ImVec2(45 * em, 30 * em), &search_string_getter, s,
+ sidebar.get_searcher().view_params,
+ selected, edited, m_mouse_wheel);
+
+ search_line = s;
+ delete [] s;
+ if (search_line == _u8L("Type here to search"))
+ search_line.clear();
+
+ if (edited)
+ sidebar.search();
+
+ if (selected != size_t(-1)) {
+ // selected == 9999 means that Esc kye was pressed
+ if (selected != 9999)
+ sidebar.jump_to_option(selected);
+ action_taken = true;
+ }
+
+ imgui->end();
+
+ return action_taken;
+}
+
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT 0
#if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
static void debug_output_thumbnail(const ThumbnailData& thumbnail_data)
@@ -4935,6 +5035,9 @@ bool GLCanvas3D::_init_toolbars()
if (!_init_view_toolbar())
return false;
+ if (!_init_collapse_toolbar())
+ return false;
+
return true;
}
@@ -5092,6 +5195,26 @@ bool GLCanvas3D::_init_main_toolbar()
if (!m_main_toolbar.add_item(item))
return false;
+ if (!m_main_toolbar.add_separator())
+ return false;
+
+ item.name = "search";
+ item.icon_filename = "search_.svg";
+ item.tooltip = _utf8(L("Search")) + " [" + GUI::shortkey_ctrl_prefix() + "F]";
+ item.sprite_id = 11;
+ item.left.render_callback = [this](float left, float right, float, float) {
+ if (m_canvas != nullptr)
+ {
+ if (_render_search_list(0.5f * (left + right)))
+ _deactivate_search_toolbar_item();
+ }
+ };
+ item.left.action_callback = GLToolbarItem::Default_Action_Callback;
+ item.visibility_callback = GLToolbarItem::Default_Visibility_Callback;
+ item.enabling_callback = GLToolbarItem::Default_Enabling_Callback;
+ if (!m_main_toolbar.add_item(item))
+ return false;
+
return true;
}
@@ -5201,6 +5324,9 @@ bool GLCanvas3D::_init_undoredo_toolbar()
if (!m_undoredo_toolbar.add_item(item))
return false;
+ if (!m_undoredo_toolbar.add_separator())
+ return false;
+
return true;
}
@@ -5209,6 +5335,106 @@ bool GLCanvas3D::_init_view_toolbar()
return wxGetApp().plater()->init_view_toolbar();
}
+bool GLCanvas3D::_init_collapse_toolbar()
+{
+ if (!m_collapse_toolbar.is_enabled())
+ return true;
+
+ BackgroundTexture::Metadata background_data;
+ background_data.filename = "toolbar_background.png";
+ background_data.left = 16;
+ background_data.top = 16;
+ background_data.right = 16;
+ background_data.bottom = 16;
+
+ if (!m_collapse_toolbar.init(background_data))
+ {
+ // unable to init the toolbar texture, disable it
+ m_collapse_toolbar.set_enabled(false);
+ return true;
+ }
+
+ m_collapse_toolbar.set_layout_type(GLToolbar::Layout::Vertical);
+ m_collapse_toolbar.set_horizontal_orientation(GLToolbar::Layout::HO_Right);
+ m_collapse_toolbar.set_vertical_orientation(GLToolbar::Layout::VO_Top);
+ m_collapse_toolbar.set_border(5.0f);
+ m_collapse_toolbar.set_separator_size(5);
+ m_collapse_toolbar.set_gap_size(2);
+
+ GLToolbarItem::Data item;
+
+ item.name = "collapse_sidebar";
+ item.icon_filename = "collapse.svg";
+ item.tooltip = wxGetApp().plater()->is_sidebar_collapsed() ? _utf8(L("Expand right panel")) : _utf8(L("Collapse right panel"));
+ item.sprite_id = 0;
+ item.left.action_callback = [this, item]() {
+ std::string new_tooltip = wxGetApp().plater()->is_sidebar_collapsed() ?
+ _utf8(L("Collapse right panel")) : _utf8(L("Expand right panel"));
+
+ int id = m_collapse_toolbar.get_item_id("collapse_sidebar");
+ m_collapse_toolbar.set_tooltip(id, new_tooltip);
+ set_tooltip("");
+
+ wxGetApp().plater()->collapse_sidebar(!wxGetApp().plater()->is_sidebar_collapsed());
+ };
+
+ if (!m_collapse_toolbar.add_item(item))
+ return false;
+
+ if (!m_collapse_toolbar.add_separator())
+ return false;
+
+ item.name = "print";
+ item.icon_filename = "cog.svg";
+ item.tooltip = _utf8(L("Switch to Print Settings")) + " [" + GUI::shortkey_ctrl_prefix() + "2]";
+ item.sprite_id = 1;
+ item.left.action_callback = [this]() { wxGetApp().mainframe->select_tab(/*0*/1); };
+
+ if (!m_collapse_toolbar.add_item(item))
+ return false;
+
+ item.name = "filament";
+ item.icon_filename = "spool.svg";
+ item.tooltip = _utf8(L("Switch to Filament Settings")) + " [" + GUI::shortkey_ctrl_prefix() + "3]";
+ item.sprite_id = 2;
+ item.left.action_callback = [this]() { wxGetApp().mainframe->select_tab(/*1*/2); };
+ item.visibility_callback = [this]() { return wxGetApp().plater()->printer_technology() == ptFFF; };
+
+ if (!m_collapse_toolbar.add_item(item))
+ return false;
+
+ item.name = "printer";
+ item.icon_filename = "printer.svg";
+ item.tooltip = _utf8(L("Switch to Printer Settings")) + " [" + GUI::shortkey_ctrl_prefix() + "4]";
+ item.sprite_id = 3;
+ item.left.action_callback = [this]() { wxGetApp().mainframe->select_tab(/*2*/3); };
+
+ if (!m_collapse_toolbar.add_item(item))
+ return false;
+
+ item.name = "resin";
+ item.icon_filename = "resin.svg";
+ item.tooltip = _utf8(L("Switch to SLA Material Settings")) + " [" + GUI::shortkey_ctrl_prefix() + "3]";
+ item.sprite_id = 4;
+ item.left.action_callback = [this]() { wxGetApp().mainframe->select_tab(/*1*/2); };
+ item.visibility_callback = [this]() { return m_process->current_printer_technology() == ptSLA; };
+
+ if (!m_collapse_toolbar.add_item(item))
+ return false;
+
+ item.name = "sla_printer";
+ item.icon_filename = "sla_printer.svg";
+ item.tooltip = _utf8(L("Switch to Printer Settings")) + " [" + GUI::shortkey_ctrl_prefix() + "4]";
+ item.sprite_id = 5;
+ item.left.action_callback = [this]() { wxGetApp().mainframe->select_tab(/*2*/3); };
+
+ if (!m_collapse_toolbar.add_item(item))
+ return false;
+
+ return true;
+
+}
+
bool GLCanvas3D::_set_current()
{
return m_context != nullptr && m_canvas->SetCurrent(*m_context);
@@ -5606,14 +5832,17 @@ void GLCanvas3D::_render_overlays() const
const float scale = m_retina_helper->get_scale_factor() * wxGetApp().toolbar_icon_scale(true);
m_main_toolbar.set_scale(scale);
m_undoredo_toolbar.set_scale(scale);
+ m_collapse_toolbar.set_scale(scale);
#else
const float size = int(GLToolbar::Default_Icons_Size * wxGetApp().toolbar_icon_scale(true));
m_main_toolbar.set_icons_size(size);
m_undoredo_toolbar.set_icons_size(size);
+ m_collapse_toolbar.set_icons_size(size);
#endif // ENABLE_RETINA_GL
_render_main_toolbar();
_render_undoredo_toolbar();
+ _render_collapse_toolbar();
_render_view_toolbar();
if ((m_layers_editing.last_object_id >= 0) && (m_layers_editing.object_max_z() > 0.0f))
@@ -5746,6 +5975,27 @@ void GLCanvas3D::_render_undoredo_toolbar() const
m_undoredo_toolbar.render(*this);
}
+void GLCanvas3D::_render_collapse_toolbar() const
+{
+ if (!m_collapse_toolbar.is_enabled())
+ return;
+
+ Size cnv_size = get_canvas_size();
+#if ENABLE_NON_STATIC_CANVAS_MANAGER
+ float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom();
+#else
+ float inv_zoom = (float)m_camera.get_inv_zoom();
+#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
+
+ float band = m_layers_editing.is_enabled() ? (wxGetApp().imgui()->get_style_scaling() * LayersEditing::THICKNESS_BAR_WIDTH) : 0.0;
+
+ float top = 0.5f * (float)cnv_size.get_height() * inv_zoom;
+ float left = (0.5f * (float)cnv_size.get_width() - (float)m_collapse_toolbar.get_width() - band) * inv_zoom;
+
+ m_collapse_toolbar.set_position(top, left);
+ m_collapse_toolbar.render(*this);
+}
+
void GLCanvas3D::_render_view_toolbar() const
{
#if ENABLE_NON_STATIC_CANVAS_MANAGER
@@ -7277,6 +7527,39 @@ bool GLCanvas3D::_deactivate_undo_redo_toolbar_items()
return false;
}
+bool GLCanvas3D::_deactivate_search_toolbar_item()
+{
+ if (m_main_toolbar.is_item_pressed("search"))
+ {
+ m_main_toolbar.force_left_action(m_main_toolbar.get_item_id("search"), *this);
+ return true;
+ }
+
+ return false;
+}
+
+bool GLCanvas3D::_activate_search_toolbar_item()
+{
+ if (!m_main_toolbar.is_item_pressed("search"))
+ {
+ m_main_toolbar.force_left_action(m_main_toolbar.get_item_id("search"), *this);
+ return true;
+ }
+
+ return false;
+}
+
+bool GLCanvas3D::_deactivate_collapse_toolbar_items()
+{
+ if (m_collapse_toolbar.is_item_pressed("print"))
+ {
+ m_collapse_toolbar.force_left_action(m_collapse_toolbar.get_item_id("print"), *this);
+ return true;
+ }
+
+ return false;
+}
+
const Print* GLCanvas3D::fff_print() const
{
return (m_process == nullptr) ? nullptr : m_process->fff_print();
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index f057ea7d6..be10e79a1 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -114,6 +114,7 @@ wxDECLARE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
+wxDECLARE_EVENT(EVT_GLCANVAS_COLLAPSE_SIDEBAR, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event);
wxDECLARE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent);
@@ -163,8 +164,8 @@ private:
Num_States
};
- private:
static const float THICKNESS_BAR_WIDTH;
+ private:
bool m_enabled;
Shader m_shader;
@@ -463,6 +464,7 @@ private:
mutable GLGizmosManager m_gizmos;
mutable GLToolbar m_main_toolbar;
mutable GLToolbar m_undoredo_toolbar;
+ mutable GLToolbar m_collapse_toolbar;
ClippingPlane m_clipping_planes[2];
mutable ClippingPlane m_camera_clipping_plane;
bool m_use_clipping_planes;
@@ -518,6 +520,7 @@ private:
#endif // ENABLE_RENDER_STATISTICS
mutable int m_imgui_undo_redo_hovered_pos{ -1 };
+ mutable int m_mouse_wheel {0};
int m_selected_extruder;
Labels m_labels;
@@ -619,6 +622,7 @@ public:
void enable_selection(bool enable);
void enable_main_toolbar(bool enable);
void enable_undoredo_toolbar(bool enable);
+ void enable_collapse_toolbar(bool enable);
void enable_dynamic_background(bool enable);
void enable_labels(bool enable) { m_labels.enable(enable); }
#if ENABLE_SLOPE_RENDERING
@@ -782,6 +786,7 @@ private:
bool _init_main_toolbar();
bool _init_undoredo_toolbar();
bool _init_view_toolbar();
+ bool _init_collapse_toolbar();
bool _set_current();
void _resize(unsigned int w, unsigned int h);
@@ -815,6 +820,7 @@ private:
void _render_gizmos_overlay() const;
void _render_main_toolbar() const;
void _render_undoredo_toolbar() const;
+ void _render_collapse_toolbar() const;
void _render_view_toolbar() const;
#if ENABLE_SHOW_CAMERA_TARGET
void _render_camera_target() const;
@@ -822,6 +828,7 @@ private:
void _render_sla_slices() const;
void _render_selection_sidebar_hints() const;
bool _render_undo_redo_stack(const bool is_undo, float pos_x) const;
+ bool _render_search_list(float pos_x) const;
void _render_thumbnail_internal(ThumbnailData& thumbnail_data, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) const;
// render thumbnail using an off-screen framebuffer
void _render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) const;
@@ -885,6 +892,9 @@ private:
void _update_selection_from_hover();
bool _deactivate_undo_redo_toolbar_items();
+ bool _deactivate_search_toolbar_item();
+ bool _activate_search_toolbar_item();
+ bool _deactivate_collapse_toolbar_items();
static std::vector _parse_colors(const std::vector& colors);
diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp
index 4219fe482..0bd087814 100644
--- a/src/slic3r/GUI/GLToolbar.cpp
+++ b/src/slic3r/GUI/GLToolbar.cpp
@@ -406,6 +406,12 @@ void GLToolbar::set_additional_tooltip(int item_id, const std::string& text)
m_items[item_id]->set_additional_tooltip(text);
}
+void GLToolbar::set_tooltip(int item_id, const std::string& text)
+{
+ if (0 <= item_id && item_id < (int)m_items.size())
+ m_items[item_id]->set_tooltip(text);
+}
+
bool GLToolbar::update_items_state()
{
bool ret = false;
diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp
index b4aac9206..27b43fef6 100644
--- a/src/slic3r/GUI/GLToolbar.hpp
+++ b/src/slic3r/GUI/GLToolbar.hpp
@@ -118,6 +118,7 @@ public:
const std::string& get_tooltip() const { return m_data.tooltip; }
const std::string& get_additional_tooltip() const { return m_data.additional_tooltip; }
void set_additional_tooltip(const std::string& text) { m_data.additional_tooltip = text; }
+ void set_tooltip(const std::string& text) { m_data.tooltip = text; }
void do_left_action() { m_last_action_type = Left; m_data.left.action_callback(); }
void do_right_action() { m_last_action_type = Right; m_data.right.action_callback(); }
@@ -317,6 +318,7 @@ public:
void get_additional_tooltip(int item_id, std::string& text);
void set_additional_tooltip(int item_id, const std::string& text);
+ void set_tooltip(int item_id, const std::string& text);
// returns true if any item changed its state
bool update_items_state();
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index c04d7ca16..0774f3208 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -350,17 +350,15 @@ bool GUI_App::on_init_inner()
// Slic3r::debugf "wxWidgets version %s, Wx version %s\n", wxVERSION_STRING, wxVERSION;
std::string msg = Http::tls_global_init();
- wxRichMessageDialog
- dlg(nullptr,
- wxString::Format(_(L("%s\nDo you want to continue?")), _(msg)),
- "PrusaSlicer", wxICON_QUESTION | wxYES_NO);
-
- bool ssl_accept = app_config->get("tls_cert_store_accepted") == "yes";
std::string ssl_cert_store = app_config->get("tls_accepted_cert_store_location");
- ssl_accept = ssl_accept && ssl_cert_store == Http::tls_system_cert_store();
+ bool ssl_accept = app_config->get("tls_cert_store_accepted") == "yes" && ssl_cert_store == Http::tls_system_cert_store();
- dlg.ShowCheckBox(_(L("Remember my choice")));
if (!msg.empty() && !ssl_accept) {
+ wxRichMessageDialog
+ dlg(nullptr,
+ wxString::Format(_(L("%s\nDo you want to continue?")), msg),
+ "PrusaSlicer", wxICON_QUESTION | wxYES_NO);
+ dlg.ShowCheckBox(_(L("Remember my choice")));
if (dlg.ShowModal() != wxID_YES) return false;
app_config->set("tls_cert_store_accepted",
@@ -415,6 +413,8 @@ bool GUI_App::on_init_inner()
if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr)
wxImage::AddHandler(new wxPNGHandler());
mainframe = new MainFrame();
+ mainframe->switch_to(true); // hide settings tabs after first Layout
+
sidebar().obj_list()->init_objects(); // propagate model objects to object list
// update_mode(); // !!! do that later
SetTopWindow(mainframe);
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index 22b3d2c25..ce79a4bcd 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -97,6 +97,7 @@ bool View3D::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_
m_canvas->enable_selection(true);
m_canvas->enable_main_toolbar(true);
m_canvas->enable_undoredo_toolbar(true);
+ m_canvas->enable_collapse_toolbar(true);
m_canvas->enable_labels(true);
#if ENABLE_SLOPE_RENDERING
m_canvas->enable_slope(true);
@@ -294,6 +295,7 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view
m_canvas->set_process(m_process);
m_canvas->enable_legend_texture(true);
m_canvas->enable_dynamic_background(true);
+ m_canvas->enable_collapse_toolbar(true);
m_double_slider_sizer = new wxBoxSizer(wxHORIZONTAL);
create_double_slider();
diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp
index a44e843b8..ea8b2afd3 100644
--- a/src/slic3r/GUI/ImGuiWrapper.cpp
+++ b/src/slic3r/GUI/ImGuiWrapper.cpp
@@ -15,12 +15,17 @@
#include
+#ifndef IMGUI_DEFINE_MATH_OPERATORS
+#define IMGUI_DEFINE_MATH_OPERATORS
+#endif
#include
#include "libslic3r/libslic3r.h"
#include "libslic3r/Utils.hpp"
#include "3DScene.hpp"
#include "GUI.hpp"
+#include "I18N.hpp"
+#include "Search.hpp"
namespace Slic3r {
namespace GUI {
@@ -374,7 +379,40 @@ bool ImGuiWrapper::combo(const wxString& label, const std::vector&
return res;
}
-bool ImGuiWrapper::undo_redo_list(const ImVec2& size, const bool is_undo, bool (*items_getter)(const bool , int , const char**), int& hovered, int& selected)
+// Scroll up for one item
+static void scroll_up()
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+
+ float item_size_y = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y;
+ float win_top = window->Scroll.y;
+
+ ImGui::SetScrollY(win_top - item_size_y);
+}
+
+// Scroll down for one item
+static void scroll_down()
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+
+ float item_size_y = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y;
+ float win_top = window->Scroll.y;
+
+ ImGui::SetScrollY(win_top + item_size_y);
+}
+
+static void process_mouse_wheel(int& mouse_wheel)
+{
+ if (mouse_wheel > 0)
+ scroll_up();
+ else if (mouse_wheel < 0)
+ scroll_down();
+ mouse_wheel = 0;
+}
+
+bool ImGuiWrapper::undo_redo_list(const ImVec2& size, const bool is_undo, bool (*items_getter)(const bool , int , const char**), int& hovered, int& selected, int& mouse_wheel)
{
bool is_hovered = false;
ImGui::ListBoxHeader("", size);
@@ -396,10 +434,312 @@ bool ImGuiWrapper::undo_redo_list(const ImVec2& size, const bool is_undo, bool (
i++;
}
+ if (is_hovered)
+ process_mouse_wheel(mouse_wheel);
+
ImGui::ListBoxFooter();
return is_hovered;
}
+// It's a copy of IMGui::Selactable function.
+// But a little beat modified to change a label text.
+// If item is hovered we should use another color for highlighted letters.
+// To do that we push a ColorMarkerHovered symbol at the very beginning of the label
+// This symbol will be used to a color selection for the highlighted letters.
+// see imgui_draw.cpp, void ImFont::RenderText()
+static bool selectable(const char* label, bool selected, ImGuiSelectableFlags flags = 0, const ImVec2& size_arg = ImVec2(0, 0))
+{
+ ImGuiWindow* window = ImGui::GetCurrentWindow();
+ if (window->SkipItems)
+ return false;
+
+ ImGuiContext& g = *GImGui;
+ const ImGuiStyle& style = g.Style;
+
+ if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.CurrentColumns) // FIXME-OPT: Avoid if vertically clipped.
+ ImGui::PushColumnsBackground();
+
+ ImGuiID id = window->GetID(label);
+ ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true);
+ ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y);
+ ImVec2 pos = window->DC.CursorPos;
+ pos.y += window->DC.CurrLineTextBaseOffset;
+ ImRect bb_inner(pos, pos + size);
+ ImGui::ItemSize(size, 0.0f);
+
+ // Fill horizontal space.
+ ImVec2 window_padding = window->WindowPadding;
+ float max_x = (flags & ImGuiSelectableFlags_SpanAllColumns) ? ImGui::GetWindowContentRegionMax().x : ImGui::GetContentRegionMax().x;
+ float w_draw = ImMax(label_size.x, window->Pos.x + max_x - window_padding.x - pos.x);
+ ImVec2 size_draw((size_arg.x != 0 && !(flags & ImGuiSelectableFlags_DrawFillAvailWidth)) ? size_arg.x : w_draw, size_arg.y != 0.0f ? size_arg.y : size.y);
+ ImRect bb(pos, pos + size_draw);
+ if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_DrawFillAvailWidth))
+ bb.Max.x += window_padding.x;
+
+ // Selectables are tightly packed together so we extend the box to cover spacing between selectable.
+ const float spacing_x = style.ItemSpacing.x;
+ const float spacing_y = style.ItemSpacing.y;
+ const float spacing_L = IM_FLOOR(spacing_x * 0.50f);
+ const float spacing_U = IM_FLOOR(spacing_y * 0.50f);
+ bb.Min.x -= spacing_L;
+ bb.Min.y -= spacing_U;
+ bb.Max.x += (spacing_x - spacing_L);
+ bb.Max.y += (spacing_y - spacing_U);
+
+ bool item_add;
+ if (flags & ImGuiSelectableFlags_Disabled)
+ {
+ ImGuiItemFlags backup_item_flags = window->DC.ItemFlags;
+ window->DC.ItemFlags |= ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNavDefaultFocus;
+ item_add = ImGui::ItemAdd(bb, id);
+ window->DC.ItemFlags = backup_item_flags;
+ }
+ else
+ {
+ item_add = ImGui::ItemAdd(bb, id);
+ }
+ if (!item_add)
+ {
+ if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.CurrentColumns)
+ ImGui::PopColumnsBackground();
+ return false;
+ }
+
+ // We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries
+ ImGuiButtonFlags button_flags = 0;
+ if (flags & ImGuiSelectableFlags_NoHoldingActiveID) { button_flags |= ImGuiButtonFlags_NoHoldingActiveId; }
+ if (flags & ImGuiSelectableFlags_PressedOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; }
+ if (flags & ImGuiSelectableFlags_PressedOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; }
+ if (flags & ImGuiSelectableFlags_Disabled) { button_flags |= ImGuiButtonFlags_Disabled; }
+ if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; }
+ if (flags & ImGuiSelectableFlags_AllowItemOverlap) { button_flags |= ImGuiButtonFlags_AllowItemOverlap; }
+
+ if (flags & ImGuiSelectableFlags_Disabled)
+ selected = false;
+
+ const bool was_selected = selected;
+ bool hovered, held;
+ bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held, button_flags);
+
+ // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard
+ if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover)))
+ {
+ if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent)
+ {
+ g.NavDisableHighlight = true;
+ ImGui::SetNavID(id, window->DC.NavLayerCurrent, window->DC.NavFocusScopeIdCurrent);
+ }
+ }
+ if (pressed)
+ ImGui::MarkItemEdited(id);
+
+ if (flags & ImGuiSelectableFlags_AllowItemOverlap)
+ ImGui::SetItemAllowOverlap();
+
+ // In this branch, Selectable() cannot toggle the selection so this will never trigger.
+ if (selected != was_selected) //-V547
+ window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
+
+ // Render
+ if (held && (flags & ImGuiSelectableFlags_DrawHoveredWhenHeld))
+ hovered = true;
+ if (hovered || selected)
+ {
+ const ImU32 col = ImGui::GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
+ ImGui::RenderFrame(bb.Min, bb.Max, col, false, 0.0f);
+ ImGui::RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding);
+ }
+
+ if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.CurrentColumns)
+ {
+ ImGui::PopColumnsBackground();
+ bb.Max.x -= (ImGui::GetContentRegionMax().x - max_x);
+ }
+
+ // mark a label with a ImGui::ColorMarkerHovered, if item is hovered
+ char* marked_label = new char[255];
+ if (hovered)
+ sprintf(marked_label, "%c%s", ImGui::ColorMarkerHovered, label);
+ else
+ strcpy(marked_label, label);
+
+ if (flags & ImGuiSelectableFlags_Disabled) ImGui::PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]);
+ ImGui::RenderTextClipped(bb_inner.Min, bb_inner.Max, marked_label, NULL, &label_size, style.SelectableTextAlign, &bb);
+ if (flags & ImGuiSelectableFlags_Disabled) ImGui::PopStyleColor();
+
+ delete[] marked_label;
+
+ // Automatically close popups
+ if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(window->DC.ItemFlags & ImGuiItemFlags_SelectableDontClosePopup)) ImGui::CloseCurrentPopup();
+
+ IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags);
+ return pressed;
+}
+
+// Scroll so that the hovered item is at the top of the window
+static void scroll_y(int hover_id)
+{
+ if (hover_id < 0)
+ return;
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+
+ float item_size_y = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y;
+ float item_delta = 0.5 * item_size_y;
+
+ float item_top = item_size_y * hover_id;
+ float item_bottom = item_top + item_size_y;
+
+ float win_top = window->Scroll.y;
+ float win_bottom = window->Scroll.y + window->Size.y;
+
+ if (item_bottom + item_delta >= win_bottom)
+ ImGui::SetScrollY(win_top + item_size_y);
+ else if (item_top - item_delta <= win_top)
+ ImGui::SetScrollY(win_top - item_size_y);
+}
+
+// Use this function instead of ImGui::IsKeyPressed.
+// ImGui::IsKeyPressed is related for *GImGui.IO.KeysDownDuration[user_key_index]
+// And after first key pressing IsKeyPressed() return "true" always even if key wasn't pressed
+static void process_key_down(ImGuiKey imgui_key, std::function f)
+{
+ if (ImGui::IsKeyDown(ImGui::GetKeyIndex(imgui_key)))
+ {
+ f();
+ // set KeysDown to false to avoid redundant key down processing
+ ImGuiContext& g = *GImGui;
+ g.IO.KeysDown[ImGui::GetKeyIndex(imgui_key)] = false;
+ }
+}
+
+void ImGuiWrapper::search_list(const ImVec2& size_, bool (*items_getter)(int, const char** label, const char** tooltip), char* search_str,
+ Search::OptionViewParameters& view_params, int& selected, bool& edited, int& mouse_wheel)
+{
+ // ImGui::ListBoxHeader("", size);
+ {
+ // rewrote part of function to add a TextInput instead of label Text
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = ImGui::GetCurrentWindow();
+ if (window->SkipItems)
+ return ;
+
+ const ImGuiStyle& style = g.Style;
+
+ // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
+ ImVec2 size = ImGui::CalcItemSize(size_, ImGui::CalcItemWidth(), ImGui::GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y);
+ ImRect frame_bb(window->DC.CursorPos, ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y + size.y));
+
+ ImRect bb(frame_bb.Min, frame_bb.Max);
+ window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy.
+ g.NextItemData.ClearFlags();
+
+ if (!ImGui::IsRectVisible(bb.Min, bb.Max))
+ {
+ ImGui::ItemSize(bb.GetSize(), style.FramePadding.y);
+ ImGui::ItemAdd(bb, 0, &frame_bb);
+ return ;
+ }
+
+ ImGui::BeginGroup();
+
+ const ImGuiID id = ImGui::GetID(search_str);
+ ImVec2 search_size = ImVec2(size.x, ImGui::GetTextLineHeightWithSpacing() + style.ItemSpacing.y);
+
+ if (!ImGui::IsAnyItemFocused() && !ImGui::IsAnyItemActive() && !ImGui::IsMouseClicked(0))
+ ImGui::SetKeyboardFocusHere(0);
+
+ // The press on Esc key invokes editing of InputText (removes last changes)
+ // So we should save previous value...
+ std::string str = search_str;
+ ImGui::InputTextEx("", NULL, search_str, 20, search_size, ImGuiInputTextFlags_AutoSelectAll, NULL, NULL);
+ edited = ImGui::IsItemEdited();
+ if (edited)
+ view_params.hovered_id = -1;
+
+ process_key_down(ImGuiKey_Escape, [&selected, search_str, str]() {
+ // use 9999 to mark selection as a Esc key
+ selected = 9999;
+ // ... and when Esc key was pressed, than revert search_str value
+ strcpy(search_str, str.c_str());
+ });
+
+ ImGui::BeginChildFrame(id, frame_bb.GetSize());
+ }
+
+ int i = 0;
+ const char* item_text;
+ const char* tooltip;
+ int mouse_hovered = -1;
+ int& hovered_id = view_params.hovered_id;
+
+ while (items_getter(i, &item_text, &tooltip))
+ {
+ selectable(item_text, i == hovered_id);
+
+ if (ImGui::IsItemHovered()) {
+ ImGui::SetTooltip("%s", /*item_text*/tooltip);
+ view_params.hovered_id = -1;
+ mouse_hovered = i;
+ }
+
+ if (ImGui::IsItemClicked())
+ selected = i;
+ i++;
+ }
+
+ scroll_y(mouse_hovered);
+
+ // Process mouse wheel
+ if (mouse_hovered > 0)
+ process_mouse_wheel(mouse_wheel);
+
+ // process Up/DownArrows and Enter
+ process_key_down(ImGuiKey_UpArrow, [&hovered_id, mouse_hovered]() {
+ if (mouse_hovered > 0)
+ scroll_up();
+ else {
+ if (hovered_id > 0 && hovered_id != size_t(-1))
+ --hovered_id;
+ scroll_y(hovered_id);
+ }
+ });
+
+ process_key_down(ImGuiKey_DownArrow, [&hovered_id, mouse_hovered, i]() {
+ if (mouse_hovered > 0)
+ scroll_down();
+ else {
+ if (hovered_id == size_t(-1))
+ hovered_id = 0;
+ else if (hovered_id < size_t(i - 1))
+ ++hovered_id;
+ scroll_y(hovered_id);
+ }
+ });
+
+ process_key_down(ImGuiKey_Enter, [&selected, hovered_id]() {
+ selected = hovered_id;
+ });
+
+ ImGui::ListBoxFooter();
+
+ auto check_box = [&edited, this](const wxString& label, bool& check) {
+ ImGui::SameLine();
+ bool ch = check;
+ checkbox(label, ch);
+ if (ImGui::IsItemClicked()) {
+ check = !check;
+ edited = true;
+ }
+ };
+
+ // add checkboxes for show/hide Categories and Groups
+ text(_L("Use for search")+":");
+ check_box(_L("Type"), view_params.type);
+ check_box(_L("Category"), view_params.category);
+ check_box(_L("Group"), view_params.group);
+}
+
void ImGuiWrapper::disabled_begin(bool disabled)
{
wxCHECK_RET(!m_disabled, "ImGUI: Unbalanced disabled_begin() call");
diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp
index 417561881..6a1e27dcb 100644
--- a/src/slic3r/GUI/ImGuiWrapper.hpp
+++ b/src/slic3r/GUI/ImGuiWrapper.hpp
@@ -8,6 +8,10 @@
#include "libslic3r/Point.hpp"
+namespace Slic3r {namespace Search {
+struct OptionViewParameters;
+}}
+
class wxString;
class wxMouseEvent;
class wxKeyEvent;
@@ -73,7 +77,9 @@ public:
bool slider_float(const std::string& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);
bool slider_float(const wxString& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);
bool combo(const wxString& label, const std::vector& options, int& selection); // Use -1 to not mark any option as selected
- bool undo_redo_list(const ImVec2& size, const bool is_undo, bool (*items_getter)(const bool, int, const char**), int& hovered, int& selected);
+ bool undo_redo_list(const ImVec2& size, const bool is_undo, bool (*items_getter)(const bool, int, const char**), int& hovered, int& selected, int& mouse_wheel);
+ void search_list(const ImVec2& size, bool (*items_getter)(int, const char** label, const char** tooltip), char* search_str,
+ Search::OptionViewParameters& view_params, int& selected, bool& edited, int& mouse_wheel);
void disabled_begin(bool disabled);
void disabled_end();
diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp
index 79a6cad20..9f31d23d8 100644
--- a/src/slic3r/GUI/KBShortcutsDialog.cpp
+++ b/src/slic3r/GUI/KBShortcutsDialog.cpp
@@ -134,6 +134,7 @@ void KBShortcutsDialog::fill_shortcuts()
{ ctrl + "C", L("Copy to clipboard") },
{ ctrl + "V", L("Paste from clipboard") },
{ "F5", L("Reload plater from disk") },
+ { ctrl + "F", L("Search") },
// Window
{ ctrl + "1", L("Select Plater Tab") },
{ ctrl + "2", L("Select Print Settings Tab") },
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index 21aad8987..d3bd2720e 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -90,6 +90,8 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
// initialize layout
auto sizer = new wxBoxSizer(wxVERTICAL);
+ if (m_plater)
+ sizer->Add(m_plater, 1, wxEXPAND);
if (m_tabpanel)
sizer->Add(m_tabpanel, 1, wxEXPAND);
sizer->SetSizeHints(this);
@@ -306,11 +308,16 @@ void MainFrame::init_tabpanel()
// before the MainFrame is fully set up.
static_cast(panel)->OnActivate();
}
+ else
+ select_tab(0);
});
- m_plater = new Slic3r::GUI::Plater(m_tabpanel, this);
+//! m_plater = new Slic3r::GUI::Plater(m_tabpanel, this);
+ m_plater = new Plater(this, this);
+
wxGetApp().plater_ = m_plater;
- m_tabpanel->AddPage(m_plater, _(L("Plater")));
+// m_tabpanel->AddPage(m_plater, _(L("Plater")));
+ m_tabpanel->AddPage(new wxPanel(m_tabpanel), _L("Plater")); // empty panel just for Plater tab
wxGetApp().obj_list()->create_popup_menus();
@@ -336,6 +343,13 @@ void MainFrame::init_tabpanel()
}
}
+void MainFrame::switch_to(bool plater)
+{
+ this->m_plater->Show(plater);
+ this->m_tabpanel->Show(!plater);
+ this->Layout();
+}
+
void MainFrame::create_preset_tabs()
{
wxGetApp().update_label_colours_from_appconfig();
@@ -739,31 +753,37 @@ void MainFrame::init_menubar()
append_menu_item(editMenu, wxID_ANY, _(L("Re&load from disk")) + sep + "F5",
_(L("Reload the plater from disk")), [this](wxCommandEvent&) { m_plater->reload_all_from_disk(); },
"", nullptr, [this]() {return !m_plater->model().objects.empty(); }, this);
+
+ editMenu->AppendSeparator();
+ append_menu_item(editMenu, wxID_ANY, _(L("Searc&h")) + "\tCtrl+F",
+ _(L("Find option")), [this](wxCommandEvent&) { m_plater->search(/*m_tabpanel->GetCurrentPage() == */m_plater->IsShown()); },
+ "search", nullptr, [this]() {return true; }, this);
}
// Window menu
auto windowMenu = new wxMenu();
{
- size_t tab_offset = 0;
+//! size_t tab_offset = 0;
if (m_plater) {
append_menu_item(windowMenu, wxID_HIGHEST + 1, _(L("&Plater Tab")) + "\tCtrl+1", _(L("Show the plater")),
- [this](wxCommandEvent&) { select_tab(0); }, "plater", nullptr,
+ [this/*, tab_offset*/](wxCommandEvent&) { select_tab(/*(size_t)(-1)*/0); }, "plater", nullptr,
[this]() {return true; }, this);
- tab_offset += 1;
- }
- if (tab_offset > 0) {
+//! tab_offset += 1;
+//! }
+//! if (tab_offset > 0) {
windowMenu->AppendSeparator();
}
append_menu_item(windowMenu, wxID_HIGHEST + 2, _(L("P&rint Settings Tab")) + "\tCtrl+2", _(L("Show the print settings")),
- [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 0); }, "cog", nullptr,
+ [this/*, tab_offset*/](wxCommandEvent&) { select_tab(/*tab_offset + 0*/1); }, "cog", nullptr,
[this]() {return true; }, this);
wxMenuItem* item_material_tab = append_menu_item(windowMenu, wxID_HIGHEST + 3, _(L("&Filament Settings Tab")) + "\tCtrl+3", _(L("Show the filament settings")),
- [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 1); }, "spool", nullptr,
+ [this/*, tab_offset*/](wxCommandEvent&) { select_tab(/*tab_offset + 1*/2); }, "spool", nullptr,
[this]() {return true; }, this);
m_changeable_menu_items.push_back(item_material_tab);
- append_menu_item(windowMenu, wxID_HIGHEST + 4, _(L("Print&er Settings Tab")) + "\tCtrl+4", _(L("Show the printer settings")),
- [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 2); }, "printer", nullptr,
+ wxMenuItem* item_printer_tab = append_menu_item(windowMenu, wxID_HIGHEST + 4, _(L("Print&er Settings Tab")) + "\tCtrl+4", _(L("Show the printer settings")),
+ [this/*, tab_offset*/](wxCommandEvent&) { select_tab(/*tab_offset + 2*/3); }, "printer", nullptr,
[this]() {return true; }, this);
+ m_changeable_menu_items.push_back(item_printer_tab);
if (m_plater) {
windowMenu->AppendSeparator();
append_menu_item(windowMenu, wxID_HIGHEST + 5, _(L("3&D")) + "\tCtrl+5", _(L("Show the 3D editing view")),
@@ -830,6 +850,9 @@ void MainFrame::init_menubar()
[this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); }, this,
[this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this);
#endif // ENABLE_SLOPE_RENDERING
+ append_menu_check_item(viewMenu, wxID_ANY, _(L("&Collapse sidebar")), _(L("Collapse sidebar")),
+ [this](wxCommandEvent&) { m_plater->collapse_sidebar(!m_plater->is_sidebar_collapsed()); }, this,
+ [this]() { return true; }, [this]() { return m_plater->is_sidebar_collapsed(); }, this);
}
// Help menu
@@ -904,7 +927,9 @@ void MainFrame::update_menubar()
m_changeable_menu_items[miSend] ->SetItemLabel((is_fff ? _(L("S&end G-code")) : _(L("S&end to print"))) + dots + "\tCtrl+Shift+G");
m_changeable_menu_items[miMaterialTab] ->SetItemLabel((is_fff ? _(L("&Filament Settings Tab")) : _(L("Mate&rial Settings Tab"))) + "\tCtrl+3");
- m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(is_fff ? "spool": "resin"));
+ m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(is_fff ? "spool" : "resin"));
+
+ m_changeable_menu_items[miPrinterTab] ->SetBitmap(create_scaled_bitmap(is_fff ? "printer" : "sla_printer"));
}
// To perform the "Quck Slice", "Quick Slice and Save As", "Repeat last Quick Slice" and "Slice to SVG".
@@ -1220,9 +1245,17 @@ void MainFrame::load_config(const DynamicPrintConfig& config)
#endif
}
-void MainFrame::select_tab(size_t tab) const
+void MainFrame::select_tab(size_t tab)
{
- m_tabpanel->SetSelection(tab);
+ if (tab == /*(size_t)(-1)*/0) {
+ if (m_plater && !m_plater->IsShown())
+ this->switch_to(true);
+ }
+ else {
+ if (m_plater && m_plater->IsShown())
+ switch_to(false);
+ m_tabpanel->SetSelection(tab);
+ }
}
// Set a camera direction, zoom to all objects.
diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp
index 6038e6d2f..8fc0ed1f2 100644
--- a/src/slic3r/GUI/MainFrame.hpp
+++ b/src/slic3r/GUI/MainFrame.hpp
@@ -86,6 +86,7 @@ class MainFrame : public DPIFrame
miExport = 0, // Export G-code Export
miSend, // Send G-code Send to print
miMaterialTab, // Filament Settings Material Settings
+ miPrinterTab, // Different bitmap for Printer Settings
};
// vector of a MenuBar items changeable in respect to printer technology
@@ -108,6 +109,7 @@ public:
void update_title();
void init_tabpanel();
+ void switch_to(bool plater);
void create_preset_tabs();
void add_created_tab(Tab* panel);
void init_menubar();
@@ -128,7 +130,7 @@ public:
void export_configbundle();
void load_configbundle(wxString file = wxEmptyString);
void load_config(const DynamicPrintConfig& config);
- void select_tab(size_t tab) const;
+ void select_tab(size_t tab);
void select_view(const std::string& direction);
// Propagate changed configuration from the Tab to the Plater and save changes to the AppConfig
void on_config_changed(DynamicPrintConfig* cfg) const ;
diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp
index d561d8e2a..83eb6c76f 100644
--- a/src/slic3r/GUI/OptionsGroup.cpp
+++ b/src/slic3r/GUI/OptionsGroup.cpp
@@ -108,6 +108,7 @@ void OptionsGroup::add_undo_buttuns_to_sizer(wxSizer* sizer, const t_field& fiel
return;
}
+ sizer->Add(field->m_blinking_bmp, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 2);
sizer->Add(field->m_Undo_to_sys_btn, 0, wxALIGN_CENTER_VERTICAL);
sizer->Add(field->m_Undo_btn, 0, wxALIGN_CENTER_VERTICAL);
}
@@ -378,6 +379,9 @@ Option ConfigOptionsGroup::get_option(const std::string& opt_key, int opt_index
std::pair pair(opt_key, opt_index);
m_opt_map.emplace(opt_id, pair);
+ if (m_show_modified_btns) // fill group and category values just fro options from Settings Tab
+ wxGetApp().sidebar().get_searcher().add_key(opt_id, title, config_category);
+
return Option(*m_config->def()->get(opt_key), opt_id);
}
diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp
index 536eb72a5..6128eb7ab 100644
--- a/src/slic3r/GUI/OptionsGroup.hpp
+++ b/src/slic3r/GUI/OptionsGroup.hpp
@@ -12,6 +12,7 @@
#include "Field.hpp"
#include "GUI_App.hpp"
+#include "I18N.hpp"
// Translate the ifdef
#ifdef __WXOSX__
@@ -59,7 +60,7 @@ public:
m_extra_widgets.push_back(widget);
}
Line(wxString label, wxString tooltip) :
- label(label), label_tooltip(tooltip) {}
+ label(_(label)), label_tooltip(_(tooltip)) {}
const std::vector& get_extra_widgets() const {return m_extra_widgets;}
const std::vector