Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/xs
diff options
context:
space:
mode:
Diffstat (limited to 'xs')
-rw-r--r--xs/CMakeLists.txt2
-rw-r--r--xs/src/avrdude/main.c2
-rw-r--r--xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp69
-rw-r--r--xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp2
-rw-r--r--xs/src/libslic3r/GCodeSender.cpp34
-rw-r--r--xs/src/libslic3r/GCodeSender.hpp2
-rw-r--r--xs/src/libslic3r/PerimeterGenerator.cpp2
-rw-r--r--xs/src/libslic3r/PrintConfig.cpp2
-rw-r--r--xs/src/libslic3r/libslic3r.h2
-rw-r--r--xs/src/slic3r/GUI/ConfigWizard.cpp64
-rw-r--r--xs/src/slic3r/GUI/ConfigWizard_private.hpp5
-rw-r--r--xs/src/slic3r/GUI/Field.cpp20
-rw-r--r--xs/src/slic3r/GUI/Field.hpp3
-rw-r--r--xs/src/slic3r/GUI/GUI.cpp108
-rw-r--r--xs/src/slic3r/GUI/GUI.hpp15
-rw-r--r--xs/src/slic3r/GUI/PresetBundle.cpp7
-rw-r--r--xs/src/slic3r/GUI/RammingChart.cpp9
-rw-r--r--xs/src/slic3r/GUI/Tab.cpp27
-rw-r--r--xs/src/slic3r/GUI/WipeTowerDialog.cpp13
-rw-r--r--xs/src/slic3r/Utils/PresetUpdater.cpp30
-rw-r--r--xs/xsp/GUI.xsp6
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)