diff options
-rw-r--r-- | resources/ui_layout/print.ui | 43 | ||||
-rw-r--r-- | resources/ui_layout/sla_material.ui | 6 | ||||
-rw-r--r-- | src/libslic3r/Config.hpp | 5 | ||||
-rw-r--r-- | src/libslic3r/Flow.cpp | 2 | ||||
-rw-r--r-- | src/libslic3r/GCode.cpp | 3 | ||||
-rw-r--r-- | src/libslic3r/PerimeterGenerator.cpp | 103 | ||||
-rw-r--r-- | src/libslic3r/PerimeterGenerator.hpp | 8 | ||||
-rw-r--r-- | src/libslic3r/Preset.cpp | 12 | ||||
-rw-r--r-- | src/libslic3r/Print.cpp | 1 | ||||
-rw-r--r-- | src/libslic3r/PrintConfig.cpp | 34 | ||||
-rw-r--r-- | src/libslic3r/PrintConfig.hpp | 4 | ||||
-rw-r--r-- | src/libslic3r/PrintObject.cpp | 1 | ||||
-rw-r--r-- | src/libslic3r/Thread.cpp | 4 | ||||
-rw-r--r-- | src/slic3r/GUI/ConfigManipulation.cpp | 3 | ||||
-rw-r--r-- | src/slic3r/GUI/Field.cpp | 117 | ||||
-rw-r--r-- | src/slic3r/GUI/Field.hpp | 4 | ||||
-rw-r--r-- | src/slic3r/GUI/GUI.cpp | 5 | ||||
-rw-r--r-- | src/slic3r/GUI/NotificationManager.cpp | 2 | ||||
-rw-r--r-- | src/slic3r/GUI/OG_CustomCtrl.cpp | 98 | ||||
-rw-r--r-- | src/slic3r/GUI/OG_CustomCtrl.hpp | 4 | ||||
-rw-r--r-- | src/slic3r/GUI/OptionsGroup.cpp | 16 | ||||
-rw-r--r-- | src/slic3r/GUI/Tab.cpp | 1 |
22 files changed, 275 insertions, 201 deletions
diff --git a/resources/ui_layout/print.ui b/resources/ui_layout/print.ui index 5e4a4b83a..00ff40a7d 100644 --- a/resources/ui_layout/print.ui +++ b/resources/ui_layout/print.ui @@ -54,7 +54,7 @@ group:label_width$12:Overhangs group:Advanced setting:width$25:no_perimeter_unsupported_algo line:Gap Fill - setting:label$_:gap_fill_enable + setting:label$_:gap_fill_enabled setting:width$5:gap_fill_min_area setting:width$5:gap_fill_last end_line @@ -68,6 +68,11 @@ group:Advanced setting:label_width$5:label$Seam:perimeter_loop_seam end_line setting:perimeter_round_corners + line:Fuzzy skin (experimental) + setting:sidetext_width$1:label$_:fuzzy_skin + setting:width$6:sidetext_width$6:fuzzy_skin_thickness + setting:width$6:sidetext_width$5:fuzzy_skin_point_dist + end_line group:External perimeter first setting:label$Activate:external_perimeters_first line:Apply on @@ -76,10 +81,6 @@ group:External perimeter first end_line setting:external_perimeters_vase setting:perimeter_bonding -group:Fuzzy skin (experimental) - settingfuzzy_skin - settingfuzzy_skin_thickness - settingfuzzy_skin_point_dist page:Slicing:layers group:Layer height @@ -149,7 +150,7 @@ group:Reducing printing time setting:sidetext_width$0:label$_:infill_dense setting:width$20:infill_dense_algo end_line -group:sidetext_width$3:Advanced +group:sidetext_width$5:Advanced setting:solid_infill_every_layers setting:solid_infill_below_area line:Angle @@ -187,7 +188,7 @@ group:Skirt setting:label$from brim:skirt_distance_from_brim end_line setting:skirt_height - setting:draft_shield + setting:width$8::draft_shield setting:skirt_brim setting:min_skirt_length group:Brim @@ -195,9 +196,9 @@ group:Brim setting:brim_inside_holes setting:brim_width_interior line:Brim ears - setting:label$_:brim_ears - setting:width$3:brim_ears_max_angle - setting:width$3:brim_ears_detection_length + setting:label$_:sidetext_width$0:brim_ears + setting:width$3:sidetext_width$1:brim_ears_max_angle + setting:width$3:sidetext_width$3:brim_ears_detection_length setting:brim_ears_pattern end_line setting:brim_separation @@ -223,7 +224,7 @@ group:Raft group:Options for support material and raft setting:support_material_style line:Z-offset - setting:width$11:support_material_contact_distance_type + setting:width$13:support_material_contact_distance_type setting:width$6:support_material_contact_distance setting:width$6:support_material_bottom_contact_distance end_line @@ -277,8 +278,8 @@ group:sidetext_width$7:Modifiers setting:label_width$8:width$4:first_layer_min_speed setting:label_width$8:width$4:first_layer_speed setting:label_width$8:width$4:first_layer_infill_speed + setting:label_width$8:width$4:label$Over raft:first_layer_speed_over_raft end_line - setting:first_layer_speed_over_raft line:Small perimeter speed setting:label_width$8:width$4:small_perimeter_min_length setting:label_width$8:width$4:small_perimeter_max_length @@ -313,7 +314,7 @@ group:label_width$9:sidetext_width$8:Acceleration control (advanced) setting:width$4:travel_deceleration_use_target line:First layer acceleration setting:width$4:first_layer_acceleration - setting:width$4:first_layer_acceleration_over_raft + setting:label_width$35:width$4:first_layer_acceleration_over_raft end_line page:Width & Flow:width @@ -355,17 +356,17 @@ group:Extrusion width recommended_extrusion_width_description group:Overlap line:Perimeter overlap - setting:label$Default:perimeter_overlap - setting:label$External:external_perimeter_overlap - setting:label$Gap Fill:gap_fill_overlap + setting:label_width$7:label$Default:perimeter_overlap + setting:label_width$7:label$External:external_perimeter_overlap + setting:label_width$7:label$Gap Fill:gap_fill_overlap end_line - setting:solid_infill_overlap + setting:width$4:solid_infill_overlap line:Bridge lines density - setting:bridge_overlap_min - setting:bridge_overlap + setting:label_width$7:bridge_overlap_min + setting:label_width$7:bridge_overlap end_line - setting:sidetext_width$7:infill_overlap -group:Flow + setting:width$4:sidetext_width$7:infill_overlap +group:sidetext_width$2:Flow line:Flow ratio setting:bridge_flow_ratio setting:over_bridge_flow_ratio diff --git a/resources/ui_layout/sla_material.ui b/resources/ui_layout/sla_material.ui index 81f7862db..bcf720ad7 100644 --- a/resources/ui_layout/sla_material.ui +++ b/resources/ui_layout/sla_material.ui @@ -16,9 +16,9 @@ group:Exposure group:label_width$19:Corrections line:material_correction - setting:label$X:width$6:material_correction_X - setting:label$Y:width$6:material_correction_Y - setting:label$Z:width$6:material_correction_Z + setting:label$X:width$6:material_correction_x + setting:label$Y:width$6:material_correction_y + setting:label$Z:width$6:material_correction_z end_line page:Notes:note diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 9709a3f6f..423bd93c5 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -16,6 +16,7 @@ #include "Exception.hpp" #include "Point.hpp" +#include <boost/any.hpp> #include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/trim.hpp> #include <boost/format/format_fwd.hpp> @@ -364,7 +365,7 @@ public: virtual ConfigOption* clone() const = 0; // Set a value from a ConfigOption. The two options should be compatible. virtual void set(const ConfigOption *option) = 0; - virtual int32_t getInt() const { throw BadOptionTypeException("Calling ConfigOption::getInt on a non-int ConfigOption"); } + virtual int32_t getInt() const { throw BadOptionTypeException("Calling ConfigOption::getInt on a non-int ConfigOption"); } virtual double getFloat() const { throw BadOptionTypeException("Calling ConfigOption::getFloat on a non-float ConfigOption"); } virtual bool getBool() const { throw BadOptionTypeException("Calling ConfigOption::getBool on a non-boolean ConfigOption"); } virtual void setInt(int32_t /* val */) { throw BadOptionTypeException("Calling ConfigOption::setInt on a non-int ConfigOption"); } @@ -1646,7 +1647,7 @@ public: ConfigOptionEnum<T>& operator=(const ConfigOption *opt) { this->set(opt); return *this; } bool operator==(const ConfigOptionEnum<T> &rhs) const throw() { return this->value == rhs.value; } bool operator< (const ConfigOptionEnum<T> &rhs) const throw() { return int(this->value) < int(rhs.value); } - int32_t getInt() const override { return (int32_t)this->value; } + int32_t getInt() const override { return (int32_t)this->value; } void setInt(int val) override { this->value = T(val); } bool operator==(const ConfigOption &rhs) const override diff --git a/src/libslic3r/Flow.cpp b/src/libslic3r/Flow.cpp index fed2f7667..eb835f4ff 100644 --- a/src/libslic3r/Flow.cpp +++ b/src/libslic3r/Flow.cpp @@ -217,7 +217,7 @@ Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent w = auto_extrusion_width(role, nozzle_diameter); } else { // If user set a manual value, use it. - w = float(width.get_abs_value(height)); + w = float(width.get_abs_value(nozzle_diameter)); } return Flow(w, height, rounded_rectangle_extrusion_spacing(w, height), nozzle_diameter, spacing_ratio, false); diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index ada1ea797..97a6a8906 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -3145,7 +3145,8 @@ GCode::LayerResult GCode::process_layer( BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z << log_memory_info(); - print.set_status(int((layer.id() * 100) / layer_count()), std::string(L("Generating G-code layer %s / %s")), std::vector<std::string>{ std::to_string(layer.id()), std::to_string(layer_count()) }, PrintBase::SlicingStatus::DEFAULT | PrintBase::SlicingStatus::SECONDARY_STATE); + if(object_layer) + print.set_status(int((layer.id() * 100) / layer_count()), std::string(L("Generating G-code layer %s / %s")), std::vector<std::string>{ std::to_string(layer.id()), std::to_string(layer_count()) }, PrintBase::SlicingStatus::DEFAULT | PrintBase::SlicingStatus::SECONDARY_STATE); result.gcode = std::move(gcode); result.cooling_buffer_flush = object_layer || raft_layer || last_layer; diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index b1f4af1f3..85d927187 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -35,7 +35,7 @@ PerimeterGeneratorLoops get_all_Childs(PerimeterGeneratorLoop loop) { } // Thanks Cura developers for this function. -static void fuzzy_polygon(Polygon& poly, double fuzzy_skin_thickness, double fuzzy_skin_point_dist) +static void fuzzy_polygon(Polygon& poly, coordf_t fuzzy_skin_thickness, coordf_t fuzzy_skin_point_dist) { const double min_dist_between_points = fuzzy_skin_point_dist * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value const double range_random_point_dist = fuzzy_skin_point_dist / 2.; @@ -731,13 +731,16 @@ void PerimeterGenerator::process() } } + // fuzzify + const bool fuzzify_contours = this->config->fuzzy_skin != FuzzySkinType::None && perimeter_idx == 0 && this->layer->id() > 0; + const bool fuzzify_holes = this->layer->id() > 0 && this->config->fuzzy_skin == FuzzySkinType::All; for (const ExPolygon& expolygon : next_onion) { //TODO: add width here to allow variable width (if we want to extrude a sightly bigger perimeter, see thin wall) - contours[perimeter_idx].emplace_back(expolygon.contour, perimeter_idx, true, has_steep_overhang); + contours[perimeter_idx].emplace_back(expolygon.contour, perimeter_idx, true, has_steep_overhang, fuzzify_contours || fuzzify_holes); if (!expolygon.holes.empty()) { holes[perimeter_idx].reserve(holes[perimeter_idx].size() + expolygon.holes.size()); for (const Polygon& hole : expolygon.holes) - holes[perimeter_idx].emplace_back(hole, perimeter_idx, false, has_steep_overhang); + holes[perimeter_idx].emplace_back(hole, perimeter_idx, false, has_steep_overhang, fuzzify_holes); } } last = std::move(next_onion); @@ -872,6 +875,9 @@ void PerimeterGenerator::process() //svg.draw(to_polylines(top_fills), "green"); //svg.Close(); //} + + // fuzzify + const bool fuzzify_gapfill = this->config->fuzzy_skin == FuzzySkinType::All && this->layer->id() > 0; // check for extracting extra perimeters from gapfill if (!gaps.empty()) { // if needed, add it to the first empty contour list @@ -892,7 +898,7 @@ void PerimeterGenerator::process() holes.emplace_back(); } //Add the new periemter - contours[contours_size].emplace_back(contour_expolygon.front().contour, contours_size, true, has_steep_overhang); + contours[contours_size].emplace_back(contour_expolygon.front().contour, contours_size, true, has_steep_overhang, fuzzify_gapfill); //create the new gapfills ExPolygons gapfill_area = offset_ex(Polygons{ expoly.contour }, -(float)(perimeter_spacing)); ExPolygons to_add = intersection_ex(ExPolygons{ expoly }, gapfill_area); @@ -1078,7 +1084,7 @@ void PerimeterGenerator::process() // collapse double min = 0.2 * perimeter_width * (1 - INSET_OVERLAP_TOLERANCE); //be sure we don't gapfill where the perimeters are already touching each other (negative spacing). - min = std::max(min, double(Flow::new_from_spacing(EPSILON, this->perimeter_flow.nozzle_diameter(), (float)this->layer->height, this->perimeter_flow.spacing_ratio(), false).scaled_width())); + min = std::max(min, double(Flow::new_from_spacing((float)EPSILON, (float)this->perimeter_flow.nozzle_diameter(), (float)this->layer->height, (float)this->perimeter_flow.spacing_ratio(), false).scaled_width())); double max = 2.2 * perimeter_spacing; //remove areas that are too big (shouldn't occur...) ExPolygons too_big = offset2_ex(gaps, double(-max / 2), double(+max / 2)); @@ -1493,6 +1499,57 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const Polyline& loop_polygon return paths; } +static void fuzzy_polygon(ExtrusionPaths& paths, coordf_t fuzzy_skin_thickness, coordf_t fuzzy_skin_point_dist) +{ + const coordf_t min_dist_between_points = fuzzy_skin_point_dist * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value + const coordf_t range_random_point_dist = fuzzy_skin_point_dist / 2.; + coordf_t dist_left_over = coordf_t(rand()) * (min_dist_between_points / 2) / double(RAND_MAX); // the distance to be traversed on the line before making the first new point + + Point last_point = paths.back().last_point(); + bool is_loop = true; //always a loop currently paths.front().first_point() == last_point; + Point p0 = last_point; + for (ExtrusionPath &path : paths) { + Points out; + size_t next_idx = 0; + if (p0 == path.polyline.points.front()) { + next_idx = 1; + } + out.reserve(path.polyline.points.size()); + for (; next_idx < path.polyline.points.size(); next_idx++) + { + Point& p1 = path.polyline.points[next_idx]; + // 'a' is the (next) new point between p0 and p1 + Vec2d p0p1 = (p1 - p0).cast<double>(); + coordf_t p0p1_size = p0p1.norm(); + // so that p0p1_size - dist_last_point evaulates to dist_left_over - p0p1_size + coordf_t dist_last_point = dist_left_over + p0p1_size * 2.; + for (coordf_t p0pa_dist = dist_left_over; p0pa_dist < p0p1_size; + p0pa_dist += min_dist_between_points + coordf_t(rand()) * range_random_point_dist / double(RAND_MAX)) + { + coordf_t r = coordf_t(rand()) * (fuzzy_skin_thickness * 2.) / double(RAND_MAX) - fuzzy_skin_thickness; + out.emplace_back(p0 + (p0p1 * (p0pa_dist / p0p1_size) + perp(p0p1).cast<double>().normalized() * r).cast<coord_t>()); + dist_last_point = p0pa_dist; + } + dist_left_over = p0p1_size - dist_last_point; + p0 = p1; + } + while (path.polyline.size() < 3) { + size_t point_idx = path.polyline.size() - 2; + out.emplace_back(path.polyline.points[point_idx]); + if (point_idx == 0) + break; + --point_idx; + } + if (out.size() >= 3) + path.polyline.points = std::move(out); + } + if (is_loop) { + paths.back().polyline.points.push_back(paths.front().polyline.points.front()); + } else { + paths.back().polyline.points.push_back(last_point); + } +} + ExtrusionEntityCollection PerimeterGenerator::_traverse_loops( const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const { @@ -1543,6 +1600,12 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops( assert(path.height == path.height); paths.push_back(path); } + if (loop.fuzzify) { + double nozle_diameter = is_external ? this->ext_perimeter_flow.nozzle_diameter() : this->perimeter_flow.nozzle_diameter(); + double fuzzy_skin_thickness = config->fuzzy_skin_thickness.get_abs_value(nozle_diameter); + double fuzzy_skin_point_dist = config->fuzzy_skin_point_dist.get_abs_value(nozle_diameter); + fuzzy_polygon(paths, scale_d(fuzzy_skin_thickness), scale_d(fuzzy_skin_point_dist)); + } coll.append(ExtrusionLoop(paths, loop_role)); } @@ -1905,12 +1968,22 @@ PerimeterGenerator::_extrude_and_cut_loop(const PerimeterGeneratorLoop &loop, co Polyline initial_polyline; const coord_t dist_cut = (coord_t)scale_(this->print_config->nozzle_diameter.get_at(this->config->perimeter_extruder - 1)); + //fuzzify first in this case, as it's a bit complicated to do it after. + Polygon fuzzy_poly; + if (loop.fuzzify) { + fuzzy_poly = loop.polygon; + double nozle_diameter = loop.is_external() ? this->ext_perimeter_flow.nozzle_diameter() : this->perimeter_flow.nozzle_diameter(); + double fuzzy_skin_thickness = config->fuzzy_skin_thickness.get_abs_value(nozle_diameter); + double fuzzy_skin_point_dist = config->fuzzy_skin_point_dist.get_abs_value(nozle_diameter); + fuzzy_polygon(fuzzy_poly, scale_d(fuzzy_skin_thickness), scale_d(fuzzy_skin_point_dist)); + } + const Polygon& poly_to_use = loop.fuzzify ? fuzzy_poly : loop.polygon; - if (loop.polygon.points.size() < 3) return ExtrusionLoop(elrDefault); - if (loop.polygon.length() < dist_cut * 2) { + if (poly_to_use.points.size() < 3) return ExtrusionLoop(elrDefault); + if (poly_to_use.length() < dist_cut * 2) { ExtrusionLoop single_point(elrDefault); Polyline poly_point; - poly_point.append(loop.polygon.centroid()); + poly_point.append(poly_to_use.centroid()); single_point.paths.emplace_back( loop.is_external() ? erExternalPerimeter : erPerimeter, (double)(loop.is_external() ? this->ext_mm3_per_mm (): this->mm3_per_mm()), @@ -1919,24 +1992,24 @@ PerimeterGenerator::_extrude_and_cut_loop(const PerimeterGeneratorLoop &loop, co single_point.paths.back().polyline = poly_point; return single_point; } - const size_t idx_closest_from_entry_point = loop.polygon.closest_point_index(entry_point); - if (loop.polygon.points[idx_closest_from_entry_point].distance_to(entry_point) > SCALED_EPSILON) { + const size_t idx_closest_from_entry_point = poly_to_use.closest_point_index(entry_point); + if (poly_to_use.points[idx_closest_from_entry_point].distance_to(entry_point) > SCALED_EPSILON * 2) { //create new Point //get first point size_t idx_before = -1; - for (size_t idx_p_a = 0; idx_p_a < loop.polygon.points.size(); ++idx_p_a) { - Line l(loop.polygon.points[idx_p_a], loop.polygon.points[(idx_p_a + 1 == loop.polygon.points.size()) ? 0 : (idx_p_a + 1)]); + for (size_t idx_p_a = 0; idx_p_a < poly_to_use.points.size(); ++idx_p_a) { + Line l(poly_to_use.points[idx_p_a], poly_to_use.points[(idx_p_a + 1 == poly_to_use.points.size()) ? 0 : (idx_p_a + 1)]); if (entry_point.distance_to(l) < SCALED_EPSILON) { idx_before = idx_p_a; break; } } if (idx_before == (size_t)-1) std::cerr << "ERROR: _traverse_and_join_loops : idx_before can't be finded to create new point\n"; - initial_polyline = loop.polygon.split_at_index(idx_before); + initial_polyline = poly_to_use.split_at_index(idx_before); initial_polyline.points.push_back(entry_point); initial_polyline.points[0] = entry_point; } else { - initial_polyline = loop.polygon.split_at_index(idx_closest_from_entry_point); + initial_polyline = poly_to_use.split_at_index(idx_closest_from_entry_point); } @@ -2323,7 +2396,7 @@ PerimeterGenerator::_traverse_and_join_loops(const PerimeterGeneratorLoop &loop, for (size_t i = 0; i < my_loop.paths.size(); i++) { if (my_loop.paths[i].polyline.size() < 2) { if (my_loop.paths[i].polyline.size() == 1) - std::cout << "erase one-point extrusion : layer " << this->layer->id() << " " << my_loop.paths[i].polyline.points.front().x() << ":" << my_loop.paths[i].polyline.points.front().y() << "\n"; + BOOST_LOG_TRIVIAL(warning) << "erase one-point extrusion : layer " << this->layer->id() << " " << my_loop.paths[i].polyline.points.front().x() << ":" << my_loop.paths[i].polyline.points.front().y() << "\n"; my_loop.paths.erase(my_loop.paths.begin() + i); i--; } diff --git a/src/libslic3r/PerimeterGenerator.hpp b/src/libslic3r/PerimeterGenerator.hpp index 18a7485a2..71368807c 100644 --- a/src/libslic3r/PerimeterGenerator.hpp +++ b/src/libslic3r/PerimeterGenerator.hpp @@ -35,12 +35,14 @@ public: unsigned short depth; // Children contour, may be both CCW and CW oriented (outer contours or holes). std::vector<PerimeterGeneratorLoop> children; + // can be fuzzified? + bool fuzzify; PerimeterGeneratorLoop(Polygon polygon, unsigned short depth, bool is_contour) : - polygon(polygon), is_contour(is_contour), depth(depth), is_steep_overhang(false) {} - PerimeterGeneratorLoop(Polygon polygon, unsigned short depth, bool is_contour, bool is_steep_overhang) : - polygon(polygon), is_contour(is_contour), depth(depth), is_steep_overhang(is_steep_overhang) {} + polygon(polygon), is_contour(is_contour), depth(depth), is_steep_overhang(false), fuzzify(false) {} + PerimeterGeneratorLoop(Polygon polygon, unsigned short depth, bool is_contour, bool is_steep_overhang, bool is_fuzzy) : + polygon(polygon), is_contour(is_contour), depth(depth), is_steep_overhang(is_steep_overhang), fuzzify(is_fuzzy) {} // External perimeter. It may be CCW or CW oriented (outer contour or hole contour). bool is_external() const { return this->depth == 0; } // it's the last loop of the contour (not hol), so the first to be printed (if all goes well) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 318673ba3..b2897f841 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -510,6 +510,7 @@ static std::vector<std::string> s_Preset_print_options { "external_perimeter_speed", "first_layer_speed", "first_layer_min_speed", + "first_layer_speed_over_raft", "infill_speed", "perimeter_speed", "small_perimeter_speed", @@ -529,6 +530,10 @@ static std::vector<std::string> s_Preset_print_options { "gap_fill_min_area", "gap_fill_overlap", "gap_fill_speed", + // fuzzy + "fuzzy_skin", + "fuzzy_skin_point_dist", + "fuzzy_skin_thickness", // acceleration "bridge_acceleration", "bridge_internal_acceleration", @@ -569,7 +574,12 @@ static std::vector<std::string> s_Preset_print_options { //"brim_type", // support "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers", - "raft_layers", "support_material_pattern", "support_material_with_sheath", "support_material_spacing", + "raft_contact_distance", + "raft_expansion", + "raft_first_layer_density", + "raft_first_layer_expansion", + "raft_layers", + "support_material_pattern", "support_material_with_sheath", "support_material_spacing", "support_material_closing_radius", "support_material_style", "support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers", "support_material_bottom_interface_layers", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 45e312ea3..cac670862 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -990,6 +990,7 @@ void Print::process() obj->infill(); for (PrintObject *obj : m_objects) obj->ironing(); + this->set_status(50, L("Generating support material")); for (PrintObject *obj : m_objects) obj->generate_support_material(); if (this->set_started(psWipeTower)) { diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 37a8ce32b..20c75a70d 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -690,7 +690,7 @@ void PrintConfigDef::init_fff_params() "\nThis setting allow you to choose the base for the bridge flow compute, the result will be multiplied by the bridge flow to have the final result." " The preview will display the expected shape of the bridge extrusion (cylinder), don't expect a magical thick and solid air to flatten the extrusion magically."); def->sidetext = L("%"); - def->enum_keys_map = &ConfigOptionEnum<FuzzySkinType>::get_enum_values(); + def->enum_keys_map = &ConfigOptionEnum<BridgeType>::get_enum_values(); def->enum_values.push_back("nozzle"); def->enum_values.push_back("height"); def->enum_values.push_back("flow"); @@ -1256,7 +1256,7 @@ void PrintConfigDef::init_fff_params() def->full_label = L("Default infill margin"); def->category = OptionCategory::infill; def->tooltip = L("This parameter grows the top/bottom/solid layers by the specified mm to anchor them into the sparse infill and support the perimeters above. Put 0 to deactivate it. Can be a % of the width of the perimeters."); - def->sidetext = L("mm/%"); + def->sidetext = L("mm or %"); def->ratio_over = "perimeter_extrusion_width"; def->min = 0; def->max_literal = { 50, true }; @@ -1268,7 +1268,7 @@ void PrintConfigDef::init_fff_params() def->full_label = L("Bridge margin"); def->category = OptionCategory::infill; def->tooltip = L("This parameter grows the bridged solid infill layers by the specified mm to anchor them into the sparse infill and over the perimeters below. Put 0 to deactivate it. Can be a % of the width of the external perimeter."); - def->sidetext = L("mm/%"); + def->sidetext = L("mm or %"); def->ratio_over = "external_perimeter_extrusion_width"; def->min = 0; def->max_literal = { 50, true }; @@ -1605,7 +1605,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Default extrusion width"); def->category = OptionCategory::width; def->tooltip = L("This is the DEFAULT extrusion width. It's ONLY used to REPLACE 0-width fields. It's useless when all other width fields have a value." - "Set this to a non-zero value to allow a manual extrusion width. " + "\nSet this to a non-zero value to allow a manual extrusion width. " "If left to zero, Slic3r derives extrusion widths from the nozzle diameter " "(see the tooltips for perimeter extrusion width, infill extrusion width etc). " "If expressed as percentage (for example: 105%), it will be computed over nozzle diameter." @@ -1617,7 +1617,7 @@ void PrintConfigDef::init_fff_params() def->max_literal = { 10, true }; def->precision = 6; def->can_phony = true; - def->mode = comAdvanced; + def->mode = comExpert; def->set_default_value(new ConfigOptionFloatOrPercent(0, false, true)); def = this->add("extrusion_spacing", coFloatOrPercent); @@ -2435,25 +2435,27 @@ void PrintConfigDef::init_fff_params() def->mode = comSimple; def->set_default_value(new ConfigOptionEnum<FuzzySkinType>(FuzzySkinType::None)); - def = this->add("fuzzy_skin_thickness", coFloat); + def = this->add("fuzzy_skin_thickness", coFloatOrPercent); def->label = L("Fuzzy skin thickness"); def->category = OptionCategory::fuzzy_skin; def->tooltip = L("The maximum distance that each skin point can be offset (both ways), " - "measured perpendicular to the perimeter wall."); - def->sidetext = L("mm"); + "measured perpendicular to the perimeter wall." + "\nCan be a % of the nozzle diameter."); + def->sidetext = L("mm or %"); def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0.3)); + def->set_default_value(new ConfigOptionFloatOrPercent(150, true)); - def = this->add("fuzzy_skin_point_dist", coFloat); + def = this->add("fuzzy_skin_point_dist", coFloatOrPercent); def->label = L("Fuzzy skin point distance"); def->category = OptionCategory::fuzzy_skin; def->tooltip = L("Perimeters will be split into multiple segments by inserting Fuzzy skin points. " - "Lowering the Fuzzy skin point distance will increase the number of randomly offset points on the perimeter wall."); - def->sidetext = L("mm"); + "Lowering the Fuzzy skin point distance will increase the number of randomly offset points on the perimeter wall." + "\nCan be a % of the nozzle diameter."); + def->sidetext = L("mm or %"); def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0.8)); + def->set_default_value(new ConfigOptionFloatOrPercent(200, true)); def = this->add("gap_fill_enabled", coBool); def->label = L("Gap fill"); @@ -3411,7 +3413,7 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->max_literal = { 15, false }; def->mode = comExpert; - def->set_default_value(new ConfigOptionFloatOrPercent(200, true)); + def->set_default_value(new ConfigOptionFloatOrPercent(100, true)); def = this->add("min_print_speed", coFloats); def->label = L("Min print speed"); @@ -3715,6 +3717,7 @@ void PrintConfigDef::init_fff_params() "\nYou can set either 'Spacing', or 'Width'; the other will be calculated, using the perimeter 'Overlap' percentages and default layer height."); def->sidetext = L("mm or %"); def->aliases = { "perimeters_extrusion_width" }; + def->ratio_over = "nozzle_diameter"; def->min = 0; def->max = 1000; def->max_literal = { 10, true }; @@ -3731,6 +3734,8 @@ void PrintConfigDef::init_fff_params() "\nYou can set either 'Spacing', or 'Width'; the other will be calculated, using the perimeter 'Overlap' percentages and default layer height."); def->sidetext = L("mm or %"); def->aliases = { "perimeters_extrusion_width" }; + def->ratio_over = "nozzle_diameter"; + def->is_vector_extruder = true; def->min = 0; def->max = 1000; def->max_literal = { 10, true }; @@ -4254,6 +4259,7 @@ void PrintConfigDef::init_fff_params() " If left as zero, first layer extrusion width will be used if set and the skirt is only 1 layer height" ", or perimeter extrusion width will be used (using the computed value if not set)."); def->sidetext = L("mm or %"); + def->ratio_over = "nozzle_diameter"; def->min = 0; def->max = 1000; def->max_literal = { 10, true }; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index ca04e05f1..e15c4519e 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -777,8 +777,8 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionPercent, fill_density)) ((ConfigOptionEnum<InfillPattern>, fill_pattern)) ((ConfigOptionEnum<FuzzySkinType>, fuzzy_skin)) - ((ConfigOptionFloat, fuzzy_skin_thickness)) - ((ConfigOptionFloat, fuzzy_skin_point_dist)) + ((ConfigOptionFloatOrPercent, fuzzy_skin_thickness)) + ((ConfigOptionFloatOrPercent, fuzzy_skin_point_dist)) ((ConfigOptionPercent, fill_top_flow_ratio)) ((ConfigOptionPercent, fill_smooth_distribution)) ((ConfigOptionFloatOrPercent, fill_smooth_width)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index aefc044f2..de64d3eef 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -613,7 +613,6 @@ std::vector<std::reference_wrapper<const PrintRegion>> PrintObject::all_regions( if (this->set_started(posSupportMaterial)) { this->clear_support_layers(); if ((this->has_support() && m_layers.size() > 1) || (this->has_raft() && ! m_layers.empty())) { - m_print->set_status(85, L("Generating support material")); this->_generate_support_material(); m_print->throw_if_canceled(); } else { diff --git a/src/libslic3r/Thread.cpp b/src/libslic3r/Thread.cpp index a77f6bc91..fc4debc69 100644 --- a/src/libslic3r/Thread.cpp +++ b/src/libslic3r/Thread.cpp @@ -202,11 +202,11 @@ void name_tbb_thread_pool_threads_set_locale() const size_t nthreads_hw = tbb::this_task_arena::max_concurrency(); size_t nthreads = nthreads_hw; -#ifdef SLIC3R_PROFILE +//#ifdef SLIC3R_PROFILE // Shiny profiler is not thread safe, thus disable parallelization. disable_multi_threading(); nthreads = 1; -#endif +//#endif size_t nthreads_running(0); std::condition_variable cv; diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 8bccaa1a2..852b1e99e 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -351,6 +351,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) for (auto el : { "gap_fill_last", "gap_fill_min_area" }) toggle_field(el, config->opt_bool("gap_fill_enabled")); + for (auto el : { "fuzzy_skin_thickness", "fuzzy_skin_point_dist" }) + toggle_field(el, config->option<ConfigOptionEnum<FuzzySkinType>>("fuzzy_skin")->value != FuzzySkinType::None); + toggle_field("avoid_crossing_not_first_layer", config->opt_bool("avoid_crossing_perimeters")); bool have_infill = config->option<ConfigOptionPercent>("fill_density")->value > 0; diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 929451f9d..e6a0463c2 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -1314,12 +1314,11 @@ void Choice::set_value(const std::string& value, bool change_event) //! Redunda m_disable_change_event = false; } -template<class T> -int Choice::idx_from_enum_value(int val) { +int32_t Choice::idx_from_enum_value(int32_t val) { if (!m_opt.enum_values.empty()) { std::string key; - t_config_enum_values map_names = ConfigOptionEnum<T>::get_enum_values(); - for (auto it : map_names) { + const t_config_enum_values* map_names = m_opt.enum_keys_map; + for (auto it : *map_names) { if (val == it.second) { key = it.first; break; @@ -1386,57 +1385,8 @@ void Choice::set_value(const boost::any& value, bool change_event) break; } case coEnum: { - int val = boost::any_cast<int>(value); -// if (m_opt_id.compare("host_type") == 0 && val != 0 && -// m_opt.enum_values.size() > field->GetCount()) // for case, when PrusaLink isn't used as a HostType -// val--; - - - - if (m_opt_id == "top_fill_pattern" || m_opt_id == "bottom_fill_pattern" || m_opt_id == "solid_fill_pattern" - || m_opt_id == "fill_pattern" || m_opt_id == "support_material_interface_pattern" || m_opt_id == "brim_ears_pattern") - val = idx_from_enum_value<InfillPattern>(val); - else if (m_opt_id.compare("complete_objects_sort") == 0) - val = idx_from_enum_value<CompleteObjectSort>(val); - else if (m_opt_id.compare("bridge_type") == 0) - val = idx_from_enum_value<BridgeType>(val); - else if (m_opt_id.compare("display_orientation") == 0) - val = idx_from_enum_value<SLADisplayOrientation>(val); - else if (m_opt_id.compare("gcode_flavor") == 0) - val = idx_from_enum_value<GCodeFlavor>(val); - else if (m_opt_id.compare("host_type") == 0) - val = idx_from_enum_value<PrintHostType>(val); - else if (m_opt_id =="infill_connection" || m_opt_id =="infill_connection_solid" - || m_opt_id =="infill_connection_top" || m_opt_id =="infill_connection_bottom") - val = idx_from_enum_value<InfillConnection>(val); - else if (m_opt_id.compare("infill_dense_algo") == 0) - val = idx_from_enum_value<DenseInfillAlgo>(val); - else if (m_opt_id == "ironing_type") - val = idx_from_enum_value<IroningType>(val); - else if (m_opt_id.compare("machine_limits_usage") == 0) - val = idx_from_enum_value<MachineLimitsUsage>(val); - else if (m_opt_id.compare("no_perimeter_unsupported_algo") == 0) - val = idx_from_enum_value<NoPerimeterUnsupportedAlgo>(val); - else if (m_opt_id.compare("perimeter_loop_seam") == 0) - val = idx_from_enum_value<SeamPosition>(val); - else if (m_opt_id == "printhost_authorization_type") - val = idx_from_enum_value<AuthorizationType>(val); - else if (m_opt_id.compare("remaining_times_type") == 0) - val = idx_from_enum_value<RemainingTimeType>(val); - else if (m_opt_id.compare("seam_position") == 0) - val = idx_from_enum_value<SeamPosition>(val); - else if (m_opt_id.compare("support_material_contact_distance_type") == 0) - val = idx_from_enum_value<SupportZDistanceType>(val); - else if (m_opt_id.compare("support_material_pattern") == 0) - val = idx_from_enum_value<SupportMaterialPattern>(val); - else if (m_opt_id.compare("support_pillar_connection_mode") == 0) - val = idx_from_enum_value<SLAPillarConnectionMode>(val); - else if (m_opt_id.compare("wipe_advanced_algo") == 0) - val = idx_from_enum_value<WipeAlgo>(val); - else if (m_opt_id.compare("output_format") == 0) - val = idx_from_enum_value<OutputFormat>(val); - else if (m_opt_id.compare("config_compatibility") == 0) - val = idx_from_enum_value<ForwardCompatibilitySubstitutionRule>(val); + int32_t val = boost::any_cast<int32_t>(value); + val = idx_from_enum_value(val); BOOST_LOG_TRIVIAL(debug) << "Set field from key "<< m_opt_id << " as int " << boost::any_cast<int>(value) << " modified to " << val; field->SetSelection(val); break; @@ -1468,17 +1418,16 @@ void Choice::set_values(const std::vector<std::string>& values) m_disable_change_event = false; } -template<class T> -void Choice::convert_to_enum_value(int ret_enum) { +void Choice::convert_to_enum_value(int32_t ret_enum) { if (!m_opt.enum_values.empty()) { std::string key = m_opt.enum_values[ret_enum]; - t_config_enum_values map_names = ConfigOptionEnum<T>::get_enum_values(); - int value = map_names.at(key); + const t_config_enum_values *map_names = m_opt.enum_keys_map; + int32_t value = map_names->at(key); - m_value = static_cast<T>(value); + m_value = value; } else - m_value = static_cast<T>(m_opt.default_value.get()->getInt()); + m_value = m_opt.default_value.get()->getInt(); } //TODO: check if used (from prusa) @@ -1517,51 +1466,7 @@ boost::any& Choice::get_value() if (m_opt.type == coEnum) { int ret_enum = field->GetSelection(); -// if (m_opt_id.compare("host_type") == 0 && -// m_opt.enum_values.size() > field->GetCount()) // for case, when PrusaLink isn't used as a HostType -// ret_enum++; - if (m_opt_id == "top_fill_pattern" || m_opt_id == "bottom_fill_pattern" || m_opt_id == "solid_fill_pattern" - || m_opt_id == "support_material_interface_pattern" || m_opt_id == "fill_pattern" || m_opt_id == "brim_ears_pattern") - convert_to_enum_value<InfillPattern>(ret_enum); - else if (m_opt_id.compare("complete_objects_sort") == 0) - convert_to_enum_value<CompleteObjectSort>(ret_enum); - else if (m_opt_id.compare("display_orientation") == 0) - convert_to_enum_value<SLADisplayOrientation>(ret_enum); - else if (m_opt_id.compare("gcode_flavor") == 0) - convert_to_enum_value<GCodeFlavor>(ret_enum); - else if (m_opt_id.compare("host_type") == 0) - convert_to_enum_value<PrintHostType>(ret_enum); - else if (m_opt_id =="infill_connection" || m_opt_id =="infill_connection_solid" - || m_opt_id =="infill_connection_top" || m_opt_id =="infill_connection_bottom") - convert_to_enum_value<InfillConnection>(ret_enum); - else if (m_opt_id.compare("infill_dense_algo") == 0) - convert_to_enum_value<DenseInfillAlgo>(ret_enum); - else if (m_opt_id == "ironing_type") - convert_to_enum_value<IroningType>(ret_enum); - else if (m_opt_id.compare("machine_limits_usage") == 0) - convert_to_enum_value<MachineLimitsUsage>(ret_enum); - else if (m_opt_id.compare("no_perimeter_unsupported_algo") == 0) - convert_to_enum_value<NoPerimeterUnsupportedAlgo>(ret_enum); - else if (m_opt_id.compare("perimeter_loop_seam") == 0) - convert_to_enum_value<SeamPosition>(ret_enum); - else if (m_opt_id == "printhost_authorization_type") - convert_to_enum_value<AuthorizationType>(ret_enum); - else if (m_opt_id.compare("remaining_times_type") == 0) - convert_to_enum_value<RemainingTimeType>(ret_enum); - else if (m_opt_id.compare("seam_position") == 0) - convert_to_enum_value<SeamPosition>(ret_enum); - else if (m_opt_id.compare("support_material_contact_distance_type") == 0) - convert_to_enum_value<SupportZDistanceType>(ret_enum); - else if (m_opt_id.compare("support_material_pattern") == 0) - convert_to_enum_value<SupportMaterialPattern>(ret_enum); - else if (m_opt_id.compare("support_pillar_connection_mode") == 0) - convert_to_enum_value<SLAPillarConnectionMode>(ret_enum); - else if (m_opt_id.compare("wipe_advanced_algo") == 0) - convert_to_enum_value<WipeAlgo>(ret_enum); - else if (m_opt_id.compare("output_format") == 0) - convert_to_enum_value<OutputFormat>(ret_enum); - else if(m_opt_id.compare("config_compatibility") == 0) - convert_to_enum_value<ForwardCompatibilitySubstitutionRule>(ret_enum); + convert_to_enum_value(ret_enum); } else if (m_opt.gui_type == ConfigOptionDef::GUIType::f_enum_open || m_opt.gui_type == ConfigOptionDef::GUIType::i_enum_open) { const int ret_enum = field->GetSelection(); diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index 573ab7670..ca37298e8 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -368,8 +368,8 @@ class Choice : public Field { protected: //used by get_value when it's an enum //convert the value from the select to the enum value. store it in m_value - template<class T> void convert_to_enum_value(int idx_val); - template<class T> int idx_from_enum_value(int enum_val); + void convert_to_enum_value(int32_t idx_val); + int32_t idx_from_enum_value(int32_t enum_val); public: Choice(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {} Choice(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 6b239b278..5ba6898de 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -193,9 +193,8 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt } break; case coEnum:{ - auto *opt = opt_def->default_value.get()->clone(); - opt->setInt(boost::any_cast<int>(value)); - // same as config.set_key_value(opt_key, new ConfigOptionEnum<InfillPattern>(boost::any_cast<InfillPattern>(value))); + ConfigOption* opt = opt_def->default_value.get()->clone(); + opt->setInt(boost::any_cast<int32_t>(value)); // we transport an int convertion of the enum in the boost anycast. BOOST_LOG_TRIVIAL(debug) << "Set enum "<< opt_key << " as int " << boost::any_cast<int>(value) << " into enum " << opt->serialize(); config.set_key_value(opt_key, opt); } diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 69f4f6455..956436ac5 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -1164,7 +1164,7 @@ void NotificationManager::SlicingProgressNotification::set_status_text(const std break; case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_PROGRESS: { - NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, text + "." }; + NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, text }; update(data); m_state = EState::NotFading; } diff --git a/src/slic3r/GUI/OG_CustomCtrl.cpp b/src/slic3r/GUI/OG_CustomCtrl.cpp index 7e2e9c05d..aae8710b8 100644 --- a/src/slic3r/GUI/OG_CustomCtrl.cpp +++ b/src/slic3r/GUI/OG_CustomCtrl.cpp @@ -90,7 +90,6 @@ void OG_CustomCtrl::init_ctrl_lines() // if we have a single option with no label, no sidetext just add it directly to sizer if (option_set.size() == 1 && opt_group->title_width == 0 && option_set.front().opt.full_width && - option_set.front().opt.label.empty() && option_set.front().opt.sidetext.size() == 0 && option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) { @@ -132,6 +131,15 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/) line_height = win_height; }; + auto correct_horiz_pos = [this](int& h_pos, Field* field) { + if (m_max_win_width > 0 && field->getWindow()) { + int win_width = field->getWindow()->GetSize().GetWidth(); + if (dynamic_cast<CheckBox*>(field)) + win_width *= 0.5; + h_pos += m_max_win_width - win_width; + } + }; + for (CtrlLine& ctrl_line : ctrl_lines) { if (&ctrl_line.og_line == &line) { @@ -170,15 +178,16 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/) // If we have a single option with no sidetext const std::vector<Option>& option_set = line.get_options(); if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 && - option_set.front().opt.label.empty() && option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) { h_pos += 2 * blinking_button_width; Field* field = opt_group->get_field(option_set.front().opt_id); correct_line_height(ctrl_line.height, field->getWindow()); + //correct_horiz_pos(h_pos, field); //TODO test break; } + bool is_multioption_line = option_set.size() > 1 || !option_set.front().opt.label.empty(); for (size_t i = 0; i < option_set.size(); ++i) { if (i >= ctrl_line.is_visible.size() || !ctrl_line.is_visible[i]) continue; @@ -188,7 +197,7 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/) ConfigOptionDef option = opt.opt; // add label if any - if (!option.label.empty()) { + if (is_multioption_line && !option.label.empty()) { std::string opt_label = (option.label.empty() || option.label.back() != '_') ? option.label : option.label.substr(0, option.label.size() - 1); //! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1 label = /*(opt_label == L_CONTEXT("Top", "Layers") || opt_label == L_CONTEXT("Bottom", "Layers")) ? @@ -246,8 +255,10 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/) // size of little widget before the real one h_pos += 2 * blinking_button_width; - if (field == field_in) + if (field == field_in) { + //correct_horiz_pos(h_pos, field); break; + } if (opt.opt.gui_type == ConfigOptionDef::GUIType::legend) h_pos += 2 * blinking_button_width; @@ -309,11 +320,20 @@ void OG_CustomCtrl::OnMotion(wxMouseEvent& event) 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); + line.is_focused = false; + wxString *str_tooltip; + size_t idx = 0; + for (; idx < line.rects_tooltip.size(); ++idx) { + line.is_focused = is_point_in_rect(pos, line.rects_tooltip[idx].first); + if (line.is_focused) { + str_tooltip = &line.rects_tooltip[idx].second; + break; + } + } if (line.is_focused) { 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; + tooltip = OptionsGroup::get_url(line.og_line.label_path) +"\n\n"; + tooltip += *str_tooltip; break; } @@ -419,6 +439,8 @@ void OG_CustomCtrl::correct_widgets_position(wxSizer* widget, const Line& line, wxPoint pos = line_pos; wxSize sz = child->GetWindow()->GetSize(); pos.y += std::max(0, int(0.5 * (line_height - sz.y))); + if (line.extra_widget_sizer && widget == line.extra_widget_sizer) + pos.x += m_h_gap; child->GetWindow()->SetPosition(pos); line_pos.x += sz.x + m_h_gap; } @@ -460,6 +482,8 @@ void OG_CustomCtrl::msw_rescale() m_bmp_blinking_sz = create_scaled_bitmap("search_blink", this).GetSize(); if (!m_has_icon) m_bmp_blinking_sz.x = 0; + m_max_win_width = 0; + wxCoord v_pos = 0; for (CtrlLine& line : ctrl_lines) { line.msw_rescale(); @@ -549,6 +573,8 @@ void OG_CustomCtrl::CtrlLine::msw_rescale() void OG_CustomCtrl::CtrlLine::update_visibility(ConfigOptionMode mode) { + if (og_line.is_separator()) + return; const std::vector<Option>& option_set = og_line.get_options(); ConfigOptionMode line_mode = option_set.front().opt.mode; @@ -588,8 +614,27 @@ void OG_CustomCtrl::CtrlLine::update_visibility(ConfigOptionMode mode) correct_items_positions(); } +void OG_CustomCtrl::CtrlLine::render_separator(wxDC& dc, wxCoord v_pos) +{ + wxPoint begin(ctrl->m_h_gap, v_pos); + wxPoint end(ctrl->GetSize().GetWidth() - ctrl->m_h_gap, v_pos); + + wxPen pen, old_pen = pen = dc.GetPen(); + pen.SetColour(*wxLIGHT_GREY); + dc.SetPen(pen); + dc.DrawLine(begin, end); + dc.SetPen(old_pen); +} + +//TODO push string manipulation out of the render loop (tooltip replace, adding ':') void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos) { + if (is_separator()) { + render_separator(dc, v_pos); + return; + } + rects_tooltip.clear(); // reset the tooltip detection area, they are re-created by draw_text + Field* field = ctrl->opt_group->get_field(og_line.get_options().front().opt_id); int blinking_button_width = ctrl->m_bmp_blinking_sz.GetWidth(); if(blinking_button_width ) blinking_button_width += ctrl->m_h_gap; @@ -613,11 +658,14 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos) bool is_url_string = false; if (ctrl->opt_group->title_width != 0 && !og_line.label.IsEmpty()) { - const wxColour* text_clr = (option_set.size() == 1 && field ? field->label_color() : og_line.full_Label_color); + bool is_multiline = option_set.size() > 1 || !option_set.front().opt.label.empty(); + // Color the line label is the first settig doesn't have a label + const wxColour* text_clr = ((option_set.front().opt.label.empty() || option_set.front().opt.label == "_") && field ? + field->label_color() : og_line.full_Label_color); is_url_string = !suppress_hyperlinks && !og_line.label_path.empty(); wxString opt_label = (og_line.label.empty() || og_line.label.Last() != '_') ? og_line.label : og_line.label.substr(0, og_line.label.size() - 1); - bool no_dots = og_line.label.empty() || og_line.label.Last() == '_'; - h_pos = draw_text(dc, wxPoint(h_pos, v_pos), (no_dots ? opt_label : opt_label + ':'), text_clr, ctrl->opt_group->title_width * ctrl->m_em_unit, is_url_string); + bool no_dots = og_line.label.empty() || og_line.label.Last() == '_' || is_multiline; + h_pos = draw_text(dc, wxPoint(h_pos, v_pos), (no_dots ? opt_label : opt_label + ':'), og_line.label_tooltip , text_clr, ctrl->opt_group->title_width * ctrl->m_em_unit, is_url_string); } // If there's a widget, build it and set result to the correct position. @@ -634,12 +682,13 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos) // If we have a single option with no sidetext just add it directly to the grid sizer if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 && - option_set.front().opt.label.empty() && option_set.front().side_widget == nullptr && og_line.get_extra_widgets().size() == 0) { if (field) { if (field->undo_to_sys_bitmap()) h_pos = draw_act_bmps(dc, wxPoint(h_pos, v_pos), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp(), field->blink()) + ctrl->m_h_gap; + else if (field && !field->undo_to_sys_bitmap() && field->blink()) + draw_blinking_bmp(dc, wxPoint(h_pos, v_pos), field->blink()); else h_pos += 2 * blinking_button_width; } @@ -650,15 +699,20 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos) } size_t bmp_rect_id = 0; - bool is_multioption_line = option_set.size() > 1; + bool is_multioption_line = option_set.size() > 1 || !option_set.front().opt.label.empty(); for (size_t i = 0; i < option_set.size(); ++i) { if (i >= is_visible.size() || !is_visible[i]) continue; const Option& opt = option_set[i]; field = ctrl->opt_group->get_field(opt.opt_id); ConfigOptionDef option = opt.opt; + + //tooltip for labels + wxString option_tooltip = _(option.tooltip); + update_Slic3r_string(option_tooltip); + // add label if any - if (!option.label.empty()) { + if (is_multioption_line && !option.label.empty()) { std::string opt_label = (option.label.empty() || option.label.back() != '_') ? option.label : option.label.substr(0, option.label.size() - 1); //! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1 wxString label = /*(opt_label == L_CONTEXT("Top", "Layers") || opt_label == L_CONTEXT("Bottom", "Layers")) ? @@ -681,8 +735,8 @@ 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 = !suppress_hyperlinks && !og_line.label_path.empty(); - h_pos = draw_text(dc, wxPoint(h_pos, v_pos), label, field ? field->label_color() : nullptr, width, is_url_string, !field->m_opt.aligned_label_left); + is_url_string = !suppress_hyperlinks && !og_line.label_path.empty(); + h_pos = draw_text(dc, wxPoint(h_pos, v_pos), label, option_tooltip, field ? field->label_color() : nullptr, width, is_url_string, !field->m_opt.aligned_label_left); } } @@ -711,7 +765,7 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos) // add sidetext if any if ( (!option.sidetext.empty() || ctrl->opt_group->sidetext_width > 0 || option.sidetext_width > 0 ) && option.sidetext_width != 0) - h_pos = draw_text(dc, wxPoint(h_pos, v_pos), _(option.sidetext), nullptr, (option.sidetext_width > 0 ? option.sidetext_width : ctrl->opt_group->sidetext_width ) * ctrl->m_em_unit); + h_pos = draw_text(dc, wxPoint(h_pos, v_pos), _(option.sidetext), option_tooltip, nullptr, (option.sidetext_width > 0 ? option.sidetext_width : ctrl->opt_group->sidetext_width ) * ctrl->m_em_unit); if (opt.opt_id != option_set.back().opt_id) //! istead of (opt != option_set.back()) h_pos += lround(0.6 * ctrl->m_em_unit); @@ -737,7 +791,7 @@ wxCoord OG_CustomCtrl::CtrlLine::draw_mode_bmp(wxDC& dc, wxCoord v_pos) return get_bitmap_size(bmp).GetWidth() + ctrl->m_h_gap; } -wxCoord OG_CustomCtrl::CtrlLine::draw_text(wxDC& dc, wxPoint pos, const wxString& text, const wxColour* color, int width, bool is_url/* = false*/, bool align_right/* = false*/) +wxCoord OG_CustomCtrl::CtrlLine::draw_text(wxDC& dc, wxPoint pos, const wxString& text, const wxString& tooltip, const wxColour* color, int width, bool is_url/* = false*/, bool align_right/* = false*/) { wxString multiline_text; if (width > 0 && dc.GetTextExtent(text).x > width) { @@ -773,8 +827,7 @@ wxCoord OG_CustomCtrl::CtrlLine::draw_text(wxDC& dc, wxPoint pos, const wxStr wxPoint draw_pos = pos; if (align_right && width > 0) draw_pos.x += width - text_width; - if (width > 0) - rect_label = wxRect(draw_pos, wxSize(text_width, text_height)); + rects_tooltip.emplace_back(wxRect{draw_pos, wxSize(text_width, text_height)}, tooltip); wxColour old_clr = dc.GetTextForeground(); wxFont old_font = dc.GetFont(); @@ -785,7 +838,12 @@ wxCoord OG_CustomCtrl::CtrlLine::draw_text(wxDC& dc, wxPoint pos, const wxStr #else dc.SetFont(old_font.Bold().Underlined()); #endif - dc.SetTextForeground(color ? *color : wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); + dc.SetTextForeground(color ? *color : +#ifdef _WIN32 + wxGetApp().get_label_clr_default()); +#else + wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); +#endif /* _WIN32 */ dc.DrawText(out_text, draw_pos); dc.SetTextForeground(old_clr); dc.SetFont(old_font); diff --git a/src/slic3r/GUI/OG_CustomCtrl.hpp b/src/slic3r/GUI/OG_CustomCtrl.hpp index 05119c2c1..965540250 100644 --- a/src/slic3r/GUI/OG_CustomCtrl.hpp +++ b/src/slic3r/GUI/OG_CustomCtrl.hpp @@ -63,7 +63,7 @@ class OG_CustomCtrl :public wxPanel void render(wxDC& dc, wxCoord v_pos); wxCoord draw_mode_bmp(wxDC& dc, wxCoord v_pos); - wxCoord draw_text (wxDC& dc, wxPoint pos, const wxString& text, const wxColour* color, int width, bool is_url = false, bool align_right = false); + wxCoord draw_text (wxDC& dc, wxPoint pos, const wxString& text, const wxString& tooltip, const wxColour* color, int width, bool is_url = false, bool align_right = false); wxPoint draw_blinking_bmp(wxDC& dc, wxPoint pos, bool is_blinking); wxCoord draw_act_bmps(wxDC& dc, wxPoint pos, const wxBitmap& bmp_undo_to_sys, const wxBitmap& bmp_undo, bool is_blinking, size_t rect_id = 0); bool launch_browser() const; @@ -71,7 +71,7 @@ class OG_CustomCtrl :public wxPanel std::vector<wxRect> rects_undo_icon; std::vector<wxRect> rects_undo_to_sys_icon; - wxRect rect_label; + std::vector<std::pair<wxRect, wxString>> rects_tooltip; }; std::vector<CtrlLine> ctrl_lines; diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 52c0f0bb0..dc569c8a6 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -192,6 +192,13 @@ void OptionsGroup::append_line(const Line& line) for (auto opt : option_set) m_options.emplace(opt.opt_id, opt); + //if first control don't have a label, use the line one for hte tooltip + if (option_set.front().opt.label.empty() || "_" == option_set.front().opt.label) { + wxString tooltip = _(option_set.front().opt.tooltip); + update_Slic3r_string(tooltip); + m_lines.back().label_tooltip = tooltip; + } + // add mode value for current line to m_options_mode if (!option_set.empty()){ m_line_sizer.emplace_back(); @@ -549,7 +556,14 @@ Line OptionsGroup::create_single_option_line(const Option& option, const std::st update_Slic3r_string(tooltip); Line retval{ _(option.opt.label), tooltip }; retval.label_path = path; - retval.append_option(option); + if(option.opt.label.empty()) { + retval.append_option(option); + } else { + //remove label from option + Option tmp(option); + tmp.opt.label = std::string(""); + retval.append_option(tmp); + } return retval; } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 506caa471..eafafdffb 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1915,6 +1915,7 @@ bool Tab::create_pages(std::string setting_type_name, int idx_page) bool need_to_notified_search = false; bool colored = false; + bool custom_label = false; std::string label_path; for (int i = 1; i < params.size() - 1; i++) { if (params[i] == "simple") |