diff options
Diffstat (limited to 'xs')
-rw-r--r-- | xs/CMakeLists.txt | 2 | ||||
-rw-r--r-- | xs/src/avrdude/main.c | 2 | ||||
-rw-r--r-- | xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 69 | ||||
-rw-r--r-- | xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp | 2 | ||||
-rw-r--r-- | xs/src/libslic3r/GCodeSender.cpp | 34 | ||||
-rw-r--r-- | xs/src/libslic3r/GCodeSender.hpp | 2 | ||||
-rw-r--r-- | xs/src/libslic3r/PerimeterGenerator.cpp | 2 | ||||
-rw-r--r-- | xs/src/libslic3r/PrintConfig.cpp | 2 | ||||
-rw-r--r-- | xs/src/libslic3r/libslic3r.h | 2 | ||||
-rw-r--r-- | xs/src/slic3r/GUI/ConfigWizard.cpp | 64 | ||||
-rw-r--r-- | xs/src/slic3r/GUI/ConfigWizard_private.hpp | 5 | ||||
-rw-r--r-- | xs/src/slic3r/GUI/Field.cpp | 20 | ||||
-rw-r--r-- | xs/src/slic3r/GUI/Field.hpp | 3 | ||||
-rw-r--r-- | xs/src/slic3r/GUI/GUI.cpp | 108 | ||||
-rw-r--r-- | xs/src/slic3r/GUI/GUI.hpp | 15 | ||||
-rw-r--r-- | xs/src/slic3r/GUI/PresetBundle.cpp | 7 | ||||
-rw-r--r-- | xs/src/slic3r/GUI/RammingChart.cpp | 9 | ||||
-rw-r--r-- | xs/src/slic3r/GUI/Tab.cpp | 27 | ||||
-rw-r--r-- | xs/src/slic3r/GUI/WipeTowerDialog.cpp | 13 | ||||
-rw-r--r-- | xs/src/slic3r/Utils/PresetUpdater.cpp | 30 | ||||
-rw-r--r-- | xs/xsp/GUI.xsp | 6 |
21 files changed, 291 insertions, 133 deletions
diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index 866374584..05293a523 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -36,7 +36,7 @@ if(WIN32) endif() endif() -add_definitions(-DwxUSE_UNICODE -D_UNICODE -DUNICODE) +add_definitions(-DwxUSE_UNICODE -D_UNICODE -DUNICODE -DWXINTL_NO_GETTEXT_MACRO) add_library(libslic3r STATIC ${LIBDIR}/libslic3r/BoundingBox.cpp diff --git a/xs/src/avrdude/main.c b/xs/src/avrdude/main.c index 51fdf7268..0550ceff1 100644 --- a/xs/src/avrdude/main.c +++ b/xs/src/avrdude/main.c @@ -252,7 +252,7 @@ static void usage(void) // setvbuf(stderr, (char*)NULL, _IOLBF, 0); // } -static bool update_progress_no_tty (int percent, double etime, char *hdr) +static void update_progress_no_tty (int percent, double etime, char *hdr) { static int done = 0; static int last = 0; diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index b414186be..6486f2917 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -42,14 +42,32 @@ namespace PrusaMultiMaterial { class Writer { public: - Writer() : + Writer(float layer_height, float line_width) : m_current_pos(std::numeric_limits<float>::max(), std::numeric_limits<float>::max()), m_current_z(0.f), m_current_feedrate(0.f), - m_layer_height(0.f), + m_layer_height(layer_height), m_extrusion_flow(0.f), m_preview_suppressed(false), - m_elapsed_time(0.f) {} + m_elapsed_time(0.f), + m_default_analyzer_line_width(line_width) + { + // adds tag for analyzer: + char buf[64]; + sprintf(buf, ";%s%f\n", GCodeAnalyzer::Height_Tag.c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming + m_gcode += buf; + sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erWipeTower); + m_gcode += buf; + change_analyzer_line_width(line_width); + } + + Writer& change_analyzer_line_width(float line_width) { + // adds tag for analyzer: + char buf[64]; + sprintf(buf, ";%s%f\n", GCodeAnalyzer::Width_Tag.c_str(), line_width); + m_gcode += buf; + return *this; + } Writer& set_initial_position(const WipeTower::xy &pos) { m_start_pos = WipeTower::xy(pos,0.f,m_y_shift).rotate(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_angle_deg); @@ -62,9 +80,6 @@ public: Writer& set_z(float z) { m_current_z = z; return *this; } - Writer& set_layer_height(float layer_height) - { m_layer_height = layer_height; return *this; } - Writer& set_extrusion_flow(float flow) { m_extrusion_flow = flow; return *this; } @@ -80,8 +95,8 @@ public: // Suppress / resume G-code preview in Slic3r. Slic3r will have difficulty to differentiate the various // filament loading and cooling moves from normal extrusion moves. Therefore the writer // is asked to suppres output of some lines, which look like extrusions. - Writer& suppress_preview() { m_preview_suppressed = true; return *this; } - Writer& resume_preview() { m_preview_suppressed = false; return *this; } + Writer& suppress_preview() { change_analyzer_line_width(0.f); m_preview_suppressed = true; return *this; } + Writer& resume_preview() { change_analyzer_line_width(m_default_analyzer_line_width); m_preview_suppressed = false; return *this; } Writer& feedrate(float f) { @@ -126,11 +141,6 @@ public: m_extrusions.emplace_back(WipeTower::Extrusion(WipeTower::xy(rot.x, rot.y), width, m_current_tool)); } - // adds tag for analyzer - char buf[64]; - sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erWipeTower); - m_gcode += buf; - m_gcode += "G1"; if (rot.x != rotated_current_pos.x) { m_gcode += set_format_X(rot.x); // Transform current position back to wipe tower coordinates (was updated by set_format_X) @@ -197,7 +207,7 @@ public: do { ++i; if (i==4) i=0; - extrude(corners[i]); + extrude(corners[i], f); } while (i != index_of_closest); return (*this); } @@ -390,6 +400,7 @@ private: float m_wipe_tower_depth = 0.f; float m_last_fan_speed = 0.f; int current_temp = -1; + const float m_default_analyzer_line_width; std::string set_format_X(float x) @@ -479,10 +490,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime( const float prime_section_width = std::min(240.f / tools.size(), 60.f); box_coordinates cleaning_box(xy(5.f, 0.f), prime_section_width, 100.f); - PrusaMultiMaterial::Writer writer; + PrusaMultiMaterial::Writer writer(m_layer_height, m_perimeter_width); writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) - .set_layer_height(m_layer_height) .set_initial_tool(m_current_tool) .append(";--------------------\n" "; CP PRIMING START\n") @@ -568,10 +578,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo (tool != (unsigned int)(-1) ? /*m_layer_info->depth*/wipe_area+m_depth_traversed-0.5*m_perimeter_width : m_wipe_tower_depth-m_perimeter_width)); - PrusaMultiMaterial::Writer writer; + PrusaMultiMaterial::Writer writer(m_layer_height, m_perimeter_width); writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) - .set_layer_height(m_layer_height) .set_initial_tool(m_current_tool) .set_rotation(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_wipe_tower_rotation_angle) .set_y_shift(m_y_shift + (tool!=(unsigned int)(-1) && (m_current_shape == SHAPE_REVERSED && !m_peters_wipe_tower) ? m_layer_info->depth - m_layer_info->toolchanges_depth(): 0.f)) @@ -640,10 +649,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::toolchange_Brim(bool sideOnly, flo m_wipe_tower_width, m_wipe_tower_depth); - PrusaMultiMaterial::Writer writer; + PrusaMultiMaterial::Writer writer(m_layer_height, m_perimeter_width); writer.set_extrusion_flow(m_extrusion_flow * 1.1f) .set_z(m_z_pos) // Let the writer know the current Z position as a base for Z-hop. - .set_layer_height(m_layer_height) .set_initial_tool(m_current_tool) .set_rotation(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_wipe_tower_rotation_angle) .append(";-------------------------------------\n" @@ -697,11 +705,12 @@ void WipeTowerPrusaMM::toolchange_Unload( float xl = cleaning_box.ld.x + 1.f * m_perimeter_width; float xr = cleaning_box.rd.x - 1.f * m_perimeter_width; - writer.append("; CP TOOLCHANGE UNLOAD\n"); - const float line_width = m_perimeter_width * m_filpar[m_current_tool].ramming_line_width_multiplicator; // desired ramming line thickness const float y_step = line_width * m_filpar[m_current_tool].ramming_step_multiplicator * m_extra_spacing; // spacing between lines in mm + writer.append("; CP TOOLCHANGE UNLOAD\n") + .change_analyzer_line_width(line_width); + unsigned i = 0; // iterates through ramming_speed m_left_to_right = true; // current direction of ramming float remaining = xr - xl ; // keeps track of distance to the next turnaround @@ -775,12 +784,14 @@ void WipeTowerPrusaMM::toolchange_Unload( } } WipeTower::xy end_of_ramming(writer.x(),writer.y()); + writer.change_analyzer_line_width(m_perimeter_width); // so the next lines are not affected by ramming_line_width_multiplier // Pull the filament end to the BEGINNING of the cooling tube while still moving the print head float oldx = writer.x(); float turning_point = (!m_left_to_right ? std::max(xl,oldx-15.f) : std::min(xr,oldx+15.f) ); // so it's not too far float xdist = std::abs(oldx-turning_point); float edist = -(m_cooling_tube_retraction+m_cooling_tube_length/2.f-42); + writer.suppress_preview() .load_move_x(turning_point,-15 , 60.f * std::hypot(xdist,15)/15 * 83 ) // fixed speed after ramming .load_move_x(oldx ,edist , 60.f * std::hypot(xdist,edist)/std::abs(edist) * m_filpar[m_current_tool].unloading_speed ) @@ -959,10 +970,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::finish_layer() // Otherwise the caller would likely travel to the wipe tower in vain. assert(! this->layer_finished()); - PrusaMultiMaterial::Writer writer; + PrusaMultiMaterial::Writer writer(m_layer_height, m_perimeter_width); writer.set_extrusion_flow(m_extrusion_flow) .set_z(m_z_pos) - .set_layer_height(m_layer_height) .set_initial_tool(m_current_tool) .set_rotation(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_wipe_tower_rotation_angle) .set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED && !m_peters_wipe_tower ? m_layer_info->toolchanges_depth() : 0.f)) @@ -1137,7 +1147,8 @@ void WipeTowerPrusaMM::save_on_last_wipe() // Resulting ToolChangeResults are appended into vector "result" void WipeTowerPrusaMM::generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &result) { - if (m_plan.empty()) return; + if (m_plan.empty()) + return; m_extra_spacing = 1.f; @@ -1151,8 +1162,9 @@ void WipeTowerPrusaMM::generate(std::vector<std::vector<WipeTower::ToolChangeRes make_wipe_tower_square(); m_layer_info = m_plan.begin(); + m_current_tool = (unsigned int)(-2); // we don't know which extruder to start with - we'll set it according to the first toolchange - std::vector<WipeTower::ToolChangeResult> layer_result; + std::vector<WipeTower::ToolChangeResult> layer_result; for (auto layer : m_plan) { set_layer(layer.z,layer.height,0,layer.z == m_plan.front().z,layer.z == m_plan.back().z); @@ -1166,8 +1178,11 @@ void WipeTowerPrusaMM::generate(std::vector<std::vector<WipeTower::ToolChangeRes if (!m_peters_wipe_tower && m_layer_info->depth < m_wipe_tower_depth - m_perimeter_width) m_y_shift = (m_wipe_tower_depth-m_layer_info->depth-m_perimeter_width)/2.f; - for (const auto &toolchange : layer.tool_changes) + for (const auto &toolchange : layer.tool_changes) { + if (m_current_tool == (unsigned int)(-2)) + m_current_tool = toolchange.old_tool; layer_result.emplace_back(tool_change(toolchange.new_tool, false)); + } if (! layer_finished()) { auto finish_layer_toolchange = finish_layer(); diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp index c83c79a04..b7c721128 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp @@ -229,7 +229,7 @@ private: bool m_print_brim = true; // A fill-in direction (positive Y, negative Y) alternates with each layer. wipe_shape m_current_shape = SHAPE_NORMAL; - unsigned int m_current_tool = 0; + unsigned int m_current_tool; std::vector<std::vector<float>> wipe_volumes; float m_depth_traversed = 0.f; // Current y position at the wipe tower. diff --git a/xs/src/libslic3r/GCodeSender.cpp b/xs/src/libslic3r/GCodeSender.cpp index bbeaf836d..c3530e00f 100644 --- a/xs/src/libslic3r/GCodeSender.cpp +++ b/xs/src/libslic3r/GCodeSender.cpp @@ -41,6 +41,7 @@ struct termios2 { //#define DEBUG_SERIAL #ifdef DEBUG_SERIAL +#include <cstdlib> #include <fstream> std::fstream fs; #endif @@ -52,7 +53,11 @@ namespace Slic3r { GCodeSender::GCodeSender() : io(), serial(io), can_send(false), sent(0), open(false), error(false), connected(false), queue_paused(false) -{} +{ +#ifdef DEBUG_SERIAL + std::srand(std::time(nullptr)); +#endif +} GCodeSender::~GCodeSender() { @@ -358,15 +363,23 @@ GCodeSender::on_read(const boost::system::error_code& error, // extract the first number from line boost::algorithm::trim_left_if(line, !boost::algorithm::is_digit()); size_t toresend = boost::lexical_cast<size_t>(line.substr(0, line.find_first_not_of("0123456789"))); - ++ toresend; // N is 0-based - if (toresend >= this->sent - this->last_sent.size() && toresend < this->last_sent.size()) { + +#ifdef DEBUG_SERIAL + fs << "!! line num out of sync: toresend = " << toresend << ", sent = " << sent << ", last_sent.size = " << last_sent.size() << std::endl; +#endif + + if (toresend > this->sent - this->last_sent.size() && toresend <= this->sent) { { boost::lock_guard<boost::mutex> l(this->queue_mutex); + const auto lines_to_resend = this->sent - toresend + 1; +#ifdef DEBUG_SERIAL + fs << "!! resending " << lines_to_resend << " lines" << std::endl; +#endif // move the unsent lines to priqueue this->priqueue.insert( this->priqueue.begin(), // insert at the beginning - this->last_sent.begin() + toresend - (this->sent - this->last_sent.size()) - 1, + this->last_sent.begin() + this->last_sent.size() - lines_to_resend, this->last_sent.end() ); @@ -477,8 +490,14 @@ GCodeSender::do_send() if (line.empty()) return; // compute full line - std::string full_line = "N" + boost::lexical_cast<std::string>(this->sent) + " " + line; ++ this->sent; +#ifndef DEBUG_SERIAL + const auto line_num = this->sent; +#else + // In DEBUG_SERIAL mode, test line re-synchronization by sending bad line number 1/4 of the time + const auto line_num = std::rand() < RAND_MAX/4 ? 0 : this->sent; +#endif + std::string full_line = "N" + boost::lexical_cast<std::string>(line_num) + " " + line; // calculate checksum int cs = 0; @@ -497,8 +516,9 @@ GCodeSender::do_send() this->last_sent.push_back(line); this->can_send = false; - if (this->last_sent.size() > KEEP_SENT) - this->last_sent.erase(this->last_sent.begin(), this->last_sent.end() - KEEP_SENT); + while (this->last_sent.size() > KEEP_SENT) { + this->last_sent.pop_front(); + } // we can't supply boost::asio::buffer(full_line) to async_write() because full_line is on the // stack and the buffer would lose its underlying storage causing memory corruption diff --git a/xs/src/libslic3r/GCodeSender.hpp b/xs/src/libslic3r/GCodeSender.hpp index 3022993cb..d7663ca55 100644 --- a/xs/src/libslic3r/GCodeSender.hpp +++ b/xs/src/libslic3r/GCodeSender.hpp @@ -51,7 +51,7 @@ class GCodeSender : private boost::noncopyable { bool can_send; bool queue_paused; size_t sent; - std::vector<std::string> last_sent; + std::deque<std::string> last_sent; // this mutex guards log, T, B mutable boost::mutex log_mutex; diff --git a/xs/src/libslic3r/PerimeterGenerator.cpp b/xs/src/libslic3r/PerimeterGenerator.cpp index c2284aad4..1d2e6248f 100644 --- a/xs/src/libslic3r/PerimeterGenerator.cpp +++ b/xs/src/libslic3r/PerimeterGenerator.cpp @@ -243,7 +243,7 @@ void PerimeterGenerator::process() perimeter_spacing / 2; // only apply infill overlap if we actually have one perimeter if (inset > 0) - inset -= this->config->get_abs_value("infill_overlap", inset + solid_infill_spacing / 2); + inset -= scale_(this->config->get_abs_value("infill_overlap", unscale(inset + solid_infill_spacing / 2))); // simplify infill contours according to resolution Polygons pp; for (ExPolygon &ex : last) diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 9333132ff..b77a3a76e 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -948,7 +948,7 @@ PrintConfigDef::PrintConfigDef() def->default_value = new ConfigOptionFloats { 10. }; def = this->add("min_skirt_length", coFloat); - def->label = L("Minimum extrusion length"); + def->label = L("Minimal filament extrusion length"); def->tooltip = L("Generate no less than the number of skirt loops required to consume " "the specified amount of filament on the bottom layer. For multi-extruder machines, " "this minimum applies to each extruder."); diff --git a/xs/src/libslic3r/libslic3r.h b/xs/src/libslic3r/libslic3r.h index 8aa0d0277..4aef4d5c1 100644 --- a/xs/src/libslic3r/libslic3r.h +++ b/xs/src/libslic3r/libslic3r.h @@ -14,7 +14,7 @@ #include <boost/thread.hpp> #define SLIC3R_FORK_NAME "Slic3r Prusa Edition" -#define SLIC3R_VERSION "1.40.0-alpha2" +#define SLIC3R_VERSION "1.40.0" #define SLIC3R_BUILD "UNKNOWN" typedef int32_t coord_t; diff --git a/xs/src/slic3r/GUI/ConfigWizard.cpp b/xs/src/slic3r/GUI/ConfigWizard.cpp index 6b8e8abaf..aed0c3534 100644 --- a/xs/src/slic3r/GUI/ConfigWizard.cpp +++ b/xs/src/slic3r/GUI/ConfigWizard.cpp @@ -3,7 +3,7 @@ #include <algorithm> #include <utility> #include <unordered_map> - +#include <boost/format.hpp> #include <boost/log/trivial.hpp> #include <wx/settings.h> @@ -59,7 +59,7 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, cons auto *sizer = new wxBoxSizer(wxVERTICAL); auto *printer_grid = new wxFlexGridSizer(models.size(), 0, 20); - printer_grid->SetFlexibleDirection(wxVERTICAL); + printer_grid->SetFlexibleDirection(wxVERTICAL | wxHORIZONTAL); sizer->Add(printer_grid); auto namefont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); @@ -136,7 +136,7 @@ void PrinterPicker::on_checkbox(const Checkbox *cbox, bool checked) // Wizard page base ConfigWizardPage::ConfigWizardPage(ConfigWizard *parent, wxString title, wxString shortname) : - wxPanel(parent), + wxPanel(parent->p->hscroll), parent(parent), shortname(std::move(shortname)), p_prev(nullptr), @@ -182,8 +182,8 @@ ConfigWizardPage* ConfigWizardPage::chain(ConfigWizardPage *page) void ConfigWizardPage::append_text(wxString text) { auto *widget = new wxStaticText(this, wxID_ANY, text, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); - widget->Wrap(CONTENT_WIDTH); - widget->SetMinSize(wxSize(CONTENT_WIDTH, -1)); + widget->Wrap(WRAP_WIDTH); + widget->SetMinSize(wxSize(WRAP_WIDTH, -1)); append(widget); } @@ -285,7 +285,7 @@ PageUpdate::PageUpdate(ConfigWizard *parent) : const auto text_bold = _(L("Updates are never applied without user's consent and never overwrite user's customized settings.")); auto *label_bold = new wxStaticText(this, wxID_ANY, text_bold); label_bold->SetFont(boldfont); - label_bold->Wrap(CONTENT_WIDTH); + label_bold->Wrap(WRAP_WIDTH); append(label_bold); append_text(_(L("Additionally a backup snapshot of the whole configuration is created before an update is applied."))); @@ -615,8 +615,14 @@ void ConfigWizard::priv::load_vendors() // Load vendors from the "vendors" directory in datadir for (fs::directory_iterator it(vendor_dir); it != fs::directory_iterator(); ++it) { if (it->path().extension() == ".ini") { - auto vp = VendorProfile::from_ini(it->path()); - vendors[vp.id] = std::move(vp); + try { + auto vp = VendorProfile::from_ini(it->path()); + vendors[vp.id] = std::move(vp); + } + catch (const std::exception& e) { + BOOST_LOG_TRIVIAL(error) << boost::format("Error loading vendor bundle %1%: %2%") % it->path() % e.what(); + } + } } @@ -625,9 +631,14 @@ void ConfigWizard::priv::load_vendors() if (it->path().extension() == ".ini") { const auto id = it->path().stem().string(); if (vendors.find(id) == vendors.end()) { - auto vp = VendorProfile::from_ini(it->path()); - vendors_rsrc[vp.id] = it->path().filename().string(); - vendors[vp.id] = std::move(vp); + try { + auto vp = VendorProfile::from_ini(it->path()); + vendors_rsrc[vp.id] = it->path().filename().string(); + vendors[vp.id] = std::move(vp); + } + catch (const std::exception& e) { + BOOST_LOG_TRIVIAL(error) << boost::format("Error loading vendor bundle %1%: %2%") % it->path() % e.what(); + } } } } @@ -657,7 +668,7 @@ void ConfigWizard::priv::index_refresh() void ConfigWizard::priv::add_page(ConfigWizardPage *page) { - topsizer->Add(page, 0, wxEXPAND); + hscroll_sizer->Add(page, 0, wxEXPAND); auto *extra_buttons = page->extra_buttons(); if (extra_buttons != nullptr) { @@ -784,12 +795,19 @@ ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) : p->index = new ConfigWizardIndex(this); auto *vsizer = new wxBoxSizer(wxVERTICAL); - p->topsizer = new wxBoxSizer(wxHORIZONTAL); + auto *topsizer = new wxBoxSizer(wxHORIZONTAL); auto *hline = new wxStaticLine(this); p->btnsizer = new wxBoxSizer(wxHORIZONTAL); - p->topsizer->Add(p->index, 0, wxEXPAND); - p->topsizer->AddSpacer(INDEX_MARGIN); + // Initially we _do not_ SetScrollRate in order to figure out the overall width of the Wizard without scrolling. + // Later, we compare that to the size of the current screen and set minimum width based on that (see below). + p->hscroll = new wxScrolledWindow(this); + p->hscroll_sizer = new wxBoxSizer(wxHORIZONTAL); + p->hscroll->SetSizer(p->hscroll_sizer); + + topsizer->Add(p->index, 0, wxEXPAND); + topsizer->AddSpacer(INDEX_MARGIN); + topsizer->Add(p->hscroll, 1, wxEXPAND); p->btn_prev = new wxButton(this, wxID_BACKWARD); p->btn_next = new wxButton(this, wxID_FORWARD); @@ -816,13 +834,25 @@ ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) : ->chain(p->page_diams) ->chain(p->page_temps); - vsizer->Add(p->topsizer, 1, wxEXPAND | wxALL, DIALOG_MARGIN); + vsizer->Add(topsizer, 1, wxEXPAND | wxALL, DIALOG_MARGIN); vsizer->Add(hline, 0, wxEXPAND); vsizer->Add(p->btnsizer, 0, wxEXPAND | wxALL, DIALOG_MARGIN); p->set_page(p->page_welcome); + SetSizer(vsizer); SetSizerAndFit(vsizer); - SetMinSize(GetSize()); + + // We can now enable scrolling on hscroll + p->hscroll->SetScrollRate(30, 30); + // Compare current ("ideal") wizard size with the size of the current screen. + // If the screen is smaller, resize wizrad to match, which will enable scrollbars. + auto wizard_size = GetSize(); + unsigned width, height; + GUI::get_current_screen_size(width, height); + wizard_size.SetWidth(std::min(wizard_size.GetWidth(), (int)(width - 2 * DIALOG_MARGIN))); + wizard_size.SetHeight(std::min(wizard_size.GetHeight(), (int)(height - 2 * DIALOG_MARGIN))); + SetMinSize(wizard_size); + Fit(); p->btn_prev->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_prev(); }); p->btn_next->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_next(); }); diff --git a/xs/src/slic3r/GUI/ConfigWizard_private.hpp b/xs/src/slic3r/GUI/ConfigWizard_private.hpp index 474394bc3..72cb88655 100644 --- a/xs/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/xs/src/slic3r/GUI/ConfigWizard_private.hpp @@ -26,7 +26,7 @@ namespace Slic3r { namespace GUI { enum { - CONTENT_WIDTH = 500, + WRAP_WIDTH = 500, DIALOG_MARGIN = 15, INDEX_MARGIN = 40, @@ -196,7 +196,8 @@ struct ConfigWizard::priv std::unordered_map<std::string, std::string> vendors_rsrc; std::unique_ptr<DynamicPrintConfig> custom_config; - wxBoxSizer *topsizer = nullptr; + wxScrolledWindow *hscroll = nullptr; + wxBoxSizer *hscroll_sizer = nullptr; wxBoxSizer *btnsizer = nullptr; ConfigWizardPage *page_current = nullptr; ConfigWizardIndex *index = nullptr; diff --git a/xs/src/slic3r/GUI/Field.cpp b/xs/src/slic3r/GUI/Field.cpp index 64f3426c4..43c9e7db9 100644 --- a/xs/src/slic3r/GUI/Field.cpp +++ b/xs/src/slic3r/GUI/Field.cpp @@ -199,7 +199,25 @@ namespace Slic3r { namespace GUI { }), temp->GetId()); #endif // __WXGTK__ - temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent) { on_change_field(); }), temp->GetId()); + temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent) + { +#ifdef __WXGTK__ + bChangedValueEvent = true; +#else + on_change_field(); +#endif //__WXGTK__ + }), temp->GetId()); + +#ifdef __WXGTK__ + temp->Bind(wxEVT_KEY_UP, [this](wxKeyEvent& event) + { + if (bChangedValueEvent) { + on_change_field(); + bChangedValueEvent = false; + } + event.Skip(); + }); +#endif //__WXGTK__ // select all text using Ctrl+A temp->Bind(wxEVT_CHAR, ([temp](wxKeyEvent& event) diff --git a/xs/src/slic3r/GUI/Field.hpp b/xs/src/slic3r/GUI/Field.hpp index 7e421244b..948178d3e 100644 --- a/xs/src/slic3r/GUI/Field.hpp +++ b/xs/src/slic3r/GUI/Field.hpp @@ -220,6 +220,9 @@ inline bool is_sizer_field(const t_field& obj) { return !is_bad_field(obj) && ob class TextCtrl : public Field { using Field::Field; +#ifdef __WXGTK__ + bool bChangedValueEvent = false; +#endif //__WXGTK__ 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) {} diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index b00813a71..974c554b6 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -37,6 +37,7 @@ #include <wx/window.h> #include <wx/msgdlg.h> #include <wx/settings.h> +#include <wx/display.h> #include "wxExtensions.hpp" @@ -308,6 +309,8 @@ enum ConfigMenuIDs { ConfigMenuCnt, }; +static wxString dots("…", wxConvUTF8); + void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_language_change) { auto local_menu = new wxMenu(); @@ -315,12 +318,12 @@ void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_l const auto config_wizard_tooltip = wxString::Format(_(L("Run %s")), ConfigWizard::name()); // Cmd+, is standard on OS X - what about other operating systems? - local_menu->Append(config_id_base + ConfigMenuWizard, ConfigWizard::name() + "\u2026", config_wizard_tooltip); - local_menu->Append(config_id_base + ConfigMenuSnapshots, _(L("Configuration Snapshots"))+"\u2026", _(L("Inspect / activate configuration snapshots"))); + local_menu->Append(config_id_base + ConfigMenuWizard, ConfigWizard::name() + dots, config_wizard_tooltip); + local_menu->Append(config_id_base + ConfigMenuSnapshots, _(L("Configuration Snapshots"))+dots, _(L("Inspect / activate configuration snapshots"))); local_menu->Append(config_id_base + ConfigMenuTakeSnapshot, _(L("Take Configuration Snapshot")), _(L("Capture a configuration snapshot"))); // local_menu->Append(config_id_base + ConfigMenuUpdate, _(L("Check for updates")), _(L("Check for configuration updates"))); local_menu->AppendSeparator(); - local_menu->Append(config_id_base + ConfigMenuPreferences, _(L("Preferences"))+"\u2026\tCtrl+,", _(L("Application preferences"))); + local_menu->Append(config_id_base + ConfigMenuPreferences, _(L("Preferences"))+dots+"\tCtrl+,", _(L("Application preferences"))); local_menu->Append(config_id_base + ConfigMenuLanguage, _(L("Change Application Language"))); local_menu->AppendSeparator(); local_menu->Append(config_id_base + ConfigMenuFlashFirmware, _(L("Flash printer firmware")), _(L("Upload a firmware image into an Arduino based printer"))); @@ -356,8 +359,7 @@ void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_l Config::SnapshotDB::singleton().restore_snapshot(dlg.snapshot_to_activate(), *g_AppConfig).id); g_PresetBundle->load_presets(*g_AppConfig); // Load the currently selected preset into the GUI, update the preset selection box. - for (Tab *tab : g_tabs_list) - tab->load_current_preset(); + load_current_presets(); } } break; @@ -394,7 +396,7 @@ void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_l void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_language_change) { - add_config_menu(menu, event_language_change, event_language_change); + add_config_menu(menu, event_preferences_changed, event_language_change); } // This is called when closing the application, when loading a config file or when starting the config wizard @@ -443,12 +445,16 @@ void config_wizard(int reason) if (! check_unsaved_changes()) return; - ConfigWizard wizard(nullptr, static_cast<ConfigWizard::RunReason>(reason)); - wizard.run(g_PresetBundle, g_PresetUpdater); + try { + ConfigWizard wizard(nullptr, static_cast<ConfigWizard::RunReason>(reason)); + wizard.run(g_PresetBundle, g_PresetUpdater); + } + catch (const std::exception &e) { + show_error(nullptr, e.what()); + } - // Load the currently selected preset into the GUI, update the preset selection box. - for (Tab *tab : g_tabs_list) - tab->load_current_preset(); + // Load the currently selected preset into the GUI, update the preset selection box. + load_current_presets(); } void open_preferences_dialog(int event_preferences) @@ -600,6 +606,13 @@ void add_created_tab(Tab* panel) g_wxTabPanel->AddPage(panel, panel->title()); } +void load_current_presets() +{ + for (Tab *tab : g_tabs_list) { + tab->load_current_preset(); + } +} + void show_error(wxWindow* parent, const wxString& message) { ErrorDialog msg(parent, message); msg.ShowModal(); @@ -836,7 +849,7 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl Line line = { "", "" }; line.widget = [config](wxWindow* parent){ - g_wiping_dialog_button = new wxButton(parent, wxID_ANY, _(L("Purging volumes")) + "\u2026", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + g_wiping_dialog_button = new wxButton(parent, wxID_ANY, _(L("Purging volumes")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(g_wiping_dialog_button); g_wiping_dialog_button->Bind(wxEVT_BUTTON, ([parent](wxCommandEvent& e) @@ -921,6 +934,14 @@ int get_export_option(wxFileDialog* dlg) } +void get_current_screen_size(unsigned &width, unsigned &height) +{ + wxDisplay display(wxDisplay::GetFromWindow(g_wxMainFrame)); + const auto disp_size = display.GetClientArea(); + width = disp_size.GetWidth(); + height = disp_size.GetHeight(); +} + void about() { AboutDialog dlg; @@ -929,34 +950,51 @@ void about() } void desktop_open_datadir_folder() -{ +{ // Execute command to open a file explorer, platform dependent. - std::string cmd = + // FIXME: The const_casts aren't needed in wxWidgets 3.1, remove them when we upgrade. + + const auto path = data_dir(); #ifdef _WIN32 - "explorer " + const auto widepath = wxString::FromUTF8(path.data()); + const wchar_t *argv[] = { L"explorer", widepath.GetData(), nullptr }; + ::wxExecute(const_cast<wchar_t**>(argv), wxEXEC_ASYNC, nullptr); #elif __APPLE__ - "open " + const char *argv[] = { "open", path.data(), nullptr }; + ::wxExecute(const_cast<char**>(argv), wxEXEC_ASYNC, nullptr); #else - "xdg-open " -#endif - ; - // Escape the path, platform dependent. - std::string path = data_dir(); -#ifdef _WIN32 - // Enclose the path into double quotes on Windows. A quote character is forbidden in file names, - // therefore it does not need to be escaped. - cmd += '"'; - cmd += path; - cmd += '"'; -#else - // Enclose the path into single quotes on Unix / OSX. All single quote characters need to be escaped - // inside a file name. - cmd += '\''; - boost::replace_all(path, "'", "\\'"); - cmd += path; - cmd += '\''; + const char *argv[] = { "xdg-open", path.data(), nullptr }; + + // Check if we're running in an AppImage container, if so, we need to remove AppImage's env vars, + // because they may mess up the environment expected by the file manager. + // Mostly this is about LD_LIBRARY_PATH, but we remove a few more too for good measure. + if (wxGetEnv("APPIMAGE", nullptr)) { + // We're running from AppImage + wxEnvVariableHashMap env_vars; + wxGetEnvMap(&env_vars); + + env_vars.erase("APPIMAGE"); + env_vars.erase("APPDIR"); + env_vars.erase("LD_LIBRARY_PATH"); + env_vars.erase("LD_PRELOAD"); + env_vars.erase("UNION_PRELOAD"); + + wxExecuteEnv exec_env; + exec_env.env = std::move(env_vars); + + wxString owd; + if (wxGetEnv("OWD", &owd)) { + // This is the original work directory from which the AppImage image was run, + // set it as CWD for the child process: + exec_env.cwd = std::move(owd); + } + + ::wxExecute(const_cast<char**>(argv), wxEXEC_ASYNC, nullptr, &exec_env); + } else { + // Looks like we're NOT running from AppImage, we'll make no changes to the environment. + ::wxExecute(const_cast<char**>(argv), wxEXEC_ASYNC, nullptr, nullptr); + } #endif - ::wxExecute(wxString::FromUTF8(cmd.c_str()), wxEXEC_ASYNC, nullptr); } } } diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp index 4deee1910..285354446 100644 --- a/xs/src/slic3r/GUI/GUI.hpp +++ b/xs/src/slic3r/GUI/GUI.hpp @@ -5,6 +5,9 @@ #include <vector> #include "Config.hpp" +#include <wx/intl.h> +#include <wx/string.h> + class wxApp; class wxWindow; class wxFrame; @@ -30,6 +33,12 @@ class PresetUpdater; class DynamicPrintConfig; class TabIface; +#define _(s) Slic3r::translate((s)) +inline wxString translate(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)); } +inline wxString translate(const wchar_t *s) { return wxGetTranslation(s); } +inline wxString translate(const std::string &s) { return wxGetTranslation(wxString(s.c_str(), wxConvUTF8)); } +inline wxString translate(const std::wstring &s) { return wxGetTranslation(s.c_str()); } + // !!! If you needed to translate some wxString, // !!! please use _(L(string)) // !!! _() - is a standard wxWidgets macro to translate @@ -116,6 +125,9 @@ void add_created_tab(Tab* panel); // Change option value in config void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0); +// Update UI / Tabs to reflect changes in the currently loaded presets +void load_current_presets(); + void show_error(wxWindow* parent, const wxString& message); void show_error_id(int id, const std::string& message); // For Perl void show_info(wxWindow* parent, const wxString& message, const wxString& title); @@ -157,6 +169,9 @@ wxButton* get_wiping_dialog_button(); void add_export_option(wxFileDialog* dlg, const std::string& format); int get_export_option(wxFileDialog* dlg); +// Returns the dimensions of the screen on which the main frame is displayed +void get_current_screen_size(unsigned &width, unsigned &height); + // Display an About dialog extern void about(); // Ask the destop to open the datadir using the default file explorer. diff --git a/xs/src/slic3r/GUI/PresetBundle.cpp b/xs/src/slic3r/GUI/PresetBundle.cpp index 1427e5086..d36ef7b6f 100644 --- a/xs/src/slic3r/GUI/PresetBundle.cpp +++ b/xs/src/slic3r/GUI/PresetBundle.cpp @@ -101,6 +101,7 @@ PresetBundle::~PresetBundle() void PresetBundle::reset(bool delete_files) { // Clear the existing presets, delete their respective files. + this->vendors.clear(); this->prints .reset(delete_files); this->filaments.reset(delete_files); this->printers .reset(delete_files); @@ -840,17 +841,13 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla // Load the print, filament or printer preset. const DynamicPrintConfig &default_config = presets->default_preset().config; DynamicPrintConfig config(default_config); - std::vector<std::string> config_keys = config.keys(); - // The following two keys are valid, but they are not mandatory. - config_keys.emplace_back("compatible_printers"); - config_keys.emplace_back("compatible_printers_condition"); for (auto &kvp : section.second) config.set_deserialize(kvp.first, kvp.second.data()); Preset::normalize(config); // Report configuration fields, which are misplaced into a wrong group. std::string incorrect_keys; size_t n_incorrect_keys = 0; - for (const std::string &key : config_keys) + for (const std::string &key : config.keys()) if (! default_config.has(key)) { if (incorrect_keys.empty()) incorrect_keys = key; diff --git a/xs/src/slic3r/GUI/RammingChart.cpp b/xs/src/slic3r/GUI/RammingChart.cpp index 97a6b7712..2603a5eab 100644 --- a/xs/src/slic3r/GUI/RammingChart.cpp +++ b/xs/src/slic3r/GUI/RammingChart.cpp @@ -2,12 +2,7 @@ #include <wx/dcbuffer.h> #include "RammingChart.hpp" - - -//! macro used to mark string used at localization, -//! return same string -#define L(s) s - +#include "GUI.hpp" wxDEFINE_EVENT(EVT_WIPE_TOWER_CHART_CHANGED, wxCommandEvent); @@ -83,7 +78,7 @@ void Chart::draw() { int text_height = 0; dc.GetTextExtent(label,&text_width,&text_height); dc.DrawText(label,wxPoint(0.5*(m_rect.GetRight()+m_rect.GetLeft())-text_width/2.f, m_rect.GetBottom()+25)); - label = _(L("Volumetric speed")) + " (" + _(L("mm")) + "\u00B3/" + _(L("s")) + ")"; + label = _(L("Volumetric speed")) + " (" + _(L("mm")) + wxString("³/", wxConvUTF8) + _(L("s")) + ")"; dc.GetTextExtent(label,&text_width,&text_height); dc.DrawRotatedText(label,wxPoint(0,0.5*(m_rect.GetBottom()+m_rect.GetTop())+text_width/2.f),90); } diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index ab5aa2bb0..6eabc2f47 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -32,6 +32,8 @@ namespace Slic3r { namespace GUI { +static wxString dots("…", wxConvUTF8); + // sub new void Tab::create_preset_tab(PresetBundle *preset_bundle) { @@ -1261,7 +1263,7 @@ void TabFilament::build() optgroup->append_single_option_line("filament_density"); optgroup->append_single_option_line("filament_cost"); - optgroup = page->new_optgroup(_(L("Temperature ")) +" (\u00B0C)"); // degree sign + optgroup = page->new_optgroup(_(L("Temperature ")) + wxString("°C", wxConvUTF8)); Line line = { _(L("Extruder")), "" }; line.append_option(optgroup->get_option("first_layer_temperature")); line.append_option(optgroup->get_option("temperature")); @@ -1319,7 +1321,7 @@ void TabFilament::build() optgroup->append_single_option_line("filament_toolchange_delay"); line = { _(L("Ramming")), "" }; line.widget = [this](wxWindow* parent){ - auto ramming_dialog_btn = new wxButton(parent, wxID_ANY, _(L("Ramming settings"))+"\u2026", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + auto ramming_dialog_btn = new wxButton(parent, wxID_ANY, _(L("Ramming settings"))+dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(ramming_dialog_btn); @@ -1441,7 +1443,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 "))+dots, 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)); @@ -1540,7 +1542,7 @@ void TabPrinter::build() optgroup = page->new_optgroup(_(L("OctoPrint upload"))); auto octoprint_host_browse = [this, optgroup] (wxWindow* parent) { - auto btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+"\u2026", wxDefaultPosition, wxDefaultSize, wxBU_LEFT); + auto btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT); btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("zoom.png")), wxBITMAP_TYPE_PNG)); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(btn); @@ -1589,7 +1591,7 @@ void TabPrinter::build() Line cafile_line = optgroup->create_single_option_line("octoprint_cafile"); auto octoprint_cafile_browse = [this, optgroup] (wxWindow* parent) { - auto btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+"\u2026", wxDefaultPosition, wxDefaultSize, wxBU_LEFT); + auto btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT); btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("zoom.png")), wxBITMAP_TYPE_PNG)); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(btn); @@ -2054,7 +2056,15 @@ bool Tab::may_discard_current_dirty_preset(PresetCollection* presets /*= nullptr void Tab::OnTreeSelChange(wxTreeEvent& event) { if (m_disable_tree_sel_changed_event) return; + +// There is a bug related to Ubuntu overlay scrollbars, see https://github.com/prusa3d/Slic3r/issues/898 and https://github.com/prusa3d/Slic3r/issues/952. +// The issue apparently manifests when Show()ing a window with overlay scrollbars while the UI is frozen. For this reason, +// we will Thaw the UI prematurely on Linux. This means destroing the no_updates object prematurely. +#ifdef __linux__ + std::unique_ptr<wxWindowUpdateLocker> no_updates(new wxWindowUpdateLocker(this)); +#else wxWindowUpdateLocker noUpdates(this); +#endif Page* page = nullptr; auto selection = m_treectrl->GetItemText(m_treectrl->GetSelection()); @@ -2070,6 +2080,11 @@ void Tab::OnTreeSelChange(wxTreeEvent& event) for (auto& el : m_pages) el.get()->Hide(); + +#ifdef __linux__ + no_updates.reset(nullptr); +#endif + page->Show(); m_hsizer->Layout(); Refresh(); @@ -2211,7 +2226,7 @@ void Tab::update_ui_from_settings() wxSizer* Tab::compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox, wxButton** btn) { *checkbox = new wxCheckBox(parent, wxID_ANY, _(L("All"))); - *btn = new wxButton(parent, wxID_ANY, _(L(" Set "))+"\u2026", wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); + *btn = new wxButton(parent, wxID_ANY, _(L(" Set "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); (*btn)->SetBitmap(wxBitmap(from_u8(Slic3r::var("printer_empty.png")), wxBITMAP_TYPE_PNG)); diff --git a/xs/src/slic3r/GUI/WipeTowerDialog.cpp b/xs/src/slic3r/GUI/WipeTowerDialog.cpp index 4b25ccd3a..eef4017c1 100644 --- a/xs/src/slic3r/GUI/WipeTowerDialog.cpp +++ b/xs/src/slic3r/GUI/WipeTowerDialog.cpp @@ -1,15 +1,10 @@ #include <algorithm> #include <sstream> #include "WipeTowerDialog.hpp" +#include "GUI.hpp" #include <wx/sizer.h> -//! macro used to mark string used at localization, -//! return same string -#define L(s) s - - - RammingDialog::RammingDialog(wxWindow* parent,const std::string& parameters) : wxDialog(parent, wxID_ANY, _(L("Ramming customization")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/) { @@ -81,7 +76,7 @@ RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters) auto gsizer_param = new wxFlexGridSizer(2, 5, 15); gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Total ramming time")) + " (" + _(L("s")) + "):")), 0, wxALIGN_CENTER_VERTICAL); gsizer_param->Add(m_widget_time); - gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Total rammed volume")) + " (" + _(L("mm")) + "\u00B3):")), 0, wxALIGN_CENTER_VERTICAL); + gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Total rammed volume")) + " (" + _(L("mm")) + wxString("³):", wxConvUTF8))), 0, wxALIGN_CENTER_VERTICAL); gsizer_param->Add(m_widget_volume); gsizer_param->AddSpacer(20); gsizer_param->AddSpacer(20); @@ -220,7 +215,7 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, con // collect and format sizer format_sizer(m_sizer_advanced, m_page_advanced, m_gridsizer_advanced, - wxString::Format(_(L("Here you can adjust required purging volume (mm%s) for any given pair of tools.")), "\u00B3"), + _(L("Here you can adjust required purging volume (mm³) for any given pair of tools.")), _(L("Extruder changed to"))); // Hide preview page before new page creating @@ -243,7 +238,7 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, con // collect and format sizer format_sizer(m_sizer_simple, m_page_simple, gridsizer_simple, _(L("Total purging volume is calculated by summing two values below, depending on which tools are loaded/unloaded.")), - wxString::Format(_(L("Volume to purge (mm%s) when the filament is being")), "\u00B3"), 50); + _(L("Volume to purge (mm³) when the filament is being")), 50); m_sizer = new wxBoxSizer(wxVERTICAL); m_sizer->Add(m_page_simple, 0, wxEXPAND | wxALL, 25); diff --git a/xs/src/slic3r/Utils/PresetUpdater.cpp b/xs/src/slic3r/Utils/PresetUpdater.cpp index 9a4d1048f..f34fc4c19 100644 --- a/xs/src/slic3r/Utils/PresetUpdater.cpp +++ b/xs/src/slic3r/Utils/PresetUpdater.cpp @@ -116,6 +116,8 @@ struct PresetUpdater::priv void check_install_indices() const; Updates get_config_updates() const; void perform_updates(Updates &&updates, bool snapshot = true) const; + + static void copy_file(const fs::path &from, const fs::path &to); }; PresetUpdater::priv::priv(int version_online_event) : @@ -162,7 +164,7 @@ bool PresetUpdater::priv::get_file(const std::string &url, const fs::path &targe % http_status % error; }) - .on_complete([&](std::string body, unsigned http_status) { + .on_complete([&](std::string body, unsigned /* http_status */) { fs::fstream file(tmp_path, std::ios::out | std::ios::binary | std::ios::trunc); file.write(body.c_str(), body.size()); file.close(); @@ -204,7 +206,7 @@ void PresetUpdater::priv::sync_version() const % http_status % error; }) - .on_complete([&](std::string body, unsigned http_status) { + .on_complete([&](std::string body, unsigned /* http_status */) { boost::trim(body); BOOST_LOG_TRIVIAL(info) << boost::format("Got Slic3rPE online version: `%1%`. Sending to GUI thread...") % body; wxCommandEvent* evt = new wxCommandEvent(version_online_event); @@ -285,7 +287,7 @@ void PresetUpdater::priv::check_install_indices() const if (! fs::exists(path_in_cache)) { BOOST_LOG_TRIVIAL(info) << "Install index from resources: " << path.filename(); - fs::copy_file(path, path_in_cache, fs::copy_option::overwrite_if_exists); + copy_file(path, path_in_cache); } else { Index idx_rsrc, idx_cache; idx_rsrc.load(path); @@ -293,7 +295,7 @@ void PresetUpdater::priv::check_install_indices() const if (idx_cache.version() < idx_rsrc.version()) { BOOST_LOG_TRIVIAL(info) << "Update index from resources: " << path.filename(); - fs::copy_file(path, path_in_cache, fs::copy_option::overwrite_if_exists); + copy_file(path, path_in_cache); } } } @@ -397,7 +399,7 @@ void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons for (const auto &update : updates.updates) { BOOST_LOG_TRIVIAL(info) << '\t' << update; - fs::copy_file(update.source, update.target, fs::copy_option::overwrite_if_exists); + copy_file(update.source, update.target); PresetBundle bundle; bundle.load_configbundle(update.target.string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); @@ -433,6 +435,18 @@ void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons } } +void PresetUpdater::priv::copy_file(const fs::path &source, const fs::path &target) +{ + static const auto perms = fs::owner_read | fs::owner_write | fs::group_read | fs::others_read; // aka 644 + + // Make sure the file has correct permission both before and after we copy over it + if (fs::exists(target)) { + fs::permissions(target, perms); + } + fs::copy_file(source, target, fs::copy_option::overwrite_if_exists); + fs::permissions(target, perms); +} + PresetUpdater::PresetUpdater(int version_online_event) : p(new priv(version_online_event)) @@ -553,6 +567,12 @@ bool PresetUpdater::config_update() const if (res == wxID_OK) { BOOST_LOG_TRIVIAL(debug) << "User agreed to perform the update"; p->perform_updates(std::move(updates)); + + // Reload global configuration + auto *app_config = GUI::get_app_config(); + app_config->reset_selections(); + GUI::get_preset_bundle()->load_presets(*app_config); + GUI::load_current_presets(); } else { BOOST_LOG_TRIVIAL(info) << "User refused the update"; } diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp index 1d860d284..af0612f19 100644 --- a/xs/xsp/GUI.xsp +++ b/xs/xsp/GUI.xsp @@ -70,11 +70,7 @@ bool check_unsaved_changes() bool config_wizard_startup(int app_config_exists) %code%{ - try { - RETVAL=Slic3r::GUI::config_wizard_startup(app_config_exists != 0); - } catch (std::exception& e) { - croak("%s\n", e.what()); - } + RETVAL=Slic3r::GUI::config_wizard_startup(app_config_exists != 0); %}; void open_preferences_dialog(int preferences_event) |