diff --git a/resources/icons/mode.svg b/resources/icons/mode.svg new file mode 100644 index 0000000000..613e99b0d8 --- /dev/null +++ b/resources/icons/mode.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/resources/icons/splashscreen-gcodepreview.jpg b/resources/icons/splashscreen-gcodepreview.jpg index bf30739be3..473b11b2ee 100644 Binary files a/resources/icons/splashscreen-gcodepreview.jpg and b/resources/icons/splashscreen-gcodepreview.jpg differ diff --git a/resources/icons/splashscreen.jpg b/resources/icons/splashscreen.jpg index bf9ad3d0f7..e42888c5c7 100644 Binary files a/resources/icons/splashscreen.jpg and b/resources/icons/splashscreen.jpg differ diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 0242a9eeee..7366d22335 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -430,7 +430,26 @@ static bool contains_skew(const Transform3d& trafo) Matrix3d rotation; Matrix3d scale; trafo.computeRotationScaling(&rotation, &scale); - return !scale.isDiagonal(); + + if (scale.isDiagonal()) + return false; + + if (scale.determinant() >= 0.0) + return true; + + // the matrix contains mirror + const Matrix3d ratio = scale.cwiseQuotient(trafo.matrix().block<3,3>(0,0)); + + auto check_skew = [&ratio](int i, int j, bool& skew) { + if (!std::isnan(ratio(i, j)) && !std::isnan(ratio(j, i))) + skew |= std::abs(ratio(i, j) * ratio(j, i) - 1.0) > EPSILON; + }; + + bool has_skew = false; + check_skew(0, 1, has_skew); + check_skew(0, 2, has_skew); + check_skew(1, 2, has_skew); + return has_skew; } Vec3d Transformation::get_rotation() const diff --git a/src/slic3r/GUI/ButtonsDescription.cpp b/src/slic3r/GUI/ButtonsDescription.cpp index 37daffd9d2..8460a94112 100644 --- a/src/slic3r/GUI/ButtonsDescription.cpp +++ b/src/slic3r/GUI/ButtonsDescription.cpp @@ -1,5 +1,6 @@ #include "ButtonsDescription.hpp" #include +#include #include #include #include @@ -7,11 +8,82 @@ #include "GUI.hpp" #include "GUI_App.hpp" #include "I18N.hpp" +#include "OptionsGroup.hpp" #include "wxExtensions.hpp" +#include "BitmapCache.hpp" namespace Slic3r { namespace GUI { +//static ModePaletteComboBox::PalettesMap MODE_PALETTES = +static std::vector>> MODE_PALETTES = +{ + { L("Palette 1 (default)"), { "#00B000", "#FFDC00", "#E70000" } }, + { L("Palette 2"), { "#FC766A", "#B0B8B4", "#184A45" } }, + { L("Palette 3"), { "#567572", "#964F4C", "#696667" } }, + { L("Palette 4"), { "#DA291C", "#56A8CB", "#53A567" } }, + { L("Palette 5"), { "#F65058", "#FBDE44", "#28334A" } }, + { L("Palette 6"), { "#FF3EA5", "#EDFF00", "#00A4CC" } }, + { L("Palette 7"), { "#E95C20", "#006747", "#4F2C1D" } }, + { L("Palette 8"), { "#D9514E", "#2A2B2D", "#2DA8D8" } } +}; + +ModePaletteComboBox::ModePaletteComboBox(wxWindow* parent) : + BitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxCB_READONLY) +{ + for (const auto& palette : MODE_PALETTES) + Append(_(palette.first), *get_bmp(palette.second)); +} + +void ModePaletteComboBox::UpdateSelection(const std::vector &palette_in) +{ + for (size_t idx = 0; idx < MODE_PALETTES.size(); ++idx ) { + const auto& palette = MODE_PALETTES[idx].second; + + bool is_selected = true; + for (size_t mode = 0; mode < palette_in.size(); mode++) + if (wxColour(palette[mode]) != palette_in[mode]) { + is_selected = false; + break; + } + if (is_selected) { + Select(int(idx)); + return; + } + } + + Select(-1); +} + +BitmapCache& ModePaletteComboBox::bitmap_cache() +{ + static BitmapCache bmps; + return bmps; +} + +wxBitmapBundle * ModePaletteComboBox::get_bmp(const std::vector &palette) +{ + std::string bitmap_key; + for (const auto& color : palette) + bitmap_key += color + "+"; + + const int icon_height = wxOSX ? 10 : 12; + + wxBitmapBundle* bmp_bndl = bitmap_cache().find_bndl(bitmap_key); + if (bmp_bndl == nullptr) { + // Create the bitmap with color bars. + std::vector bmps; + for (const auto& color : palette) { + bmps.emplace_back(get_bmp_bundle("mode", icon_height, color)); + bmps.emplace_back(get_empty_bmp_bundle(wxOSX ? 5 : 6, icon_height)); + } + bmp_bndl = bitmap_cache().insert_bndl(bitmap_key, bmps); + } + + return bmp_bndl; +} + + void ButtonsDescription::FillSizerWithTextColorDescriptions(wxSizer* sizer, wxWindow* parent, wxColourPickerCtrl** sys_colour, wxColourPickerCtrl** mod_colour) { wxFlexGridSizer* grid_sizer = new wxFlexGridSizer(3, 5, 5); @@ -48,13 +120,81 @@ void ButtonsDescription::FillSizerWithTextColorDescriptions(wxSizer* sizer, wxWi grid_sizer->Add(*color_picker, 0, wxALIGN_CENTRE_VERTICAL); grid_sizer->Add(btn, 0, wxALIGN_CENTRE_VERTICAL); - grid_sizer->Add(sys_label, 0, wxALIGN_CENTRE_VERTICAL | wxEXPAND); + grid_sizer->Add(sys_label, 0, wxALIGN_CENTRE_VERTICAL); }; add_color(sys_colour, wxGetApp().get_label_clr_sys(), wxGetApp().get_label_default_clr_system(), _L("Value is the same as the system value")); add_color(mod_colour, wxGetApp().get_label_clr_modified(),wxGetApp().get_label_default_clr_modified(), _L("Value was changed and is not equal to the system value or the last saved preset")); } +void ButtonsDescription::FillSizerWithModeColorDescriptions( + wxSizer* sizer, wxWindow* parent, + std::vector clr_pickers, + std::vector& mode_palette) +{ + const int margin = em_unit(parent); + + auto palette_cb = new ModePaletteComboBox(parent); + palette_cb->UpdateSelection(mode_palette); + + palette_cb->Bind(wxEVT_COMBOBOX, [clr_pickers, &mode_palette](wxCommandEvent& evt) { + const int selection = evt.GetSelection(); + if (selection < 0) + return; + const auto& palette = MODE_PALETTES[selection]; + for (int mode = 0; mode < 3; mode++) + if (*clr_pickers[mode]) { + wxColour clr = wxColour(palette.second[mode]); + (*clr_pickers[mode])->SetColour(clr); + mode_palette[mode] = clr; + } + }); + + wxBoxSizer* h_sizer = new wxBoxSizer(wxHORIZONTAL); + h_sizer->Add(new wxStaticText(parent, wxID_ANY, _L("Default palette for mode markers") + ": "), 0, wxALIGN_CENTER_VERTICAL); + h_sizer->Add(palette_cb, 1, wxEXPAND); + + sizer->Add(h_sizer, 0, wxEXPAND | wxBOTTOM, margin); + + wxFlexGridSizer* grid_sizer = new wxFlexGridSizer(9, 5, 5); + sizer->Add(grid_sizer, 0, wxEXPAND); + + const std::vector names = { _L("Simple"), _CTX(L_CONTEXT("Advanced", "Mode"), "Mode"), _L("Expert") }; + + for (size_t mode = 0; mode < names.size(); ++mode) { + wxColour& color = mode_palette[mode]; + + wxColourPickerCtrl** color_picker = clr_pickers[mode]; + *color_picker = new wxColourPickerCtrl(parent, wxID_ANY, color); + wxGetApp().UpdateDarkUI((*color_picker)->GetPickerCtrl(), true); + + (*color_picker)->Bind(wxEVT_COLOURPICKER_CHANGED, [color_picker, &color, palette_cb, &mode_palette](wxCommandEvent&) { + const wxColour new_color = (*color_picker)->GetColour(); + if (new_color != color) { + color = new_color; + palette_cb->UpdateSelection(mode_palette); + } + }); + + wxColour def_color = color; + auto btn = new ScalableButton(parent, wxID_ANY, "undo"); + btn->SetToolTip(_L("Revert color")); + + btn->Bind(wxEVT_BUTTON, [color_picker, &color, def_color, palette_cb, &mode_palette](wxEvent& event) { + color = def_color; + (*color_picker)->SetColour(def_color); + palette_cb->UpdateSelection(mode_palette); + }); + parent->Bind(wxEVT_UPDATE_UI, [color_picker, def_color](wxUpdateUIEvent& evt) { + evt.Enable((*color_picker)->GetColour() != def_color); + }, btn->GetId()); + + grid_sizer->Add(*color_picker, 0, wxALIGN_CENTRE_VERTICAL); + grid_sizer->Add(btn, 0, wxALIGN_CENTRE_VERTICAL); + grid_sizer->Add(new wxStaticText(parent, wxID_ANY, names[mode]), 0, wxALIGN_CENTRE_VERTICAL | wxRIGHT, 2*margin); + } +} + ButtonsDescription::ButtonsDescription(wxWindow* parent, const std::vector &entries) : wxDialog(parent, wxID_ANY, _(L("Buttons And Text Colors Description")), wxDefaultPosition, wxDefaultSize), m_entries(entries) @@ -74,13 +214,20 @@ ButtonsDescription::ButtonsDescription(wxWindow* parent, const std::vectorAdd(description, -1, wxALIGN_CENTRE_VERTICAL); description = new wxStaticText(this, wxID_ANY, _(entry.explanation)); - grid_sizer->Add(description, -1, wxALIGN_CENTRE_VERTICAL | wxEXPAND); + grid_sizer->Add(description, -1, wxALIGN_CENTRE_VERTICAL); } // Text color description wxSizer* sizer = new wxBoxSizer(wxVERTICAL); FillSizerWithTextColorDescriptions(sizer, this, &sys_colour, &mod_colour); - main_sizer->Add(sizer, 0, wxEXPAND | wxALL, 20); + main_sizer->Add(sizer, 0, wxEXPAND | wxALL, 20); + + // Mode color markers description + mode_palette = wxGetApp().get_mode_palette(); + + wxSizer* mode_sizer = new wxBoxSizer(wxVERTICAL); + FillSizerWithModeColorDescriptions(mode_sizer, this, { &simple, &advanced, &expert }, mode_palette); + main_sizer->Add(mode_sizer, 0, wxEXPAND | wxALL, 20); auto buttons = CreateStdDialogButtonSizer(wxOK|wxCANCEL); main_sizer->Add(buttons, 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 10); @@ -89,8 +236,10 @@ ButtonsDescription::ButtonsDescription(wxWindow* parent, const std::vectorBind(wxEVT_BUTTON, [this](wxCommandEvent&) { wxGetApp().set_label_clr_sys(sys_colour->GetColour()); wxGetApp().set_label_clr_modified(mod_colour->GetColour()); + wxGetApp().set_mode_palette(mode_palette); + EndModal(wxID_OK); - }); + }); wxGetApp().UpdateDarkUI(btn); wxGetApp().UpdateDarkUI(static_cast(FindWindowById(wxID_CANCEL, this))); diff --git a/src/slic3r/GUI/ButtonsDescription.hpp b/src/slic3r/GUI/ButtonsDescription.hpp index fbed36c2ab..d1315d3d09 100644 --- a/src/slic3r/GUI/ButtonsDescription.hpp +++ b/src/slic3r/GUI/ButtonsDescription.hpp @@ -4,16 +4,48 @@ #include #include +#include + +#include "BitmapComboBox.hpp" + class ScalableBitmap; class wxColourPickerCtrl; namespace Slic3r { namespace GUI { +class BitmapCache; + +// --------------------------------- +// *** PaletteComboBox *** +// --------------------------------- + +// BitmapComboBox used to palets list in GUI Preferences +class ModePaletteComboBox : public BitmapComboBox +{ +public: + ModePaletteComboBox(wxWindow* parent); + ~ModePaletteComboBox() = default; + + void UpdateSelection(const std::vector& palette_in); + +protected: + // Caching bitmaps for the all bitmaps, used in preset comboboxes + static BitmapCache& bitmap_cache(); + wxBitmapBundle* get_bmp( const std::vector& palette); +}; + + class ButtonsDescription : public wxDialog { wxColourPickerCtrl* sys_colour{ nullptr }; wxColourPickerCtrl* mod_colour{ nullptr }; + + wxColourPickerCtrl* simple { nullptr }; + wxColourPickerCtrl* advanced { nullptr }; + wxColourPickerCtrl* expert { nullptr }; + + std::vector mode_palette; public: struct Entry { Entry(ScalableBitmap *bitmap, const std::string &symbol, const std::string &explanation) : bitmap(bitmap), symbol(symbol), explanation(explanation) {} @@ -27,6 +59,9 @@ public: ~ButtonsDescription() {} static void FillSizerWithTextColorDescriptions(wxSizer* sizer, wxWindow* parent, wxColourPickerCtrl** sys_colour, wxColourPickerCtrl** mod_colour); + static void FillSizerWithModeColorDescriptions(wxSizer* sizer, wxWindow* parent, + std::vector clr_pickers, + std::vector& mode_palette); private: std::vector m_entries; diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 71f59c7572..204067a951 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -1176,31 +1176,20 @@ PageCustom::PageCustom(ConfigWizard *parent) : ConfigWizardPage(parent, _L("Custom Printer Setup"), _L("Custom Printer")) { cb_custom = new wxCheckBox(this, wxID_ANY, _L("Define a custom printer profile")); - tc_profile_name = new wxTextCtrl(this, wxID_ANY, default_profile_name); auto *label = new wxStaticText(this, wxID_ANY, _L("Custom profile name:")); - wxGetApp().UpdateDarkUI(tc_profile_name); + wxBoxSizer* profile_name_sizer = new wxBoxSizer(wxVERTICAL); + profile_name_editor = new SavePresetDialog::Item{ this, profile_name_sizer, default_profile_name }; + profile_name_editor->Enable(false); - tc_profile_name->Enable(false); - tc_profile_name->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent &evt) { - if (tc_profile_name->GetValue().IsEmpty()) { - if (profile_name_prev.IsEmpty()) { tc_profile_name->SetValue(default_profile_name); } - else { tc_profile_name->SetValue(profile_name_prev); } - } else { - profile_name_prev = tc_profile_name->GetValue(); - } - evt.Skip(); - }); - - cb_custom->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { - tc_profile_name->Enable(custom_wanted()); + cb_custom->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &) { + profile_name_editor->Enable(custom_wanted()); wizard_p()->on_custom_setup(custom_wanted()); - }); append(cb_custom); append(label); - append(tc_profile_name); + append(profile_name_sizer); } PageUpdate::PageUpdate(ConfigWizard *parent) @@ -2825,7 +2814,7 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem, {preferred_model, preferred_variant, first_added_filament, first_added_sla_material}); - if (!only_sla_mode && page_custom->custom_wanted()) { + if (!only_sla_mode && page_custom->custom_wanted() && page_custom->is_valid_profile_name()) { // if unsaved changes was not cheched till this moment if (!check_unsaved_preset_changes && !wxGetApp().check_and_keep_current_preset_changes(caption, _L("Custom printer was installed and it will be activated."), act_btns, &apply_keeped_changes)) diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index dc705cab94..c1e848a63a 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -26,6 +26,7 @@ #include "slic3r/Utils/PresetUpdater.hpp" #include "BedShapeDialog.hpp" #include "GUI.hpp" +#include "SavePresetDialog.hpp" #include "wxExtensions.hpp" @@ -370,16 +371,20 @@ struct PageMaterials: ConfigWizardPage struct PageCustom: ConfigWizardPage { PageCustom(ConfigWizard *parent); + ~PageCustom() { + if (profile_name_editor) + delete profile_name_editor; + } - bool custom_wanted() const { return cb_custom->GetValue(); } - std::string profile_name() const { return into_u8(tc_profile_name->GetValue()); } + bool custom_wanted() const { return cb_custom->GetValue(); } + bool is_valid_profile_name() const { return profile_name_editor->is_valid();} + std::string profile_name() const { return profile_name_editor->preset_name(); } private: static const char* default_profile_name; - wxCheckBox *cb_custom; - wxTextCtrl *tc_profile_name; - wxString profile_name_prev; + wxCheckBox *cb_custom {nullptr}; + SavePresetDialog::Item *profile_name_editor {nullptr}; }; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index de912a1344..088451b79f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3471,10 +3471,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) for (int hover_volume_id : m_hover_volume_idxs) { const GLVolume &hover_gl_volume = *m_volumes.volumes[hover_volume_id]; int object_idx = hover_gl_volume.object_idx(); - if (object_idx < 0 || object_idx >= m_model->objects.size()) continue; + if (object_idx < 0 || static_cast(object_idx) >= m_model->objects.size()) continue; const ModelObject* hover_object = m_model->objects[object_idx]; int hover_volume_idx = hover_gl_volume.volume_idx(); - if (hover_volume_idx < 0 || hover_volume_idx >= hover_object->volumes.size()) continue; + if (hover_volume_idx < 0 || static_cast(hover_volume_idx) >= hover_object->volumes.size()) continue; const ModelVolume* hover_volume = hover_object->volumes[hover_volume_idx]; if (!hover_volume->text_configuration.has_value()) continue; m_selection.add_volumes(Selection::EMode::Volume, {(unsigned) hover_volume_id}); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 7a42e1eec2..ebb4a7ef22 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1127,7 +1127,7 @@ bool GUI_App::on_init_inner() NppDarkMode::InitDarkMode(init_dark_color_mode, init_sys_menu_enabled); #endif // initialize label colors and fonts - init_label_colours(); + init_ui_colours(); init_fonts(); std::string older_data_dir_path; @@ -1145,8 +1145,8 @@ bool GUI_App::on_init_inner() if (bool new_dark_color_mode = app_config->get("dark_color_mode") == "1"; init_dark_color_mode != new_dark_color_mode) { NppDarkMode::SetDarkMode(new_dark_color_mode); - init_label_colours(); - update_label_colours_from_appconfig(); + init_ui_colours(); + update_ui_colours_from_appconfig(); } if (bool new_sys_menu_enabled = app_config->get("sys_menu_enabled") == "1"; init_sys_menu_enabled != new_sys_menu_enabled) @@ -1431,10 +1431,16 @@ const wxColour GUI_App::get_label_default_clr_modified() return dark_mode() ? wxColour(253, 111, 40) : wxColour(252, 77, 1); } -void GUI_App::init_label_colours() +const std::vector GUI_App::get_mode_default_palette() +{ + return { "#7DF028", "#FFDC00", "#E70000" }; +} + +void GUI_App::init_ui_colours() { m_color_label_modified = get_label_default_clr_modified(); m_color_label_sys = get_label_default_clr_system(); + m_mode_palette = get_mode_default_palette(); bool is_dark_mode = dark_mode(); #ifdef _WIN32 @@ -1450,19 +1456,30 @@ void GUI_App::init_label_colours() m_color_window_default = is_dark_mode ? wxColour(43, 43, 43) : wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); } -void GUI_App::update_label_colours_from_appconfig() +void GUI_App::update_ui_colours_from_appconfig() { + // load label colors if (app_config->has("label_clr_sys")) { auto str = app_config->get("label_clr_sys"); - if (str != "") + if (!str.empty()) m_color_label_sys = wxColour(str); } if (app_config->has("label_clr_modified")) { auto str = app_config->get("label_clr_modified"); - if (str != "") + if (!str.empty()) m_color_label_modified = wxColour(str); } + + // load mode markers colors + if (app_config->has("mode_palette")) { + const auto colors = app_config->get("mode_palette"); + if (!colors.empty()) { + m_mode_palette.clear(); + if (!unescape_strings_cstyle(colors, m_mode_palette)) + m_mode_palette = get_mode_default_palette(); + } + } } void GUI_App::update_label_colours() @@ -1649,6 +1666,39 @@ void GUI_App::set_label_clr_sys(const wxColour& clr) app_config->save(); } +const std::string& GUI_App::get_mode_btn_color(int mode_id) +{ + assert(0 <= mode_id && size_t(mode_id) < m_mode_palette.size()); + return m_mode_palette[mode_id]; +} + +std::vector GUI_App::get_mode_palette() +{ + return { wxColor(m_mode_palette[0]), + wxColor(m_mode_palette[1]), + wxColor(m_mode_palette[2]) }; +} + +void GUI_App::set_mode_palette(const std::vector& palette) +{ + bool save = false; + + for (size_t mode = 0; mode < palette.size(); ++mode) { + const wxColour& clr = palette[mode]; + std::string color_str = clr == wxTransparentColour ? std::string("") : encode_color(ColorRGB(clr.Red(), clr.Green(), clr.Blue())); + if (m_mode_palette[mode] != color_str) { + m_mode_palette[mode] = color_str; + save = true; + } + } + + if (save) { + mainframe->update_mode_markers(); + app_config->set("mode_palette", escape_strings_cstyle(m_mode_palette)); + app_config->save(); + } +} + bool GUI_App::tabs_as_menu() const { return app_config->get("tabs_as_menu") == "1"; // || dark_mode(); diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 682aa1d001..39d713dba8 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -139,6 +139,7 @@ private: wxColour m_color_selected_btn_bg; bool m_force_colors_update { false }; #endif + std::vector m_mode_palette; wxFont m_small_font; wxFont m_bold_font; @@ -194,8 +195,9 @@ public: static bool dark_mode(); const wxColour get_label_default_clr_system(); const wxColour get_label_default_clr_modified(); - void init_label_colours(); - void update_label_colours_from_appconfig(); + const std::vector get_mode_default_palette(); + void init_ui_colours(); + void update_ui_colours_from_appconfig(); void update_label_colours(); // update color mode for window void UpdateDarkUI(wxWindow *window, bool highlited = false, bool just_font = false); @@ -215,6 +217,9 @@ public: const wxColour& get_label_clr_default() { return m_color_label_default; } const wxColour& get_window_default_clr(){ return m_color_window_default; } + const std::string& get_mode_btn_color(int mode_id); + std::vector get_mode_palette(); + void set_mode_palette(const std::vector &palette); #ifdef _WIN32 const wxColour& get_label_highlight_clr() { return m_color_highlight_label_default; } diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 3d55e21741..6de339a7fc 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2660,47 +2660,59 @@ void ObjectList::part_selection_changed() disable_ununiform_scale = true; } else if ( multiple_selection() || (item && m_objects_model->GetItemType(item) == itInstanceRoot )) { - og_name = _L("Group manipulation"); - const Selection& selection = scene_selection(); - // don't show manipulation panel for case of all Object's parts selection - update_and_show_manipulations = !selection.is_single_full_instance(); - if (int obj_idx = selection.get_object_idx(); obj_idx >= 0) { - if (selection.is_any_volume() || selection.is_any_modifier()) - enable_manipulation = !(*m_objects)[obj_idx]->is_cut(); - else// if (item && m_objects_model->GetItemType(item) == itInstanceRoot) - disable_ss_manipulation = (*m_objects)[obj_idx]->is_cut(); + if (selection.is_single_full_object()) { + og_name = _L("Object manipulation"); + update_and_show_manipulations = true; + + obj_idx = selection.get_object_idx(); + ModelObject* object = (*m_objects)[obj_idx]; + m_config = &object->config; + disable_ss_manipulation = object->is_cut(); } else { - wxDataViewItemArray sels; - GetSelections(sels); - if (selection.is_single_full_object() || selection.is_multiple_full_instance() ) { - int obj_idx = m_objects_model->GetObjectIdByItem(sels.front()); - disable_ss_manipulation = (*m_objects)[obj_idx]->is_cut(); + og_name = _L("Group manipulation"); + + // don't show manipulation panel for case of all Object's parts selection + update_and_show_manipulations = !selection.is_single_full_instance(); + + if (int obj_idx = selection.get_object_idx(); obj_idx >= 0) { + if (selection.is_any_volume() || selection.is_any_modifier()) + enable_manipulation = !(*m_objects)[obj_idx]->is_cut(); + else// if (item && m_objects_model->GetItemType(item) == itInstanceRoot) + disable_ss_manipulation = (*m_objects)[obj_idx]->is_cut(); } - else if (selection.is_mixed() || selection.is_multiple_full_object()) { - std::map> cut_objects; - - // find cut objects - for (auto item : sels) { - int obj_idx = m_objects_model->GetObjectIdByItem(item); - const ModelObject* obj = object(obj_idx); - if (obj->is_cut()) { - if (cut_objects.find(obj->cut_id) == cut_objects.end()) - cut_objects[obj->cut_id] = std::set{ obj_idx }; - else - cut_objects.at(obj->cut_id).insert(obj_idx); - } + else { + wxDataViewItemArray sels; + GetSelections(sels); + if (selection.is_single_full_object() || selection.is_multiple_full_instance() ) { + int obj_idx = m_objects_model->GetObjectIdByItem(sels.front()); + disable_ss_manipulation = (*m_objects)[obj_idx]->is_cut(); } + else if (selection.is_mixed() || selection.is_multiple_full_object()) { + std::map> cut_objects; - // check if selected cut objects are "full selected" - for (auto cut_object : cut_objects) - if (cut_object.first.check_sum() != cut_object.second.size()) { - disable_ss_manipulation = true; - break; + // find cut objects + for (auto item : sels) { + int obj_idx = m_objects_model->GetObjectIdByItem(item); + const ModelObject* obj = object(obj_idx); + if (obj->is_cut()) { + if (cut_objects.find(obj->cut_id) == cut_objects.end()) + cut_objects[obj->cut_id] = std::set{ obj_idx }; + else + cut_objects.at(obj->cut_id).insert(obj_idx); + } } - disable_ununiform_scale = !cut_objects.empty(); + + // check if selected cut objects are "full selected" + for (auto cut_object : cut_objects) + if (cut_object.first.check_sum() != cut_object.second.size()) { + disable_ss_manipulation = true; + break; + } + disable_ununiform_scale = !cut_objects.empty(); + } } } } diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index edf4d5b07e..a0336c6853 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -1198,7 +1198,11 @@ void ObjectManipulation::change_scale_value(int axis, double value) #if ENABLE_WORLD_COORDINATE const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); Vec3d ref_scale = m_cache.scale; - if (selection.is_single_full_instance()) { + if (selection.is_single_volume_or_modifier()) { + if (is_local_coordinates()) + ref_scale = 100.0 * Vec3d::Ones(); + } + else if (selection.is_single_full_instance()) { scale = scale.cwiseQuotient(ref_scale); ref_scale = Vec3d::Ones(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index a296650296..ecbfd5a8c0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -246,7 +246,7 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type) DataBase emboss_data = priv::create_emboss_data_base(m_text, m_style_manager); const ModelObjectPtrs &objects = selection.get_model()->objects; // No selected object so create new object - if (selection.is_empty() || object_idx < 0 || object_idx >= objects.size()) { + if (selection.is_empty() || object_idx < 0 || static_cast(object_idx) >= objects.size()) { // create Object on center of screen // when ray throw center of screen not hit bed it create object on center of bed priv::start_create_object_job(emboss_data, screen_center); @@ -2231,6 +2231,18 @@ void GLGizmoEmboss::draw_delete_style_button() { } } +namespace priv { +/// +/// Transform origin of Text volume onto surface of model. +/// +/// Text +/// AABB trees of object +/// Transformation of actual instance +/// True when transform otherwise false +bool transform_on_surface(ModelVolume &volume, RaycastManager &raycast_manager, const Selection &selection); +} // namespace priv + + void GLGizmoEmboss::fix_transformation(const FontProp &from, const FontProp &to) { @@ -2252,6 +2264,10 @@ void GLGizmoEmboss::fix_transformation(const FontProp &from, float t_move = t_move_opt.has_value() ? *t_move_opt : .0f; do_translate(Vec3d::UnitZ() * (t_move - f_move)); } + + // when start using surface than move volume origin onto surface + if (!from.use_surface && to.use_surface) + priv::transform_on_surface(*m_volume, m_raycast_manager, m_parent.get_selection()); } void GLGizmoEmboss::draw_style_list() { @@ -2354,8 +2370,11 @@ void GLGizmoEmboss::draw_style_list() { // selected style from combo box if (selected_style_index.has_value()) { const EmbossStyle &style = m_style_manager.get_styles()[*selected_style_index].style; - fix_transformation(actual_style.prop, style.prop); + // create copy to be able do fix transformation only when successfully load style + FontProp act_prop = actual_style.prop; // copy + FontProp new_prop = style.prop; // copy if (m_style_manager.load_style(*selected_style_index)) { + fix_transformation(act_prop, new_prop); process(); } else { wxString title = _L("Not valid style."); @@ -2867,16 +2886,8 @@ void GLGizmoEmboss::do_rotate(float relative_z_angle) // snapshot_name = L("Set text rotation"); m_parent.do_rotate(snapshot_name); } -namespace priv { -/// -/// Transform origin of Text volume onto surface of model. -/// -/// Text -/// AABB trees of object -/// Transformation of actual instance -/// True when transform otherwise false -bool transform_on_surface(ModelVolume &volume, RaycastManager &raycast_manager, const Selection &selection) +bool priv::transform_on_surface(ModelVolume &volume, RaycastManager &raycast_manager, const Selection &selection) { // Move object on surface auto cond = RaycastManager::SkipVolume({volume.id().id}); @@ -2911,7 +2922,6 @@ bool transform_on_surface(ModelVolume &volume, RaycastManager &raycast_manager, volume.set_transformation(volume.get_matrix() * Eigen::Translation(offset_volume)); return true; } -} // namespace priv void GLGizmoEmboss::draw_advanced() { @@ -3590,7 +3600,7 @@ bool priv::start_create_volume_on_surface_job( const ModelObjectPtrs &objects = plater->model().objects; int object_idx = gl_volume->object_idx(); - if (object_idx < 0 || object_idx >= objects.size()) return false; + if (object_idx < 0 || static_cast(object_idx) >= objects.size()) return false; ModelObject *obj = objects[object_idx]; size_t vol_id = obj->volumes[gl_volume->volume_idx()]->id().id; auto cond = RaycastManager::AllowVolumes({vol_id}); diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index cf23c85d37..66961b2cd4 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -53,6 +53,15 @@ KBShortcutsDialog::KBShortcutsDialog() SetSizer(main_sizer); main_sizer->SetSizeHints(this); this->CenterOnParent(); + +#ifdef __linux__ + // workaround to correct pages layout + book->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, [book](wxBookCtrlEvent& e) { + book->GetPage(e.GetSelection())->Fit(); + }); + const wxSize sz = this->GetBestSize(); + this->SetSize(sz.x + 1, sz.y); +#endif } void KBShortcutsDialog::on_dpi_changed(const wxRect& suggested_rect) diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 5764b283c6..b095d46c21 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -715,6 +715,8 @@ void MainFrame::update_title() void MainFrame::init_tabpanel() { + wxGetApp().update_ui_colours_from_appconfig(); + // wxNB_NOPAGETHEME: Disable Windows Vista theme for the Notebook background. The theme performance is terrible on Windows 10 // with multiple high resolution displays connected. #ifdef _MSW_DARK_MODE @@ -847,7 +849,6 @@ void MainFrame::register_win32_callbacks() void MainFrame::create_preset_tabs() { - wxGetApp().update_label_colours_from_appconfig(); add_created_tab(new TabPrint(m_tabpanel), "cog"); add_created_tab(new TabFilament(m_tabpanel), "spool"); add_created_tab(new TabSLAPrint(m_tabpanel), "cog"); @@ -1091,7 +1092,9 @@ void MainFrame::on_sys_color_changed() wxBusyCursor wait; // update label colors in respect to the system mode - wxGetApp().init_label_colours(); + wxGetApp().init_ui_colours(); + // but if there are some ui colors in appconfig, they have to be applied + wxGetApp().update_ui_colours_from_appconfig(); #ifdef __WXMSW__ wxGetApp().UpdateDarkUI(m_tabpanel); // m_statusbar->update_dark_ui(); @@ -1114,6 +1117,24 @@ void MainFrame::on_sys_color_changed() this->Refresh(); } +void MainFrame::update_mode_markers() +{ +#ifdef __WXMSW__ +#ifdef _MSW_DARK_MODE + // update markers in common mode sizer + if (!wxGetApp().tabs_as_menu()) + dynamic_cast(m_tabpanel)->UpdateModeMarkers(); +#endif +#endif + + // update mode markers on side_bar + wxGetApp().sidebar().update_mode_markers(); + + // update mode markers in tabs + for (auto tab : wxGetApp().tabs_list) + tab->update_mode_markers(); +} + #ifdef _MSC_VER // \xA0 is a non-breaking space. It is entered here to spoil the automatic accelerators, // as the simple numeric accelerators spoil all numeric data entry. diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 66adf806aa..78ec13f64e 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -143,6 +143,7 @@ public: ~MainFrame() = default; void update_layout(); + void update_mode_markers(); // Called when closing the application and when switching the application language. void shutdown(); diff --git a/src/slic3r/GUI/Notebook.cpp b/src/slic3r/GUI/Notebook.cpp index 380b402d51..71d0951601 100644 --- a/src/slic3r/GUI/Notebook.cpp +++ b/src/slic3r/GUI/Notebook.cpp @@ -109,9 +109,16 @@ void ButtonsListCtrl::OnColorsChanged() for (ScalableButton* btn : m_pageButtons) btn->sys_color_changed(); + m_mode_sizer->sys_color_changed(); + m_sizer->Layout(); } +void ButtonsListCtrl::UpdateModeMarkers() +{ + m_mode_sizer->update_mode_markers(); +} + void ButtonsListCtrl::SetSelection(int sel) { if (m_selection == sel) diff --git a/src/slic3r/GUI/Notebook.hpp b/src/slic3r/GUI/Notebook.hpp index bd6c5d85a8..c945be3001 100644 --- a/src/slic3r/GUI/Notebook.hpp +++ b/src/slic3r/GUI/Notebook.hpp @@ -22,6 +22,7 @@ public: void UpdateMode(); void Rescale(); void OnColorsChanged(); + void UpdateModeMarkers(); bool InsertPage(size_t n, const wxString& text, bool bSelect = false, const std::string& bmp_name = ""); void RemovePage(size_t n); bool SetPageImage(size_t n, const std::string& bmp_name) const; @@ -251,6 +252,11 @@ public: GetBtnsListCtrl()->OnColorsChanged(); } + void UpdateModeMarkers() + { + GetBtnsListCtrl()->UpdateModeMarkers(); + } + void OnNavigationKey(wxNavigationKeyEvent& event) { if (event.IsWindowChange()) { diff --git a/src/slic3r/GUI/OG_CustomCtrl.cpp b/src/slic3r/GUI/OG_CustomCtrl.cpp index 0c845fc68c..2f4f91302c 100644 --- a/src/slic3r/GUI/OG_CustomCtrl.cpp +++ b/src/slic3r/GUI/OG_CustomCtrl.cpp @@ -45,7 +45,7 @@ OG_CustomCtrl::OG_CustomCtrl( wxWindow* parent, m_v_gap = lround(1.0 * m_em_unit); m_h_gap = lround(0.2 * m_em_unit); - m_bmp_mode_sz = get_bitmap_size(get_bmp_bundle("mode_simple", wxOSX ? 10 : 12), this); + m_bmp_mode_sz = get_bitmap_size(get_bmp_bundle("mode", wxOSX ? 10 : 12), this); m_bmp_blinking_sz = get_bitmap_size(get_bmp_bundle("search_blink"), this); init_ctrl_lines();// from og.lines() @@ -188,7 +188,7 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/) #else GetTextExtent(label, &label_w, &label_h, 0, 0, &m_font); #endif //__WXMSW__ - h_pos += label_w + 1 + m_h_gap; + h_pos += label_w + m_h_gap; } h_pos += (opt.opt.gui_type == ConfigOptionDef::GUIType::legend ? 1 : 3) * blinking_button_width; @@ -199,7 +199,7 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/) if (opt.opt.gui_type == ConfigOptionDef::GUIType::legend) h_pos += 2 * blinking_button_width; - h_pos += field->getWindow()->GetSize().x; + h_pos += field->getWindow()->GetSize().x + m_h_gap; if (option_set.size() == 1 && option_set.front().opt.full_width) break; @@ -418,7 +418,7 @@ void OG_CustomCtrl::msw_rescale() m_v_gap = lround(1.0 * m_em_unit); m_h_gap = lround(0.2 * m_em_unit); - m_bmp_mode_sz = get_bitmap_size(get_bmp_bundle("mode_simple", wxOSX ? 10 : 12), this); + m_bmp_mode_sz = get_bitmap_size(get_bmp_bundle("mode", wxOSX ? 10 : 12), this); m_bmp_blinking_sz = get_bitmap_size(get_bmp_bundle("search_blink"), this); init_max_win_width(); @@ -666,9 +666,7 @@ wxCoord OG_CustomCtrl::CtrlLine::draw_mode_bmp(wxDC& dc, wxCoord v_pos) return ctrl->m_h_gap; ConfigOptionMode mode = og_line.get_options()[0].opt.mode; - const std::string& bmp_name = mode == ConfigOptionMode::comSimple ? "mode_simple" : - mode == ConfigOptionMode::comAdvanced ? "mode_advanced" : "mode_expert"; - wxBitmapBundle* bmp = get_bmp_bundle(bmp_name, wxOSX ? 10 : 12); + wxBitmapBundle* bmp = get_bmp_bundle("mode", wxOSX ? 10 : 12, wxGetApp().get_mode_btn_color(mode)); wxCoord y_draw = v_pos + lround((height - get_bitmap_size(bmp, ctrl).GetHeight()) / 2); if (og_line.get_options().front().opt.gui_type != ConfigOptionDef::GUIType::legend) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 68a1bc01d8..1b536baa8f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1183,6 +1183,12 @@ void Sidebar::sys_color_changed() p->searcher.dlg_sys_color_changed(); } +void Sidebar::update_mode_markers() +{ + if (p->mode_sizer) + p->mode_sizer->update_mode_markers(); +} + void Sidebar::search() { p->searcher.search(); @@ -2180,9 +2186,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) this->q->Bind(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, [this](EjectDriveNotificationClickedEvent&) { this->q->eject_drive(); }); this->q->Bind(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, [this](ExportGcodeNotificationClickedEvent&) { this->q->export_gcode(true); }); this->q->Bind(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, [](PresetUpdateAvailableClickedEvent&) { wxGetApp().get_preset_updater()->on_update_notification_confirm(); }); - this->q->Bind(EVT_REMOVABLE_DRIVE_EJECTED, [this](RemovableDriveEjectEvent &evt) { + this->q->Bind(EVT_REMOVABLE_DRIVE_EJECTED, [this, q](RemovableDriveEjectEvent &evt) { if (evt.data.second) { - this->show_action_buttons(this->ready_to_slice); + q->show_action_buttons(); notification_manager->close_notification_of_type(NotificationType::ExportFinished); notification_manager->push_notification(NotificationType::CustomNotification, NotificationManager::NotificationLevel::RegularNotificationLevel, @@ -2196,8 +2202,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) ); } }); - this->q->Bind(EVT_REMOVABLE_DRIVES_CHANGED, [this](RemovableDrivesChangedEvent &) { - this->show_action_buttons(this->ready_to_slice); + this->q->Bind(EVT_REMOVABLE_DRIVES_CHANGED, [this, q](RemovableDrivesChangedEvent &) { + q->show_action_buttons(); // Close notification ExportingFinished but only if last export was to removable notification_manager->device_ejected(); }); @@ -3302,7 +3308,15 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool } } } - else if (! this->delayed_error_message.empty()) { + else { + if (invalidated == Print::APPLY_STATUS_UNCHANGED && !background_process.empty()) { + std::string warning; + std::string err = background_process.validate(&warning); + if (!err.empty()) + return return_state; + } + + if (! this->delayed_error_message.empty()) // Reusing the old state. return_state |= UPDATE_BACKGROUND_PROCESS_INVALID; } @@ -4987,10 +5001,10 @@ bool Plater::priv::can_layers_editing() const return layers_height_allowed(); } -void Plater::priv::show_action_buttons(const bool ready_to_slice) const +void Plater::priv::show_action_buttons(const bool ready_to_slice_) const { // Cache this value, so that the callbacks from the RemovableDriveManager may repeat that value when calling show_action_buttons(). - this->ready_to_slice = ready_to_slice; + this->ready_to_slice = ready_to_slice_; wxWindowUpdateLocker noUpdater(sidebar); @@ -7015,6 +7029,7 @@ void Plater::split_object() { p->split_object(); } void Plater::split_volume() { p->split_volume(); } void Plater::update_menus() { p->menus.update(); } void Plater::show_action_buttons(const bool ready_to_slice) const { p->show_action_buttons(ready_to_slice); } +void Plater::show_action_buttons() const { p->show_action_buttons(p->ready_to_slice); } void Plater::copy_selection_to_clipboard() { diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 77a401f3f1..34b1abc5ad 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -84,6 +84,7 @@ public: void update_reslice_btn_tooltip() const; void msw_rescale(); void sys_color_changed(); + void update_mode_markers(); void search(); void jump_to_option(size_t selected); void jump_to_option(const std::string& opt_key, Preset::Type type, const std::wstring& category); @@ -312,6 +313,7 @@ public: void update_menus(); void show_action_buttons(const bool is_ready_to_slice) const; + void show_action_buttons() const; wxString get_project_filename(const wxString& extension = wxEmptyString) const; void set_project_filename(const wxString& filename); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index b04b0a3f11..719f0bc162 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -80,9 +80,15 @@ void PreferencesDialog::show(const std::string& highlight_opt_key /*= std::strin m_use_custom_toolbar_size = get_app_config()->get("use_custom_toolbar_size") == "1"; if (wxGetApp().is_editor()) { - // update colors for color pickers + // update colors for color pickers of the labels update_color(m_sys_colour, wxGetApp().get_label_clr_sys()); update_color(m_mod_colour, wxGetApp().get_label_clr_modified()); + + // update color pickers for mode palette + const auto palette = wxGetApp().get_mode_palette(); + std::vector color_pickres = {m_mode_simple, m_mode_advanced, m_mode_expert}; + for (size_t mode = 0; mode < color_pickres.size(); ++mode) + update_color(color_pickres[mode], palette[mode]); } this->ShowModal(); @@ -506,6 +512,7 @@ void PreferencesDialog::build() create_settings_mode_widget(); create_settings_text_color_widget(); + create_settings_mode_color_widget(); #if ENABLE_ENVIRONMENT_MAP // Add "Render" tab @@ -660,6 +667,7 @@ void PreferencesDialog::accept(wxEvent&) if (wxGetApp().is_editor()) { wxGetApp().set_label_clr_sys(m_sys_colour->GetColour()); wxGetApp().set_label_clr_modified(m_mod_colour->GetColour()); + wxGetApp().set_mode_palette(m_mode_palette); } EndModal(wxID_OK); @@ -935,6 +943,33 @@ void PreferencesDialog::create_settings_text_color_widget() append_preferences_option_to_searcer(m_optgroup_gui, opt_key, title); } +void PreferencesDialog::create_settings_mode_color_widget() +{ + wxWindow* parent = m_optgroup_gui->parent(); + + wxString title = L("Mode markers"); + wxStaticBox* stb = new wxStaticBox(parent, wxID_ANY, _(title)); + wxGetApp().UpdateDarkUI(stb); + if (!wxOSX) stb->SetBackgroundStyle(wxBG_STYLE_PAINT); + + std::string opt_key = "mode_markers"; + m_blinkers[opt_key] = new BlinkingBitmap(parent); + + wxSizer* stb_sizer = new wxStaticBoxSizer(stb, wxVERTICAL); + + // Mode color markers description + m_mode_palette = wxGetApp().get_mode_palette(); + ButtonsDescription::FillSizerWithModeColorDescriptions(stb_sizer, parent, { &m_mode_simple, &m_mode_advanced, &m_mode_expert }, m_mode_palette); + + auto sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(m_blinkers[opt_key], 0, wxRIGHT, 2); + sizer->Add(stb_sizer, 1, wxALIGN_CENTER_VERTICAL); + + m_optgroup_gui->sizer->Add(sizer, 0, wxEXPAND | wxTOP, em_unit()); + + append_preferences_option_to_searcer(m_optgroup_gui, opt_key, title); +} + void PreferencesDialog::init_highlighter(const t_config_option_key& opt_key) { if (m_blinkers.find(opt_key) != m_blinkers.end()) diff --git a/src/slic3r/GUI/Preferences.hpp b/src/slic3r/GUI/Preferences.hpp index 4a82cee003..8e11c7375b 100644 --- a/src/slic3r/GUI/Preferences.hpp +++ b/src/slic3r/GUI/Preferences.hpp @@ -48,6 +48,12 @@ class PreferencesDialog : public DPIDialog wxColourPickerCtrl* m_sys_colour {nullptr}; wxColourPickerCtrl* m_mod_colour {nullptr}; + + std::vector m_mode_palette; + wxColourPickerCtrl* m_mode_simple { nullptr }; + wxColourPickerCtrl* m_mode_advanced { nullptr }; + wxColourPickerCtrl* m_mode_expert { nullptr }; + wxBookCtrlBase* tabs {nullptr}; bool isOSX {false}; @@ -81,6 +87,7 @@ protected: void create_icon_size_slider(); void create_settings_mode_widget(); void create_settings_text_color_widget(); + void create_settings_mode_color_widget(); void init_highlighter(const t_config_option_key& opt_key); std::vector optgroups(); diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index 1d3c275e88..6fcde3bf69 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -555,7 +555,8 @@ bool PresetComboBox::selection_is_changed_according_to_physical_printers() // if new preset wasn't selected, there is no need to call update preset selection if (old_printer_preset == preset_name) { tab->update_preset_choice(); - wxGetApp().plater()->show_action_buttons(false); + // update action buttons to show/hide "Send to" button + wxGetApp().plater()->show_action_buttons(); // we need just to update according Plater<->Tab PresetComboBox if (dynamic_cast(this)!=nullptr) { diff --git a/src/slic3r/GUI/SavePresetDialog.cpp b/src/slic3r/GUI/SavePresetDialog.cpp index 40f9817227..fbb84d08b4 100644 --- a/src/slic3r/GUI/SavePresetDialog.cpp +++ b/src/slic3r/GUI/SavePresetDialog.cpp @@ -29,7 +29,7 @@ constexpr auto BORDER_W = 10; std::string SavePresetDialog::Item::get_init_preset_name(const std::string &suffix) { - PresetBundle* preset_bundle = m_parent->get_preset_bundle(); + PresetBundle* preset_bundle = dynamic_cast(m_parent)->get_preset_bundle(); if (!preset_bundle) preset_bundle = wxGetApp().preset_bundle; m_presets = &preset_bundle->get_presets(m_type); @@ -50,13 +50,14 @@ std::string SavePresetDialog::Item::get_init_preset_name(const std::string &suff void SavePresetDialog::Item::init_input_name_ctrl(wxBoxSizer *input_name_sizer, const std::string preset_name) { - if (m_parent->is_for_rename()) { + if (m_use_text_ctrl) { #ifdef _WIN32 long style = wxBORDER_SIMPLE; #else long style = 0L; #endif m_text_ctrl = new wxTextCtrl(m_parent, wxID_ANY, from_u8(preset_name), wxDefaultPosition, wxSize(35 * wxGetApp().em_unit(), -1), style); + wxGetApp().UpdateDarkUI(m_text_ctrl); m_text_ctrl->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { update(); }); input_name_sizer->Add(m_text_ctrl,1, wxEXPAND, BORDER_W); @@ -86,13 +87,14 @@ void SavePresetDialog::Item::init_input_name_ctrl(wxBoxSizer *input_name_sizer, wxString SavePresetDialog::Item::get_top_label_text() const { - const std::string label_str = m_parent->is_for_rename() ?_u8L("Rename %s to:") : _u8L("Save %s as:"); + const std::string label_str = m_use_text_ctrl ?_u8L("Rename %s to:") : _u8L("Save %s as:"); Tab* tab = wxGetApp().get_tab(m_type); return from_u8((boost::format(label_str) % into_u8(tab->title())).str()); } SavePresetDialog::Item::Item(Preset::Type type, const std::string& suffix, wxBoxSizer* sizer, SavePresetDialog* parent): m_type(type), + m_use_text_ctrl(parent->is_for_rename()), m_parent(parent), m_valid_bmp(new wxStaticBitmap(m_parent, wxID_ANY, *get_bmp_bundle("tick_mark"))), m_valid_label(new wxStaticText(m_parent, wxID_ANY, "")) @@ -110,15 +112,51 @@ SavePresetDialog::Item::Item(Preset::Type type, const std::string& suffix, wxBox sizer->Add(m_valid_label, 0, wxEXPAND | wxLEFT, 3*BORDER_W); if (m_type == Preset::TYPE_PRINTER) - m_parent->add_info_for_edit_ph_printer(sizer); + parent->add_info_for_edit_ph_printer(sizer); update(); } +SavePresetDialog::Item::Item(wxWindow* parent, wxBoxSizer* sizer, const std::string& def_name, PrinterTechnology pt /*= ptFFF*/): + m_preset_name(def_name), + m_printer_technology(pt), + m_parent(parent), + m_valid_bmp(new wxStaticBitmap(m_parent, wxID_ANY, *get_bmp_bundle("tick_mark"))), + m_valid_label(new wxStaticText(m_parent, wxID_ANY, "")) +{ + m_valid_label->SetFont(wxGetApp().bold_font()); + + wxBoxSizer* input_name_sizer = new wxBoxSizer(wxHORIZONTAL); + input_name_sizer->Add(m_valid_bmp, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, BORDER_W); + init_input_name_ctrl(input_name_sizer, m_preset_name); + + sizer->Add(input_name_sizer,0, wxEXPAND | wxBOTTOM, BORDER_W); + sizer->Add(m_valid_label, 0, wxEXPAND | wxLEFT, 3*BORDER_W); + + update(); +} + +const Preset* SavePresetDialog::Item::get_existing_preset() const +{ + if (m_presets) + return m_presets->find_preset(m_preset_name, false); + + const auto types = m_printer_technology == ptFFF ? + std::initializer_list{Preset::TYPE_PRINTER, Preset::TYPE_PRINT, Preset::TYPE_FILAMENT } : + std::initializer_list{Preset::TYPE_PRINTER, Preset::TYPE_SLA_PRINT, Preset::TYPE_SLA_MATERIAL }; + + for (auto type : types) { + const PresetCollection& presets = wxGetApp().preset_bundle->get_presets(type); + if (const Preset* preset = presets.find_preset(m_preset_name, false)) + return preset; + } + + return nullptr; +} + void SavePresetDialog::Item::update() { - bool rename = m_parent->is_for_rename(); - m_preset_name = into_u8(rename ? m_text_ctrl->GetValue() : m_combo->GetValue()); + m_preset_name = into_u8(m_use_text_ctrl ? m_text_ctrl->GetValue() : m_combo->GetValue()); m_valid_type = ValidationType::Valid; wxString info_line; @@ -138,7 +176,7 @@ void SavePresetDialog::Item::update() if (m_valid_type == ValidationType::Valid && m_preset_name.find(unusable_suffix) != std::string::npos) { info_line = _L("The supplied name is not valid;") + "\n" + _L("the following suffix is not allowed:") + "\n\t" + - from_u8(PresetCollection::get_suffix_modified()); + from_u8(unusable_suffix); m_valid_type = ValidationType::NoValid; } @@ -147,24 +185,25 @@ void SavePresetDialog::Item::update() m_valid_type = ValidationType::NoValid; } - const Preset* existing = m_presets->find_preset(m_preset_name, false); + const Preset* existing = get_existing_preset(); if (m_valid_type == ValidationType::Valid && existing && (existing->is_default || existing->is_system)) { - info_line = rename ? _L("The supplied name is used for a system profile.") : + info_line = m_use_text_ctrl ? _L("The supplied name is used for a system profile.") : _L("Cannot overwrite a system profile."); m_valid_type = ValidationType::NoValid; } if (m_valid_type == ValidationType::Valid && existing && (existing->is_external)) { - info_line = rename ? _L("The supplied name is used for a external profile.") : + info_line = m_use_text_ctrl ? _L("The supplied name is used for a external profile.") : _L("Cannot overwrite an external profile."); m_valid_type = ValidationType::NoValid; } + SavePresetDialog* dlg = dynamic_cast(m_parent); if (m_valid_type == ValidationType::Valid && existing) { - if (m_preset_name == m_presets->get_selected_preset_name()) { - if ((!rename && m_presets->get_edited_preset().is_dirty) || - m_parent->get_preset_bundle()) // means that we save modifications from the DiffDialog + if (m_presets && m_preset_name == m_presets->get_selected_preset_name()) { + if ((!m_use_text_ctrl && m_presets->get_edited_preset().is_dirty) || + (dlg && dlg->get_preset_bundle())) // means that we save modifications from the DiffDialog info_line = _L("Save preset modifications to existing user profile"); else info_line = _L("Nothing changed"); @@ -185,6 +224,17 @@ void SavePresetDialog::Item::update() m_valid_type = ValidationType::NoValid; } +#ifdef __WXMSW__ + const int max_path_length = MAX_PATH; +#else + const int max_path_length = 255; +#endif + + if (m_valid_type == ValidationType::Valid && m_presets && m_presets->path_from_name(m_preset_name).length() >= max_path_length) { + info_line = _L("The name is too long."); + m_valid_type = ValidationType::NoValid; + } + if (m_valid_type == ValidationType::Valid && m_preset_name.find_first_of(' ') == 0) { info_line = _L("The name cannot start with space character."); m_valid_type = ValidationType::NoValid; @@ -195,23 +245,23 @@ void SavePresetDialog::Item::update() m_valid_type = ValidationType::NoValid; } - if (m_valid_type == ValidationType::Valid && m_presets->get_preset_name_by_alias(m_preset_name) != m_preset_name) { + if (m_valid_type == ValidationType::Valid && m_presets && m_presets->get_preset_name_by_alias(m_preset_name) != m_preset_name) { info_line = _L("The name cannot be the same as a preset alias name."); m_valid_type = ValidationType::NoValid; } - if (!m_parent->get_info_line_extention().IsEmpty() && m_valid_type != ValidationType::NoValid) - info_line += "\n\n" + m_parent->get_info_line_extention(); + if ((dlg && !dlg->get_info_line_extention().IsEmpty()) && m_valid_type != ValidationType::NoValid) + info_line += "\n\n" + dlg->get_info_line_extention(); m_valid_label->SetLabel(info_line); m_valid_label->Show(!info_line.IsEmpty()); update_valid_bmp(); - if (m_type == Preset::TYPE_PRINTER) - m_parent->update_info_for_edit_ph_printer(m_preset_name); + if (dlg && m_type == Preset::TYPE_PRINTER) + dlg->update_info_for_edit_ph_printer(m_preset_name); - m_parent->layout(); + m_parent->Layout(); } void SavePresetDialog::Item::update_valid_bmp() @@ -227,6 +277,13 @@ void SavePresetDialog::Item::accept() m_presets->delete_preset(m_preset_name); } +void SavePresetDialog::Item::Enable(bool enable /*= true*/) +{ + m_valid_label->Enable(enable); + m_valid_bmp->Enable(enable); + m_use_text_ctrl ? m_text_ctrl->Enable(enable) : m_combo->Enable(enable); +} + //----------------------------------------------- // SavePresetDialog @@ -387,10 +444,11 @@ void SavePresetDialog::update_info_for_edit_ph_printer(const std::string& preset } } -void SavePresetDialog::layout() +bool SavePresetDialog::Layout() { - this->Layout(); + const bool ret = DPIDialog::Layout(); this->Fit(); + return ret; } void SavePresetDialog::on_dpi_changed(const wxRect& suggested_rect) diff --git a/src/slic3r/GUI/SavePresetDialog.hpp b/src/slic3r/GUI/SavePresetDialog.hpp index c40a5896f2..e34ed9e5df 100644 --- a/src/slic3r/GUI/SavePresetDialog.hpp +++ b/src/slic3r/GUI/SavePresetDialog.hpp @@ -26,7 +26,7 @@ class SavePresetDialog : public DPIDialog Switch, UndefAction }; - +public: struct Item { enum class ValidationType @@ -37,20 +37,24 @@ class SavePresetDialog : public DPIDialog }; Item(Preset::Type type, const std::string& suffix, wxBoxSizer* sizer, SavePresetDialog* parent); + Item(wxWindow* parent, wxBoxSizer* sizer, const std::string& def_name, PrinterTechnology pt = ptFFF); void update_valid_bmp(); void accept(); + void Enable(bool enable = true); bool is_valid() const { return m_valid_type != ValidationType::NoValid; } Preset::Type type() const { return m_type; } std::string preset_name() const { return m_preset_name; } private: - Preset::Type m_type; + Preset::Type m_type {Preset::TYPE_INVALID}; std::string m_preset_name; + bool m_use_text_ctrl {true}; + PrinterTechnology m_printer_technology {ptAny}; ValidationType m_valid_type {ValidationType::NoValid}; - SavePresetDialog* m_parent {nullptr}; + wxWindow* m_parent {nullptr}; wxStaticBitmap* m_valid_bmp {nullptr}; wxComboBox* m_combo {nullptr}; wxTextCtrl* m_text_ctrl {nullptr}; @@ -60,11 +64,12 @@ class SavePresetDialog : public DPIDialog std::string get_init_preset_name(const std::string &suffix); void init_input_name_ctrl(wxBoxSizer *input_name_sizer, std::string preset_name); - wxString get_top_label_text() const ; + const Preset* get_existing_preset() const ; + wxString get_top_label_text() const ; void update(); }; - +private: std::vector m_items; wxBoxSizer* m_presets_sizer {nullptr}; @@ -97,7 +102,7 @@ public: bool enable_ok_btn() const; void add_info_for_edit_ph_printer(wxBoxSizer *sizer); void update_info_for_edit_ph_printer(const std::string &preset_name); - void layout(); + bool Layout() override; bool is_for_rename() { return m_use_for_rename; } protected: diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index ba8378d1f9..d7b1297827 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -826,17 +826,26 @@ void Selection::translate(const Vec3d& displacement, TransformationType transfor const VolumeCache& volume_data = m_cache.volumes_data[i]; if (m_mode == Instance && !is_wipe_tower()) { assert(is_from_fully_selected_instance(i)); - if (transformation_type.world()) - v.set_instance_transformation(Geometry::translation_transform(displacement) * volume_data.get_instance_full_matrix()); - else if (transformation_type.instance()) { - const Vec3d world_displacement = volume_data.get_instance_rotation_matrix() * displacement; - v.set_instance_transformation(Geometry::translation_transform(world_displacement) * volume_data.get_instance_full_matrix()); + if (transformation_type.instance()) { + const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform(); + v.set_instance_offset(inst_trafo.get_offset() + inst_trafo.get_rotation_matrix() * displacement); } else - assert(false); + transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(displacement), m_cache.dragging_center); + } + else { + if (transformation_type.local()) { + const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform(); + v.set_volume_offset(vol_trafo.get_offset() + vol_trafo.get_rotation_matrix() * displacement); + } + else { + Vec3d relative_disp = displacement; + if (transformation_type.instance()) + relative_disp = volume_data.get_instance_scale_matrix().inverse() * relative_disp; + + transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(relative_disp), m_cache.dragging_center); + } } - else - transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(displacement), m_cache.dragging_center); } #if !DISABLE_INSTANCES_SYNCH @@ -909,23 +918,16 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform(); if (m_mode == Instance && !is_wipe_tower()) { assert(is_from_fully_selected_instance(i)); - Transform3d new_rotation_matrix = Transform3d::Identity(); - if (transformation_type.absolute()) - new_rotation_matrix = rotation_matrix; - else { - if (transformation_type.world()) - new_rotation_matrix = rotation_matrix * inst_trafo.get_rotation_matrix(); - else if (transformation_type.instance()) - new_rotation_matrix = inst_trafo.get_rotation_matrix() * rotation_matrix; - else - assert(false); + if (transformation_type.instance()) { + const Vec3d world_inst_pivot = m_cache.dragging_center - inst_trafo.get_offset(); + const Vec3d local_inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * world_inst_pivot; + Matrix3d inst_rotation, inst_scale; + inst_trafo.get_matrix().computeRotationScaling(&inst_rotation, &inst_scale); + const Transform3d trafo = inst_trafo.get_rotation_matrix() * rotation_matrix; + v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * inst_trafo.get_offset_matrix() * trafo * Transform3d(inst_scale) * Geometry::translation_transform(-local_inst_pivot)); } - - const Vec3d new_offset = transformation_type.independent() ? inst_trafo.get_offset() : - m_cache.dragging_center + new_rotation_matrix * inst_trafo.get_rotation_matrix().inverse() * - (inst_trafo.get_offset() - m_cache.dragging_center); - v.set_instance_transformation(Geometry::assemble_transform(Geometry::translation_transform(new_offset), new_rotation_matrix, - inst_trafo.get_scaling_factor_matrix(), inst_trafo.get_mirror_matrix())); + else + transform_instance_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); } else { if (!is_single_volume_or_modifier()) { @@ -933,8 +935,15 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); } else { - transformation_type.set_independent(); - transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); + if (transformation_type.local()) { + const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform(); + Matrix3d vol_rotation, vol_scale; + vol_trafo.get_matrix().computeRotationScaling(&vol_rotation, &vol_scale); + const Transform3d trafo = vol_trafo.get_rotation_matrix() * rotation_matrix; + v.set_volume_transformation(vol_trafo.get_offset_matrix() * trafo * Transform3d(vol_scale)); + } + else + transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center); } } } @@ -1357,32 +1366,17 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation } if (m_mode == Instance) { - assert(is_from_fully_selected_instance(i)); - if (transformation_type.world()) { - const Transform3d scale_matrix = Geometry::scale_transform(relative_scale); - const Transform3d offset_matrix = (transformation_type.joint() && translation.isApprox(Vec3d::Zero())) ? - // non-constrained scaling - add offset to scale around selection center - Geometry::translation_transform(m_cache.dragging_center + scale_matrix * (inst_trafo.get_offset() - m_cache.dragging_center)) : - // constrained scaling - add offset to keep constraint - Geometry::translation_transform(translation) * inst_trafo.get_offset_matrix(); - v.set_instance_transformation(offset_matrix * scale_matrix * inst_trafo.get_matrix_no_offset()); - } - else if (transformation_type.instance()) { - const Transform3d scale_matrix = Geometry::scale_transform(relative_scale); - Vec3d offset; - if (transformation_type.joint() && translation.isApprox(Vec3d::Zero())) { - // non-constrained scaling - add offset to scale around selection center - offset = inst_trafo.get_matrix_no_offset().inverse() * (inst_trafo.get_offset() - m_cache.dragging_center); - offset = inst_trafo.get_matrix_no_offset() * (scale_matrix * offset - offset); - } - else - // constrained scaling - add offset to keep constraint - offset = translation; - - v.set_instance_transformation(Geometry::translation_transform(offset) * inst_trafo.get_matrix() * scale_matrix); + if (transformation_type.instance()) { + const Vec3d world_inst_pivot = m_cache.dragging_center - inst_trafo.get_offset(); + const Vec3d local_inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * world_inst_pivot; + Matrix3d inst_rotation, inst_scale; + inst_trafo.get_matrix().computeRotationScaling(&inst_rotation, &inst_scale); + const Transform3d offset_trafo = Geometry::translation_transform(inst_trafo.get_offset() + inst_rotation * translation); + const Transform3d scale_trafo = Transform3d(inst_scale) * Geometry::scale_transform(relative_scale); + v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * offset_trafo * Transform3d(inst_rotation) * scale_trafo * Geometry::translation_transform(-local_inst_pivot)); } else - assert(false); + transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center); } else { if (!is_single_volume_or_modifier()) { @@ -1390,8 +1384,18 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center); } else { - transformation_type.set_independent(); - transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center); + if (transformation_type.local()) { + const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform(); + Matrix3d vol_rotation, vol_scale; + vol_trafo.get_matrix().computeRotationScaling(&vol_rotation, &vol_scale); + const Transform3d offset_trafo = Geometry::translation_transform(vol_trafo.get_offset() + vol_rotation * translation); + const Transform3d scale_trafo = Transform3d(vol_scale) * Geometry::scale_transform(relative_scale); + v.set_volume_transformation(offset_trafo * Transform3d(vol_rotation) * scale_trafo); + } + else { + transformation_type.set_independent(); + transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center); + } } } } @@ -3040,28 +3044,36 @@ void Selection::paste_objects_from_clipboard() } #if ENABLE_WORLD_COORDINATE +void Selection::transform_instance_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, + const Transform3d& transform, const Vec3d& world_pivot) +{ + assert(transformation_type.relative()); + assert(transformation_type.world()); + + const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform(); + const Vec3d inst_pivot = transformation_type.independent() && !is_from_single_instance() ? inst_trafo.get_offset() : world_pivot; + const Transform3d trafo = Geometry::translation_transform(inst_pivot) * transform * Geometry::translation_transform(-inst_pivot); + volume.set_instance_transformation(trafo * inst_trafo.get_matrix()); +} + void Selection::transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, const Transform3d& transform, const Vec3d& world_pivot) { assert(transformation_type.relative()); - const Geometry::Transformation& volume_trafo = volume_data.get_volume_transform(); + const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform(); const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform(); if (transformation_type.world()) { - const Vec3d inst_pivot = transformation_type.independent() ? volume_trafo.get_offset() : (Vec3d)(inst_trafo.get_matrix().inverse() * world_pivot); + const Vec3d inst_pivot = transformation_type.independent() ? vol_trafo.get_offset() : (Vec3d)(inst_trafo.get_matrix().inverse() * world_pivot); const Transform3d inst_matrix_no_offset = inst_trafo.get_matrix_no_offset(); const Transform3d trafo = Geometry::translation_transform(inst_pivot) * inst_matrix_no_offset.inverse() * transform * inst_matrix_no_offset * Geometry::translation_transform(-inst_pivot); - volume.set_volume_transformation(trafo * volume_trafo.get_matrix()); + volume.set_volume_transformation(trafo * vol_trafo.get_matrix()); } else if (transformation_type.instance()) { - const Vec3d inst_pivot = transformation_type.independent() ? volume_trafo.get_offset() : (Vec3d)(inst_trafo.get_matrix().inverse() * world_pivot); + const Vec3d inst_pivot = transformation_type.independent() ? vol_trafo.get_offset() : (Vec3d)(inst_trafo.get_matrix().inverse() * world_pivot); const Transform3d trafo = Geometry::translation_transform(inst_pivot) * transform * Geometry::translation_transform(-inst_pivot); - volume.set_volume_transformation(trafo * volume_trafo.get_matrix()); - } - else if (transformation_type.local()) { - const Geometry::Transformation trafo(transform); - volume.set_volume_transformation(trafo.get_offset_matrix() * volume_trafo.get_matrix() * trafo.get_matrix_no_offset()); + volume.set_volume_transformation(trafo * vol_trafo.get_matrix()); } else assert(false); diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index f6bc412601..029a70a252 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -501,6 +501,8 @@ private: void paste_objects_from_clipboard(); #if ENABLE_WORLD_COORDINATE + void transform_instance_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, + const Transform3d& transform, const Vec3d& world_pivot); void transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type, const Transform3d& transform, const Vec3d& world_pivot); #endif // ENABLE_WORLD_COORDINATE diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index ad9172de3c..8a7c41f62b 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -892,6 +892,16 @@ void Tab::update_mode() update_changed_tree_ui(); } +void Tab::update_mode_markers() +{ + // update mode for ModeSizer + if (m_mode_sizer) + m_mode_sizer->update_mode_markers(); + + if (m_active_page) + m_active_page->refresh(); +} + void Tab::update_visibility() { Freeze(); // There is needed Freeze/Thaw to avoid a flashing after Show/Layout diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 0e189496af..f5dd4c5225 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -355,6 +355,7 @@ public: void load_config(const DynamicPrintConfig& config); virtual void reload_config(); void update_mode(); + void update_mode_markers(); void update_visibility(); virtual void msw_rescale(); virtual void sys_color_changed(); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index c397b4b397..bd2949cbfb 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -416,7 +416,7 @@ static int scale() } #endif // __WXGTK2__ -wxBitmapBundle* get_bmp_bundle(const std::string& bmp_name_in, int px_cnt/* = 16*/) +wxBitmapBundle* get_bmp_bundle(const std::string& bmp_name_in, int px_cnt/* = 16*/, const std::string& new_color/* = std::string()*/) { #ifdef __WXGTK2__ px_cnt *= scale(); @@ -428,7 +428,7 @@ wxBitmapBundle* get_bmp_bundle(const std::string& bmp_name_in, int px_cnt/* = 16 boost::replace_last(bmp_name, ".png", ""); // Try loading an SVG first, then PNG if SVG is not found: - wxBitmapBundle* bmp = cache.from_svg(bmp_name, px_cnt, px_cnt, Slic3r::GUI::wxGetApp().dark_mode()); + wxBitmapBundle* bmp = cache.from_svg(bmp_name, px_cnt, px_cnt, Slic3r::GUI::wxGetApp().dark_mode(), new_color); if (bmp == nullptr) { bmp = cache.from_png(bmp_name, px_cnt, px_cnt); if (!bmp) @@ -655,6 +655,17 @@ ModeButton::ModeButton( wxWindow* parent, Init(mode); } +ModeButton::ModeButton( wxWindow* parent, + int mode_id,/*ConfigOptionMode*/ + const wxString& mode /*= wxEmptyString*/, + int px_cnt /*= = 16*/) : + ScalableButton(parent, wxID_ANY, "", mode, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT, px_cnt), + m_mode_id(mode_id) +{ + update_bitmap(); + Init(mode); +} + void ModeButton::Init(const wxString &mode) { std::string mode_str = std::string(mode.ToUTF8()); @@ -684,6 +695,15 @@ void ModeButton::SetState(const bool state) SetToolTip(state ? m_tt_selected : m_tt_focused); } +void ModeButton::update_bitmap() +{ + m_bmp = *get_bmp_bundle("mode", m_px_cnt, Slic3r::GUI::wxGetApp().get_mode_btn_color(m_mode_id)); + + SetBitmap(m_bmp); + SetBitmapCurrent(m_bmp); + SetBitmapPressed(m_bmp); +} + void ModeButton::focus_button(const bool focus) { const wxFont& new_font = focus ? @@ -709,6 +729,12 @@ void ModeButton::focus_button(const bool focus) Update(); } +void ModeButton::sys_color_changed() +{ + Slic3r::GUI::wxGetApp().UpdateDarkUI(this, m_has_border); + update_bitmap(); +} + // ---------------------------------------------------------------------------- // ModeSizer @@ -721,21 +747,15 @@ ModeSizer::ModeSizer(wxWindow *parent, int hgap/* = 0*/) : { SetFlexibleDirection(wxHORIZONTAL); - std::vector < std::pair < wxString, std::string >> buttons = { - {_(L("Simple")), "mode_simple"}, -// {_(L("Advanced")), "mode_advanced"}, - {_CTX(L_CONTEXT("Advanced", "Mode"), "Mode"), "mode_advanced"}, - {_(L("Expert")), "mode_expert"}, - }; - auto modebtnfn = [](wxCommandEvent &event, int mode_id) { Slic3r::GUI::wxGetApp().save_mode(mode_id); event.Skip(); }; m_mode_btns.reserve(3); - for (const auto& button : buttons) { - m_mode_btns.push_back(new ModeButton(parent, button.first, button.second, mode_icon_px_size())); + int mode_id = 0; + for (const wxString& label : {_L("Simple"), _CTX(L_CONTEXT("Advanced", "Mode"), "Mode"),_L("Expert")}) { + m_mode_btns.push_back(new ModeButton(parent, mode_id++, label, mode_icon_px_size())); m_mode_btns.back()->Bind(wxEVT_BUTTON, std::bind(modebtnfn, std::placeholders::_1, int(m_mode_btns.size() - 1))); Add(m_mode_btns.back()); @@ -762,8 +782,14 @@ void ModeSizer::set_items_border(int border) void ModeSizer::sys_color_changed() { - for (size_t m = 0; m < m_mode_btns.size(); m++) - m_mode_btns[m]->sys_color_changed(); + for (ModeButton* btn : m_mode_btns) + btn->sys_color_changed(); +} + +void ModeSizer::update_mode_markers() +{ + for (ModeButton* btn : m_mode_btns) + btn->update_bitmap(); } // ---------------------------------------------------------------------------- diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index db05af9eb1..5b15b34700 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -50,7 +50,7 @@ void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector< int em_unit(wxWindow* win); int mode_icon_px_size(); -wxBitmapBundle* get_bmp_bundle(const std::string& bmp_name, int px_cnt = 16); +wxBitmapBundle* get_bmp_bundle(const std::string& bmp_name, int px_cnt = 16, const std::string& new_color_rgb = std::string()); wxBitmapBundle* get_empty_bmp_bundle(int width, int height); wxBitmapBundle* get_solid_bmp_bundle(int width, int height, const std::string& color); @@ -247,7 +247,7 @@ public: void SetBitmapDisabled_(const ScalableBitmap &bmp); int GetBitmapHeight(); - void sys_color_changed(); + virtual void sys_color_changed(); private: wxWindow* m_parent { nullptr }; @@ -256,6 +256,7 @@ private: int m_width {-1}; // should be multiplied to em_unit int m_height{-1}; // should be multiplied to em_unit +protected: // bitmap dimensions int m_px_cnt{ 16 }; bool m_has_border {false}; @@ -283,6 +284,12 @@ public: const std::string& icon_name = "", int px_cnt = 16); + ModeButton( + wxWindow* parent, + int mode_id,/*ConfigOptionMode*/ + const wxString& mode = wxEmptyString, + int px_cnt = 16); + ~ModeButton() {} void Init(const wxString& mode); @@ -292,16 +299,20 @@ public: void OnLeaveBtn(wxMouseEvent& event) { focus_button(m_is_selected); event.Skip(); } void SetState(const bool state); + void update_bitmap(); bool is_selected() { return m_is_selected; } + void sys_color_changed() override; protected: void focus_button(const bool focus); private: - bool m_is_selected = false; + bool m_is_selected {false}; + int m_mode_id {-1}; wxString m_tt_selected; wxString m_tt_focused; + wxBitmapBundle m_bmp; }; @@ -322,6 +333,7 @@ public: void set_items_border(int border); void sys_color_changed(); + void update_mode_markers(); const std::vector& get_btns() { return m_mode_btns; } private: diff --git a/tests/libslic3r/test_emboss.cpp b/tests/libslic3r/test_emboss.cpp index a045d49902..2aba5ef19a 100644 --- a/tests/libslic3r/test_emboss.cpp +++ b/tests/libslic3r/test_emboss.cpp @@ -381,9 +381,9 @@ TEST_CASE("triangle intersection", "[]") #if defined _WIN32 #define FONT_DIR_PATH "C:/Windows/Fonts"; -#elif defined __linux__ -#define FONT_DIR_PATH "/usr/share/fonts"; #endif +//#elif defined __linux__ +//#define FONT_DIR_PATH "/usr/share/fonts"; //#elif defined __APPLE__ //#define FONT_DIR_PATH "//System/Library/Fonts"; //#endif @@ -391,8 +391,10 @@ TEST_CASE("triangle intersection", "[]") #ifdef FONT_DIR_PATH #include #include -#include -namespace fs = std::filesystem; +#include +namespace fs = boost::filesystem; +//#include +//namespace fs = std::filesystem; // Check function Emboss::is_italic that exist some italic and some non-italic font. TEST_CASE("Italic check", "[Emboss]") { @@ -406,15 +408,15 @@ TEST_CASE("Italic check", "[Emboss]") dir_paths.pop(); for (const auto &entry : fs::directory_iterator(dir_path)) { const fs::path &act_path = entry.path(); - if (entry.is_directory()) { - dir_paths.push(act_path.u8string()); + if (fs::is_directory(entry)) { + dir_paths.push(act_path.string()); continue; } - std::string ext = act_path.extension().u8string(); + std::string ext = act_path.extension().string(); std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c) { return std::tolower(c); }); if (ext != ".ttf") continue; - std::string path_str = act_path.u8string(); + std::string path_str = act_path.string(); auto font_opt = Emboss::create_font_file(path_str.c_str()); if (font_opt == nullptr) continue;