Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_wipe_moves

This commit is contained in:
enricoturri1966 2020-11-23 10:11:04 +01:00
commit f68cf49f3d
29 changed files with 5731 additions and 4062 deletions

View file

@ -84,10 +84,14 @@ public:
template<typename VISITOR> void visit_cells_intersecting_line(Slic3r::Point p1, Slic3r::Point p2, VISITOR &visitor) const
{
// End points of the line segment.
p1(0) -= m_bbox.min(0);
p1(1) -= m_bbox.min(1);
p2(0) -= m_bbox.min(0);
p2(1) -= m_bbox.min(1);
assert(m_bbox.contains(p1));
assert(m_bbox.contains(p2));
p1 -= m_bbox.min;
p2 -= m_bbox.min;
assert(p1.x() >= 0 && p1.x() < m_cols * m_resolution);
assert(p1.y() >= 0 && p1.y() < m_rows * m_resolution);
assert(p2.x() >= 0 && p2.x() < m_cols * m_resolution);
assert(p2.y() >= 0 && p2.y() < m_rows * m_resolution);
// Get the cells of the end points.
coord_t ix = p1(0) / m_resolution;
coord_t iy = p1(1) / m_resolution;
@ -115,18 +119,22 @@ public:
ey -= ex;
ex = int64_t(dy) * m_resolution;
ix += 1;
assert(ix <= ixb);
}
else if (ex == ey) {
ex = int64_t(dy) * m_resolution;
ey = int64_t(dx) * m_resolution;
ix += 1;
iy += 1;
assert(ix <= ixb);
assert(iy <= iyb);
}
else {
assert(ex > ey);
ex -= ey;
ey = int64_t(dx) * m_resolution;
iy += 1;
assert(iy <= iyb);
}
if (! visitor(iy, ix))
return;
@ -141,11 +149,13 @@ public:
ey -= ex;
ex = int64_t(dy) * m_resolution;
ix += 1;
assert(ix <= ixb);
}
else {
ex -= ey;
ey = int64_t(dx) * m_resolution;
iy -= 1;
assert(iy >= iyb);
}
if (! visitor(iy, ix))
return;
@ -163,12 +173,14 @@ public:
ey -= ex;
ex = int64_t(dy) * m_resolution;
ix -= 1;
assert(ix >= ixb);
}
else {
assert(ex >= ey);
ex -= ey;
ey = int64_t(dx) * m_resolution;
iy += 1;
assert(iy <= iyb);
}
if (! visitor(iy, ix))
return;
@ -183,6 +195,7 @@ public:
ey -= ex;
ex = int64_t(dy) * m_resolution;
ix -= 1;
assert(ix >= ixb);
}
else if (ex == ey) {
// The lower edge of a grid cell belongs to the cell.
@ -191,10 +204,12 @@ public:
if (dx > 0) {
ex = int64_t(dy) * m_resolution;
ix -= 1;
assert(ix >= ixb);
}
if (dy > 0) {
ey = int64_t(dx) * m_resolution;
iy -= 1;
assert(iy >= iyb);
}
}
else {
@ -202,6 +217,7 @@ public:
ex -= ey;
ey = int64_t(dx) * m_resolution;
iy -= 1;
assert(iy >= iyb);
}
if (! visitor(iy, ix))
return;

View file

@ -1,4 +1,5 @@
#include <stdio.h>
#include <numeric>
#include "../ClipperUtils.hpp"
#include "../EdgeGrid.hpp"
@ -28,6 +29,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
case ip3DHoneycomb: return new Fill3DHoneycomb();
case ipGyroid: return new FillGyroid();
case ipRectilinear: return new FillRectilinear();
case ipAlignedRectilinear: return new FillAlignedRectilinear();
case ipMonotonic: return new FillMonotonic();
case ipLine: return new FillLine();
case ipGrid: return new FillGrid();
@ -840,7 +842,7 @@ void mark_boundary_segments_touching_infill(
EdgeGrid::Grid grid;
// Make sure that the the grid is big enough for queries against the thick segment.
grid.set_bbox(boundary_bbox.inflated(distance_colliding + SCALED_EPSILON));
grid.set_bbox(boundary_bbox.inflated(distance_colliding * 1.43));
// Inflate the bounding box by a thick line width.
grid.create(boundary, std::max(clip_distance, distance_colliding) + scale_(10.));
@ -960,9 +962,6 @@ void mark_boundary_segments_touching_infill(
#endif // INFILL_DEBUG_OUTPUT
} visitor(grid, boundary, boundary_parameters, boundary_intersections, distance_colliding);
BoundingBoxf bboxf(boundary_bbox.min.cast<double>(), boundary_bbox.max.cast<double>());
bboxf.offset(- SCALED_EPSILON);
for (const Polyline &polyline : infill) {
#ifdef INFILL_DEBUG_OUTPUT
++ iStep;
@ -1018,12 +1017,14 @@ void mark_boundary_segments_touching_infill(
Vec2d vperp = perp(v);
Vec2d a = pt1 - v - vperp;
Vec2d b = pt2 + v - vperp;
if (Geometry::liang_barsky_line_clipping(a, b, bboxf))
grid.visit_cells_intersecting_line(a.cast<coord_t>(), b.cast<coord_t>(), visitor);
assert(grid.bbox().contains(a.cast<coord_t>()));
assert(grid.bbox().contains(b.cast<coord_t>()));
grid.visit_cells_intersecting_line(a.cast<coord_t>(), b.cast<coord_t>(), visitor);
a = pt1 - v + vperp;
b = pt2 + v + vperp;
if (Geometry::liang_barsky_line_clipping(a, b, bboxf))
grid.visit_cells_intersecting_line(a.cast<coord_t>(), b.cast<coord_t>(), visitor);
assert(grid.bbox().contains(a.cast<coord_t>()));
assert(grid.bbox().contains(b.cast<coord_t>()));
grid.visit_cells_intersecting_line(a.cast<coord_t>(), b.cast<coord_t>(), visitor);
#endif
#ifdef INFILL_DEBUG_OUTPUT
// export_infill_to_svg(boundary, boundary_parameters, boundary_intersections, infill, distance_colliding * 2, debug_out_path("%s-%03d-%03d-%03d.svg", "FillBase-mark_boundary_segments_touching_infill-step", iRun, iStep, int(point_idx)), { polyline });

View file

@ -29,6 +29,17 @@ protected:
bool fill_surface_by_multilines(const Surface *surface, FillParams params, const std::initializer_list<SweepParams> &sweep_params, Polylines &polylines_out);
};
class FillAlignedRectilinear : public FillRectilinear
{
public:
Fill* clone() const override { return new FillAlignedRectilinear(*this); };
~FillAlignedRectilinear() override = default;
protected:
// Always generate infill at the same angle.
virtual float _layer_angle(size_t idx) const { return 0.f; }
};
class FillMonotonic : public FillRectilinear
{
public:

View file

@ -399,13 +399,11 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
};
// check for temporary lines
auto is_temporary_decoration = [](const std::string& gcode_line) {
auto is_temporary_decoration = [](const std::string_view gcode_line) {
// remove trailing '\n'
std::string line = gcode_line.substr(0, gcode_line.length() - 1);
if (line == ";" + Layer_Change_Tag)
return true;
else
return false;
assert(! gcode_line.empty());
assert(gcode_line.back() == '\n');
return gcode_line.substr(0, gcode_line.length() - 1) == ";" + Layer_Change_Tag;
};
// Iterators for the normal and silent cached time estimate entry recently processed, used by process_line_G1.

View file

@ -2,6 +2,7 @@
#include "Line.hpp"
#include "MultiPoint.hpp"
#include "Int128.hpp"
#include "BoundingBox.hpp"
#include <algorithm>
namespace Slic3r {

View file

@ -439,7 +439,7 @@ const std::vector<std::string>& Preset::filament_options()
{
static std::vector<std::string> s_opts {
"filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed",
"extrusion_multiplier", "filament_density", "filament_cost", "filament_loading_speed", "filament_loading_speed_start", "filament_load_time",
"extrusion_multiplier", "filament_density", "filament_cost", "filament_spool_weight", "filament_loading_speed", "filament_loading_speed_start", "filament_load_time",
"filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves",
"filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_minimal_purge_on_wipe_tower",
"temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed",

View file

@ -98,6 +98,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
"filament_density",
"filament_notes",
"filament_cost",
"filament_spool_weight",
"first_layer_acceleration",
"first_layer_bed_temperature",
"first_layer_speed",

View file

@ -460,12 +460,14 @@ void PrintConfigDef::init_fff_params()
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
def->enum_values.push_back("rectilinear");
def->enum_values.push_back("monotonic");
def->enum_values.push_back("alignedrectilinear");
def->enum_values.push_back("concentric");
def->enum_values.push_back("hilbertcurve");
def->enum_values.push_back("archimedeanchords");
def->enum_values.push_back("octagramspiral");
def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Monotonic"));
def->enum_labels.push_back(L("Aligned Rectilinear"));
def->enum_labels.push_back(L("Concentric"));
def->enum_labels.push_back(L("Hilbert Curve"));
def->enum_labels.push_back(L("Archimedean Chords"));
@ -483,7 +485,7 @@ void PrintConfigDef::init_fff_params()
def->enum_values = def_top_fill_pattern->enum_values;
def->enum_labels = def_top_fill_pattern->enum_labels;
def->aliases = def_top_fill_pattern->aliases;
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipRectilinear));
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipMonotonic));
def = this->add("external_perimeter_extrusion_width", coFloatOrPercent);
def->label = L("External perimeters");
@ -806,6 +808,16 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->set_default_value(new ConfigOptionFloats { 0. });
def = this->add("filament_spool_weight", coFloats);
def->label = L("Spool weight");
def->tooltip = L("Enter weight of the empty filament spool. "
"One may weigh a partially consumed filament spool before printing and one may compare the measured weight "
"with the calculated weight of the filament with the spool to find out whether the amount "
"of filament on the spool is sufficient to finish the print.");
def->sidetext = L("g");
def->min = 0;
def->set_default_value(new ConfigOptionFloats { 0. });
def = this->add("filament_settings_id", coStrings);
def->set_default_value(new ConfigOptionStrings { "" });
def->cli = ConfigOptionDef::nocli;
@ -871,6 +883,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("Fill pattern for general low-density infill.");
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
def->enum_values.push_back("rectilinear");
def->enum_values.push_back("alignedrectilinear");
def->enum_values.push_back("grid");
def->enum_values.push_back("triangles");
def->enum_values.push_back("stars");
@ -886,6 +899,7 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("adaptivecubic");
def->enum_values.push_back("supportcubic");
def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Aligned Rectilinear"));
def->enum_labels.push_back(L("Grid"));
def->enum_labels.push_back(L("Triangles"));
def->enum_labels.push_back(L("Stars"));
@ -1541,8 +1555,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("perimeter_acceleration", coFloat);
def->label = L("Perimeters");
def->tooltip = L("This is the acceleration your printer will use for perimeters. "
"A high value like 9000 usually gives good results if your hardware is up to the job. "
"Set zero to disable acceleration control for perimeters.");
"Set zero to disable acceleration control for perimeters.");
def->sidetext = L("mm/s²");
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0));

View file

@ -44,7 +44,7 @@ enum AuthorizationType {
};
enum InfillPattern : int {
ipRectilinear, ipMonotonic, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
ipRectilinear, ipMonotonic, ipAlignedRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipAdaptiveCubic, ipSupportCubic, ipCount,
};
@ -145,6 +145,7 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<InfillPattern>::g
if (keys_map.empty()) {
keys_map["rectilinear"] = ipRectilinear;
keys_map["monotonic"] = ipMonotonic;
keys_map["alignedrectilinear"] = ipAlignedRectilinear;
keys_map["grid"] = ipGrid;
keys_map["triangles"] = ipTriangles;
keys_map["stars"] = ipStars;
@ -683,6 +684,7 @@ public:
ConfigOptionStrings filament_type;
ConfigOptionBools filament_soluble;
ConfigOptionFloats filament_cost;
ConfigOptionFloats filament_spool_weight;
ConfigOptionFloats filament_max_volumetric_speed;
ConfigOptionFloats filament_loading_speed;
ConfigOptionFloats filament_loading_speed_start;
@ -759,6 +761,7 @@ protected:
OPT_PTR(filament_type);
OPT_PTR(filament_soluble);
OPT_PTR(filament_cost);
OPT_PTR(filament_spool_weight);
OPT_PTR(filament_max_volumetric_speed);
OPT_PTR(filament_loading_speed);
OPT_PTR(filament_loading_speed_start);

View file

@ -1,11 +1,6 @@
#include "libslic3r/libslic3r.h"
#if ENABLE_GCODE_VIEWER
#include "DoubleSlider.hpp"
#include "libslic3r/GCode.hpp"
#else
#include "wxExtensions.hpp"
#include "libslic3r/GCode/PreviewData.hpp"
#endif // ENABLE_GCODE_VIEWER
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "Plater.hpp"
@ -137,14 +132,13 @@ Control::Control( wxWindow *parent,
m_line_pens = { &DARK_GREY_PEN, &GREY_PEN, &LIGHT_GREY_PEN };
m_segm_pens = { &DARK_ORANGE_PEN, &ORANGE_PEN, &LIGHT_ORANGE_PEN };
const wxFont& font = GetFont();
m_font = is_osx ? font.Smaller().Smaller() : font.Smaller();
m_font = GetFont();
this->SetMinSize(get_min_size());
}
void Control::msw_rescale()
{
const wxFont& font = GUI::wxGetApp().normal_font();
m_font = is_osx ? font.Smaller().Smaller() : font.Smaller();
m_font = GUI::wxGetApp().normal_font();
m_bmp_thumb_higher.msw_rescale();
m_bmp_thumb_lower .msw_rescale();
@ -182,8 +176,7 @@ int Control::GetActiveValue() const
wxSize Control::get_min_size() const
{
const int min_side = GUI::wxGetApp().em_unit() * ( is_horizontal() ? (is_osx ? 8 : 6) : 10 );
const int min_side = GUI::wxGetApp().em_unit() * ( is_horizontal() ? 5 : 11 );
return wxSize(min_side, min_side);
}
@ -713,7 +706,7 @@ void Control::draw_tick_text(wxDC& dc, const wxPoint& pos, int tick, LabelType l
text_pos = wxPoint(xx, pos.y - m_thumb_size.x / 2 - text_height - 1);
}
else
text_pos = wxPoint(pos.x - text_width - 1 - m_thumb_size.x, pos.y - 0.5 * text_height + 1);
text_pos = wxPoint(std::max(2, pos.x - text_width - 1 - m_thumb_size.x), pos.y - 0.5 * text_height + 1);
}
if (label_type == ltEstimatedTime)

View file

@ -2743,7 +2743,9 @@ void GCodeViewer::render_legend() const
}
if (!m_settings_ids.filament.empty()) {
for (unsigned char i : m_extruder_ids) {
imgui.text(_u8L("Filament") + " " + std::to_string(i + 1) + ":");
std::string txt = _u8L("Filament");
txt += (m_extruder_ids.size() == 1) ? ":" : " " + std::to_string(i + 1);
imgui.text(txt);
ImGui::SameLine(offset);
imgui.text(m_settings_ids.filament[i]);
}

View file

@ -1091,7 +1091,7 @@ wxDEFINE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent);
const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25;
GLCanvas3D::ArrangeSettings load_arrange_settings()
static GLCanvas3D::ArrangeSettings load_arrange_settings()
{
GLCanvas3D::ArrangeSettings settings;
@ -2392,7 +2392,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
return;
}
if (keyCode == WXK_ESCAPE && (_deactivate_undo_redo_toolbar_items() || _deactivate_search_toolbar_item()))
if (keyCode == WXK_ESCAPE && (_deactivate_undo_redo_toolbar_items() || _deactivate_search_toolbar_item() || _deactivate_arrange_menu()))
return;
if (m_gizmos.on_char(evt))
@ -3083,7 +3083,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_dirty = true;
}
else if (evt.LeftDown() || evt.RightDown() || evt.MiddleDown()) {
if (_deactivate_undo_redo_toolbar_items() || _deactivate_search_toolbar_item())
if (_deactivate_undo_redo_toolbar_items() || _deactivate_search_toolbar_item() || _deactivate_arrange_menu())
return;
// If user pressed left or right button we first check whether this happened
@ -3868,11 +3868,12 @@ bool GLCanvas3D::_render_search_list(float pos_x) const
return action_taken;
}
void GLCanvas3D:: _render_arrange_popup()
bool GLCanvas3D::_render_arrange_menu(float pos_x)
{
ImGuiWrapper *imgui = wxGetApp().imgui();
float x = 0.5f * (float)get_canvas_size().get_width();
auto canvas_w = float(get_canvas_size().get_width());
const float x = pos_x * float(wxGetApp().plater()->get_camera().get_zoom()) + 0.5f * canvas_w;
imgui->set_next_window_pos(x, m_main_toolbar.get_height(), ImGuiCond_Always, 0.5f, 0.0f);
imgui->begin(_(L("Arrange options")), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
@ -3880,17 +3881,39 @@ void GLCanvas3D:: _render_arrange_popup()
auto &appcfg = wxGetApp().app_config;
bool settings_changed = false;
if (imgui->slider_float(_(L("Gap size")), &settings.distance, 0.f, 100.f)) {
m_arrange_settings.distance = settings.distance;
appcfg->set("arrange", "min_object_distance", std::to_string(settings.distance));
settings_changed = true;
}
if (imgui->checkbox(_(L("Enable rotations")), settings.enable_rotation)) {
m_arrange_settings.enable_rotation = settings.enable_rotation;
appcfg->set("arrange", "enable_rotation", "1");
settings_changed = true;
}
ImGui::Separator();
if (imgui->button(_(L("Reset")))) {
m_arrange_settings = ArrangeSettings{};
settings_changed = true;
}
if (settings_changed) {
appcfg->set("arrange", "min_object_distance", std::to_string(m_arrange_settings.distance));
appcfg->set("arrange", "enable_rotation", m_arrange_settings.enable_rotation? "1" : "0");
}
ImGui::SameLine();
if (imgui->button(_(L("Arrange")))) {
wxGetApp().plater()->arrange();
}
imgui->end();
return settings_changed;
}
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT 0
@ -4305,7 +4328,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.name = "arrange";
item.icon_filename = "arrange.svg";
item.tooltip = _utf8(L("Arrange")) + " [A]\n" + _utf8(L("Arrange selection")) + " [Shift+A]";
item.tooltip = _utf8(L("Arrange")) + " [A]\n" + _utf8(L("Arrange selection")) + " [Shift+A]\n" + _utf8(L("Click right mouse button to show arrangement options"));
item.sprite_id = 3;
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ARRANGE)); };
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_arrange(); };
@ -4313,7 +4336,7 @@ bool GLCanvas3D::_init_main_toolbar()
item.right.render_callback = [this](float left, float right, float, float) {
if (m_canvas != nullptr)
{
_render_arrange_popup();
_render_arrange_menu(0.5f * (left + right));
}
};
if (!m_main_toolbar.add_item(item))
@ -6246,6 +6269,16 @@ bool GLCanvas3D::is_search_pressed() const
return m_main_toolbar.is_item_pressed("search");
}
bool GLCanvas3D::_deactivate_arrange_menu()
{
if (m_main_toolbar.is_item_pressed("arrange")) {
m_main_toolbar.force_right_action(m_main_toolbar.get_item_id("arrange"), *this);
return true;
}
return false;
}
bool GLCanvas3D::_deactivate_search_toolbar_item()
{
if (is_search_pressed())

View file

@ -728,7 +728,7 @@ private:
void _render_selection_sidebar_hints() const;
bool _render_undo_redo_stack(const bool is_undo, float pos_x) const;
bool _render_search_list(float pos_x) const;
void _render_arrange_popup();
bool _render_arrange_menu(float pos_x);
void _render_thumbnail_internal(ThumbnailData& thumbnail_data, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) const;
// render thumbnail using an off-screen framebuffer
void _render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) const;
@ -780,6 +780,7 @@ private:
bool _deactivate_search_toolbar_item();
bool _activate_search_toolbar_item();
bool _deactivate_collapse_toolbar_items();
bool _deactivate_arrange_menu();
float get_overlay_window_width() { return LayersEditing::get_overlay_window_width(); }

View file

@ -283,7 +283,7 @@ bool Preview::init(wxWindow* parent, Model* model)
wxBoxSizer* right_sizer = new wxBoxSizer(wxVERTICAL);
right_sizer->Add(m_layers_slider_sizer, 1, wxEXPAND, 0);
m_moves_slider = new DoubleSlider::Control(m_bottom_toolbar_panel, wxID_ANY, 0, 0, 0, 100, wxDefaultPosition, wxSize(-1, 3 * GetTextExtent("m").y), wxSL_HORIZONTAL);
m_moves_slider = new DoubleSlider::Control(m_bottom_toolbar_panel, wxID_ANY, 0, 0, 0, 100, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL);
m_moves_slider->SetDrawMode(DoubleSlider::dmSequentialGCodeView);
wxBoxSizer* bottom_toolbar_sizer = new wxBoxSizer(wxHORIZONTAL);
@ -692,7 +692,7 @@ void Preview::update_layers_slider(const std::vector<double>& layers_z, bool kee
if (sla_print_technology)
m_layers_slider->SetLayersTimes(plater->sla_print().print_statistics().layers_times);
else
m_layers_slider->SetLayersTimes(m_gcode_result->time_statistics.modes[0].layers_times);
m_layers_slider->SetLayersTimes(m_gcode_result->time_statistics.modes.front().layers_times);
m_layers_slider_sizer->Show((size_t)0);
Layout();

View file

@ -259,16 +259,15 @@ bool instance_check(int argc, char** argv, bool app_config_single_instance)
std::hash<std::string>{}(boost::filesystem::system_complete(argv[0]).string());
#else
std::hash<std::string>{}(boost::filesystem::canonical(boost::filesystem::system_complete(argv[0]), ec).string());
if(ec.value() > 0) { // canonical was not able to find execitable (can happen with appimage on some systems)
ec.clear();
// Compose path with boost canonical of folder and filename
hashed_path = std::hash<std::string>{}(boost::filesystem::canonical(boost::filesystem::system_complete(argv[0]).parent_path(), ec).string() + "/" + boost::filesystem::system_complete(argv[0]).filename().string());
if(ec.value() > 0) {
// Still not valid, process without canonical
hashed_path = std::hash<std::string>{}(boost::filesystem::system_complete(argv[0]).string());
}
if (ec.value() > 0) { // canonical was not able to find the executable (can happen with appimage on some systems. Does it fail on Fuse file systems?)
ec.clear();
// Compose path with boost canonical of folder and filename
hashed_path = std::hash<std::string>{}(boost::filesystem::canonical(boost::filesystem::system_complete(argv[0]).parent_path(), ec).string() + "/" + boost::filesystem::system_complete(argv[0]).filename().string());
if (ec.value() > 0) {
// Still not valid, process without canonical
hashed_path = std::hash<std::string>{}(boost::filesystem::system_complete(argv[0]).string());
}
}
#endif // win32
std::string lock_name = std::to_string(hashed_path);

View file

@ -8,6 +8,7 @@
#include <boost/algorithm/string/split.hpp>
#include "libslic3r/Utils.hpp"
#include "I18N.hpp"
#include "format.hpp"
namespace Slic3r { namespace GUI {
@ -174,7 +175,15 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/)
label += ":";
wxCoord label_w, label_h;
#ifdef __WXMSW__
// when we use 2 monitors with different DPIs, GetTextExtent() return value for the primary display
// so, use dc.GetMultiLineTextExtent on Windows
wxPaintDC dc(this);
dc.SetFont(m_font);
dc.GetMultiLineTextExtent(label, &label_w, &label_h);
#else
GetTextExtent(label, &label_w, &label_h, 0, 0, &m_font);
#endif //__WXMSW__
h_pos += label_w + 1 + m_h_gap;
}
h_pos += (opt.opt.gui_type == "legend" ? 1 : 3) * blinking_button_width;
@ -231,10 +240,14 @@ void OG_CustomCtrl::OnMotion(wxMouseEvent& event)
wxString language = wxGetApp().app_config->get("translation_language");
bool suppress_hyperlinks = get_app_config()->get("suppress_hyperlinks") == "1";
for (CtrlLine& line : ctrl_lines) {
line.is_focused = is_point_in_rect(pos, line.rect_label);
if (line.is_focused) {
tooltip = get_url(line.og_line.label_path);
if (!suppress_hyperlinks && !line.og_line.label_path.empty())
tooltip = get_url(line.og_line.label_path) +"\n\n";
tooltip += line.og_line.label_tooltip;
break;
}
@ -464,6 +477,7 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos)
{
Field* field = ctrl->opt_group->get_field(og_line.get_options().front().opt_id);
bool suppress_hyperlinks = get_app_config()->get("suppress_hyperlinks") == "1";
if (draw_just_act_buttons) {
if (field)
draw_act_bmps(dc, wxPoint(0, v_pos), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp(), field->blink());
@ -481,7 +495,7 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos)
bool is_url_string = false;
if (ctrl->opt_group->label_width != 0 && !label.IsEmpty()) {
const wxColour* text_clr = (option_set.size() == 1 && field ? field->label_color() : og_line.full_Label_color);
is_url_string = !og_line.label_path.IsEmpty();
is_url_string = !suppress_hyperlinks && !og_line.label_path.IsEmpty();
h_pos = draw_text(dc, wxPoint(h_pos, v_pos), label + ":", text_clr, ctrl->opt_group->label_width * ctrl->m_em_unit, is_url_string);
}
@ -521,7 +535,7 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos)
if (is_url_string)
is_url_string = false;
else if(opt == option_set.front())
is_url_string = !og_line.label_path.IsEmpty();
is_url_string = !suppress_hyperlinks && !og_line.label_path.IsEmpty();
h_pos = draw_text(dc, wxPoint(h_pos, v_pos), label, field ? field->label_color() : nullptr, ctrl->opt_group->sublabel_width * ctrl->m_em_unit, is_url_string);
}
@ -598,7 +612,7 @@ wxCoord OG_CustomCtrl::CtrlLine::draw_text(wxDC& dc, wxPoint pos, const wxStr
dc.GetMultiLineTextExtent(out_text, &text_width, &text_height);
pos.y = pos.y + lround((height - text_height) / 2);
if (width > 0 && is_url)
if (width > 0)
rect_label = wxRect(pos, wxSize(text_width, text_height));
wxColour old_clr = dc.GetTextForeground();
@ -660,7 +674,19 @@ wxCoord OG_CustomCtrl::CtrlLine::draw_act_bmps(wxDC& dc, wxPoint pos, const wxBi
bool OG_CustomCtrl::CtrlLine::launch_browser() const
{
return is_focused && !og_line.label_path.IsEmpty() && wxLaunchDefaultBrowser(get_url(og_line.label_path));
if (get_app_config()->get("suppress_hyperlinks").empty()) {
wxString preferences_item = _L("Suppress to open hyperlink in browser");
wxString msg =
_L("PrusaSlicer will remember your action.") + "\n" +
_L("You will not be asked about it again on label hovering.") + "\n\n" +
format_wxstr(_L("Visit \"Preferences\" and check \"%1%\"\nto changes your choise."), preferences_item) + "\n\n" +
_L("Should we suppress to use hyperlinks in PrusaSlicer?");
wxMessageDialog dialog(nullptr, msg, _L("PrusaSlicer: Don't ask me again"), wxYES | wxNO | wxICON_INFORMATION);
get_app_config()->set("suppress_hyperlinks", dialog.ShowModal() == wxID_YES ? "1" : "0");
}
return get_app_config()->get("suppress_hyperlinks") == "0" && is_focused && !og_line.label_path.IsEmpty() && wxLaunchDefaultBrowser(get_url(og_line.label_path));
}

View file

@ -1156,7 +1156,43 @@ void Sidebar::update_sliced_info_sizer()
new_label = imperial_units ? _L("Used Filament (in³)") : _L("Used Filament (mm³)");
info_text = wxString::Format("%.2f", imperial_units ? ps.total_extruded_volume * koef : ps.total_extruded_volume);
p->sliced_info->SetTextAndShow(siFilament_mm3, info_text, new_label);
p->sliced_info->SetTextAndShow(siFilament_g, ps.total_weight == 0.0 ? "N/A" : wxString::Format("%.2f", ps.total_weight));
if (ps.total_weight == 0.0)
p->sliced_info->SetTextAndShow(siFilament_g, "N/A");
else {
new_label = _L("Used Filament (g)");
info_text = wxString::Format("%.2f", ps.total_weight);
const std::vector<std::string>& filament_presets = wxGetApp().preset_bundle->filament_presets;
const PresetCollection& filaments = wxGetApp().preset_bundle->filaments;
if (ps.filament_stats.size() > 1)
new_label += ":";
for (auto filament : ps.filament_stats) {
const Preset* filament_preset = filaments.find_preset(filament_presets[filament.first], false);
if (filament_preset) {
double filament_weight;
if (ps.filament_stats.size() == 1)
filament_weight = ps.total_weight;
else {
double filament_density = filament_preset->config.opt_float("filament_density", 0);
filament_weight = filament.second * filament_density * 2.4052f * 0.001; // assumes 1.75mm filament diameter;
new_label += "\n - " + format_wxstr(_L("Filament at extruder %1%"), filament.first + 1);
info_text += wxString::Format("\n%.2f", filament_weight);
}
double spool_weight = filament_preset->config.opt_float("filament_spool_weight", 0);
if (spool_weight != 0.0) {
new_label += "\n " + _L("(weight with spool)");
info_text += wxString::Format(" (%.2f)\n", filament_weight + spool_weight);
}
}
}
p->sliced_info->SetTextAndShow(siFilament_g, info_text, new_label);
}
new_label = _L("Cost");
if (is_wipe_tower)

View file

@ -235,6 +235,14 @@ void PreferencesDialog::build()
option = Option(def, "seq_top_layer_only");
m_optgroup_gui->append_single_option_line(option);
def.label = L("Suppress to open hyperlink in browser");
def.type = coBool;
def.tooltip = L("If enabled, the descriptions of configuration parameters in settings tabs woldn't work as hyperlinks. "
"If disabled, the descriptions of configuration parameters in settings tabs will work as hyperlinks.");
def.set_default_value(new ConfigOptionBool{ app_config->get("suppress_hyperlinks") == "1" });
option = Option(def, "suppress_hyperlinks");
m_optgroup_gui->append_single_option_line(option);
m_optgroup_gui->activate();
if (is_editor) {

View file

@ -1785,6 +1785,19 @@ void TabFilament::build()
optgroup->append_single_option_line("extrusion_multiplier");
optgroup->append_single_option_line("filament_density");
optgroup->append_single_option_line("filament_cost");
optgroup->append_single_option_line("filament_spool_weight");
optgroup->m_on_change = [this, optgroup](t_config_option_key opt_key, boost::any value)
{
update_dirty();
if (opt_key == "filament_spool_weight") {
// Change of this option influences for an update of "Sliced Info"
wxGetApp().sidebar().update_sliced_info_sizer();
wxGetApp().sidebar().Layout();
}
else
on_value_change(opt_key, value);
};
// optgroup = page->new_optgroup(_(L("Temperature")) + wxString(" °C", wxConvUTF8));
optgroup = page->new_optgroup(L("Temperature"));