diff --git a/resources/icons/action_undo.png b/resources/icons/action_undo.png index 866ae9773..877f15986 100644 Binary files a/resources/icons/action_undo.png and b/resources/icons/action_undo.png differ diff --git a/resources/icons/sys_lock.png b/resources/icons/sys_lock.png index 0519c44a1..a33eadbca 100644 Binary files a/resources/icons/sys_lock.png and b/resources/icons/sys_lock.png differ diff --git a/resources/icons/sys_unlock.png b/resources/icons/sys_unlock.png index 189bc24e7..d53c288a1 100644 Binary files a/resources/icons/sys_unlock.png and b/resources/icons/sys_unlock.png differ diff --git a/xs/src/slic3r/GUI/2DBed.hpp b/xs/src/slic3r/GUI/2DBed.hpp index 859417efb..a170b708a 100644 --- a/xs/src/slic3r/GUI/2DBed.hpp +++ b/xs/src/slic3r/GUI/2DBed.hpp @@ -6,7 +6,7 @@ namespace GUI { class Bed_2D : public wxPanel { - bool m_user_drawn_background = false; + bool m_user_drawn_background = true; bool m_painted = false; bool m_interactive = false; @@ -26,7 +26,9 @@ public: { Create(parent, wxID_ANY, wxDefaultPosition, wxSize(250, -1), wxTAB_TRAVERSAL); // m_user_drawn_background = $^O ne 'darwin'; - m_user_drawn_background = true; +#ifdef __APPLE__ + m_user_drawn_background = false; +#endif /*__APPLE__*/ Bind(wxEVT_PAINT, ([this](wxPaintEvent e) { repaint(); })); // EVT_ERASE_BACKGROUND($self, sub{}) if $self->{user_drawn_background}; // Bind(EVT_MOUSE_EVENTS, ([this](wxMouseEvent event){/*mouse_event()*/; })); diff --git a/xs/src/slic3r/GUI/BitmapCache.cpp b/xs/src/slic3r/GUI/BitmapCache.cpp index f92369650..93853458e 100644 --- a/xs/src/slic3r/GUI/BitmapCache.cpp +++ b/xs/src/slic3r/GUI/BitmapCache.cpp @@ -1,5 +1,14 @@ #include "BitmapCache.hpp" +#if ! defined(WIN32) && ! defined(__APPLE__) +#define BROKEN_ALPHA +#endif + +#ifdef BROKEN_ALPHA + #include + #include +#endif /* BROKEN_ALPHA */ + namespace Slic3r { namespace GUI { void BitmapCache::clear() @@ -8,19 +17,31 @@ void BitmapCache::clear() delete bitmap.second; } +static wxBitmap wxImage_to_wxBitmap_with_alpha(wxImage &&image) +{ +#ifdef BROKEN_ALPHA + wxMemoryOutputStream stream; + image.SaveFile(stream, wxBITMAP_TYPE_PNG); + wxStreamBuffer *buf = stream.GetOutputStreamBuffer(); + return wxBitmap::NewFromPNGData(buf->GetBufferStart(), buf->GetBufferSize()); +#else + return wxBitmap(std::move(image)); +#endif +} + wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_t height) { - wxBitmap *bitmap = nullptr; - auto it = m_map.find(bitmap_key); - if (it == m_map.end()) { - bitmap = new wxBitmap(width, height); - m_map[bitmap_key] = bitmap; - } else { - bitmap = it->second; - if (bitmap->GetWidth() != width || bitmap->GetHeight() != height) - bitmap->Create(width, height); - } -#if defined(__APPLE__) || defined(_MSC_VER) + wxBitmap *bitmap = nullptr; + auto it = m_map.find(bitmap_key); + if (it == m_map.end()) { + bitmap = new wxBitmap(width, height); + m_map[bitmap_key] = bitmap; + } else { + bitmap = it->second; + if (bitmap->GetWidth() != width || bitmap->GetHeight() != height) + bitmap->Create(width, height); + } +#ifndef BROKEN_ALPHA bitmap->UseAlpha(); #endif return bitmap; @@ -28,77 +49,108 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp) { - wxBitmap *bitmap = this->insert(bitmap_key, bmp.GetWidth(), bmp.GetHeight()); - - wxMemoryDC memDC; - memDC.SelectObject(*bitmap); - memDC.SetBackground(*wxTRANSPARENT_BRUSH); - memDC.Clear(); - memDC.DrawBitmap(bmp, 0, 0, true); - memDC.SelectObject(wxNullBitmap); - - return bitmap; + wxBitmap *bitmap = nullptr; + auto it = m_map.find(bitmap_key); + if (it == m_map.end()) { + bitmap = new wxBitmap(bmp); + m_map[bitmap_key] = bitmap; + } else { + bitmap = it->second; + *bitmap = bmp; + } + return bitmap; } wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp, const wxBitmap &bmp2) { - wxBitmap *bitmap = this->insert(bitmap_key, bmp.GetWidth() + bmp2.GetWidth(), std::max(bmp.GetHeight(), bmp2.GetHeight())); - - wxMemoryDC memDC; - memDC.SelectObject(*bitmap); - memDC.SetBackground(*wxTRANSPARENT_BRUSH); - memDC.Clear(); - if (bmp.GetWidth() > 0) - memDC.DrawBitmap(bmp, 0, 0, true); - if (bmp2.GetWidth() > 0) - memDC.DrawBitmap(bmp2, bmp.GetWidth(), 0, true); - memDC.SelectObject(wxNullBitmap); - - return bitmap; + // Copying the wxBitmaps is cheap as the bitmap's content is reference counted. + const wxBitmap bmps[2] = { bmp, bmp2 }; + return this->insert(bitmap_key, bmps, bmps + 2); } wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3) { - wxBitmap *bitmap = this->insert(bitmap_key, bmp.GetWidth() + bmp2.GetWidth() + bmp3.GetWidth(), std::max(std::max(bmp.GetHeight(), bmp2.GetHeight()), bmp3.GetHeight())); - - wxMemoryDC memDC; - memDC.SelectObject(*bitmap); - memDC.SetBackground(*wxTRANSPARENT_BRUSH); - memDC.Clear(); - if (bmp.GetWidth() > 0) - memDC.DrawBitmap(bmp, 0, 0, true); - if (bmp2.GetWidth() > 0) - memDC.DrawBitmap(bmp2, bmp.GetWidth(), 0, true); - if (bmp3.GetWidth() > 0) - memDC.DrawBitmap(bmp3, bmp.GetWidth() + bmp2.GetWidth(), 0, true); - memDC.SelectObject(wxNullBitmap); - - return bitmap; + // Copying the wxBitmaps is cheap as the bitmap's content is reference counted. + const wxBitmap bmps[3] = { bmp, bmp2, bmp3 }; + return this->insert(bitmap_key, bmps, bmps + 3); } -wxBitmap* BitmapCache::insert(const std::string &bitmap_key, std::vector &bmps) +wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *begin, const wxBitmap *end) { - size_t width = 0; - size_t height = 0; - for (wxBitmap &bmp : bmps) { - width += bmp.GetWidth(); - height = std::max(height, bmp.GetHeight()); - } - wxBitmap *bitmap = this->insert(bitmap_key, width, height); + size_t width = 0; + size_t height = 0; + for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) { + width += bmp->GetWidth(); + height = std::max(height, bmp->GetHeight()); + } +#ifdef BROKEN_ALPHA + + wxImage image(width, height); + image.InitAlpha(); + // Fill in with a white color. + memset(image.GetData(), 0x0ff, width * height * 3); + // Fill in with full transparency. + memset(image.GetAlpha(), 0, width * height); + size_t x = 0; + for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) { + if (bmp->GetWidth() > 0) { + if (bmp->GetDepth() == 32) { + wxAlphaPixelData data(*const_cast(bmp)); + data.UseAlpha(); + if (data) { + for (int r = 0; r < bmp->GetHeight(); ++ r) { + wxAlphaPixelData::Iterator src(data); + src.Offset(data, 0, r); + unsigned char *dst_pixels = image.GetData() + (x + r * width) * 3; + unsigned char *dst_alpha = image.GetAlpha() + x + r * width; + for (int c = 0; c < bmp->GetWidth(); ++ c, ++ src) { + *dst_pixels ++ = src.Red(); + *dst_pixels ++ = src.Green(); + *dst_pixels ++ = src.Blue(); + *dst_alpha ++ = src.Alpha(); + } + } + } + } else if (bmp->GetDepth() == 24) { + wxNativePixelData data(*const_cast(bmp)); + if (data) { + for (int r = 0; r < bmp->GetHeight(); ++ r) { + wxNativePixelData::Iterator src(data); + src.Offset(data, 0, r); + unsigned char *dst_pixels = image.GetData() + (x + r * width) * 3; + unsigned char *dst_alpha = image.GetAlpha() + x + r * width; + for (int c = 0; c < bmp->GetWidth(); ++ c, ++ src) { + *dst_pixels ++ = src.Red(); + *dst_pixels ++ = src.Green(); + *dst_pixels ++ = src.Blue(); + *dst_alpha ++ = wxALPHA_OPAQUE; + } + } + } + } + } + x += bmp->GetWidth(); + } + return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image))); + +#else + + wxBitmap *bitmap = this->insert(bitmap_key, width, height); wxMemoryDC memDC; memDC.SelectObject(*bitmap); memDC.SetBackground(*wxTRANSPARENT_BRUSH); memDC.Clear(); size_t x = 0; - for (wxBitmap &bmp : bmps) { - if (bmp.GetWidth() > 0) - memDC.DrawBitmap(bmp, x, 0, true); - x += bmp.GetWidth(); - } + for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) { + if (bmp->GetWidth() > 0) + memDC.DrawBitmap(*bmp, x, 0, true); + x += bmp->GetWidth(); + } memDC.SelectObject(wxNullBitmap); + return bitmap; - return bitmap; +#endif } wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency) @@ -113,7 +165,7 @@ wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsi *imgdata ++ = b; *imgalpha ++ = transparency; } - return wxBitmap(std::move(image)); + return wxImage_to_wxBitmap_with_alpha(std::move(image)); } } // namespace GUI diff --git a/xs/src/slic3r/GUI/BitmapCache.hpp b/xs/src/slic3r/GUI/BitmapCache.hpp index 0cf9d8acf..bec9a7ad2 100644 --- a/xs/src/slic3r/GUI/BitmapCache.hpp +++ b/xs/src/slic3r/GUI/BitmapCache.hpp @@ -27,7 +27,8 @@ public: wxBitmap* insert(const std::string &name, const wxBitmap &bmp); wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2); wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3); - wxBitmap* insert(const std::string &name, std::vector &bmps); + wxBitmap* insert(const std::string &name, const std::vector &bmps) { return this->insert(name, &bmps.front(), &bmps.front() + bmps.size()); } + wxBitmap* insert(const std::string &name, const wxBitmap *begin, const wxBitmap *end); static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency); static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); } diff --git a/xs/src/slic3r/GUI/Field.cpp b/xs/src/slic3r/GUI/Field.cpp index fee08e27e..c68b2304c 100644 --- a/xs/src/slic3r/GUI/Field.cpp +++ b/xs/src/slic3r/GUI/Field.cpp @@ -75,13 +75,13 @@ namespace Slic3r { namespace GUI { return tooltip_text; } - bool Field::is_matched(std::string string, std::string pattern) + bool Field::is_matched(const std::string& string, const std::string& pattern) { std::regex regex_pattern(pattern, std::regex_constants::icase); // use ::icase to make the matching case insensitive like /i in perl return std::regex_match(string, regex_pattern); } - boost::any Field::get_value_by_opt_type(wxString str) + boost::any Field::get_value_by_opt_type(wxString& str) { boost::any ret_val; switch (m_opt.type){ @@ -173,8 +173,7 @@ namespace Slic3r { namespace GUI { temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent& e) { -// on_kill_focus(e); - e.Skip(); + e.Skip();// on_kill_focus(e); temp->GetToolTip()->Enable(true); }), temp->GetId()); @@ -378,7 +377,7 @@ void Choice::set_selection() } } -void Choice::set_value(const std::string value, bool change_event) //! Redundant? +void Choice::set_value(const std::string& value, bool change_event) //! Redundant? { m_disable_change_event = !change_event; @@ -397,7 +396,7 @@ void Choice::set_value(const std::string value, bool change_event) //! Redundan m_disable_change_event = false; } -void Choice::set_value(boost::any value, bool change_event) +void Choice::set_value(const boost::any& value, bool change_event) { m_disable_change_event = !change_event; @@ -436,7 +435,7 @@ void Choice::set_value(boost::any value, bool change_event) } //! it's needed for _update_serial_ports() -void Choice::set_values(const std::vector values) +void Choice::set_values(const std::vector& values) { if (values.empty()) return; @@ -555,7 +554,7 @@ void PointCtrl::BUILD() y_textctrl->SetToolTip(get_tooltip_text(X+", "+Y)); } -void PointCtrl::set_value(const Pointf value, bool change_event) +void PointCtrl::set_value(const Pointf& value, bool change_event) { m_disable_change_event = !change_event; @@ -567,10 +566,10 @@ void PointCtrl::set_value(const Pointf value, bool change_event) m_disable_change_event = false; } -void PointCtrl::set_value(boost::any value, bool change_event) +void PointCtrl::set_value(const boost::any& value, bool change_event) { Pointf pt; - Pointf *ptf = boost::any_cast(&value); + const Pointf *ptf = boost::any_cast(&value); if (!ptf) { ConfigOptionPoints* pts = boost::any_cast(value); @@ -578,21 +577,6 @@ void PointCtrl::set_value(boost::any value, bool change_event) } else pt = *ptf; -// try -// { -// pt = boost::any_cast(value)->values.at(0); -// } -// catch (const std::exception &e) -// { -// try{ -// pt = boost::any_cast(value); -// } -// catch (const std::exception &e) -// { -// std::cerr << "Error! Can't cast PointCtrl value" << m_opt_id << "\n"; -// return; -// } -// } set_value(pt, change_event); } diff --git a/xs/src/slic3r/GUI/Field.hpp b/xs/src/slic3r/GUI/Field.hpp index da3e23ccd..cdc7c0d81 100644 --- a/xs/src/slic3r/GUI/Field.hpp +++ b/xs/src/slic3r/GUI/Field.hpp @@ -31,8 +31,8 @@ namespace Slic3r { namespace GUI { class Field; using t_field = std::unique_ptr; using t_kill_focus = std::function; -using t_change = std::function; -using t_back_to_init = std::function; +using t_change = std::function; +using t_back_to_init = std::function; wxString double_to_string(double const value); @@ -81,7 +81,7 @@ public: /// Sets a value for this control. /// subclasses should overload with a specific version /// Postcondition: Method does not fire the on_change event. - virtual void set_value(boost::any value, bool change_event) = 0; + virtual void set_value(const boost::any& value, bool change_event) = 0; /// Gets a boost::any representing this control. /// subclasses should overload with a specific version @@ -100,7 +100,7 @@ public: virtual wxString get_tooltip_text(const wxString& default_string); // set icon to "UndoToSystemValue" button according to an inheritance of preset - void set_nonsys_btn_icon(const std::string& icon); + void set_nonsys_btn_icon(const std::string& icon); Field(const ConfigOptionDef& opt, const t_config_option_key& id) : m_opt(opt), m_opt_id(id) {}; Field(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : m_parent(parent), m_opt(opt), m_opt_id(id) {}; @@ -109,8 +109,8 @@ public: virtual wxSizer* getSizer() { return nullptr; } virtual wxWindow* getWindow() { return nullptr; } - bool is_matched(std::string string, std::string pattern); - boost::any get_value_by_opt_type(wxString str); + bool is_matched(const std::string& string, const std::string& pattern); + boost::any get_value_by_opt_type(wxString& str); /// Factory method for generating new derived classes. template @@ -137,16 +137,17 @@ class TextCtrl : public Field { public: TextCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {} TextCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} + ~TextCtrl() {} void BUILD(); wxWindow* window {nullptr}; - virtual void set_value(std::string value, bool change_event = false) { + virtual void set_value(const std::string& value, bool change_event = false) { m_disable_change_event = !change_event; dynamic_cast(window)->SetValue(wxString(value)); m_disable_change_event = false; } - virtual void set_value(boost::any value, bool change_event = false) { + virtual void set_value(const boost::any& value, bool change_event = false) { m_disable_change_event = !change_event; dynamic_cast(window)->SetValue(boost::any_cast(value)); m_disable_change_event = false; @@ -164,6 +165,7 @@ class CheckBox : public Field { public: CheckBox(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {} CheckBox(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} + ~CheckBox() {} wxWindow* window{ nullptr }; void BUILD() override; @@ -173,7 +175,7 @@ public: dynamic_cast(window)->SetValue(value); m_disable_change_event = false; } - void set_value(boost::any value, bool change_event = false) { + void set_value(const boost::any& value, bool change_event = false) { m_disable_change_event = !change_event; dynamic_cast(window)->SetValue(boost::any_cast(value)); m_disable_change_event = false; @@ -190,21 +192,22 @@ class SpinCtrl : public Field { public: SpinCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id), tmp_value(-9999) {} SpinCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id), tmp_value(-9999) {} + ~SpinCtrl() {} int tmp_value; wxWindow* window{ nullptr }; void BUILD() override; - void set_value(const std::string value, bool change_event = false) { + void set_value(const std::string& value, bool change_event = false) { m_disable_change_event = !change_event; dynamic_cast(window)->SetValue(value); m_disable_change_event = false; } - void set_value(boost::any value, bool change_event = false) { + void set_value(const boost::any& value, bool change_event = false) { m_disable_change_event = !change_event; tmp_value = boost::any_cast(value); - dynamic_cast(window)->SetValue(tmp_value/*boost::any_cast(value)*/); + dynamic_cast(window)->SetValue(tmp_value); m_disable_change_event = false; } boost::any get_value() override { @@ -221,14 +224,15 @@ class Choice : public Field { public: Choice(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {} Choice(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} + ~Choice() {} wxWindow* window{ nullptr }; void BUILD() override; void set_selection(); - void set_value(const std::string value, bool change_event = false); - void set_value(boost::any value, bool change_event = false); - void set_values(const std::vector values); + void set_value(const std::string& value, bool change_event = false); + void set_value(const boost::any& value, bool change_event = false); + void set_values(const std::vector &values); boost::any get_value() override; void enable() override { dynamic_cast(window)->Enable(); }; @@ -241,16 +245,17 @@ class ColourPicker : public Field { public: ColourPicker(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {} ColourPicker(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} + ~ColourPicker() {} wxWindow* window{ nullptr }; void BUILD() override; - void set_value(const std::string value, bool change_event = false) { + void set_value(const std::string& value, bool change_event = false) { m_disable_change_event = !change_event; dynamic_cast(window)->SetColour(value); m_disable_change_event = false; } - void set_value(boost::any value, bool change_event = false) { + void set_value(const boost::any& value, bool change_event = false) { m_disable_change_event = !change_event; dynamic_cast(window)->SetColour(boost::any_cast(value)); m_disable_change_event = false; @@ -268,23 +273,24 @@ class PointCtrl : public Field { public: PointCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {} PointCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} + ~PointCtrl() {} wxSizer* sizer{ nullptr }; - wxTextCtrl* x_textctrl; - wxTextCtrl* y_textctrl; + wxTextCtrl* x_textctrl{ nullptr }; + wxTextCtrl* y_textctrl{ nullptr }; void BUILD() override; - void set_value(const Pointf value, bool change_event = false); - void set_value(boost::any value, bool change_event = false); + void set_value(const Pointf& value, bool change_event = false); + void set_value(const boost::any& value, bool change_event = false); boost::any get_value() override; void enable() override { x_textctrl->Enable(); - y_textctrl->Enable(); }; + y_textctrl->Enable(); } void disable() override{ x_textctrl->Disable(); - y_textctrl->Disable(); }; + y_textctrl->Disable(); } wxSizer* getSizer() override { return sizer; } }; diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index d350584c1..cc135931a 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -405,7 +405,7 @@ TabIface* get_preset_tab_iface(char *name) } // opt_index = 0, by the reason of zero-index in ConfigOptionVector by default (in case only one element) -void change_opt_value(DynamicPrintConfig& config, t_config_option_key opt_key, boost::any value, int opt_index /*= 0*/) +void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index /*= 0*/) { try{ switch (config.def()->get(opt_key)->type){ @@ -441,11 +441,18 @@ void change_opt_value(DynamicPrintConfig& config, t_config_option_key opt_key, b config.set_key_value(opt_key, new ConfigOptionString(boost::any_cast(value))); break; case coStrings:{ - if (opt_key.compare("compatible_printers") == 0 || - config.def()->get(opt_key)->gui_flags.compare("serialized") == 0){ - config.option(opt_key)->values.resize(0); - std::vector values = boost::any_cast>(value); - if (values.size() == 1 && values[0] == "") + if (opt_key.compare("compatible_printers") == 0) { + config.option(opt_key)->values = + boost::any_cast>(value); + } + else if (config.def()->get(opt_key)->gui_flags.compare("serialized") == 0){ + std::string str = boost::any_cast(value); + if (str.back() == ';') str.pop_back(); + // Split a string to multiple strings by a semi - colon.This is the old way of storing multi - string values. + // Currently used for the post_process config value only. + std::vector values; + boost::split(values, str, boost::is_any_of(";")); + if (values.size() == 1 && values[0] == "") break; config.option(opt_key)->values = values; } @@ -512,17 +519,17 @@ void add_created_tab(Tab* panel) g_wxTabPanel->AddPage(panel, panel->title()); } -void show_error(wxWindow* parent, wxString message){ +void show_error(wxWindow* parent, const wxString& message){ auto msg_wingow = new wxMessageDialog(parent, message, _(L("Error")), wxOK | wxICON_ERROR); msg_wingow->ShowModal(); } -void show_info(wxWindow* parent, wxString message, wxString title){ +void show_info(wxWindow* parent, const wxString& message, const wxString& title){ auto msg_wingow = new wxMessageDialog(parent, message, title.empty() ? _(L("Notice")) : title, wxOK | wxICON_INFORMATION); msg_wingow->ShowModal(); } -void warning_catcher(wxWindow* parent, wxString message){ +void warning_catcher(wxWindow* parent, const wxString& message){ if (message == _(L("GLUquadricObjPtr | Attempt to free unreferenced scalar")) ) return; auto msg = new wxMessageDialog(parent, message, _(L("Warning")), wxOK | wxICON_WARNING); diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp index 28c450eb8..0b681f48f 100644 --- a/xs/src/slic3r/GUI/GUI.hpp +++ b/xs/src/slic3r/GUI/GUI.hpp @@ -97,11 +97,11 @@ TabIface* get_preset_tab_iface(char *name); // add it at the end of the tab panel. void add_created_tab(Tab* panel); // Change option value in config -void change_opt_value(DynamicPrintConfig& config, t_config_option_key opt_key, boost::any value, int opt_index = 0); +void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0); -void show_error(wxWindow* parent, wxString message); -void show_info(wxWindow* parent, wxString message, wxString title); -void warning_catcher(wxWindow* parent, wxString message); +void show_error(wxWindow* parent, const wxString& message); +void show_info(wxWindow* parent, const wxString& message, const wxString& title); +void warning_catcher(wxWindow* parent, const wxString& message); // load language saved at application config bool load_language(); diff --git a/xs/src/slic3r/GUI/OptionsGroup.cpp b/xs/src/slic3r/GUI/OptionsGroup.cpp index 48d81bebd..168ffcdc9 100644 --- a/xs/src/slic3r/GUI/OptionsGroup.cpp +++ b/xs/src/slic3r/GUI/OptionsGroup.cpp @@ -97,7 +97,7 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co return field; } -void OptionsGroup::append_line(const Line& line) { +void OptionsGroup::append_line(const Line& line, wxStaticText** colored_Label/* = nullptr*/) { //! if (line.sizer != nullptr || (line.widget != nullptr && line.full_width > 0)){ if ( (line.sizer != nullptr || line.widget != nullptr) && line.full_width){ if (line.sizer != nullptr) { @@ -149,7 +149,8 @@ void OptionsGroup::append_line(const Line& line) { // If there's a widget, build it and add the result to the sizer. if (line.widget != nullptr) { auto wgt = line.widget(parent()); - grid_sizer->Add(wgt, 0, wxEXPAND | wxBOTTOM | wxTOP, wxOSX ? 0 : 1); + grid_sizer->Add(wgt, 0, wxEXPAND | wxBOTTOM | wxTOP, wxOSX ? 0 : 5); + if (colored_Label != nullptr) *colored_Label = label; return; } @@ -227,12 +228,12 @@ Line OptionsGroup::create_single_option_line(const Option& option) const { return retval; } -void OptionsGroup::on_change_OG(t_config_option_key id, /*config_value*/boost::any value) { +void OptionsGroup::on_change_OG(const t_config_option_key& opt_id, const boost::any& value) { if (m_on_change != nullptr) - m_on_change(id, value); + m_on_change(opt_id, value); } -Option ConfigOptionsGroup::get_option(const std::string opt_key, int opt_index /*= -1*/) +Option ConfigOptionsGroup::get_option(const std::string& opt_key, int opt_index /*= -1*/) { if (!m_config->has(opt_key)) { std::cerr << "No " << opt_key << " in ConfigOptionsGroup config."; @@ -245,7 +246,7 @@ Option ConfigOptionsGroup::get_option(const std::string opt_key, int opt_index / return Option(*m_config->def()->get(opt_key), opt_id); } -void ConfigOptionsGroup::on_change_OG(t_config_option_key opt_id, boost::any value) +void ConfigOptionsGroup::on_change_OG(const t_config_option_key& opt_id, const boost::any& value) { if (!m_opt_map.empty()) { @@ -268,16 +269,7 @@ void ConfigOptionsGroup::on_change_OG(t_config_option_key opt_id, boost::any val if (opt_index != -1){ // die "Can't set serialized option indexed value" ; } - // # Split a string to multiple strings by a semi - colon.This is the old way of storing multi - string values. - // # Currently used for the post_process config value only. - // my @values = split / ; / , $field_value; - // $self->config->set($opt_key, \@values); - std::string str = boost::any_cast(value); - if (str.back() == ';') - str.pop_back(); - std::vector values; - boost::split(values, str, boost::is_any_of(";")); - change_opt_value(*m_config, opt_key, values); + change_opt_value(*m_config, opt_key, value); } else { if (opt_index == -1) { @@ -297,14 +289,14 @@ void ConfigOptionsGroup::on_change_OG(t_config_option_key opt_id, boost::any val OptionsGroup::on_change_OG(opt_id, value); //!? Why doing this } -void ConfigOptionsGroup::back_to_initial_value(const std::string opt_key) +void ConfigOptionsGroup::back_to_initial_value(const std::string& opt_key) { if (m_get_initial_config == nullptr) return; back_to_config_value(m_get_initial_config(), opt_key); } -void ConfigOptionsGroup::back_to_sys_value(const std::string opt_key) +void ConfigOptionsGroup::back_to_sys_value(const std::string& opt_key) { if (m_get_sys_config == nullptr) return; @@ -313,7 +305,7 @@ void ConfigOptionsGroup::back_to_sys_value(const std::string opt_key) back_to_config_value(m_get_sys_config(), opt_key); } -void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config, const std::string opt_key) +void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config, const std::string& opt_key) { boost::any value; if (opt_key == "extruders_count"){ @@ -348,7 +340,7 @@ void ConfigOptionsGroup::reload_config(){ } -boost::any ConfigOptionsGroup::config_value(std::string opt_key, int opt_index, bool deserialize){ +boost::any ConfigOptionsGroup::config_value(const std::string& opt_key, int opt_index, bool deserialize){ if (deserialize) { // Want to edit a vector value(currently only multi - strings) in a single edit box. @@ -365,7 +357,7 @@ boost::any ConfigOptionsGroup::config_value(std::string opt_key, int opt_index, } } -boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config, std::string opt_key, int opt_index /*= -1*/) +boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config, const std::string& opt_key, int opt_index /*= -1*/) { size_t idx = opt_index == -1 ? 0 : opt_index; @@ -405,6 +397,10 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config ret = static_cast(config.opt_string(opt_key)); break; case coStrings: + if (opt_key.compare("compatible_printers") == 0){ + ret = config.option(opt_key)->values; + break; + } if (config.option(opt_key)->values.empty()) ret = text_value; else if (opt->gui_flags.compare("serialized") == 0){ @@ -457,7 +453,7 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config return ret; } -Field* ConfigOptionsGroup::get_fieldc(t_config_option_key opt_key, int opt_index){ +Field* ConfigOptionsGroup::get_fieldc(const t_config_option_key& opt_key, int opt_index){ Field* field = get_field(opt_key); if (field != nullptr) return field; @@ -471,7 +467,7 @@ Field* ConfigOptionsGroup::get_fieldc(t_config_option_key opt_key, int opt_index return opt_id.empty() ? nullptr : get_field(opt_id); } -void ogStaticText::SetText(wxString value) +void ogStaticText::SetText(const wxString& value) { SetLabel(value); Wrap(400); diff --git a/xs/src/slic3r/GUI/OptionsGroup.hpp b/xs/src/slic3r/GUI/OptionsGroup.hpp index e58d9c9a9..dd6d48f46 100644 --- a/xs/src/slic3r/GUI/OptionsGroup.hpp +++ b/xs/src/slic3r/GUI/OptionsGroup.hpp @@ -93,21 +93,21 @@ public: /// but defining it as const means a lot of const_casts to deal with wx functions. inline wxWindow* parent() const { return m_parent; } - void append_line(const Line& line); + void append_line(const Line& line, wxStaticText** colored_Label = nullptr); Line create_single_option_line(const Option& option) const; void append_single_option_line(const Option& option) { append_line(create_single_option_line(option)); } // return a non-owning pointer reference - inline Field* get_field(t_config_option_key id) const{ + inline Field* get_field(const t_config_option_key& id) const{ if (m_fields.find(id) == m_fields.end()) return nullptr; return m_fields.at(id).get(); } - bool set_value(t_config_option_key id, boost::any value, bool change_event = false) { + bool set_value(const t_config_option_key& id, const boost::any& value, bool change_event = false) { if (m_fields.find(id) == m_fields.end()) return false; m_fields.at(id)->set_value(value, change_event); return true; } - boost::any get_value(t_config_option_key id) { + boost::any get_value(const t_config_option_key& id) { boost::any out; if (m_fields.find(id) == m_fields.end()) ; else @@ -118,7 +118,7 @@ public: inline void enable() { for (auto& field : m_fields) field.second->enable(); } inline void disable() { for (auto& field : m_fields) field.second->disable(); } - OptionsGroup(wxWindow* _parent, wxString title, bool is_tab_opt=false) : + OptionsGroup(wxWindow* _parent, const wxString& title, bool is_tab_opt=false) : m_parent(_parent), title(title), m_is_tab_opt(is_tab_opt), staticbox(title!="") { sizer = (staticbox ? new wxStaticBoxSizer(new wxStaticBox(_parent, wxID_ANY, title), wxVERTICAL) : new wxBoxSizer(wxVERTICAL)); auto num_columns = 1U; @@ -152,14 +152,14 @@ protected: const t_field& build_field(const Option& opt, wxStaticText* label = nullptr); virtual void on_kill_focus (){}; - virtual void on_change_OG(t_config_option_key opt_id, boost::any value); - virtual void back_to_initial_value(const std::string opt_key){}; - virtual void back_to_sys_value(const std::string opt_key){}; + virtual void on_change_OG(const t_config_option_key& opt_id, const boost::any& value); + virtual void back_to_initial_value(const std::string& opt_key){} + virtual void back_to_sys_value(const std::string& opt_key){} }; class ConfigOptionsGroup: public OptionsGroup { public: - ConfigOptionsGroup(wxWindow* parent, wxString title, DynamicPrintConfig* _config = nullptr, bool is_tab_opt = false) : + ConfigOptionsGroup(wxWindow* parent, const wxString& title, DynamicPrintConfig* _config = nullptr, bool is_tab_opt = false) : OptionsGroup(parent, title, is_tab_opt), m_config(_config) {} /// reference to libslic3r config, non-owning pointer (?). @@ -167,8 +167,8 @@ public: bool m_full_labels {0}; t_opt_map m_opt_map; - Option get_option(const std::string opt_key, int opt_index = -1); - Line create_single_option_line(const std::string title, int idx = -1) /*const*/{ + Option get_option(const std::string& opt_key, int opt_index = -1); + Line create_single_option_line(const std::string& title, int idx = -1) /*const*/{ Option option = get_option(title, idx); return OptionsGroup::create_single_option_line(option); } @@ -181,16 +181,16 @@ public: append_single_option_line(option); } - void on_change_OG(t_config_option_key opt_id, boost::any value) override; - void back_to_initial_value(const std::string opt_key) override; - void back_to_sys_value(const std::string opt_key) override; - void back_to_config_value(const DynamicPrintConfig& config, const std::string opt_key); + void on_change_OG(const t_config_option_key& opt_id, const boost::any& value) override; + void back_to_initial_value(const std::string& opt_key) override; + void back_to_sys_value(const std::string& opt_key) override; + void back_to_config_value(const DynamicPrintConfig& config, const std::string& opt_key); void on_kill_focus() override{ reload_config();} void reload_config(); - boost::any config_value(std::string opt_key, int opt_index, bool deserialize); + boost::any config_value(const std::string& opt_key, int opt_index, bool deserialize); // return option value from config - boost::any get_config_value(const DynamicPrintConfig& config, std::string opt_key, int opt_index = -1); - Field* get_fieldc(t_config_option_key opt_key, int opt_index); + boost::any get_config_value(const DynamicPrintConfig& config, const std::string& opt_key, int opt_index = -1); + Field* get_fieldc(const t_config_option_key& opt_key, int opt_index); }; // Static text shown among the options. @@ -200,7 +200,7 @@ public: ogStaticText(wxWindow* parent, const char *text) : wxStaticText(parent, wxID_ANY, text, wxDefaultPosition, wxDefaultSize){} ~ogStaticText(){} - void SetText(wxString value); + void SetText(const wxString& value); }; }} diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index 5b3363a19..d48c9bf8f 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -416,6 +416,20 @@ const Preset* PresetCollection::get_selected_preset_parent() const return (preset == nullptr || preset->is_default || preset->is_external) ? nullptr : preset; } +const Preset* PresetCollection::get_preset_parent(const Preset& child) const +{ + auto *inherits = dynamic_cast(child.config.option("inherits")); + if (inherits == nullptr || inherits->value.empty()) +// return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr; + return nullptr; + const Preset* preset = this->find_preset(inherits->value, false); + return (preset == nullptr/* || preset->is_default */|| preset->is_external) ? nullptr : preset; +} + +const std::string& PresetCollection::get_suffix_modified() { + return g_suffix_modified; +} + // Return a preset by its name. If the preset is active, a temporary copy is returned. // If a preset is not found by its name, null is returned. Preset* PresetCollection::find_preset(const std::string &name, bool first_visible_if_not_found) @@ -497,16 +511,44 @@ void PresetCollection::update_platter_ui(wxBitmapComboBox *ui) // Otherwise fill in the list from scratch. ui->Freeze(); ui->Clear(); + std::map nonsys_presets; + wxString selected = ""; for (size_t i = this->m_presets.front().is_visible ? 0 : 1; i < this->m_presets.size(); ++ i) { const Preset &preset = this->m_presets[i]; if (! preset.is_visible || (! preset.is_compatible && i != m_idx_selected)) continue; const wxBitmap *bmp = (i == 0 || preset.is_compatible) ? m_bitmap_main_frame : m_bitmap_incompatible; - ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), - (bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp); - if (i == m_idx_selected) - ui->SetSelection(ui->GetCount() - 1); - } +// ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), +// (bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp); +// if (i == m_idx_selected) +// ui->SetSelection(ui->GetCount() - 1); + + if (preset.is_default || preset.is_system){ + ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), + (bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp); + if (i == m_idx_selected) + ui->SetSelection(ui->GetCount() - 1); + } + else + { + nonsys_presets.emplace(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), preset.is_compatible); + if (i == m_idx_selected) + selected = wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()); + } + if (preset.is_default) + ui->Append("------------------------------------", wxNullBitmap); + } + if (!nonsys_presets.empty()) + { + ui->Append("------------------------------------", wxNullBitmap); + for (std::map::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) { + const wxBitmap *bmp = it->second ? m_bitmap_compatible : m_bitmap_incompatible; + ui->Append(it->first, + (bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp); + if (it->first == selected) + ui->SetSelection(ui->GetCount() - 1); + } + } ui->Thaw(); } @@ -516,16 +558,44 @@ void PresetCollection::update_tab_ui(wxBitmapComboBox *ui, bool show_incompatibl return; ui->Freeze(); ui->Clear(); + std::map nonsys_presets; + wxString selected = ""; for (size_t i = this->m_presets.front().is_visible ? 0 : 1; i < this->m_presets.size(); ++ i) { const Preset &preset = this->m_presets[i]; if (! preset.is_visible || (! show_incompatible && ! preset.is_compatible && i != m_idx_selected)) continue; const wxBitmap *bmp = preset.is_compatible ? m_bitmap_compatible : m_bitmap_incompatible; - ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), - (bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp); - if (i == m_idx_selected) - ui->SetSelection(ui->GetCount() - 1); +// ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), +// (bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp); +// if (i == m_idx_selected) +// ui->SetSelection(ui->GetCount() - 1); + + if (preset.is_default || preset.is_system){ + ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), + (bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp); + if (i == m_idx_selected) + ui->SetSelection(ui->GetCount() - 1); + } + else + { + nonsys_presets.emplace(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), preset.is_compatible); + if (i == m_idx_selected) + selected = wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()); + } + if (preset.is_default) + ui->Append("------------------------------------", wxNullBitmap); } + if (!nonsys_presets.empty()) + { + ui->Append("------------------------------------", wxNullBitmap); + for (std::map::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) { + const wxBitmap *bmp = it->second ? m_bitmap_compatible : m_bitmap_incompatible; + ui->Append(it->first, + (bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp); + if (it->first == selected) + ui->SetSelection(ui->GetCount() - 1); + } + } ui->Thaw(); } diff --git a/xs/src/slic3r/GUI/Preset.hpp b/xs/src/slic3r/GUI/Preset.hpp index 3634c5dd9..c038160f4 100644 --- a/xs/src/slic3r/GUI/Preset.hpp +++ b/xs/src/slic3r/GUI/Preset.hpp @@ -209,9 +209,17 @@ public: // The parent preset may be a system preset or a user preset, which will be // reflected by the UI. const Preset* get_selected_preset_parent() const; - // Return the selected preset including the user modifications. + // get parent preset for some child preset + const Preset* get_preset_parent(const Preset& child) const; + // Return the selected preset including the user modifications. Preset& get_edited_preset() { return m_edited_preset; } const Preset& get_edited_preset() const { return m_edited_preset; } + + // used to update preset_choice from Tab + const std::deque& get_presets() { return m_presets; } + int get_idx_selected() { return m_idx_selected; } + const std::string& get_suffix_modified(); + // Return a preset possibly with modifications. const Preset& default_preset() const { return m_presets.front(); } // Return a preset by an index. If the preset is active, a temporary copy is returned. diff --git a/xs/src/slic3r/GUI/PresetBundle.cpp b/xs/src/slic3r/GUI/PresetBundle.cpp index 207968f1b..1c3a6dcac 100644 --- a/xs/src/slic3r/GUI/PresetBundle.cpp +++ b/xs/src/slic3r/GUI/PresetBundle.cpp @@ -261,8 +261,8 @@ bool PresetBundle::load_compatible_bitmaps() { const std::string path_bitmap_compatible = "flag-green-icon.png"; const std::string path_bitmap_incompatible = "flag-red-icon.png"; - const std::string path_bitmap_lock = "lock.png"; - const std::string path_bitmap_lock_open = "lock_open.png"; + const std::string path_bitmap_lock = "sys_lock.png";//"lock.png"; + const std::string path_bitmap_lock_open = "sys_unlock.png";//"lock_open.png"; bool loaded_compatible = m_bitmapCompatible ->LoadFile( wxString::FromUTF8(Slic3r::var(path_bitmap_compatible).c_str()), wxBITMAP_TYPE_PNG); bool loaded_incompatible = m_bitmapIncompatible->LoadFile( @@ -1025,6 +1025,8 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, wxBitma // and draw a red flag in front of the selected preset. bool wide_icons = selected_preset != nullptr && ! selected_preset->is_compatible && m_bitmapIncompatible != nullptr; assert(selected_preset != nullptr); + std::map nonsys_presets; + wxString selected_str = ""; for (int i = this->filaments().front().is_visible ? 0 : 1; i < int(this->filaments().size()); ++ i) { const Preset &preset = this->filaments.preset(i); bool selected = this->filament_presets[idx_extruder] == preset.name; @@ -1062,10 +1064,36 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, wxBitma (preset.is_dirty ? *m_bitmapLockOpen : *m_bitmapLock) : m_bitmapCache->mkclear(16, 16)); bitmap = m_bitmapCache->insert(bitmap_key, bmps); } - ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()), (bitmap == 0) ? wxNullBitmap : *bitmap); - if (selected) - ui->SetSelection(ui->GetCount() - 1); +// ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()), (bitmap == 0) ? wxNullBitmap : *bitmap); +// if (selected) +// ui->SetSelection(ui->GetCount() - 1); + + if (preset.is_default || preset.is_system){ + ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()), + (bitmap == 0) ? wxNullBitmap : *bitmap); + if (selected) + ui->SetSelection(ui->GetCount() - 1); + } + else + { + nonsys_presets.emplace(wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()), + (bitmap == 0) ? wxNullBitmap : *bitmap); + if (selected) + selected_str = wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()); + } + if (preset.is_default) + ui->Append("------------------------------------", wxNullBitmap); } + + if (!nonsys_presets.empty()) + { + ui->Append("------------------------------------", wxNullBitmap); + for (std::map::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) { + ui->Append(it->first, it->second); + if (it->first == selected_str) + ui->SetSelection(ui->GetCount() - 1); + } + } ui->Thaw(); } diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index 59994ecc3..cc4b18c7c 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -22,6 +22,7 @@ #include #include +#include "wxExtensions.hpp" namespace Slic3r { namespace GUI { @@ -39,7 +40,42 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle) // preset chooser m_presets_choice = new wxBitmapComboBox(panel, wxID_ANY, "", wxDefaultPosition, wxSize(270, -1), 0, 0,wxCB_READONLY); + /* + m_cc_presets_choice = new wxComboCtrl(panel, wxID_ANY, L(""), wxDefaultPosition, wxDefaultSize, wxCB_READONLY); + wxDataViewTreeCtrlComboPopup* popup = new wxDataViewTreeCtrlComboPopup; + if (popup != nullptr) + { + // FIXME If the following line is removed, the combo box popup list will not react to mouse clicks. + // On the other side, with this line the combo box popup cannot be closed by clicking on the combo button on Windows 10. +// m_cc_presets_choice->UseAltPopupWindow(); +// m_cc_presets_choice->EnablePopupAnimation(false); + m_cc_presets_choice->SetPopupControl(popup); + popup->SetStringValue(from_u8("Text1")); + + popup->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this, popup](wxCommandEvent& evt) + { + auto selected = popup->GetItemText(popup->GetSelection()); + if (selected != _(L("System presets")) && selected != _(L("Default presets"))) + { + m_cc_presets_choice->SetText(selected); + std::string selected_string = selected.ToUTF8().data(); +#ifdef __APPLE__ +#else + select_preset(selected_string); +#endif + } + }); + +// popup->Bind(wxEVT_KEY_DOWN, [popup](wxKeyEvent& evt) { popup->OnKeyEvent(evt); }); +// popup->Bind(wxEVT_KEY_UP, [popup](wxKeyEvent& evt) { popup->OnKeyEvent(evt); }); + + auto icons = new wxImageList(16, 16, true, 1); + popup->SetImageList(icons); + icons->Add(*new wxIcon(from_u8(Slic3r::var("flag-green-icon.png")), wxBITMAP_TYPE_PNG)); + icons->Add(*new wxIcon(from_u8(Slic3r::var("flag-red-icon.png")), wxBITMAP_TYPE_PNG)); + } +*/ auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); //buttons @@ -84,11 +120,44 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle) m_hsizer->AddSpacer(64); m_hsizer->Add(m_undo_to_sys_btn, 0, wxALIGN_CENTER_VERTICAL); m_hsizer->Add(m_undo_btn, 0, wxALIGN_CENTER_VERTICAL); +// m_hsizer->AddSpacer(64); +// m_hsizer->Add(m_cc_presets_choice, 1, wxLEFT | wxRIGHT | wxTOP | wxALIGN_CENTER_VERTICAL, 3); //Horizontal sizer to hold the tree and the selected page. m_hsizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(m_hsizer, 1, wxEXPAND, 0); + +/* + + + //temporary left vertical sizer + m_left_sizer = new wxBoxSizer(wxVERTICAL); + m_hsizer->Add(m_left_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 3); + + // tree + m_presetctrl = new wxDataViewTreeCtrl(panel, wxID_ANY, wxDefaultPosition, wxSize(200, -1), wxDV_NO_HEADER); + m_left_sizer->Add(m_presetctrl, 1, wxEXPAND); + m_preset_icons = new wxImageList(16, 16, true, 1); + m_presetctrl->SetImageList(m_preset_icons); + m_preset_icons->Add(*new wxIcon(from_u8(Slic3r::var("flag-green-icon.png")), wxBITMAP_TYPE_PNG)); + m_preset_icons->Add(*new wxIcon(from_u8(Slic3r::var("flag-red-icon.png")), wxBITMAP_TYPE_PNG)); + + m_presetctrl->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxCommandEvent& evt) + { + auto selected = m_presetctrl->GetItemText(m_presetctrl->GetSelection()); + if (selected != _(L("System presets")) && selected != _(L("Default presets"))) + { + std::string selected_string = selected.ToUTF8().data(); +#ifdef __APPLE__ +#else + select_preset(selected_string); +#endif + } + }); + +*/ + //left vertical sizer m_left_sizer = new wxBoxSizer(wxVERTICAL); m_hsizer->Add(m_left_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 3); @@ -136,11 +205,10 @@ void Tab::load_initial_data() { m_config = &m_presets->get_edited_preset().config; m_nonsys_btn_icon = m_presets->get_selected_preset_parent() == nullptr ? - "bullet_white.png" : - wxMSW ? "sys_unlock.png" : "lock_open.png"; + "bullet_white.png" : "sys_unlock.png"; } -PageShp Tab::add_options_page(wxString title, std::string icon, bool is_extruder_pages/* = false*/) +PageShp Tab::add_options_page(const wxString& title, const std::string& icon, bool is_extruder_pages/* = false*/) { // Index of icon in an icon list $self->{icons}. auto icon_idx = 0; @@ -260,13 +328,14 @@ void Tab::update_changed_ui() m_dirty_options = dirty_options; } + Freeze(); //update options "decoration" for (const auto opt_key : m_full_options_list) { bool is_nonsys_value = false; bool is_modified_value = true; - std::string sys_icon = wxMSW ? "sys_lock.png" : "lock.png"; - std::string icon = wxMSW ? "action_undo.png" : "arrow_undo.png"; + std::string sys_icon = "sys_lock.png"; + std::string icon = "action_undo.png"; wxColour color = get_sys_label_clr(); if (find(m_sys_options.begin(), m_sys_options.end(), opt_key) == m_sys_options.end()) { is_nonsys_value = true; @@ -281,6 +350,14 @@ void Tab::update_changed_ui() is_modified_value = false; icon = "bullet_white.png"; } + if (opt_key == "bed_shape" || opt_key == "compatible_printers") { + if (m_colored_Label != nullptr) { + m_colored_Label->SetForegroundColour(color); + m_colored_Label->Refresh(true); + } + continue; + } + Field* field = get_field(opt_key); if (field == nullptr) continue; field->m_is_nonsys_value = is_nonsys_value; @@ -292,6 +369,7 @@ void Tab::update_changed_ui() field->m_Label->Refresh(true); } } + Thaw(); wxTheApp->CallAfter([this]() { update_changed_tree_ui(); @@ -353,13 +431,20 @@ void Tab::update_sys_ui_after_sel_preset() m_sys_options.resize(0); } +void Tab::get_sys_and_mod_flags(const std::string& opt_key, bool& sys_page, bool& modified_page) +{ + if (sys_page && find(m_sys_options.begin(), m_sys_options.end(), opt_key) == m_sys_options.end()) + sys_page = false; + if (!modified_page && find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) != m_dirty_options.end()) + modified_page = true; +} + void Tab::update_changed_tree_ui() { auto cur_item = m_treectrl->GetFirstVisibleItem(); auto selection = m_treectrl->GetItemText(m_treectrl->GetSelection()); while (cur_item){ auto title = m_treectrl->GetItemText(cur_item); - int i=0; for (auto page : m_pages) { if (page->title() != title) @@ -369,23 +454,20 @@ void Tab::update_changed_tree_ui() if (title == _("General")){ std::initializer_list optional_keys{ "extruders_count", "bed_shape" }; for (auto &opt_key : optional_keys) { - if (sys_page && find(m_sys_options.begin(), m_sys_options.end(), opt_key) == m_sys_options.end()) - sys_page = false; - if (!modified_page && find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) != m_dirty_options.end()) - modified_page = true; + get_sys_and_mod_flags(opt_key, sys_page, modified_page); } } + if (title == _("Dependencies")){ + get_sys_and_mod_flags("compatible_printers", sys_page, modified_page); + } for (auto group : page->m_optgroups) { - for (t_opt_map::iterator it = group->m_opt_map.begin(); it != group->m_opt_map.end(); ++it) { - const std::string& opt_key = it->first; - if (sys_page && find(m_sys_options.begin(), m_sys_options.end(), opt_key) == m_sys_options.end()) - sys_page = false; - if (!modified_page && find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) != m_dirty_options.end()) - modified_page = true; - } if (!sys_page && modified_page) break; + for (t_opt_map::iterator it = group->m_opt_map.begin(); it != group->m_opt_map.end(); ++it) { + const std::string& opt_key = it->first; + get_sys_and_mod_flags(opt_key, sys_page, modified_page); + } } if (sys_page) m_treectrl->SetItemTextColour(cur_item, get_sys_label_clr()); @@ -411,10 +493,8 @@ void Tab::update_changed_tree_ui() void Tab::update_undo_buttons() { - const std::string& undo_icon = !m_is_modified_values ? "bullet_white.png" : - wxMSW ? "action_undo.png" : "arrow_undo.png"; - const std::string& undo_to_sys_icon = m_is_nonsys_values ? m_nonsys_btn_icon : - wxMSW ? "sys_lock.png" : "lock.png"; + const std::string& undo_icon = !m_is_modified_values ? "bullet_white.png" : "action_undo.png"; + const std::string& undo_to_sys_icon = m_is_nonsys_values ? m_nonsys_btn_icon : "sys_lock.png"; m_undo_btn->SetBitmap(wxBitmap(from_u8(var(undo_icon)), wxBITMAP_TYPE_PNG)); m_undo_to_sys_btn->SetBitmap(wxBitmap(from_u8(var(undo_to_sys_icon)), wxBITMAP_TYPE_PNG)); @@ -436,6 +516,14 @@ void Tab::on_back_to_initial_value() if (find(m_dirty_options.begin(), m_dirty_options.end(), "bed_shape") != m_dirty_options.end()) group->back_to_initial_value("bed_shape"); } + if (group->title == _("Profile dependencies")){ + if (find(m_dirty_options.begin(), m_dirty_options.end(), "compatible_printers") != m_dirty_options.end()) + group->back_to_initial_value("compatible_printers"); + + bool is_empty = m_config->option("compatible_printers")->values.empty(); + m_compatible_printers_checkbox->SetValue(is_empty); + is_empty ? m_compatible_printers_btn->Disable() : m_compatible_printers_btn->Enable(); + } for (t_opt_map::iterator it = group->m_opt_map.begin(); it != group->m_opt_map.end(); ++it) { const std::string& opt_key = it->first; if (find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) != m_dirty_options.end()) @@ -463,6 +551,14 @@ void Tab::on_back_to_sys_value() if (find(m_sys_options.begin(), m_sys_options.end(), "bed_shape") == m_sys_options.end()) group->back_to_sys_value("bed_shape"); } + if (group->title == _("Profile dependencies")){ + if (find(m_sys_options.begin(), m_sys_options.end(), "compatible_printers") == m_sys_options.end()) + group->back_to_sys_value("compatible_printers"); + + bool is_empty = m_config->option("compatible_printers")->values.empty(); + m_compatible_printers_checkbox->SetValue(is_empty); + is_empty ? m_compatible_printers_btn->Disable() : m_compatible_printers_btn->Enable(); + } for (t_opt_map::iterator it = group->m_opt_map.begin(); it != group->m_opt_map.end(); ++it) { const std::string& opt_key = it->first; if (find(m_sys_options.begin(), m_sys_options.end(), opt_key) == m_sys_options.end()) @@ -480,16 +576,19 @@ void Tab::update_dirty(){ m_presets->update_dirty_ui(m_presets_choice); on_presets_changed(); update_changed_ui(); +// update_dirty_presets(m_cc_presets_choice); } void Tab::update_tab_ui() { m_presets->update_tab_ui(m_presets_choice, m_show_incompatible_presets); +// update_tab_presets(m_cc_presets_choice, m_show_incompatible_presets); +// update_presetsctrl(m_presetctrl, m_show_incompatible_presets); } // Load a provied DynamicConfig into the tab, modifying the active preset. // This could be used for example by setting a Wipe Tower position by interactive manipulation in the 3D view. -void Tab::load_config(DynamicPrintConfig config) +void Tab::load_config(const DynamicPrintConfig& config) { bool modified = 0; for(auto opt_key : m_config->diff(config)) { @@ -512,7 +611,7 @@ void Tab::reload_config(){ Thaw(); } -Field* Tab::get_field(t_config_option_key opt_key, int opt_index/* = -1*/) const +Field* Tab::get_field(const t_config_option_key& opt_key, int opt_index/* = -1*/) const { Field* field = nullptr; for (auto page : m_pages){ @@ -526,7 +625,7 @@ Field* Tab::get_field(t_config_option_key opt_key, int opt_index/* = -1*/) const // Set a key/value pair on this page. Return true if the value has been modified. // Currently used for distributing extruders_count over preset pages of Slic3r::GUI::Tab::Printer // after a preset is loaded. -bool Tab::set_value(t_config_option_key opt_key, boost::any value){ +bool Tab::set_value(const t_config_option_key& opt_key, const boost::any& value){ bool changed = false; for(auto page: m_pages) { if (page->set_value(opt_key, value)) @@ -537,7 +636,7 @@ bool Tab::set_value(t_config_option_key opt_key, boost::any value){ // To be called by custom widgets, load a value into a config, // update the preset selection boxes (the dirty flags) -void Tab::load_key_value(std::string opt_key, boost::any value) +void Tab::load_key_value(const std::string& opt_key, const boost::any& value) { change_opt_value(*m_config, opt_key, value); // Mark the print & filament enabled if they are compatible with the currently selected preset. @@ -551,7 +650,7 @@ void Tab::load_key_value(std::string opt_key, boost::any value) extern wxFrame *g_wxMainFrame; -void Tab::on_value_change(std::string opt_key, boost::any value) +void Tab::on_value_change(const std::string& opt_key, const boost::any& value) { if (m_event_value_change > 0) { wxCommandEvent event(m_event_value_change); @@ -566,8 +665,8 @@ void Tab::on_value_change(std::string opt_key, boost::any value) } if (opt_key == "fill_density") { - value = get_optgroup()->get_config_value(*m_config, opt_key); - get_optgroup()->set_value(opt_key, value); + boost::any val = get_optgroup()->get_config_value(*m_config, opt_key); + get_optgroup()->set_value(opt_key, val); } if (opt_key == "support_material" || opt_key == "support_material_buildplate_only") { @@ -858,7 +957,7 @@ void TabPrint::build() line.widget = [this](wxWindow* parent){ return compatible_printers_widget(parent, &m_compatible_printers_checkbox, &m_compatible_printers_btn); }; - optgroup->append_line(line); + optgroup->append_line(line, &m_colored_Label); option = optgroup->get_option("compatible_printers_condition"); option.opt.full_width = true; @@ -1233,7 +1332,7 @@ void TabFilament::build() line.widget = [this](wxWindow* parent){ return compatible_printers_widget(parent, &m_compatible_printers_checkbox, &m_compatible_printers_btn); }; - optgroup->append_line(line); + optgroup->append_line(line, &m_colored_Label); option = optgroup->get_option("compatible_printers_condition"); option.opt.full_width = true; @@ -1327,7 +1426,7 @@ void TabPrinter::build() return sizer; }; - optgroup->append_line(line); + optgroup->append_line(line, &m_colored_Label); optgroup->append_single_option_line("max_print_height"); optgroup->append_single_option_line("z_offset"); @@ -1755,9 +1854,7 @@ void Tab::load_current_preset() // Reload preset pages with the new configuration values. reload_config(); const Preset* parent = m_presets->get_selected_preset_parent(); - m_nonsys_btn_icon = parent == nullptr ? - "bullet_white.png" : - wxMSW ? "sys_unlock.png" : "lock_open.png"; + m_nonsys_btn_icon = parent == nullptr ? "bullet_white.png" : "sys_unlock.png"; // use CallAfter because some field triggers schedule on_change calls using CallAfter, // and we don't want them to be called after this update_dirty() as they would mark the @@ -1814,7 +1911,7 @@ void Tab::rebuild_page_tree() // Called by the UI combo box when the user switches profiles. // Select a preset by a name.If !defined(name), then the default preset is selected. // If the current profile is modified, user is asked to save the changes. -void Tab::select_preset(std::string preset_name /*= ""*/) +void Tab::select_preset(const std::string& preset_name /*= ""*/) { std::string name = preset_name; auto force = false; @@ -1881,7 +1978,7 @@ void Tab::select_preset(std::string preset_name /*= ""*/) // If the current preset is dirty, the user is asked whether the changes may be discarded. // if the current preset was not dirty, or the user agreed to discard the changes, 1 is returned. -bool Tab::may_discard_current_dirty_preset(PresetCollection* presets /*= nullptr*/, std::string new_printer_name /*= ""*/) +bool Tab::may_discard_current_dirty_preset(PresetCollection* presets /*= nullptr*/, const std::string& new_printer_name /*= ""*/) { if (presets == nullptr) presets = m_presets; // Display a dialog showing the dirty options in a human readable form. @@ -2089,6 +2186,7 @@ wxSizer* Tab::compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox if ((*checkbox)->GetValue()) load_key_value("compatible_printers", std::vector {}); get_field("compatible_printers_condition")->toggle((*checkbox)->GetValue()); + update_changed_ui(); }) ); (*btn)->Bind(wxEVT_BUTTON, ([this, parent, checkbox, btn](wxCommandEvent e) @@ -2131,18 +2229,186 @@ wxSizer* Tab::compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox } // All printers have been made compatible with this preset. load_key_value("compatible_printers", value); + update_changed_ui(); } })); return sizer; } +void Tab::update_presetsctrl(wxDataViewTreeCtrl* ui, bool show_incompatible) +{ + if (ui == nullptr) + return; + ui->Freeze(); + ui->DeleteAllItems(); + auto presets = m_presets->get_presets(); + auto idx_selected = m_presets->get_idx_selected(); + auto suffix_modified = m_presets->get_suffix_modified(); + int icon_compatible = 0; + int icon_incompatible = 1; + int cnt_items = 0; + + auto root_sys = ui->AppendContainer(wxDataViewItem(0), _(L("System presets"))); + auto root_def = ui->AppendContainer(wxDataViewItem(0), _(L("Default presets"))); + + auto show_def = get_app_config()->get("no_defaults")[0] != '1'; + + for (size_t i = presets.front().is_visible ? 0 : 1; i < presets.size(); ++i) { + const Preset &preset = presets[i]; + if (!preset.is_visible || (!show_incompatible && !preset.is_compatible && i != idx_selected)) + continue; + + auto preset_name = wxString::FromUTF8((preset.name + (preset.is_dirty ? suffix_modified : "")).c_str()); + + wxDataViewItem item; + if (preset.is_system) + item = ui->AppendItem(root_sys, preset_name, + preset.is_compatible ? icon_compatible : icon_incompatible); + else if (show_def && preset.is_default) + item = ui->AppendItem(root_def, preset_name, + preset.is_compatible ? icon_compatible : icon_incompatible); + else + { + auto parent = m_presets->get_preset_parent(preset); + if (parent == nullptr) + item = ui->AppendItem(root_def, preset_name, + preset.is_compatible ? icon_compatible : icon_incompatible); + else + { + auto parent_name = parent->name; + + wxDataViewTreeStoreContainerNode *node = ui->GetStore()->FindContainerNode(root_sys); + if (node) + { + wxDataViewTreeStoreNodeList::iterator iter; + for (iter = node->GetChildren().begin(); iter != node->GetChildren().end(); iter++) + { + wxDataViewTreeStoreNode* child = *iter; + auto child_item = child->GetItem(); + auto item_text = ui->GetItemText(child_item); + if (item_text == parent_name) + { + auto added_child = ui->AppendItem(child->GetItem(), preset_name, + preset.is_compatible ? icon_compatible : icon_incompatible); + if (!added_child){ + ui->DeleteItem(child->GetItem()); + auto new_parent = ui->AppendContainer(root_sys, parent_name, + preset.is_compatible ? icon_compatible : icon_incompatible); + ui->AppendItem(new_parent, preset_name, + preset.is_compatible ? icon_compatible : icon_incompatible); + } + break; + } + } + } + } + } + + cnt_items++; + if (i == idx_selected){ + ui->Select(item); + m_cc_presets_choice->SetText(preset_name); + } + } + if (ui->GetStore()->GetChildCount(root_def) == 0) + ui->DeleteItem(root_def); + + ui->Thaw(); +} + +void Tab::update_tab_presets(wxComboCtrl* ui, bool show_incompatible) +{ + if (ui == nullptr) + return; + ui->Freeze(); + ui->Clear(); + auto presets = m_presets->get_presets(); + auto idx_selected = m_presets->get_idx_selected(); + auto suffix_modified = m_presets->get_suffix_modified(); + int icon_compatible = 0; + int icon_incompatible = 1; + int cnt_items = 0; + + wxDataViewTreeCtrlComboPopup* popup = wxDynamicCast(m_cc_presets_choice->GetPopupControl(), wxDataViewTreeCtrlComboPopup); + if (popup != nullptr) + { + popup->DeleteAllItems(); + + auto root_sys = popup->AppendContainer(wxDataViewItem(0), _(L("System presets"))); + auto root_def = popup->AppendContainer(wxDataViewItem(0), _(L("Default presets"))); + + auto show_def = get_app_config()->get("no_defaults")[0] != '1'; + + for (size_t i = presets.front().is_visible ? 0 : 1; i < presets.size(); ++i) { + const Preset &preset = presets[i]; + if (!preset.is_visible || (!show_incompatible && !preset.is_compatible && i != idx_selected)) + continue; + + auto preset_name = wxString::FromUTF8((preset.name + (preset.is_dirty ? suffix_modified : "")).c_str()); + + wxDataViewItem item; + if (preset.is_system) + item = popup->AppendItem(root_sys, preset_name, + preset.is_compatible ? icon_compatible : icon_incompatible); + else if (show_def && preset.is_default) + item = popup->AppendItem(root_def, preset_name, + preset.is_compatible ? icon_compatible : icon_incompatible); + else + { + auto parent = m_presets->get_preset_parent(preset); + if (parent == nullptr) + item = popup->AppendItem(root_def, preset_name, + preset.is_compatible ? icon_compatible : icon_incompatible); + else + { + auto parent_name = parent->name; + + wxDataViewTreeStoreContainerNode *node = popup->GetStore()->FindContainerNode(root_sys); + if (node) + { + wxDataViewTreeStoreNodeList::iterator iter; + for (iter = node->GetChildren().begin(); iter != node->GetChildren().end(); iter++) + { + wxDataViewTreeStoreNode* child = *iter; + auto child_item = child->GetItem(); + auto item_text = popup->GetItemText(child_item); + if (item_text == parent_name) + { + auto added_child = popup->AppendItem(child->GetItem(), preset_name, + preset.is_compatible ? icon_compatible : icon_incompatible); + if (!added_child){ + popup->DeleteItem(child->GetItem()); + auto new_parent = popup->AppendContainer(root_sys, parent_name, + preset.is_compatible ? icon_compatible : icon_incompatible); + popup->AppendItem(new_parent, preset_name, + preset.is_compatible ? icon_compatible : icon_incompatible); + } + break; + } + } + } + } + } + + cnt_items++; + if (i == idx_selected){ + popup->Select(item); + m_cc_presets_choice->SetText(preset_name); + } + } + if (popup->GetStore()->GetChildCount(root_def) == 0) + popup->DeleteItem(root_def); + } + ui->Thaw(); +} + void Page::reload_config() { for (auto group : m_optgroups) group->reload_config(); } -Field* Page::get_field(t_config_option_key opt_key, int opt_index/* = -1*/) const +Field* Page::get_field(const t_config_option_key& opt_key, int opt_index /*= -1*/) const { Field* field = nullptr; for (auto opt : m_optgroups){ @@ -2153,7 +2419,7 @@ Field* Page::get_field(t_config_option_key opt_key, int opt_index/* = -1*/) cons return field; } -bool Page::set_value(t_config_option_key opt_key, boost::any value){ +bool Page::set_value(const t_config_option_key& opt_key, const boost::any& value){ bool changed = false; for(auto optgroup: m_optgroups) { if (optgroup->set_value(opt_key, value)) @@ -2163,7 +2429,7 @@ bool Page::set_value(t_config_option_key opt_key, boost::any value){ } // package Slic3r::GUI::Tab::Page; -ConfigOptionsGroupShp Page::new_optgroup(wxString title, int noncommon_label_width /*= -1*/) +ConfigOptionsGroupShp Page::new_optgroup(const wxString& title, int noncommon_label_width /*= -1*/) { //! config_ have to be "right" ConfigOptionsGroupShp optgroup = std::make_shared(this, title, m_config, true); @@ -2204,7 +2470,7 @@ ConfigOptionsGroupShp Page::new_optgroup(wxString title, int noncommon_label_wid return optgroup; } -void SavePresetWindow::build(wxString title, std::string default_name, std::vector &values) +void SavePresetWindow::build(const wxString& title, const std::string& default_name, std::vector &values) { auto text = new wxStaticText(this, wxID_ANY, _(L("Save ")) + title + _(L(" as:")), wxDefaultPosition, wxDefaultSize); diff --git a/xs/src/slic3r/GUI/Tab.hpp b/xs/src/slic3r/GUI/Tab.hpp index c3a6fb573..f9ee4f363 100644 --- a/xs/src/slic3r/GUI/Tab.hpp +++ b/xs/src/slic3r/GUI/Tab.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -67,9 +68,9 @@ public: size_t iconID() const { return m_iconID; } void set_config(DynamicPrintConfig* config_in) { m_config = config_in; } void reload_config(); - Field* get_field(t_config_option_key opt_key, int opt_index = -1) const; - bool set_value(t_config_option_key opt_key, boost::any value); - ConfigOptionsGroupShp new_optgroup(wxString title, int noncommon_label_width = -1); + Field* get_field(const t_config_option_key& opt_key, int opt_index = -1) const; + bool set_value(const t_config_option_key& opt_key, const boost::any& value); + ConfigOptionsGroupShp new_optgroup(const wxString& title, int noncommon_label_width = -1); }; // Slic3r::GUI::Tab; @@ -95,6 +96,9 @@ protected: wxButton* m_compatible_printers_btn; wxButton* m_undo_btn; wxButton* m_undo_to_sys_btn; + wxComboCtrl* m_cc_presets_choice; + wxDataViewTreeCtrl* m_presetctrl; + wxImageList* m_preset_icons; int m_icon_count; std::map m_icon_index; // Map from an icon file name to its index @@ -122,10 +126,11 @@ public: DynamicPrintConfig* m_config; std::string m_nonsys_btn_icon; ogStaticText* m_parent_preset_description_line; + wxStaticText* m_colored_Label = nullptr; public: Tab() {} - Tab(wxNotebook* parent, wxString title, const char* name, bool no_controller) : + Tab(wxNotebook* parent, const wxString& title, const char* name, bool no_controller) : m_parent(parent), m_title(title), m_name(name), m_no_controller(no_controller) { Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL); get_tabs_list().push_back(this); @@ -143,11 +148,12 @@ public: void create_preset_tab(PresetBundle *preset_bundle); void load_current_preset(); void rebuild_page_tree(); - void select_preset(std::string preset_name = ""); - bool may_discard_current_dirty_preset(PresetCollection* presets = nullptr, std::string new_printer_name = ""); + void select_preset(const std::string& preset_name = ""); + bool may_discard_current_dirty_preset(PresetCollection* presets = nullptr, const std::string& new_printer_name = ""); wxSizer* compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox, wxButton** btn); - void load_key_value(std::string opt_key, boost::any value); + void update_presetsctrl(wxDataViewTreeCtrl* ui, bool show_incompatible); + void load_key_value(const std::string& opt_key, const boost::any& value); void reload_compatible_printers_widget(); void OnTreeSelChange(wxTreeEvent& event); @@ -161,13 +167,14 @@ public: void update_changed_ui(); void update_full_options_list(); void update_sys_ui_after_sel_preset(); + void get_sys_and_mod_flags(const std::string& opt_key, bool& sys_page, bool& modified_page); void update_changed_tree_ui(); void update_undo_buttons(); void on_back_to_initial_value(); void on_back_to_sys_value(); - PageShp add_options_page(wxString title, std::string icon, bool is_extruder_pages = false); + PageShp add_options_page(const wxString& title, const std::string& icon, bool is_extruder_pages = false); virtual void OnActivate(){} virtual void on_preset_loaded(){} @@ -176,10 +183,10 @@ public: void load_initial_data(); void update_dirty(); void update_tab_ui(); - void load_config(DynamicPrintConfig config); + void load_config(const DynamicPrintConfig& config); virtual void reload_config(); - Field* get_field(t_config_option_key opt_key, int opt_index = -1) const; - bool set_value(t_config_option_key opt_key, boost::any value); + Field* get_field(const t_config_option_key& opt_key, int opt_index = -1) const; + bool set_value(const t_config_option_key& opt_key, const boost::any& value); wxSizer* description_line_widget(wxWindow* parent, ogStaticText** StaticText); bool current_preset_is_dirty(); DynamicPrintConfig* get_config() { return m_config; } @@ -189,12 +196,13 @@ public: } std::vector get_dependent_tabs() { return m_reload_dependent_tabs; } - void on_value_change(std::string opt_key, boost::any value); + void on_value_change(const std::string& opt_key, const boost::any& value); protected: void on_presets_changed(); void update_frequently_changed_parameters(); void update_wiping_button_visibility(); + void update_tab_presets(wxComboCtrl* ui, bool show_incompatible); }; //Slic3r::GUI::Tab::Print; @@ -265,7 +273,7 @@ public: std::string m_chosen_name; wxComboBox* m_combo; - void build(wxString title, std::string default_name, std::vector &values); + void build(const wxString& title, const std::string& default_name, std::vector &values); void accept(); std::string get_name() { return m_chosen_name; } }; diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp index 1ebd7979e..8bc282474 100644 --- a/xs/src/slic3r/GUI/wxExtensions.cpp +++ b/xs/src/slic3r/GUI/wxExtensions.cpp @@ -109,3 +109,59 @@ void wxCheckListBoxComboPopup::OnListBoxSelection(wxCommandEvent& evt) ProcessEvent(event); } } + + +// *** wxDataViewTreeCtrlComboPopup *** + +const unsigned int wxDataViewTreeCtrlComboPopup::DefaultWidth = 270; +const unsigned int wxDataViewTreeCtrlComboPopup::DefaultHeight = 200; +const unsigned int wxDataViewTreeCtrlComboPopup::DefaultItemHeight = 22; + +bool wxDataViewTreeCtrlComboPopup::Create(wxWindow* parent) +{ + return wxDataViewTreeCtrl::Create(parent, wxID_ANY/*HIGHEST + 1*/, wxPoint(0, 0), wxDefaultSize/*wxSize(270, -1)*/, wxDV_NO_HEADER); +} +/* +wxSize wxDataViewTreeCtrlComboPopup::GetAdjustedSize(int minWidth, int prefHeight, int maxHeight) +{ + // matches owner wxComboCtrl's width + // and sets height dinamically in dependence of contained items count + wxComboCtrl* cmb = GetComboCtrl(); + if (cmb != nullptr) + { + wxSize size = GetComboCtrl()->GetSize(); + if (m_cnt_open_items > 0) + size.SetHeight(m_cnt_open_items * DefaultItemHeight); + else + size.SetHeight(DefaultHeight); + + return size; + } + else + return wxSize(DefaultWidth, DefaultHeight); +} +*/ +void wxDataViewTreeCtrlComboPopup::OnKeyEvent(wxKeyEvent& evt) +{ + // filters out all the keys which are not working properly + if (evt.GetKeyCode() == WXK_UP) + { + return; + } + else if (evt.GetKeyCode() == WXK_DOWN) + { + return; + } + else + { + evt.Skip(); + return; + } +} + +void wxDataViewTreeCtrlComboPopup::OnDataViewTreeCtrlSelection(wxCommandEvent& evt) +{ + wxComboCtrl* cmb = GetComboCtrl(); + auto selected = GetItemText(GetSelection()); + cmb->SetText(selected); +} diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp index e61c17bbc..ed8bb9276 100644 --- a/xs/src/slic3r/GUI/wxExtensions.hpp +++ b/xs/src/slic3r/GUI/wxExtensions.hpp @@ -3,6 +3,7 @@ #include #include +#include class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup { @@ -25,4 +26,28 @@ public: void OnListBoxSelection(wxCommandEvent& evt); }; + +// *** wxDataViewTreeCtrlComboBox *** + +class wxDataViewTreeCtrlComboPopup: public wxDataViewTreeCtrl, public wxComboPopup +{ + static const unsigned int DefaultWidth; + static const unsigned int DefaultHeight; + static const unsigned int DefaultItemHeight; + + wxString m_text; + int m_cnt_open_items{0}; + +public: + virtual bool Create(wxWindow* parent); + virtual wxWindow* GetControl() { return this; } + virtual void SetStringValue(const wxString& value) { m_text = value; } + virtual wxString GetStringValue() const { return m_text; } +// virtual wxSize GetAdjustedSize(int minWidth, int prefHeight, int maxHeight); + + virtual void OnKeyEvent(wxKeyEvent& evt); + void OnDataViewTreeCtrlSelection(wxCommandEvent& evt); + void SetItemsCnt(int cnt) { m_cnt_open_items = cnt; } +}; + #endif // slic3r_GUI_wxExtensions_hpp_