mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Merge branch 'master' of https://github.com/Prusa3d/Slic3r
This commit is contained in:
		
						commit
						2b9319eea1
					
				
					 16 changed files with 206 additions and 102 deletions
				
			
		| 
						 | 
				
			
			@ -1,10 +1,10 @@
 | 
			
		|||
#include <iostream>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include <libslic3r.h>
 | 
			
		||||
#include "TriangleMesh.hpp"
 | 
			
		||||
#include "SLABasePool.hpp"
 | 
			
		||||
#include "benchmark.h"
 | 
			
		||||
#include <libslic3r/libslic3r.h>
 | 
			
		||||
#include <libslic3r/TriangleMesh.hpp>
 | 
			
		||||
#include <libslic3r/SLA/SLABasePool.hpp>
 | 
			
		||||
#include <libnest2d/tools/benchmark.h>
 | 
			
		||||
 | 
			
		||||
const std::string USAGE_STR = {
 | 
			
		||||
    "Usage: slabasebed stlfilename.stl"
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ int main(const int argc, const char *argv[]) {
 | 
			
		|||
    ExPolygons ground_slice;
 | 
			
		||||
    TriangleMesh basepool;
 | 
			
		||||
 | 
			
		||||
    sla::ground_layer(model, ground_slice, 0.1f);
 | 
			
		||||
    sla::base_plate(model, ground_slice, 0.1f);
 | 
			
		||||
 | 
			
		||||
    bench.start();
 | 
			
		||||
    sla::create_base_pool(ground_slice, basepool);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,10 @@
 | 
			
		|||
 | 
			
		||||
namespace Slic3r { namespace sla {
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
ThrowOnCancel throw_on_cancel = [](){};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Convert the triangulation output to an intermediate mesh.
 | 
			
		||||
Contour3D convert(const Polygons& triangles, coord_t z, bool dir) {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -60,9 +64,13 @@ Contour3D walls(const ExPolygon& floor_plate, const ExPolygon& ceiling,
 | 
			
		|||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    auto& thr = throw_on_cancel;
 | 
			
		||||
 | 
			
		||||
    std::for_each(tri.begin(), tri.end(),
 | 
			
		||||
                  [&rp, &rpi, &poly, &idx, is_upper, fz, cz](const Polygon& pp)
 | 
			
		||||
                  [&rp, &rpi, thr, &idx, is_upper, fz, cz](const Polygon& pp)
 | 
			
		||||
    {
 | 
			
		||||
        thr(); // may throw if cancellation was requested
 | 
			
		||||
 | 
			
		||||
        for(auto& p : pp.points)
 | 
			
		||||
            if(is_upper(p))
 | 
			
		||||
                rp.emplace_back(unscale(x(p), y(p), mm(cz)));
 | 
			
		||||
| 
						 | 
				
			
			@ -231,6 +239,8 @@ Contour3D round_edges(const ExPolygon& base_plate,
 | 
			
		|||
 | 
			
		||||
    if(degrees >= 90) {
 | 
			
		||||
        for(int i = 1; i <= steps; ++i) {
 | 
			
		||||
            throw_on_cancel();
 | 
			
		||||
 | 
			
		||||
            ob = base_plate;
 | 
			
		||||
 | 
			
		||||
            double r2 = radius_mm * radius_mm;
 | 
			
		||||
| 
						 | 
				
			
			@ -254,6 +264,7 @@ Contour3D round_edges(const ExPolygon& base_plate,
 | 
			
		|||
    int tos = int(tox / stepx);
 | 
			
		||||
 | 
			
		||||
    for(int i = 1; i <= tos; ++i) {
 | 
			
		||||
        throw_on_cancel();
 | 
			
		||||
        ob = base_plate;
 | 
			
		||||
 | 
			
		||||
        double r2 = radius_mm * radius_mm;
 | 
			
		||||
| 
						 | 
				
			
			@ -385,7 +396,7 @@ ExPolygons concave_hull(const ExPolygons& polys, double max_dist_mm = 50)
 | 
			
		|||
                   std::back_inserter(punion),
 | 
			
		||||
                   [&punion, &boxindex, cc, max_dist_mm, &idx](const Point& c)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        throw_on_cancel();
 | 
			
		||||
        double dx = x(c) - x(cc), dy = y(c) - y(cc);
 | 
			
		||||
        double l = std::sqrt(dx * dx + dy * dy);
 | 
			
		||||
        double nx = dx / l, ny = dy / l;
 | 
			
		||||
| 
						 | 
				
			
			@ -419,7 +430,7 @@ ExPolygons concave_hull(const ExPolygons& polys, double max_dist_mm = 50)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
 | 
			
		||||
                float layerh)
 | 
			
		||||
                float layerh, ThrowOnCancel thrfn)
 | 
			
		||||
{
 | 
			
		||||
    TriangleMesh m = mesh;
 | 
			
		||||
    TriangleMeshSlicer slicer(&m);
 | 
			
		||||
| 
						 | 
				
			
			@ -431,7 +442,7 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
 | 
			
		|||
        heights.emplace_back(hi);
 | 
			
		||||
 | 
			
		||||
    std::vector<ExPolygons> out; out.reserve(size_t(std::ceil(h/layerh)));
 | 
			
		||||
    slicer.slice(heights, &out, [](){});
 | 
			
		||||
    slicer.slice(heights, &out, thrfn);
 | 
			
		||||
 | 
			
		||||
    size_t count = 0; for(auto& o : out) count += o.size();
 | 
			
		||||
    ExPolygons tmp; tmp.reserve(count);
 | 
			
		||||
| 
						 | 
				
			
			@ -444,6 +455,8 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
 | 
			
		|||
void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
 | 
			
		||||
                      const PoolConfig& cfg)
 | 
			
		||||
{
 | 
			
		||||
    throw_on_cancel = cfg.throw_on_cancel;
 | 
			
		||||
 | 
			
		||||
    double mdist = 2*(1.8*cfg.min_wall_thickness_mm + 4*cfg.edge_radius_mm) +
 | 
			
		||||
                   cfg.max_merge_distance_mm;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
#define SLABASEPOOL_HPP
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
namespace Slic3r {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -11,12 +12,14 @@ class TriangleMesh;
 | 
			
		|||
namespace sla {
 | 
			
		||||
 | 
			
		||||
using ExPolygons = std::vector<ExPolygon>;
 | 
			
		||||
using ThrowOnCancel = std::function<void(void)>;
 | 
			
		||||
 | 
			
		||||
/// Calculate the polygon representing the silhouette from the specified height
 | 
			
		||||
void base_plate(const TriangleMesh& mesh,
 | 
			
		||||
                ExPolygons& output,
 | 
			
		||||
                float zlevel = 0.1f,
 | 
			
		||||
                float layerheight = 0.05f);
 | 
			
		||||
void base_plate(const TriangleMesh& mesh,       // input mesh
 | 
			
		||||
                ExPolygons& output,             // Output will be merged with
 | 
			
		||||
                float zlevel = 0.1f,            // Plate creation level
 | 
			
		||||
                float layerheight = 0.05f,      // The sampling height
 | 
			
		||||
                ThrowOnCancel thrfn = [](){});  // Will be called frequently
 | 
			
		||||
 | 
			
		||||
struct PoolConfig {
 | 
			
		||||
    double min_wall_thickness_mm = 2;
 | 
			
		||||
| 
						 | 
				
			
			@ -24,6 +27,8 @@ struct PoolConfig {
 | 
			
		|||
    double max_merge_distance_mm = 50;
 | 
			
		||||
    double edge_radius_mm = 1;
 | 
			
		||||
 | 
			
		||||
    ThrowOnCancel throw_on_cancel = [](){};
 | 
			
		||||
 | 
			
		||||
    inline PoolConfig() {}
 | 
			
		||||
    inline PoolConfig(double wt, double wh, double md, double er):
 | 
			
		||||
        min_wall_thickness_mm(wt),
 | 
			
		||||
| 
						 | 
				
			
			@ -35,8 +40,7 @@ struct PoolConfig {
 | 
			
		|||
/// Calculate the pool for the mesh for SLA printing
 | 
			
		||||
void create_base_pool(const ExPolygons& base_plate,
 | 
			
		||||
                      TriangleMesh& output_mesh,
 | 
			
		||||
                      const PoolConfig& = PoolConfig()
 | 
			
		||||
                      );
 | 
			
		||||
                      const PoolConfig& = PoolConfig());
 | 
			
		||||
 | 
			
		||||
/// TODO: Currently the base plate of the pool will have half the height of the
 | 
			
		||||
/// whole pool. So the carved out space has also half the height. This is not
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,7 +58,7 @@ struct Contour3D {
 | 
			
		|||
        points.insert(points.end(), ctr.points.begin(), ctr.points.end());
 | 
			
		||||
        indices.insert(indices.end(), ctr.indices.begin(), ctr.indices.end());
 | 
			
		||||
 | 
			
		||||
        for(auto n = s; n < indices.size(); n++) {
 | 
			
		||||
        for(size_t n = s; n < indices.size(); n++) {
 | 
			
		||||
            auto& idx = indices[n]; x(idx) += s3; y(idx) += s3; z(idx) += s3;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -515,8 +515,13 @@ struct Pad {
 | 
			
		|||
        zlevel(ground_level + sla::get_pad_elevation(pcfg))
 | 
			
		||||
    {
 | 
			
		||||
        ExPolygons basep;
 | 
			
		||||
        cfg.throw_on_cancel();
 | 
			
		||||
 | 
			
		||||
        // The 0.1f is the layer height with which the mesh is sampled and then
 | 
			
		||||
        // the layers are unified into one vector of polygons.
 | 
			
		||||
        base_plate(object_support_mesh, basep,
 | 
			
		||||
                   float(cfg.min_wall_height_mm)/*,layer_height*/);
 | 
			
		||||
                   float(cfg.min_wall_height_mm), 0.1f, pcfg.throw_on_cancel);
 | 
			
		||||
 | 
			
		||||
        for(auto& bp : baseplate) basep.emplace_back(bp);
 | 
			
		||||
 | 
			
		||||
        create_base_pool(basep, tmesh, cfg);
 | 
			
		||||
| 
						 | 
				
			
			@ -622,12 +627,19 @@ class SLASupportTree::Impl {
 | 
			
		|||
    std::vector<Junction> m_junctions;
 | 
			
		||||
    std::vector<Bridge> m_bridges;
 | 
			
		||||
    std::vector<CompactBridge> m_compact_bridges;
 | 
			
		||||
    Controller m_ctl;
 | 
			
		||||
 | 
			
		||||
    Pad m_pad;
 | 
			
		||||
    mutable TriangleMesh meshcache; mutable bool meshcache_valid;
 | 
			
		||||
    mutable double model_height = 0; // the full height of the model
 | 
			
		||||
public:
 | 
			
		||||
    double ground_level = 0;
 | 
			
		||||
 | 
			
		||||
    Impl() = default;
 | 
			
		||||
    inline Impl(const Controller& ctl): m_ctl(ctl) {}
 | 
			
		||||
 | 
			
		||||
    const Controller& ctl() const { return m_ctl; }
 | 
			
		||||
 | 
			
		||||
    template<class...Args> Head& add_head(Args&&... args) {
 | 
			
		||||
        m_heads.emplace_back(std::forward<Args>(args)...);
 | 
			
		||||
        m_heads.back().id = long(m_heads.size() - 1);
 | 
			
		||||
| 
						 | 
				
			
			@ -710,27 +722,38 @@ public:
 | 
			
		|||
        meshcache = TriangleMesh();
 | 
			
		||||
 | 
			
		||||
        for(auto& head : heads()) {
 | 
			
		||||
            if(m_ctl.stopcondition()) break;
 | 
			
		||||
            auto&& m = mesh(head.mesh);
 | 
			
		||||
            meshcache.merge(m);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for(auto& stick : pillars()) {
 | 
			
		||||
            if(m_ctl.stopcondition()) break;
 | 
			
		||||
            meshcache.merge(mesh(stick.mesh));
 | 
			
		||||
            meshcache.merge(mesh(stick.base));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for(auto& j : junctions()) {
 | 
			
		||||
            if(m_ctl.stopcondition()) break;
 | 
			
		||||
            meshcache.merge(mesh(j.mesh));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for(auto& cb : compact_bridges()) {
 | 
			
		||||
            if(m_ctl.stopcondition()) break;
 | 
			
		||||
            meshcache.merge(mesh(cb.mesh));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for(auto& bs : bridges()) {
 | 
			
		||||
            if(m_ctl.stopcondition()) break;
 | 
			
		||||
            meshcache.merge(mesh(bs.mesh));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(m_ctl.stopcondition()) {
 | 
			
		||||
            // In case of failure we have to return an empty mesh
 | 
			
		||||
            meshcache = TriangleMesh();
 | 
			
		||||
            return meshcache;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // TODO: Is this necessary?
 | 
			
		||||
        meshcache.repair();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1659,22 +1682,19 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const
 | 
			
		|||
    fullmesh.merge(get_pad());
 | 
			
		||||
    TriangleMeshSlicer slicer(&fullmesh);
 | 
			
		||||
    SlicedSupports ret;
 | 
			
		||||
    slicer.slice(heights, &ret, m_ctl.cancelfn);
 | 
			
		||||
    slicer.slice(heights, &ret, get().ctl().cancelfn);
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const TriangleMesh &SLASupportTree::add_pad(const SliceLayer& baseplate,
 | 
			
		||||
                                            double min_wall_thickness_mm,
 | 
			
		||||
                                            double min_wall_height_mm,
 | 
			
		||||
                                            double max_merge_distance_mm,
 | 
			
		||||
                                            double edge_radius_mm) const
 | 
			
		||||
                                            const PoolConfig& pcfg) const
 | 
			
		||||
{
 | 
			
		||||
    PoolConfig pcfg;
 | 
			
		||||
    pcfg.min_wall_thickness_mm = min_wall_thickness_mm;
 | 
			
		||||
    pcfg.min_wall_height_mm    = min_wall_height_mm;
 | 
			
		||||
    pcfg.max_merge_distance_mm = max_merge_distance_mm;
 | 
			
		||||
    pcfg.edge_radius_mm        = edge_radius_mm;
 | 
			
		||||
//    PoolConfig pcfg;
 | 
			
		||||
//    pcfg.min_wall_thickness_mm = min_wall_thickness_mm;
 | 
			
		||||
//    pcfg.min_wall_height_mm    = min_wall_height_mm;
 | 
			
		||||
//    pcfg.max_merge_distance_mm = max_merge_distance_mm;
 | 
			
		||||
//    pcfg.edge_radius_mm        = edge_radius_mm;
 | 
			
		||||
    return m_impl->create_pad(merged_mesh(), baseplate, pcfg).tmesh;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1687,14 +1707,14 @@ SLASupportTree::SLASupportTree(const PointSet &points,
 | 
			
		|||
                               const EigenMesh3D& emesh,
 | 
			
		||||
                               const SupportConfig &cfg,
 | 
			
		||||
                               const Controller &ctl):
 | 
			
		||||
    m_impl(new Impl()), m_ctl(ctl)
 | 
			
		||||
    m_impl(new Impl(ctl))
 | 
			
		||||
{
 | 
			
		||||
    m_impl->ground_level = emesh.ground_level - cfg.object_elevation_mm;
 | 
			
		||||
    generate(points, emesh, cfg, ctl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SLASupportTree::SLASupportTree(const SLASupportTree &c):
 | 
			
		||||
    m_impl(new Impl(*c.m_impl)), m_ctl(c.m_ctl) {}
 | 
			
		||||
    m_impl(new Impl(*c.m_impl)) {}
 | 
			
		||||
 | 
			
		||||
SLASupportTree &SLASupportTree::operator=(const SLASupportTree &c)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -69,6 +69,8 @@ struct SupportConfig {
 | 
			
		|||
    double object_elevation_mm = 10;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PoolConfig;
 | 
			
		||||
 | 
			
		||||
/// A Control structure for the support calculation. Consists of the status
 | 
			
		||||
/// indicator callback and the stop condition predicate.
 | 
			
		||||
struct Controller {
 | 
			
		||||
| 
						 | 
				
			
			@ -119,7 +121,6 @@ public:
 | 
			
		|||
class SLASupportTree {
 | 
			
		||||
    class Impl;
 | 
			
		||||
    std::unique_ptr<Impl> m_impl;
 | 
			
		||||
    Controller m_ctl;
 | 
			
		||||
 | 
			
		||||
    Impl& get() { return *m_impl; }
 | 
			
		||||
    const Impl& get() const { return *m_impl; }
 | 
			
		||||
| 
						 | 
				
			
			@ -158,10 +159,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    /// Adding the "pad" (base pool) under the supports
 | 
			
		||||
    const TriangleMesh& add_pad(const SliceLayer& baseplate,
 | 
			
		||||
                                double min_wall_thickness_mm,
 | 
			
		||||
                                double min_wall_height_mm,
 | 
			
		||||
                                double max_merge_distance_mm,
 | 
			
		||||
                                double edge_radius_mm) const;
 | 
			
		||||
                                const PoolConfig& pcfg) const;
 | 
			
		||||
 | 
			
		||||
    /// Get the pad geometry
 | 
			
		||||
    const TriangleMesh& get_pad() const;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -445,7 +445,7 @@ void SLAPrint::process()
 | 
			
		|||
 | 
			
		||||
    // Slicing the model object. This method is oversimplified and needs to
 | 
			
		||||
    // be compared with the fff slicing algorithm for verification
 | 
			
		||||
    auto slice_model = [this, ilh, ilhd](SLAPrintObject& po) {
 | 
			
		||||
    auto slice_model = [this, ilh](SLAPrintObject& po) {
 | 
			
		||||
        double lh = po.m_config.layer_height.getFloat();
 | 
			
		||||
 | 
			
		||||
        TriangleMesh mesh = po.transformed_mesh();
 | 
			
		||||
| 
						 | 
				
			
			@ -530,6 +530,11 @@ void SLAPrint::process()
 | 
			
		|||
            po.m_supportdata->support_tree_ptr.reset(
 | 
			
		||||
                        new SLASupportTree(pts, emesh, scfg, ctl));
 | 
			
		||||
 | 
			
		||||
            // Create the unified mesh
 | 
			
		||||
            auto rc = SlicingStatus::RELOAD_SCENE;
 | 
			
		||||
            set_status(-1, L("Visualizing supports"));
 | 
			
		||||
            po.m_supportdata->support_tree_ptr->merged_mesh();
 | 
			
		||||
            set_status(-1, L("Visualizing supports"), rc);
 | 
			
		||||
        } catch(sla::SLASupportsStoppedException&) {
 | 
			
		||||
            // no need to rethrow
 | 
			
		||||
            // throw_if_canceled();
 | 
			
		||||
| 
						 | 
				
			
			@ -560,18 +565,23 @@ void SLAPrint::process()
 | 
			
		|||
            auto&& trmesh = po.transformed_mesh();
 | 
			
		||||
 | 
			
		||||
            // This call can get pretty time consuming
 | 
			
		||||
            if(elevation < pad_h) sla::base_plate(trmesh, bp,
 | 
			
		||||
                                                  float(pad_h), float(lh));
 | 
			
		||||
            auto thrfn = [this](){ throw_if_canceled(); };
 | 
			
		||||
 | 
			
		||||
            po.m_supportdata->support_tree_ptr->add_pad(bp, wt, h, md, er);
 | 
			
		||||
            if(elevation < pad_h)
 | 
			
		||||
                sla::base_plate(trmesh, bp, float(pad_h), float(lh),
 | 
			
		||||
                                            thrfn);
 | 
			
		||||
 | 
			
		||||
            pcfg.throw_on_cancel = thrfn;
 | 
			
		||||
            po.m_supportdata->support_tree_ptr->add_pad(bp, pcfg);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // if the base pool (which means also the support tree) is
 | 
			
		||||
        // done, do a refresh when indicating progress. Now the
 | 
			
		||||
        // geometries for the supports and the optional base pad are
 | 
			
		||||
        // ready. We can grant access for the control thread to read
 | 
			
		||||
        // the geometries, but first we have to update the caches:
 | 
			
		||||
        po.support_mesh(); /*po->pad_mesh();*/
 | 
			
		||||
//        // if the base pool (which means also the support tree) is
 | 
			
		||||
//        // done, do a refresh when indicating progress. Now the
 | 
			
		||||
//        // geometries for the supports and the optional base pad are
 | 
			
		||||
//        // ready. We can grant access for the control thread to read
 | 
			
		||||
//        // the geometries, but first we have to update the caches:
 | 
			
		||||
//        po.support_mesh(); /*po->pad_mesh();*/
 | 
			
		||||
        po.throw_if_canceled();
 | 
			
		||||
        auto rc = SlicingStatus::RELOAD_SCENE;
 | 
			
		||||
        set_status(-1, L("Visualizing supports"), rc);
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			@ -589,9 +599,9 @@ void SLAPrint::process()
 | 
			
		|||
 | 
			
		||||
    // We have the layer polygon collection but we need to unite them into
 | 
			
		||||
    // an index where the key is the height level in discrete levels (clipper)
 | 
			
		||||
    auto index_slices = [this, ilh, ilhd](SLAPrintObject& po) {
 | 
			
		||||
    auto index_slices = [ilhd](SLAPrintObject& po) {
 | 
			
		||||
        po.m_slice_index.clear();
 | 
			
		||||
        auto sih = LevelID(scale_(ilh));
 | 
			
		||||
        auto sih = LevelID(scale_(ilhd));
 | 
			
		||||
 | 
			
		||||
        // For all print objects, go through its initial layers and place them
 | 
			
		||||
        // into the layers hash
 | 
			
		||||
| 
						 | 
				
			
			@ -635,7 +645,7 @@ void SLAPrint::process()
 | 
			
		|||
        // shortcut for empty index into the slice vectors
 | 
			
		||||
        static const auto EMPTY_SLICE = SLAPrintObject::SliceRecord::NONE;
 | 
			
		||||
        
 | 
			
		||||
        for(int i = 0; i < oslices.size(); ++i) {
 | 
			
		||||
        for(size_t i = 0; i < oslices.size(); ++i) {
 | 
			
		||||
            LevelID h = levelids[i];
 | 
			
		||||
 | 
			
		||||
            float fh = float(double(h) * SCALING_FACTOR);
 | 
			
		||||
| 
						 | 
				
			
			@ -652,7 +662,7 @@ void SLAPrint::process()
 | 
			
		|||
            po.m_supportdata->level_ids.clear();
 | 
			
		||||
            po.m_supportdata->level_ids.reserve(sslices.size());
 | 
			
		||||
 | 
			
		||||
            for(int i = 0; i < sslices.size(); ++i) {
 | 
			
		||||
            for(int i = 0; i < int(sslices.size()); ++i) {
 | 
			
		||||
                int a = i == 0 ? 0 : 1;
 | 
			
		||||
                int b = i == 0 ? 0 : i - 1;
 | 
			
		||||
                LevelID h = sminZ + a * sih + b * slh;
 | 
			
		||||
| 
						 | 
				
			
			@ -662,7 +672,7 @@ void SLAPrint::process()
 | 
			
		|||
 | 
			
		||||
                SLAPrintObject::SliceRecord& sr = po.m_slice_index[fh];
 | 
			
		||||
                assert(sr.support_slices_idx == EMPTY_SLICE);
 | 
			
		||||
                sr.support_slices_idx = i;
 | 
			
		||||
                sr.support_slices_idx = SLAPrintObject::SliceRecord::Idx(i);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			@ -670,7 +680,7 @@ void SLAPrint::process()
 | 
			
		|||
    auto& levels = m_printer_input;
 | 
			
		||||
 | 
			
		||||
    // Rasterizing the model objects, and their supports
 | 
			
		||||
    auto rasterize = [this, ilh, ilhd, max_objstatus, &levels]() {
 | 
			
		||||
    auto rasterize = [this, max_objstatus, &levels]() {
 | 
			
		||||
        if(canceled()) return;
 | 
			
		||||
 | 
			
		||||
        // clear the rasterizer input
 | 
			
		||||
| 
						 | 
				
			
			@ -688,14 +698,14 @@ void SLAPrint::process()
 | 
			
		|||
            // now merge this object's support and object slices with the rest
 | 
			
		||||
            // of the print object slices
 | 
			
		||||
 | 
			
		||||
            for(int i = 0; i < oslices.size(); ++i) {
 | 
			
		||||
            for(size_t i = 0; i < oslices.size(); ++i) {
 | 
			
		||||
                auto& lyrs = levels[gndlvl + po.m_level_ids[i]];
 | 
			
		||||
                lyrs.emplace_back(oslices[i], po.m_instances);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(!po.m_supportdata) continue;
 | 
			
		||||
            auto& sslices = po.m_supportdata->support_slices;
 | 
			
		||||
            for(int i = 0; i < sslices.size(); ++i) {
 | 
			
		||||
            for(size_t i = 0; i < sslices.size(); ++i) {
 | 
			
		||||
                auto& lyrs = levels[gndlvl + po.m_supportdata->level_ids[i]];
 | 
			
		||||
                lyrs.emplace_back(sslices[i], po.m_instances);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -713,8 +723,8 @@ void SLAPrint::process()
 | 
			
		|||
 | 
			
		||||
            double w = printcfg.display_width.getFloat();
 | 
			
		||||
            double h = printcfg.display_height.getFloat();
 | 
			
		||||
            unsigned pw = printcfg.display_pixels_x.getInt();
 | 
			
		||||
            unsigned ph = printcfg.display_pixels_y.getInt();
 | 
			
		||||
            auto pw = unsigned(printcfg.display_pixels_x.getInt());
 | 
			
		||||
            auto ph = unsigned(printcfg.display_pixels_y.getInt());
 | 
			
		||||
            double lh = ocfg.layer_height.getFloat();
 | 
			
		||||
            double exp_t = matcfg.exposure_time.getFloat();
 | 
			
		||||
            double iexp_t = matcfg.initial_exposure_time.getFloat();
 | 
			
		||||
| 
						 | 
				
			
			@ -1098,7 +1108,9 @@ TriangleMesh SLAPrintObject::get_mesh(SLAPrintObjectStep step) const
 | 
			
		|||
const TriangleMesh& SLAPrintObject::support_mesh() const
 | 
			
		||||
{
 | 
			
		||||
    if(m_config.supports_enable.getBool() && m_supportdata &&
 | 
			
		||||
       m_supportdata->support_tree_ptr) return m_supportdata->support_tree_ptr->merged_mesh();
 | 
			
		||||
       m_supportdata->support_tree_ptr) {
 | 
			
		||||
        return m_supportdata->support_tree_ptr->merged_mesh();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return EMPTY_MESH;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,7 +74,16 @@ void Field::on_kill_focus(wxEvent& event)
 | 
			
		|||
	event.Skip();
 | 
			
		||||
	// call the registered function if it is available
 | 
			
		||||
    if (m_on_kill_focus!=nullptr) 
 | 
			
		||||
        m_on_kill_focus();
 | 
			
		||||
        m_on_kill_focus(m_opt_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Field::on_set_focus(wxEvent& event)
 | 
			
		||||
{
 | 
			
		||||
    // to allow the default behavior
 | 
			
		||||
	event.Skip();
 | 
			
		||||
	// call the registered function if it is available
 | 
			
		||||
    if (m_on_set_focus!=nullptr) 
 | 
			
		||||
        m_on_set_focus(m_opt_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Field::on_change_field()
 | 
			
		||||
| 
						 | 
				
			
			@ -125,9 +134,9 @@ void Field::get_value_by_opt_type(wxString& str)
 | 
			
		|||
	case coPercents:
 | 
			
		||||
	case coFloats:
 | 
			
		||||
	case coFloat:{
 | 
			
		||||
		if (m_opt.type == coPercent && str.Last() == '%') 
 | 
			
		||||
		if (m_opt.type == coPercent && !str.IsEmpty() &&  str.Last() == '%') 
 | 
			
		||||
			str.RemoveLast();
 | 
			
		||||
		else if (str.Last() == '%')	{
 | 
			
		||||
		else if (!str.IsEmpty() && str.Last() == '%')	{
 | 
			
		||||
			wxString label = m_Label->GetLabel();
 | 
			
		||||
			if		(label.Last() == '\n')	label.RemoveLast();
 | 
			
		||||
			while	(label.Last() == ' ')	label.RemoveLast();
 | 
			
		||||
| 
						 | 
				
			
			@ -162,7 +171,7 @@ void Field::get_value_by_opt_type(wxString& str)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TextCtrl::is_defined_input_value()
 | 
			
		||||
bool TextCtrl::is_defined_input_value() const 
 | 
			
		||||
{
 | 
			
		||||
    if (static_cast<wxTextCtrl*>(window)->GetValue().empty() && m_opt.type != coString && m_opt.type != coStrings)
 | 
			
		||||
        return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -216,11 +225,13 @@ void TextCtrl::BUILD() {
 | 
			
		|||
		break; 
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    const long style = m_opt.multiline ? wxTE_MULTILINE : 0 | m_process_enter ? wxTE_PROCESS_ENTER : 0;
 | 
			
		||||
    const long style = m_opt.multiline ? wxTE_MULTILINE : 0;
 | 
			
		||||
	auto temp = new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, style);
 | 
			
		||||
 | 
			
		||||
	temp->SetToolTip(get_tooltip_text(text_value));
 | 
			
		||||
 | 
			
		||||
    temp->Bind(wxEVT_SET_FOCUS, ([this](wxEvent& e) { on_set_focus(e); }), temp->GetId());
 | 
			
		||||
    
 | 
			
		||||
	temp->Bind(wxEVT_LEFT_DOWN, ([temp](wxEvent& event)
 | 
			
		||||
	{
 | 
			
		||||
		//! to allow the default handling
 | 
			
		||||
| 
						 | 
				
			
			@ -240,17 +251,13 @@ void TextCtrl::BUILD() {
 | 
			
		|||
		e.Skip();
 | 
			
		||||
		temp->GetToolTip()->Enable(true);
 | 
			
		||||
#endif // __WXGTK__
 | 
			
		||||
        if (!is_defined_input_value()) 
 | 
			
		||||
//         if (!is_defined_input_value()) 
 | 
			
		||||
        if (is_defined_input_value())
 | 
			
		||||
            on_change_field();
 | 
			
		||||
        else
 | 
			
		||||
            on_kill_focus(e);
 | 
			
		||||
	}), temp->GetId());
 | 
			
		||||
 | 
			
		||||
    if (m_process_enter) {
 | 
			
		||||
        temp->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent& evt) {
 | 
			
		||||
            if(is_defined_input_value()) 
 | 
			
		||||
                on_change_field();
 | 
			
		||||
        }), temp->GetId());
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
    /*
 | 
			
		||||
        temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent& evt)
 | 
			
		||||
        {
 | 
			
		||||
#ifdef __WXGTK__
 | 
			
		||||
| 
						 | 
				
			
			@ -267,8 +274,7 @@ void TextCtrl::BUILD() {
 | 
			
		|||
        temp->Bind(wxEVT_KEY_DOWN, &TextCtrl::change_field_value, this);
 | 
			
		||||
        temp->Bind(wxEVT_KEY_UP, &TextCtrl::change_field_value, this);
 | 
			
		||||
#endif //__WXGTK__
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
	// select all text using Ctrl+A
 | 
			
		||||
	temp->Bind(wxEVT_CHAR, ([temp](wxKeyEvent& event)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -371,7 +377,15 @@ void SpinCtrl::BUILD() {
 | 
			
		|||
		0, min_val, max_val, default_value);
 | 
			
		||||
 | 
			
		||||
// 	temp->Bind(wxEVT_SPINCTRL, ([this](wxCommandEvent e) { tmp_value = undef_spin_val; on_change_field(); }), temp->GetId());
 | 
			
		||||
	temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { on_kill_focus(e); }), temp->GetId());
 | 
			
		||||
	temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e)
 | 
			
		||||
	{
 | 
			
		||||
        if (tmp_value < 0)
 | 
			
		||||
	        on_kill_focus(e);
 | 
			
		||||
        else {
 | 
			
		||||
            e.Skip();
 | 
			
		||||
            on_change_field();
 | 
			
		||||
        }
 | 
			
		||||
	}), temp->GetId());
 | 
			
		||||
	temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e)
 | 
			
		||||
	{
 | 
			
		||||
// 		# On OSX / Cocoa, wxSpinCtrl::GetValue() doesn't return the new value
 | 
			
		||||
| 
						 | 
				
			
			@ -382,7 +396,8 @@ void SpinCtrl::BUILD() {
 | 
			
		|||
		std::string value = e.GetString().utf8_str().data();
 | 
			
		||||
		if (is_matched(value, "^\\d+$"))
 | 
			
		||||
			tmp_value = std::stoi(value);
 | 
			
		||||
		on_change_field();
 | 
			
		||||
        else tmp_value = -9999;
 | 
			
		||||
// 		on_change_field();
 | 
			
		||||
// 		# We don't reset tmp_value here because _on_change might put callbacks
 | 
			
		||||
// 		# in the CallAfter queue, and we want the tmp value to be available from
 | 
			
		||||
// 		# them as well.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,8 +29,8 @@ namespace Slic3r { namespace GUI {
 | 
			
		|||
 | 
			
		||||
class Field;
 | 
			
		||||
using t_field = std::unique_ptr<Field>;
 | 
			
		||||
using t_kill_focus = std::function<void()>;
 | 
			
		||||
using t_change = std::function<void(t_config_option_key, const boost::any&)>;
 | 
			
		||||
using t_kill_focus = std::function<void(const std::string&)>;
 | 
			
		||||
using t_change = std::function<void(const t_config_option_key&, const boost::any&)>;
 | 
			
		||||
using t_back_to_init = std::function<void(const std::string&)>;
 | 
			
		||||
 | 
			
		||||
wxString double_to_string(double const value, const int max_precision = 4);
 | 
			
		||||
| 
						 | 
				
			
			@ -76,6 +76,8 @@ protected:
 | 
			
		|||
	//! in another case we can't unfocused control at all
 | 
			
		||||
	void			on_kill_focus(wxEvent& event);
 | 
			
		||||
    /// Call the attached on_change method. 
 | 
			
		||||
    void			on_set_focus(wxEvent& event);
 | 
			
		||||
    /// Call the attached on_change method. 
 | 
			
		||||
    void			on_change_field();
 | 
			
		||||
    /// Call the attached m_back_to_initial_value method. 
 | 
			
		||||
	void			on_back_to_initial_value();
 | 
			
		||||
| 
						 | 
				
			
			@ -89,6 +91,9 @@ public:
 | 
			
		|||
    /// Function object to store callback passed in from owning object.
 | 
			
		||||
	t_kill_focus	m_on_kill_focus {nullptr};
 | 
			
		||||
 | 
			
		||||
    /// Function object to store callback passed in from owning object.
 | 
			
		||||
	t_kill_focus	m_on_set_focus {nullptr};
 | 
			
		||||
 | 
			
		||||
    /// Function object to store callback passed in from owning object.
 | 
			
		||||
	t_change		m_on_change {nullptr};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -139,10 +144,9 @@ public:
 | 
			
		|||
 | 
			
		||||
    /// Factory method for generating new derived classes.
 | 
			
		||||
    template<class T>
 | 
			
		||||
    static t_field Create(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id, const bool process_enter = false)// interface for creating shared objects
 | 
			
		||||
    static t_field Create(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id)// interface for creating shared objects
 | 
			
		||||
    {
 | 
			
		||||
        auto p = Slic3r::make_unique<T>(parent, opt, id);
 | 
			
		||||
        p->m_process_enter = process_enter;
 | 
			
		||||
        p->PostInitialize();
 | 
			
		||||
		return std::move(p); //!p;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -223,9 +227,6 @@ protected:
 | 
			
		|||
	// current value
 | 
			
		||||
	boost::any			m_value;
 | 
			
		||||
    
 | 
			
		||||
    //this variable shows a mode of a call of the on_change function
 | 
			
		||||
    bool                m_process_enter { false };
 | 
			
		||||
 | 
			
		||||
	friend class OptionsGroup;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -265,7 +266,7 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
	boost::any&		get_value() override;
 | 
			
		||||
    bool            is_defined_input_value();
 | 
			
		||||
    bool            is_defined_input_value() const ;
 | 
			
		||||
    
 | 
			
		||||
    virtual void	enable();
 | 
			
		||||
    virtual void	disable();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -971,6 +971,8 @@ public:
 | 
			
		|||
    void viewport_changed();
 | 
			
		||||
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
 | 
			
		||||
 | 
			
		||||
    void handle_sidebar_focus_event(const std::string& opt_key) {}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool _is_shown_on_screen() const;
 | 
			
		||||
    void _force_zoom_to_bed();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -453,7 +453,6 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
 | 
			
		|||
    obj->SetText(wxString::Format("%d", m_objects_model->GetVolumeIdByItem(item)));
 | 
			
		||||
    event.SetDataObject(obj);
 | 
			
		||||
    event.SetDragFlags(/*wxDrag_AllowMove*/wxDrag_DefaultMove); // allows both copy and move;
 | 
			
		||||
    printf("BeginDrag\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ObjectList::OnDropPossible(wxDataViewEvent &event)
 | 
			
		||||
| 
						 | 
				
			
			@ -464,7 +463,6 @@ void ObjectList::OnDropPossible(wxDataViewEvent &event)
 | 
			
		|||
    if (event.GetDataFormat() != wxDF_UNICODETEXT || item.IsOk() && 
 | 
			
		||||
        (m_objects_model->GetParent(item) == wxDataViewItem(0) || m_objects_model->GetItemType(item) != itVolume))
 | 
			
		||||
        event.Veto();
 | 
			
		||||
    printf("DropPossible\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ObjectList::OnDrop(wxDataViewEvent &event)
 | 
			
		||||
| 
						 | 
				
			
			@ -477,13 +475,14 @@ void ObjectList::OnDrop(wxDataViewEvent &event)
 | 
			
		|||
        event.Veto();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    printf("Drop\n");
 | 
			
		||||
 | 
			
		||||
    wxTextDataObject obj;
 | 
			
		||||
    obj.SetData(wxDF_UNICODETEXT, event.GetDataSize(), event.GetDataBuffer());
 | 
			
		||||
    printf("Drop\n");
 | 
			
		||||
 | 
			
		||||
    int from_volume_id = std::stoi(obj.GetText().ToStdString());
 | 
			
		||||
    int to_volume_id = m_objects_model->GetVolumeIdByItem(item);
 | 
			
		||||
    printf("from %d to %d\n", from_volume_id, to_volume_id);
 | 
			
		||||
 | 
			
		||||
#ifdef __WXGTK__
 | 
			
		||||
    /* Under GTK, DnD moves an item between another two items.
 | 
			
		||||
| 
						 | 
				
			
			@ -498,10 +497,12 @@ void ObjectList::OnDrop(wxDataViewEvent &event)
 | 
			
		|||
    int cnt = 0;
 | 
			
		||||
    for (int id = from_volume_id; cnt < abs(from_volume_id - to_volume_id); id += delta, cnt++)
 | 
			
		||||
        std::swap(volumes[id], volumes[id + delta]);
 | 
			
		||||
    printf("Volumes are swapped\n");
 | 
			
		||||
 | 
			
		||||
    select_item(m_objects_model->ReorganizeChildren(from_volume_id, to_volume_id,
 | 
			
		||||
                                                    m_objects_model->GetParent(item)));
 | 
			
		||||
 | 
			
		||||
    printf("ItemChildren are Reorganized\n");
 | 
			
		||||
    m_parts_changed = true;
 | 
			
		||||
    parts_changed(m_selected_object_id);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,9 +21,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
 | 
			
		|||
    m_og->set_name(_(L("Object Manipulation")));
 | 
			
		||||
    m_og->label_width = 100;
 | 
			
		||||
    m_og->set_grid_vgap(5);
 | 
			
		||||
    m_og->set_process_enter(); // We need to update new values only after press ENTER 
 | 
			
		||||
    
 | 
			
		||||
    m_og->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
 | 
			
		||||
    m_og->m_on_change = [this](const std::string& opt_key, const boost::any& value) {
 | 
			
		||||
        std::vector<std::string> axes{ "_x", "_y", "_z" };
 | 
			
		||||
 | 
			
		||||
        if (opt_key == "scale_unit") {
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +53,29 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
 | 
			
		|||
            change_scale_value(new_value);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    m_og->m_fill_empty_value = [this](const std::string& opt_key)
 | 
			
		||||
    {
 | 
			
		||||
        if (opt_key == "scale_unit")
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        std::string param;
 | 
			
		||||
        std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param)); 
 | 
			
		||||
        if (param == "position") {
 | 
			
		||||
            int axis = opt_key.back() == 'x' ? 0 :
 | 
			
		||||
                       opt_key.back() == 'y' ? 1 : 2;
 | 
			
		||||
 | 
			
		||||
            m_og->set_value(opt_key, double_to_string(cache_position(axis)));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        m_og->set_value(opt_key, double_to_string(0.0));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    m_og->m_set_focus = [this](const std::string& opt_key)
 | 
			
		||||
    {
 | 
			
		||||
        wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ConfigOptionDef def;
 | 
			
		||||
 | 
			
		||||
    // Objects(sub-objects) name
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ protected:
 | 
			
		|||
    wxWindow* m_parent;
 | 
			
		||||
public:
 | 
			
		||||
    OG_Settings(wxWindow* parent, const bool staticbox);
 | 
			
		||||
    ~OG_Settings() {}
 | 
			
		||||
    virtual ~OG_Settings() {}
 | 
			
		||||
 | 
			
		||||
    virtual bool        IsShown();
 | 
			
		||||
    virtual void        Show(const bool show);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,7 +44,7 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
 | 
			
		|||
			case coPercents:
 | 
			
		||||
			case coString:
 | 
			
		||||
			case coStrings:
 | 
			
		||||
				m_fields.emplace(id, std::move(TextCtrl::Create<TextCtrl>(parent(), opt, id, process_enter)));
 | 
			
		||||
				m_fields.emplace(id, std::move(TextCtrl::Create<TextCtrl>(parent(), opt, id)));
 | 
			
		||||
                break;
 | 
			
		||||
			case coBool:
 | 
			
		||||
			case coBools:
 | 
			
		||||
| 
						 | 
				
			
			@ -67,16 +67,21 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
 | 
			
		|||
    }
 | 
			
		||||
    // Grab a reference to fields for convenience
 | 
			
		||||
    const t_field& field = m_fields[id];
 | 
			
		||||
	field->m_on_change = [this](std::string opt_id, boost::any value) {
 | 
			
		||||
	field->m_on_change = [this](const std::string& opt_id, const boost::any& value) {
 | 
			
		||||
			//! This function will be called from Field.					
 | 
			
		||||
			//! Call OptionGroup._on_change(...)
 | 
			
		||||
			if (!m_disabled) 
 | 
			
		||||
				this->on_change_OG(opt_id, value);
 | 
			
		||||
	};
 | 
			
		||||
	field->m_on_kill_focus = [this]() {
 | 
			
		||||
    field->m_on_kill_focus = [this](const std::string& opt_id) {
 | 
			
		||||
			//! This function will be called from Field.					
 | 
			
		||||
			if (!m_disabled) 
 | 
			
		||||
				this->on_kill_focus();
 | 
			
		||||
				this->on_kill_focus(opt_id);
 | 
			
		||||
	};
 | 
			
		||||
    field->m_on_set_focus = [this](const std::string& opt_id) {
 | 
			
		||||
			//! This function will be called from Field.					
 | 
			
		||||
			if (!m_disabled) 
 | 
			
		||||
				this->on_set_focus(opt_id);
 | 
			
		||||
	};
 | 
			
		||||
    field->m_parent = parent();
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			@ -277,6 +282,12 @@ Line OptionsGroup::create_single_option_line(const Option& option) const {
 | 
			
		|||
    return retval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OptionsGroup::on_set_focus(const std::string& opt_key)
 | 
			
		||||
{
 | 
			
		||||
    if (m_set_focus != nullptr)
 | 
			
		||||
        m_set_focus(opt_key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OptionsGroup::on_change_OG(const t_config_option_key& opt_id, const boost::any& value) {
 | 
			
		||||
	if (m_on_change != nullptr)
 | 
			
		||||
		m_on_change(opt_id, value);
 | 
			
		||||
| 
						 | 
				
			
			@ -378,6 +389,15 @@ void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config,
 | 
			
		|||
	on_change_OG(opt_key, get_value(opt_key));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigOptionsGroup::on_kill_focus(const std::string& opt_key)
 | 
			
		||||
{
 | 
			
		||||
    if (m_fill_empty_value) {
 | 
			
		||||
        m_fill_empty_value(opt_key);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    reload_config();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigOptionsGroup::reload_config() {
 | 
			
		||||
	for (t_opt_map::iterator it = m_opt_map.begin(); it != m_opt_map.end(); ++it) {
 | 
			
		||||
		auto opt_id = it->first;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -85,7 +85,9 @@ public:
 | 
			
		|||
    size_t			label_width {200};
 | 
			
		||||
    wxSizer*		sizer {nullptr};
 | 
			
		||||
    column_t		extra_column {nullptr};
 | 
			
		||||
    t_change		m_on_change {nullptr};
 | 
			
		||||
    t_change		m_on_change { nullptr };
 | 
			
		||||
    t_kill_focus    m_fill_empty_value { nullptr };
 | 
			
		||||
    t_kill_focus    m_set_focus { nullptr };
 | 
			
		||||
	std::function<DynamicPrintConfig()>	m_get_initial_config{ nullptr };
 | 
			
		||||
	std::function<DynamicPrintConfig()>	m_get_sys_config{ nullptr };
 | 
			
		||||
	std::function<bool()>	have_sys_config{ nullptr };
 | 
			
		||||
| 
						 | 
				
			
			@ -94,8 +96,6 @@ public:
 | 
			
		|||
    wxFont			label_font {wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) };
 | 
			
		||||
	int				sidetext_width{ -1 };
 | 
			
		||||
 | 
			
		||||
    bool            process_enter { false };
 | 
			
		||||
 | 
			
		||||
    /// Returns a copy of the pointer of the parent wxWindow.
 | 
			
		||||
    /// Accessor function is because users are not allowed to change the parent
 | 
			
		||||
    /// but defining it as const means a lot of const_casts to deal with wx functions.
 | 
			
		||||
| 
						 | 
				
			
			@ -154,11 +154,6 @@ public:
 | 
			
		|||
		                m_show_modified_btns = show;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The controls inside this option group will generate the event wxEVT_TEXT_ENTER
 | 
			
		||||
    void            set_process_enter() { 
 | 
			
		||||
                        process_enter = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	OptionsGroup(	wxWindow* _parent, const wxString& title, bool is_tab_opt = false, 
 | 
			
		||||
					column_t extra_clmn = nullptr) :
 | 
			
		||||
					m_parent(_parent), title(title), 
 | 
			
		||||
| 
						 | 
				
			
			@ -215,7 +210,8 @@ protected:
 | 
			
		|||
	const t_field&		build_field(const Option& opt, wxStaticText* label = nullptr);
 | 
			
		||||
	void				add_undo_buttuns_to_sizer(wxSizer* sizer, const t_field& field);
 | 
			
		||||
 | 
			
		||||
    virtual void		on_kill_focus () {};
 | 
			
		||||
    virtual void		on_kill_focus(const std::string& opt_key) {};
 | 
			
		||||
	virtual void		on_set_focus(const std::string& opt_key);
 | 
			
		||||
	virtual void		on_change_OG(const t_config_option_key& opt_id, const boost::any& value);
 | 
			
		||||
	virtual void		back_to_initial_value(const std::string& opt_key) {}
 | 
			
		||||
	virtual void		back_to_sys_value(const std::string& opt_key) {}
 | 
			
		||||
| 
						 | 
				
			
			@ -251,7 +247,7 @@ public:
 | 
			
		|||
	void		back_to_initial_value(const std::string& opt_key) override;
 | 
			
		||||
	void		back_to_sys_value(const std::string& opt_key) override;
 | 
			
		||||
	void		back_to_config_value(const DynamicPrintConfig& config, const std::string& opt_key);
 | 
			
		||||
	void		on_kill_focus() override{ reload_config();}
 | 
			
		||||
    void		on_kill_focus(const std::string& opt_key) override;// { reload_config(); }
 | 
			
		||||
	void		reload_config();
 | 
			
		||||
    // return value shows visibility : false => all options are hidden
 | 
			
		||||
    void        Hide();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -270,7 +270,7 @@ Slic3r::GUI::PageShp Tab::add_options_page(const wxString& title, const std::str
 | 
			
		|||
	auto panel = this;
 | 
			
		||||
#endif
 | 
			
		||||
	PageShp page(new Page(panel, title, icon_idx));
 | 
			
		||||
	page->SetScrollbars(1, 1, 1, 1);
 | 
			
		||||
	page->SetScrollbars(1, 1, 1, 2);
 | 
			
		||||
	page->Hide();
 | 
			
		||||
	m_hsizer->Add(page.get(), 1, wxEXPAND | wxLEFT, 5);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue