diff --git a/resources/icons/action_undo.png b/resources/icons/action_undo.png new file mode 100644 index 000000000..866ae9773 Binary files /dev/null and b/resources/icons/action_undo.png differ diff --git a/resources/icons/arrow_undo.png b/resources/icons/arrow_undo.png new file mode 100644 index 000000000..6972c5e59 Binary files /dev/null and b/resources/icons/arrow_undo.png differ diff --git a/resources/localization/uk/Slic3rPE_.mo b/resources/localization/uk/Slic3rPE_.mo new file mode 100644 index 000000000..c980ae64d Binary files /dev/null and b/resources/localization/uk/Slic3rPE_.mo differ diff --git a/slic3r.pl b/slic3r.pl index a3cc3cfc2..d9bed0ab6 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -12,7 +12,7 @@ BEGIN { use File::Basename qw(basename); use Getopt::Long qw(:config no_auto_abbrev); use List::Util qw(first); -use POSIX qw(setlocale LC_NUMERIC); +#use POSIX qw(setlocale LC_NUMERIC); use Slic3r; use Slic3r::Geometry qw(deg2rad); use Time::HiRes qw(gettimeofday tv_interval); @@ -112,7 +112,7 @@ if ((!@ARGV || $opt{gui}) && !$opt{no_gui} && !$opt{save} && eval "require Slic3 $Slic3r::GUI::autosave = $opt{autosave}; } $gui = Slic3r::GUI->new; - setlocale(LC_NUMERIC, 'C'); + #setlocale(LC_NUMERIC, 'C'); $gui->{mainframe}->load_config_file($_) for @{$opt{load}}; $gui->{mainframe}->load_config($cli_config); my @input_files = @ARGV; diff --git a/xs/src/slic3r/GUI/Field.hpp b/xs/src/slic3r/GUI/Field.hpp index 0d8c237d2..56de333cf 100644 --- a/xs/src/slic3r/GUI/Field.hpp +++ b/xs/src/slic3r/GUI/Field.hpp @@ -18,6 +18,7 @@ //#include "slic3r_gui.hpp" #include "GUI.hpp" +#include "Utils.hpp" namespace Slic3r { namespace GUI { @@ -31,7 +32,15 @@ wxString double_to_string(double const value); class Field { protected: // factory function to defer and enforce creation of derived type. - virtual void PostInitialize() { BUILD(); } + virtual void PostInitialize(){ + m_Undo_btn = new wxButton(m_parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT|wxNO_BORDER); + // use bouth of temporary_icons till don't have "undo_icon" + m_Undo_btn->SetBitmap(wxBitmap(from_u8(__WXMSW__ ? var("action_undo.png") : var("arrow_undo.png")), wxBITMAP_TYPE_PNG)); + auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); + m_Undo_btn->SetBackgroundColour(color); + m_Undo_btn->Hide(); + BUILD(); + } /// Finish constructing the Field's wxWidget-related properties, including setting its own sizer, etc. virtual void BUILD() = 0; @@ -73,6 +82,7 @@ public: virtual void disable() = 0; wxStaticText* m_Label = nullptr; + wxButton* m_Undo_btn = nullptr; /// Fires the enable or disable function, based on the input. inline void toggle(bool en) { en ? enable() : disable(); } diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index f9561d7b6..1ccf80365 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -240,6 +240,7 @@ bool select_language(wxArrayString & names, g_wxLocale->Init(identifiers[index]); g_wxLocale->AddCatalogLookupPathPrefix(wxPathOnly(localization_dir())); g_wxLocale->AddCatalog(g_wxApp->GetAppName()); + wxSetlocale(LC_NUMERIC, "C"); return true; } return false; @@ -268,6 +269,7 @@ bool load_language() g_wxLocale->Init(identifiers[i]); g_wxLocale->AddCatalogLookupPathPrefix(wxPathOnly(localization_dir())); g_wxLocale->AddCatalog(g_wxApp->GetAppName()); + wxSetlocale(LC_NUMERIC, "C"); return true; } } @@ -507,7 +509,7 @@ wxApp* get_app(){ wxColour* get_modified_label_clr() { - return new wxColour(254, 189, 101); + return new wxColour(253, 88, 0); } void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string items, bool initial_value) @@ -567,13 +569,13 @@ AppConfig* get_app_config() return g_AppConfig; } -wxString L_str(std::string str) +wxString L_str(const std::string &str) { //! Explicitly specify that the source string is already in UTF-8 encoding return wxGetTranslation(wxString(str.c_str(), wxConvUTF8)); } -wxString from_u8(std::string str) +wxString from_u8(const std::string &str) { return wxString::FromUTF8(str.c_str()); } diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp index 7a8039e64..b7e67af92 100644 --- a/xs/src/slic3r/GUI/GUI.hpp +++ b/xs/src/slic3r/GUI/GUI.hpp @@ -119,9 +119,9 @@ void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string int combochecklist_get_flags(wxComboCtrl* comboCtrl); // Return translated std::string as a wxString -wxString L_str(std::string str); +wxString L_str(const std::string &str); // Return wxString from std::string in UTF8 -wxString from_u8(std::string str); +wxString from_u8(const std::string &str); } } diff --git a/xs/src/slic3r/GUI/OptionsGroup.cpp b/xs/src/slic3r/GUI/OptionsGroup.cpp index 14142d207..138496b2e 100644 --- a/xs/src/slic3r/GUI/OptionsGroup.cpp +++ b/xs/src/slic3r/GUI/OptionsGroup.cpp @@ -3,6 +3,7 @@ #include #include +#include "Utils.hpp" namespace Slic3r { namespace GUI { @@ -104,6 +105,7 @@ void OptionsGroup::append_line(const Line& line) { const auto& option = option_set.front(); const auto& field = build_field(option); + sizer->Add(field->m_Undo_btn); if (is_window_field(field)) sizer->Add(field->getWindow(), 0, wxEXPAND | wxALL, wxOSX ? 0 : 5); if (is_sizer_field(field)) @@ -116,9 +118,8 @@ void OptionsGroup::append_line(const Line& line) { // Build a label if we have it wxStaticText* label=nullptr; if (label_width != 0) { - /*auto*/ label = new wxStaticText(parent(), wxID_ANY, line.label + (line.label.IsEmpty() ? "" : ":"), + label = new wxStaticText(parent(), wxID_ANY, line.label + (line.label.IsEmpty() ? "" : ":"), wxDefaultPosition, wxSize(label_width, -1)); -// label->SetBackgroundColour(*new wxColour(254, 189, 101)); label->SetFont(label_font); label->Wrap(label_width); // avoid a Linux/GTK bug grid_sizer->Add(label, 0, wxALIGN_CENTER_VERTICAL,0); @@ -134,25 +135,24 @@ void OptionsGroup::append_line(const Line& line) { } // if we have a single option with no sidetext just add it directly to the grid sizer - if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 && - option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) { - const auto& option = option_set.front(); - const auto& field = build_field(option, label); -//! std::cerr << "single option, no sidetext.\n"; -//! std::cerr << "field parent is not null?: " << (field->parent != nullptr) << "\n"; + auto sizer = new wxBoxSizer(wxHORIZONTAL); + grid_sizer->Add(sizer, 0, wxEXPAND | wxALL, 0); + if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 && + option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) { + const auto& option = option_set.front(); + const auto& field = build_field(option, label); - if (is_window_field(field)) - grid_sizer->Add(field->getWindow(), 0, (option.opt.full_width ? wxEXPAND : 0) | + sizer->Add(field->m_Undo_btn, 0, wxALIGN_CENTER_VERTICAL); + if (is_window_field(field)) + sizer->Add(field->getWindow(), 0, (option.opt.full_width ? wxEXPAND : 0) | wxBOTTOM | wxTOP | wxALIGN_CENTER_VERTICAL, wxOSX ? 0 : 2); - if (is_sizer_field(field)) - grid_sizer->Add(field->getSizer(), 0, (option.opt.full_width ? wxEXPAND : 0) | wxALIGN_CENTER_VERTICAL, 0); - return; - } + if (is_sizer_field(field)) + sizer->Add(field->getSizer(), 0, (option.opt.full_width ? wxEXPAND : 0) | wxALIGN_CENTER_VERTICAL, 0); + return; + } // if we're here, we have more than one option or a single option with sidetext // so we need a horizontal sizer to arrange these things - auto sizer = new wxBoxSizer(wxHORIZONTAL); - grid_sizer->Add(sizer, 0, wxEXPAND | wxALL, 0); for (auto opt : option_set) { ConfigOptionDef option = opt.opt; // add label if any @@ -162,14 +162,15 @@ void OptionsGroup::append_line(const Line& line) { // wxString str_label = (option.label == "Top" || option.label == "Bottom") ? // wxGETTEXT_IN_CONTEXT("Layers", wxString(option.label.c_str()): // L_str(option.label); - /*auto field_*/label = new wxStaticText(parent(), wxID_ANY, str_label + ":", wxDefaultPosition, wxDefaultSize); - /*field_*/label->SetFont(label_font); - sizer->Add(/*field_*/label, 0, wxALIGN_CENTER_VERTICAL, 0); + label = new wxStaticText(parent(), wxID_ANY, str_label + ":", wxDefaultPosition, wxDefaultSize); + label->SetFont(label_font); + sizer->Add(label, 0, wxALIGN_CENTER_VERTICAL, 0); } // add field const Option& opt_ref = opt; auto& field = build_field(opt_ref, label); + sizer->Add(field->m_Undo_btn, 0, wxALIGN_CENTER_VERTICAL, 0); is_sizer_field(field) ? sizer->Add(field->getSizer(), 0, wxALIGN_CENTER_VERTICAL, 0) : sizer->Add(field->getWindow(), 0, wxALIGN_CENTER_VERTICAL, 0); diff --git a/xs/src/slic3r/GUI/PresetHints.cpp b/xs/src/slic3r/GUI/PresetHints.cpp index 07c8e3b07..d4c929c1c 100644 --- a/xs/src/slic3r/GUI/PresetHints.cpp +++ b/xs/src/slic3r/GUI/PresetHints.cpp @@ -13,10 +13,11 @@ namespace Slic3r { +#define MIN_BUF_LENGTH 4096 std::string PresetHints::cooling_description(const Preset &preset) { std::string out; - char buf[4096]; + char buf[MIN_BUF_LENGTH/*4096*/]; if (preset.config.opt_bool("cooling", 0)) { int slowdown_below_layer_time = preset.config.opt_int("slowdown_below_layer_time", 0); int min_fan_speed = preset.config.opt_int("min_fan_speed", 0); @@ -220,7 +221,7 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle + _CHB(L(" with a volumetric rate ")); if (limited_by_max_volumetric_speed) max_flow = max_volumetric_speed; - char buf[2048]; + char buf[MIN_BUF_LENGTH/*2048*/]; sprintf(buf, _CHB(L("%3.2f mm³/s")), max_flow); out += buf; sprintf(buf, _CHB(L(" at filament speed %3.2f mm/s.")), max_flow / filament_crossection); @@ -258,7 +259,7 @@ std::string PresetHints::recommended_thin_wall_thickness(const PresetBundle &pre if (num_perimeters > 0) { int num_lines = std::min(num_perimeters * 2, 10); - char buf[256]; + char buf[MIN_BUF_LENGTH/*256*/]; sprintf(buf, _CHB(L("Recommended object thin wall thickness for layer height %.2f and ")), layer_height); out += buf; // Start with the width of two closely spaced diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index 15fc5f006..aa30a655c 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -33,19 +33,23 @@ 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); - const wxBitmap* bmp = new wxBitmap(from_u8(Slic3r::var("flag-green-icon.png")), wxBITMAP_TYPE_PNG); + + auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); //buttons wxBitmap bmpMenu; bmpMenu = wxBitmap(from_u8(Slic3r::var("disk.png")), wxBITMAP_TYPE_PNG); m_btn_save_preset = new wxBitmapButton(panel, wxID_ANY, bmpMenu, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); + m_btn_save_preset->SetBackgroundColour(color); bmpMenu = wxBitmap(from_u8(Slic3r::var("delete.png")), wxBITMAP_TYPE_PNG); m_btn_delete_preset = new wxBitmapButton(panel, wxID_ANY, bmpMenu, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); + m_btn_delete_preset->SetBackgroundColour(color); m_show_incompatible_presets = false; m_bmp_show_incompatible_presets = new wxBitmap(from_u8(Slic3r::var("flag-red-icon.png")), wxBITMAP_TYPE_PNG); m_bmp_hide_incompatible_presets = new wxBitmap(from_u8(Slic3r::var("flag-green-icon.png")), wxBITMAP_TYPE_PNG); m_btn_hide_incompatible_presets = new wxBitmapButton(panel, wxID_ANY, *m_bmp_hide_incompatible_presets, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); + m_btn_hide_incompatible_presets->SetBackgroundColour(color); m_btn_save_preset->SetToolTip(_(L("Save current ")) + m_title); m_btn_delete_preset->SetToolTip(_(L("Delete this preset"))); @@ -140,12 +144,34 @@ void Tab::update_dirty(){ m_presets->update_dirty_ui(m_presets_choice); on_presets_changed(); auto dirty_options = m_presets->current_dirty_options(); + // Add new dirty options to m_dirty_options for (auto opt_key : dirty_options){ - if (find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) == m_dirty_options.end()){ - get_field(opt_key)->m_Label->SetBackgroundColour(*get_modified_label_clr()); + Field* field = get_field(opt_key/*, opt_index*/); + if (field != nullptr && find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) == m_dirty_options.end()){ + field->m_Label->SetForegroundColour(*get_modified_label_clr()); + field->m_Undo_btn->Show(); + m_dirty_options.push_back(opt_key); } } + + // Delete undirty options from m_dirty_options + size_t cnt = m_dirty_options.size(); + for (auto i = 0; i < /*cnt*/m_dirty_options.size(); ++i) + { + const std::string &opt_key = m_dirty_options[i]; + Field* field = get_field(opt_key/*, opt_index*/); + if (field != nullptr && find(dirty_options.begin(), dirty_options.end(), opt_key) == dirty_options.end()) + { + field->m_Undo_btn->Hide(); + field->m_Label->SetForegroundColour(wxSYS_COLOUR_WINDOWTEXT); + std::vector::iterator itr = find(m_dirty_options.begin(), m_dirty_options.end(), opt_key); + if (itr != m_dirty_options.end()){ + m_dirty_options.erase(itr); + --i; + } + } + } } void Tab::update_tab_ui() @@ -947,7 +973,7 @@ void TabPrinter::build() Line line{ _(L("Bed shape")), "" }; line.widget = [this](wxWindow* parent){ - auto btn = new wxButton(parent, wxID_ANY, _(L(" Set "))+"\u2026", wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); + auto btn = new wxButton(parent, wxID_ANY, _(L(" Set "))+"\u2026", wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); // btn->SetFont(Slic3r::GUI::small_font); btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("printer_empty.png")), wxBITMAP_TYPE_PNG));