mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master' into ys_printable_property
This commit is contained in:
		
						commit
						825446d145
					
				
					 22 changed files with 241 additions and 150 deletions
				
			
		| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
#include "libslic3r.h"
 | 
			
		||||
#include "I18N.hpp"
 | 
			
		||||
#include "GCode.hpp"
 | 
			
		||||
#include "ExtrusionEntity.hpp"
 | 
			
		||||
#include "EdgeGrid.hpp"
 | 
			
		||||
| 
						 | 
				
			
			@ -36,6 +37,11 @@
 | 
			
		|||
 | 
			
		||||
namespace Slic3r {
 | 
			
		||||
 | 
			
		||||
//! macro used to mark string used at localization,
 | 
			
		||||
//! return same string
 | 
			
		||||
#define L(s) (s)
 | 
			
		||||
#define _(s) Slic3r::I18N::translate(s)
 | 
			
		||||
 | 
			
		||||
// Only add a newline in case the current G-code does not end with a newline.
 | 
			
		||||
static inline void check_add_eol(std::string &gcode)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -405,7 +411,8 @@ std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id,
 | 
			
		|||
	assert(m_layer_idx >= 0 && size_t(m_layer_idx) <= m_tool_changes.size());
 | 
			
		||||
    if (! m_brim_done || gcodegen.writer().need_toolchange(extruder_id) || finish_layer) {
 | 
			
		||||
		if (m_layer_idx < (int)m_tool_changes.size()) {
 | 
			
		||||
			assert(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size());
 | 
			
		||||
			if (! (size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size()))
 | 
			
		||||
                throw std::runtime_error("Wipe tower generation failed, possibly due to empty first layer.");
 | 
			
		||||
			gcode += append_tcr(gcodegen, m_tool_changes[m_layer_idx][m_tool_change_idx++], extruder_id);
 | 
			
		||||
		}
 | 
			
		||||
        m_brim_done = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -448,6 +455,17 @@ std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObjec
 | 
			
		|||
                -- idx_object_layer;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Let's make sure that the last layer is not empty, so we don't build on top of it.
 | 
			
		||||
        if (! layers_to_print.empty()
 | 
			
		||||
         && ((layer_to_print.object_layer && layer_to_print.object_layer->has_extrusions())
 | 
			
		||||
          || (layer_to_print.support_layer && layer_to_print.support_layer->has_extrusions()))
 | 
			
		||||
         && (! layers_to_print.back().object_layer  || ! layers_to_print.back().object_layer->has_extrusions())
 | 
			
		||||
         && (! layers_to_print.back().support_layer || ! layers_to_print.back().support_layer->has_extrusions()))
 | 
			
		||||
            throw std::runtime_error(_(L("Empty layers detected, the output would not be printable.")) + "\n\n" +
 | 
			
		||||
                                     _(L("Object name: ")) + object.model_object()->name + "\n" + _(L("Print z: ")) +
 | 
			
		||||
                                     std::to_string(layers_to_print.back().print_z()));
 | 
			
		||||
 | 
			
		||||
        layers_to_print.emplace_back(layer_to_print);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1138,9 +1156,9 @@ void GCode::_do_export(Print &print, FILE *file)
 | 
			
		|||
    print.m_print_statistics.clear();
 | 
			
		||||
    print.m_print_statistics.estimated_normal_print_time = m_normal_time_estimator.get_time_dhms();
 | 
			
		||||
    print.m_print_statistics.estimated_silent_print_time = m_silent_time_estimator_enabled ? m_silent_time_estimator.get_time_dhms() : "N/A";
 | 
			
		||||
    print.m_print_statistics.estimated_normal_color_print_times = m_normal_time_estimator.get_color_times_dhms();
 | 
			
		||||
    print.m_print_statistics.estimated_normal_color_print_times = m_normal_time_estimator.get_color_times_dhms(true);
 | 
			
		||||
    if (m_silent_time_estimator_enabled)
 | 
			
		||||
        print.m_print_statistics.estimated_silent_color_print_times = m_silent_time_estimator.get_color_times_dhms();
 | 
			
		||||
        print.m_print_statistics.estimated_silent_color_print_times = m_silent_time_estimator.get_color_times_dhms(true);
 | 
			
		||||
 | 
			
		||||
    std::vector<Extruder> extruders = m_writer.extruders();
 | 
			
		||||
    if (! extruders.empty()) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -78,8 +78,13 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
 | 
			
		|||
                zs.emplace_back(layer->print_z);
 | 
			
		||||
            for (auto layer : object->support_layers())
 | 
			
		||||
                zs.emplace_back(layer->print_z);
 | 
			
		||||
            if (! object->layers().empty())
 | 
			
		||||
                object_bottom_z = object->layers().front()->print_z - object->layers().front()->height;
 | 
			
		||||
 | 
			
		||||
            // Find first object layer that is not empty and save its print_z
 | 
			
		||||
            for (const Layer* layer : object->layers())
 | 
			
		||||
                if (layer->has_extrusions()) {
 | 
			
		||||
                    object_bottom_z = layer->print_z - layer->height;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
        this->initialize_layers(zs);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -324,6 +329,7 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_
 | 
			
		|||
						m_layer_tools[j].has_wipe_tower = true;
 | 
			
		||||
					} else {
 | 
			
		||||
						LayerTools <_extra = *m_layer_tools.insert(m_layer_tools.begin() + j, lt_new);
 | 
			
		||||
                        //LayerTools <_prev  = m_layer_tools[j];
 | 
			
		||||
                        LayerTools <_next  = m_layer_tools[j + 1];
 | 
			
		||||
                        assert(! m_layer_tools[j - 1].extruders.empty() && ! lt_next.extruders.empty());
 | 
			
		||||
                        // FIXME: Following assert tripped when running combine_infill.t. I decided to comment it out for now.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1242,6 +1242,8 @@ void WipeTower::generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &
 | 
			
		|||
    for (auto& used : m_used_filament_length) // reset used filament stats
 | 
			
		||||
        used = 0.f;
 | 
			
		||||
 | 
			
		||||
    m_old_temperature = -1; // reset last temperature written in the gcode
 | 
			
		||||
 | 
			
		||||
    std::vector<WipeTower::ToolChangeResult> layer_result;
 | 
			
		||||
	for (auto layer : m_plan)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -694,22 +694,39 @@ namespace Slic3r {
 | 
			
		|||
        return m_color_times;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::vector<std::string> GCodeTimeEstimator::get_color_times_dhms() const
 | 
			
		||||
    std::vector<std::string> GCodeTimeEstimator::get_color_times_dhms(bool include_remaining) const
 | 
			
		||||
    {
 | 
			
		||||
        std::vector<std::string> ret;
 | 
			
		||||
        float total_time = 0.0f;
 | 
			
		||||
        for (float t : m_color_times)
 | 
			
		||||
        {
 | 
			
		||||
            ret.push_back(_get_time_dhms(t));
 | 
			
		||||
            std::string time = _get_time_dhms(t);
 | 
			
		||||
            if (include_remaining)
 | 
			
		||||
            {
 | 
			
		||||
                time += " (";
 | 
			
		||||
                time += _get_time_dhms(m_time - total_time);
 | 
			
		||||
                time += ")";
 | 
			
		||||
            }
 | 
			
		||||
            total_time += t;
 | 
			
		||||
            ret.push_back(time);
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::vector<std::string> GCodeTimeEstimator::get_color_times_minutes() const
 | 
			
		||||
    std::vector<std::string> GCodeTimeEstimator::get_color_times_minutes(bool include_remaining) const
 | 
			
		||||
    {
 | 
			
		||||
        std::vector<std::string> ret;
 | 
			
		||||
        float total_time = 0.0f;
 | 
			
		||||
        for (float t : m_color_times)
 | 
			
		||||
        {
 | 
			
		||||
            ret.push_back(_get_time_minutes(t));
 | 
			
		||||
            std::string time = _get_time_minutes(t);
 | 
			
		||||
            if (include_remaining)
 | 
			
		||||
            {
 | 
			
		||||
                time += " (";
 | 
			
		||||
                time += _get_time_minutes(m_time - total_time);
 | 
			
		||||
                time += ")";
 | 
			
		||||
            }
 | 
			
		||||
            total_time += t;
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -346,14 +346,16 @@ namespace Slic3r {
 | 
			
		|||
        // Returns the estimated time, in minutes (integer)
 | 
			
		||||
        std::string get_time_minutes() const;
 | 
			
		||||
 | 
			
		||||
       // Returns the estimated time, in seconds, for each color
 | 
			
		||||
        // Returns the estimated time, in seconds, for each color
 | 
			
		||||
        std::vector<float> get_color_times() const;
 | 
			
		||||
 | 
			
		||||
        // Returns the estimated time, in format DDd HHh MMm SSs, for each color
 | 
			
		||||
        std::vector<std::string> get_color_times_dhms() const;
 | 
			
		||||
        // If include_remaining==true the strings will be formatted as: "time for color (remaining time at color start)"
 | 
			
		||||
        std::vector<std::string> get_color_times_dhms(bool include_remaining) const;
 | 
			
		||||
 | 
			
		||||
        // Returns the estimated time, in minutes (integer), for each color
 | 
			
		||||
        std::vector<std::string> get_color_times_minutes() const;
 | 
			
		||||
        // If include_remaining==true the strings will be formatted as: "time for color (remaining time at color start)"
 | 
			
		||||
        std::vector<std::string> get_color_times_minutes(bool include_remaining) const;
 | 
			
		||||
 | 
			
		||||
        // Return an estimate of the memory consumed by the time estimator.
 | 
			
		||||
        size_t memory_used() const;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -99,8 +99,7 @@ Model Model::read_from_file(const std::string &input_file, DynamicPrintConfig *c
 | 
			
		|||
        result = load_stl(input_file.c_str(), &model);
 | 
			
		||||
    else if (boost::algorithm::iends_with(input_file, ".obj"))
 | 
			
		||||
        result = load_obj(input_file.c_str(), &model);
 | 
			
		||||
    else if (!boost::algorithm::iends_with(input_file, ".zip.amf") && (boost::algorithm::iends_with(input_file, ".amf") ||
 | 
			
		||||
        boost::algorithm::iends_with(input_file, ".amf.xml")))
 | 
			
		||||
    else if (boost::algorithm::iends_with(input_file, ".amf") || boost::algorithm::iends_with(input_file, ".amf.xml"))
 | 
			
		||||
        result = load_amf(input_file.c_str(), config, &model);
 | 
			
		||||
    else if (boost::algorithm::iends_with(input_file, ".3mf"))
 | 
			
		||||
        result = load_3mf(input_file.c_str(), config, &model);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1723,7 +1723,7 @@ void Print::_make_wipe_tower()
 | 
			
		|||
                    break;
 | 
			
		||||
                lt.has_support = true;
 | 
			
		||||
                // Insert the new support layer.
 | 
			
		||||
                double height    = lt.print_z - m_wipe_tower_data.tool_ordering.layer_tools()[i-1].print_z;
 | 
			
		||||
                double height    = lt.print_z - (i == 0 ? 0. : m_wipe_tower_data.tool_ordering.layer_tools()[i-1].print_z);
 | 
			
		||||
                //FIXME the support layer ID is set to -1, as Vojtech hopes it is not being used anyway.
 | 
			
		||||
                it_layer = m_objects.front()->insert_support_layer(it_layer, -1, height, lt.print_z, lt.print_z - 0.5 * height);
 | 
			
		||||
                ++ it_layer;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -422,6 +422,7 @@ void PrintConfigDef::init_fff_params()
 | 
			
		|||
    def->cli = "bottom-fill-pattern|external-fill-pattern|solid-fill-pattern";
 | 
			
		||||
    def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
 | 
			
		||||
    def->enum_values = def_top_fill_pattern->enum_values;
 | 
			
		||||
    def->enum_labels = def_top_fill_pattern->enum_labels;
 | 
			
		||||
    def->aliases = def_top_fill_pattern->aliases;
 | 
			
		||||
    def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipRectilinear));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,10 +22,10 @@ namespace Slic3r {
 | 
			
		|||
namespace GUI {
 | 
			
		||||
 | 
			
		||||
const double Camera::DefaultDistance = 1000.0;
 | 
			
		||||
double Camera::FrustrumMinZSize = 50.0;
 | 
			
		||||
double Camera::FrustrumMinZRange = 50.0;
 | 
			
		||||
double Camera::FrustrumMinNearZ = 100.0;
 | 
			
		||||
double Camera::FrustrumZMargin = 10.0;
 | 
			
		||||
double Camera::FovMinDeg = 0.5;
 | 
			
		||||
double Camera::FovMaxDeg = 75.0;
 | 
			
		||||
double Camera::MaxFovDeg = 60.0;
 | 
			
		||||
 | 
			
		||||
Camera::Camera()
 | 
			
		||||
    : phi(45.0f)
 | 
			
		||||
| 
						 | 
				
			
			@ -186,7 +186,8 @@ void Camera::apply_view_matrix() const
 | 
			
		|||
 | 
			
		||||
void Camera::apply_projection(const BoundingBoxf3& box) const
 | 
			
		||||
{
 | 
			
		||||
    m_distance = DefaultDistance;
 | 
			
		||||
    set_distance(DefaultDistance);
 | 
			
		||||
 | 
			
		||||
    double w = 0.0;
 | 
			
		||||
    double h = 0.0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -194,15 +195,14 @@ void Camera::apply_projection(const BoundingBoxf3& box) const
 | 
			
		|||
    {
 | 
			
		||||
        m_frustrum_zs = calc_tight_frustrum_zs_around(box);
 | 
			
		||||
 | 
			
		||||
        w = (double)m_viewport[2];
 | 
			
		||||
        h = (double)m_viewport[3];
 | 
			
		||||
        w = 0.5 * (double)m_viewport[2];
 | 
			
		||||
        h = 0.5 * (double)m_viewport[3];
 | 
			
		||||
 | 
			
		||||
        double two_zoom = 2.0 * m_zoom;
 | 
			
		||||
        if (two_zoom != 0.0)
 | 
			
		||||
        if (m_zoom != 0.0)
 | 
			
		||||
        {
 | 
			
		||||
            double inv_two_zoom = 1.0 / two_zoom;
 | 
			
		||||
            w *= inv_two_zoom;
 | 
			
		||||
            h *= inv_two_zoom;
 | 
			
		||||
            double inv_zoom = 1.0 / m_zoom;
 | 
			
		||||
            w *= inv_zoom;
 | 
			
		||||
            h *= inv_zoom;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        switch (m_type)
 | 
			
		||||
| 
						 | 
				
			
			@ -226,21 +226,16 @@ void Camera::apply_projection(const BoundingBoxf3& box) const
 | 
			
		|||
 | 
			
		||||
        if (m_type == Perspective)
 | 
			
		||||
        {
 | 
			
		||||
            double fov_rad = 2.0 * std::atan(h / m_frustrum_zs.first);
 | 
			
		||||
            double fov_deg = Geometry::rad2deg(fov_rad);
 | 
			
		||||
            double fov_deg = Geometry::rad2deg(2.0 * std::atan(h / m_frustrum_zs.first));
 | 
			
		||||
 | 
			
		||||
            // adjust camera distance to keep fov in a limited range
 | 
			
		||||
            if (fov_deg > FovMaxDeg + 0.001)
 | 
			
		||||
            if (fov_deg > MaxFovDeg)
 | 
			
		||||
            {
 | 
			
		||||
                double new_near_z = h / ::tan(0.5 * Geometry::deg2rad(FovMaxDeg));
 | 
			
		||||
                m_distance += (new_near_z - m_frustrum_zs.first);
 | 
			
		||||
                apply_view_matrix();
 | 
			
		||||
            }
 | 
			
		||||
            else if (fov_deg < FovMinDeg - 0.001)
 | 
			
		||||
            {
 | 
			
		||||
                double new_near_z = h / ::tan(0.5 * Geometry::deg2rad(FovMinDeg));
 | 
			
		||||
                m_distance += (new_near_z - m_frustrum_zs.first);
 | 
			
		||||
                apply_view_matrix();
 | 
			
		||||
                double delta_z = h / ::tan(0.5 * Geometry::deg2rad(MaxFovDeg)) - m_frustrum_zs.first;
 | 
			
		||||
                if (delta_z > 0.001)
 | 
			
		||||
                    set_distance(m_distance + delta_z);
 | 
			
		||||
                else
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                break;
 | 
			
		||||
| 
						 | 
				
			
			@ -328,42 +323,50 @@ void Camera::debug_render() const
 | 
			
		|||
 | 
			
		||||
std::pair<double, double> Camera::calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const
 | 
			
		||||
{
 | 
			
		||||
    std::pair<double, double> ret = std::make_pair(DBL_MAX, -DBL_MAX);
 | 
			
		||||
    std::pair<double, double> ret;
 | 
			
		||||
 | 
			
		||||
    Vec3d bb_min = box.min;
 | 
			
		||||
    Vec3d bb_max = box.max;
 | 
			
		||||
 | 
			
		||||
    // box vertices in world space
 | 
			
		||||
    std::vector<Vec3d> vertices;
 | 
			
		||||
    vertices.reserve(8);
 | 
			
		||||
    vertices.push_back(bb_min);
 | 
			
		||||
    vertices.emplace_back(bb_max(0), bb_min(1), bb_min(2));
 | 
			
		||||
    vertices.emplace_back(bb_max(0), bb_max(1), bb_min(2));
 | 
			
		||||
    vertices.emplace_back(bb_min(0), bb_max(1), bb_min(2));
 | 
			
		||||
    vertices.emplace_back(bb_min(0), bb_min(1), bb_max(2));
 | 
			
		||||
    vertices.emplace_back(bb_max(0), bb_min(1), bb_max(2));
 | 
			
		||||
    vertices.push_back(bb_max);
 | 
			
		||||
    vertices.emplace_back(bb_min(0), bb_max(1), bb_max(2));
 | 
			
		||||
 | 
			
		||||
    // set the Z range in eye coordinates (negative Zs are in front of the camera)
 | 
			
		||||
    for (const Vec3d& v : vertices)
 | 
			
		||||
    while (true)
 | 
			
		||||
    {
 | 
			
		||||
        double z = -(m_view_matrix * v)(2);
 | 
			
		||||
        ret.first = std::min(ret.first, z);
 | 
			
		||||
        ret.second = std::max(ret.second, z);
 | 
			
		||||
    }
 | 
			
		||||
        ret = std::make_pair(DBL_MAX, -DBL_MAX);
 | 
			
		||||
 | 
			
		||||
    // apply margin
 | 
			
		||||
    ret.first -= FrustrumZMargin;
 | 
			
		||||
    ret.second += FrustrumZMargin;
 | 
			
		||||
        // box vertices in world space
 | 
			
		||||
        std::vector<Vec3d> vertices;
 | 
			
		||||
        vertices.reserve(8);
 | 
			
		||||
        vertices.push_back(box.min);
 | 
			
		||||
        vertices.emplace_back(box.max(0), box.min(1), box.min(2));
 | 
			
		||||
        vertices.emplace_back(box.max(0), box.max(1), box.min(2));
 | 
			
		||||
        vertices.emplace_back(box.min(0), box.max(1), box.min(2));
 | 
			
		||||
        vertices.emplace_back(box.min(0), box.min(1), box.max(2));
 | 
			
		||||
        vertices.emplace_back(box.max(0), box.min(1), box.max(2));
 | 
			
		||||
        vertices.push_back(box.max);
 | 
			
		||||
        vertices.emplace_back(box.min(0), box.max(1), box.max(2));
 | 
			
		||||
 | 
			
		||||
    // ensure min size
 | 
			
		||||
    if (ret.second - ret.first < FrustrumMinZSize)
 | 
			
		||||
    {
 | 
			
		||||
        double mid_z = 0.5 * (ret.first + ret.second);
 | 
			
		||||
        double half_size = 0.5 * FrustrumMinZSize;
 | 
			
		||||
        ret.first = mid_z - half_size;
 | 
			
		||||
        ret.second = mid_z + half_size;
 | 
			
		||||
        // set the Z range in eye coordinates (negative Zs are in front of the camera)
 | 
			
		||||
        for (const Vec3d& v : vertices)
 | 
			
		||||
        {
 | 
			
		||||
            double z = -(m_view_matrix * v)(2);
 | 
			
		||||
            ret.first = std::min(ret.first, z);
 | 
			
		||||
            ret.second = std::max(ret.second, z);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // apply margin
 | 
			
		||||
        ret.first -= FrustrumZMargin;
 | 
			
		||||
        ret.second += FrustrumZMargin;
 | 
			
		||||
 | 
			
		||||
        // ensure min size
 | 
			
		||||
        if (ret.second - ret.first < FrustrumMinZRange)
 | 
			
		||||
        {
 | 
			
		||||
            double mid_z = 0.5 * (ret.first + ret.second);
 | 
			
		||||
            double half_size = 0.5 * FrustrumMinZRange;
 | 
			
		||||
            ret.first = mid_z - half_size;
 | 
			
		||||
            ret.second = mid_z + half_size;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (ret.first >= FrustrumMinNearZ)
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        // ensure min Near Z
 | 
			
		||||
        set_distance(m_distance + FrustrumMinNearZ - ret.first);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -385,21 +388,19 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int ca
 | 
			
		|||
    Vec3d up = get_dir_up();
 | 
			
		||||
    Vec3d forward = get_dir_forward();
 | 
			
		||||
 | 
			
		||||
    Vec3d bb_min = box.min;
 | 
			
		||||
    Vec3d bb_max = box.max;
 | 
			
		||||
    Vec3d bb_center = box.center();
 | 
			
		||||
 | 
			
		||||
    // box vertices in world space
 | 
			
		||||
    std::vector<Vec3d> vertices;
 | 
			
		||||
    vertices.reserve(8);
 | 
			
		||||
    vertices.push_back(bb_min);
 | 
			
		||||
    vertices.emplace_back(bb_max(0), bb_min(1), bb_min(2));
 | 
			
		||||
    vertices.emplace_back(bb_max(0), bb_max(1), bb_min(2));
 | 
			
		||||
    vertices.emplace_back(bb_min(0), bb_max(1), bb_min(2));
 | 
			
		||||
    vertices.emplace_back(bb_min(0), bb_min(1), bb_max(2));
 | 
			
		||||
    vertices.emplace_back(bb_max(0), bb_min(1), bb_max(2));
 | 
			
		||||
    vertices.push_back(bb_max);
 | 
			
		||||
    vertices.emplace_back(bb_min(0), bb_max(1), bb_max(2));
 | 
			
		||||
    vertices.push_back(box.min);
 | 
			
		||||
    vertices.emplace_back(box.max(0), box.min(1), box.min(2));
 | 
			
		||||
    vertices.emplace_back(box.max(0), box.max(1), box.min(2));
 | 
			
		||||
    vertices.emplace_back(box.min(0), box.max(1), box.min(2));
 | 
			
		||||
    vertices.emplace_back(box.min(0), box.min(1), box.max(2));
 | 
			
		||||
    vertices.emplace_back(box.max(0), box.min(1), box.max(2));
 | 
			
		||||
    vertices.push_back(box.max);
 | 
			
		||||
    vertices.emplace_back(box.min(0), box.max(1), box.max(2));
 | 
			
		||||
 | 
			
		||||
    double max_x = 0.0;
 | 
			
		||||
    double max_y = 0.0;
 | 
			
		||||
| 
						 | 
				
			
			@ -430,6 +431,12 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int ca
 | 
			
		|||
    return std::min((double)canvas_w / (2.0 * max_x), (double)canvas_h / (2.0 * max_y));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Camera::set_distance(double distance) const
 | 
			
		||||
{
 | 
			
		||||
    m_distance = distance;
 | 
			
		||||
    apply_view_matrix();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // GUI
 | 
			
		||||
} // Slic3r
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,10 +10,10 @@ namespace GUI {
 | 
			
		|||
struct Camera
 | 
			
		||||
{
 | 
			
		||||
    static const double DefaultDistance;
 | 
			
		||||
    static double FrustrumMinZSize;
 | 
			
		||||
    static double FrustrumMinZRange;
 | 
			
		||||
    static double FrustrumMinNearZ;
 | 
			
		||||
    static double FrustrumZMargin;
 | 
			
		||||
    static double FovMinDeg;
 | 
			
		||||
    static double FovMaxDeg;
 | 
			
		||||
    static double MaxFovDeg;
 | 
			
		||||
 | 
			
		||||
    enum EType : unsigned char
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -101,6 +101,7 @@ private:
 | 
			
		|||
    // the camera MUST be outside of the bounding box in eye coordinate of the given box
 | 
			
		||||
    std::pair<double, double> calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const;
 | 
			
		||||
    double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const;
 | 
			
		||||
    void set_distance(double distance) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // GUI
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -354,7 +354,7 @@ bool FirmwareDialog::priv::check_model_id()
 | 
			
		|||
	// Therefore, regretably, so far the check cannot be used and we just return true here.
 | 
			
		||||
	// TODO: Rewrite Serial using more platform-native code.
 | 
			
		||||
	return true;
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	// if (hex_file.model_id.empty()) {
 | 
			
		||||
	// 	// No data to check against, assume it's ok
 | 
			
		||||
	// 	return true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1529,7 +1529,7 @@ void GLCanvas3D::render()
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    m_camera.apply_view_matrix();
 | 
			
		||||
    m_camera.apply_projection(_max_bounding_box(true));
 | 
			
		||||
    m_camera.apply_projection(_max_bounding_box(true, true));
 | 
			
		||||
 | 
			
		||||
    GLfloat position_cam[4] = { 1.0f, 0.0f, 1.0f, 0.0f };
 | 
			
		||||
    glsafe(::glLightfv(GL_LIGHT1, GL_POSITION, position_cam));
 | 
			
		||||
| 
						 | 
				
			
			@ -3273,7 +3273,7 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
 | 
			
		|||
void GLCanvas3D::set_camera_zoom(double zoom)
 | 
			
		||||
{
 | 
			
		||||
    const Size& cnv_size = get_canvas_size();
 | 
			
		||||
    m_camera.set_zoom(zoom, _max_bounding_box(false), cnv_size.get_width(), cnv_size.get_height());
 | 
			
		||||
    m_camera.set_zoom(zoom, _max_bounding_box(false, false), cnv_size.get_width(), cnv_size.get_height());
 | 
			
		||||
    m_dirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3699,9 +3699,20 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h)
 | 
			
		|||
    m_dirty = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_bed_model) const
 | 
			
		||||
BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_bed_model) const
 | 
			
		||||
{
 | 
			
		||||
    BoundingBoxf3 bb = volumes_bounding_box();
 | 
			
		||||
 | 
			
		||||
    // The following is a workaround for gizmos not being taken in account when calculating the tight camera frustrum
 | 
			
		||||
    // A better solution would ask the gizmo manager for the bounding box of the current active gizmo, if any
 | 
			
		||||
    if (include_gizmos && m_gizmos.is_running())
 | 
			
		||||
    {
 | 
			
		||||
        BoundingBoxf3 sel_bb = m_selection.get_bounding_box();
 | 
			
		||||
        Vec3d sel_bb_center = sel_bb.center();
 | 
			
		||||
        Vec3d extend_by = sel_bb.max_size() * Vec3d::Ones();
 | 
			
		||||
        bb.merge(BoundingBoxf3(sel_bb_center - extend_by, sel_bb_center + extend_by));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bb.merge(m_bed.get_bounding_box(include_bed_model));
 | 
			
		||||
    return bb;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -652,7 +652,7 @@ private:
 | 
			
		|||
    bool _set_current();
 | 
			
		||||
    void _resize(unsigned int w, unsigned int h);
 | 
			
		||||
 | 
			
		||||
    BoundingBoxf3 _max_bounding_box(bool include_bed_model) const;
 | 
			
		||||
    BoundingBoxf3 _max_bounding_box(bool include_gizmos, bool include_bed_model) const;
 | 
			
		||||
 | 
			
		||||
    void _zoom_to_box(const BoundingBoxf3& box);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -494,7 +494,7 @@ void ObjectList::update_name_in_model(const wxDataViewItem& item) const
 | 
			
		|||
    if (obj_idx < 0) return;
 | 
			
		||||
    const int volume_id = m_objects_model->GetVolumeIdByItem(item);
 | 
			
		||||
 | 
			
		||||
    take_snapshot(wxString::Format(_(L("Rename %s")), volume_id < 0 ? _(L("Object")) : _(L("Sub-object"))));
 | 
			
		||||
    take_snapshot(volume_id < 0 ? _(L("Rename Object")) : _(L("Rename Sub-object")));
 | 
			
		||||
 | 
			
		||||
    if (m_objects_model->GetItemType(item) & itObject) {
 | 
			
		||||
        (*m_objects)[obj_idx]->name = m_objects_model->GetName(item).ToUTF8().data();
 | 
			
		||||
| 
						 | 
				
			
			@ -1049,8 +1049,10 @@ void ObjectList::get_settings_choice(const wxString& category_name)
 | 
			
		|||
    wxArrayInt selections;
 | 
			
		||||
    wxDataViewItem item = GetSelection();
 | 
			
		||||
 | 
			
		||||
    const ItemType item_type = m_objects_model->GetItemType(item);
 | 
			
		||||
 | 
			
		||||
    settings_menu_hierarchy settings_menu;
 | 
			
		||||
    const bool is_part = m_objects_model->GetItemType(item) & (itVolume | itLayer);
 | 
			
		||||
    const bool is_part = item_type & (itVolume | itLayer);
 | 
			
		||||
    get_options_menu(settings_menu, is_part);
 | 
			
		||||
    std::vector< std::pair<std::string, std::string> > *settings_list = nullptr;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1127,7 +1129,10 @@ void ObjectList::get_settings_choice(const wxString& category_name)
 | 
			
		|||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    take_snapshot(wxString::Format(_(L("Add Settings for %s")), is_part ? _(L("Sub-object")) : _(L("Object"))));
 | 
			
		||||
    const wxString snapshot_text =  item_type & itLayer   ? _(L("Add Settings for Layers")) :
 | 
			
		||||
                                    item_type & itVolume  ? _(L("Add Settings for Sub-object")) :
 | 
			
		||||
                                                            _(L("Add Settings for Object"));
 | 
			
		||||
    take_snapshot(snapshot_text);
 | 
			
		||||
 | 
			
		||||
    std::vector <std::string> selected_options;
 | 
			
		||||
    selected_options.reserve(selection_cnt);
 | 
			
		||||
| 
						 | 
				
			
			@ -1159,7 +1164,7 @@ void ObjectList::get_settings_choice(const wxString& category_name)
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
    // Add settings item for object/sub-object and show them 
 | 
			
		||||
    if (!(m_objects_model->GetItemType(item) & (itObject | itVolume | itLayer)))
 | 
			
		||||
    if (!(item_type & (itObject | itVolume | itLayer)))
 | 
			
		||||
        item = m_objects_model->GetTopParent(item);
 | 
			
		||||
    show_settings(add_settings_item(item, m_config));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1169,11 +1174,13 @@ void ObjectList::get_freq_settings_choice(const wxString& bundle_name)
 | 
			
		|||
    std::vector<std::string> options = get_options_for_bundle(bundle_name);
 | 
			
		||||
    wxDataViewItem item = GetSelection();
 | 
			
		||||
 | 
			
		||||
    ItemType item_type = m_objects_model->GetItemType(item);
 | 
			
		||||
 | 
			
		||||
    /* Because of we couldn't edited layer_height for ItVolume from settings list,
 | 
			
		||||
     * correct options according to the selected item type :
 | 
			
		||||
     * remove "layer_height" option
 | 
			
		||||
     */
 | 
			
		||||
    if ((m_objects_model->GetItemType(item) & itVolume) && bundle_name == _("Layers and Perimeters")) {
 | 
			
		||||
    if ((item_type & itVolume) && bundle_name == _("Layers and Perimeters")) {
 | 
			
		||||
        const auto layer_height_it = std::find(options.begin(), options.end(), "layer_height");
 | 
			
		||||
        if (layer_height_it != options.end())
 | 
			
		||||
            options.erase(layer_height_it);
 | 
			
		||||
| 
						 | 
				
			
			@ -1185,7 +1192,10 @@ void ObjectList::get_freq_settings_choice(const wxString& bundle_name)
 | 
			
		|||
    assert(m_config);
 | 
			
		||||
    auto opt_keys = m_config->keys();
 | 
			
		||||
 | 
			
		||||
    take_snapshot(wxString::Format(_(L("Add Settings Bundle for %s")), m_objects_model->GetItemType(item) & (itVolume|itLayer) ? _(L("Sub-object")) : _(L("Object"))));
 | 
			
		||||
    const wxString snapshot_text = item_type & itLayer  ? _(L("Add Settings Bundle for Layers")) :
 | 
			
		||||
                                   item_type & itVolume ? _(L("Add Settings Bundle for Sub-object")) :
 | 
			
		||||
                                                          _(L("Add Settings Bundle for Object"));
 | 
			
		||||
    take_snapshot(snapshot_text);
 | 
			
		||||
 | 
			
		||||
    const DynamicPrintConfig& from_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
 | 
			
		||||
    for (auto& opt_key : options)
 | 
			
		||||
| 
						 | 
				
			
			@ -1202,7 +1212,7 @@ void ObjectList::get_freq_settings_choice(const wxString& bundle_name)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // Add settings item for object/sub-object and show them 
 | 
			
		||||
    if (!(m_objects_model->GetItemType(item) & (itObject | itVolume | itLayer)))
 | 
			
		||||
    if (!(item_type & (itObject | itVolume | itLayer)))
 | 
			
		||||
        item = m_objects_model->GetTopParent(item);
 | 
			
		||||
    show_settings(add_settings_item(item, m_config));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1217,26 +1227,6 @@ void ObjectList::show_settings(const wxDataViewItem settings_item)
 | 
			
		|||
    // update object selection on Plater
 | 
			
		||||
    if (!m_prevent_canvas_selection_update)
 | 
			
		||||
        update_selections_on_canvas();
 | 
			
		||||
/*    auto item = GetSelection();
 | 
			
		||||
    if (item) {
 | 
			
		||||
        if (m_objects_model->GetItemType(item) == itInstance)
 | 
			
		||||
            item = m_objects_model->GetTopParent(item);
 | 
			
		||||
        const auto settings_item = m_objects_model->IsSettingsItem(item) ? item : m_objects_model->GetSettingsItem(item);
 | 
			
		||||
        select_item(settings_item ? settings_item :
 | 
			
		||||
            m_objects_model->AddSettingsChild(item));
 | 
			
		||||
 | 
			
		||||
        // update object selection on Plater
 | 
			
		||||
        if (!m_prevent_canvas_selection_update)
 | 
			
		||||
            update_selections_on_canvas();
 | 
			
		||||
    }
 | 
			
		||||
    else { 
 | 
			
		||||
        //# ys_FIXME ??? use case ???
 | 
			
		||||
        auto panel = wxGetApp().sidebar().scrolled_panel();
 | 
			
		||||
        panel->Freeze();
 | 
			
		||||
        wxGetApp().obj_settings()->UpdateAndShow(true);
 | 
			
		||||
        panel->Thaw();
 | 
			
		||||
    }
 | 
			
		||||
    */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
wxMenu* ObjectList::append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1778,7 +1768,19 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
 | 
			
		|||
    if (type & itVolume && (*m_objects)[obj_idx]->get_mesh_errors_count() == 0)
 | 
			
		||||
        m_objects_model->DeleteWarningIcon(m_objects_model->GetParent(item));
 | 
			
		||||
 | 
			
		||||
    // If last two Instances of object is selected, show the message about impossible action
 | 
			
		||||
    bool show_msg = false;
 | 
			
		||||
    if (type & itInstance) { 
 | 
			
		||||
        wxDataViewItemArray instances;
 | 
			
		||||
        m_objects_model->GetChildren(m_objects_model->GetParent(item), instances);
 | 
			
		||||
        if (instances.Count() == 2 && IsSelected(instances[0]) && IsSelected(instances[1]))
 | 
			
		||||
            show_msg = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_objects_model->Delete(item);
 | 
			
		||||
 | 
			
		||||
    if (show_msg)
 | 
			
		||||
        Slic3r::GUI::show_error(nullptr, _(L("From Object List You can't delete the last intance from object.")));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item)
 | 
			
		||||
| 
						 | 
				
			
			@ -1861,7 +1863,7 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con
 | 
			
		|||
            if (vol->is_model_part())
 | 
			
		||||
                ++solid_cnt;
 | 
			
		||||
        if (volume->is_model_part() && solid_cnt == 1) {
 | 
			
		||||
            Slic3r::GUI::show_error(nullptr, _(L("You can't delete the last solid part from object.")));
 | 
			
		||||
            Slic3r::GUI::show_error(nullptr, _(L("From Object List You can't delete the last solid part from object.")));
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1880,7 +1882,7 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con
 | 
			
		|||
    }
 | 
			
		||||
    else if (type == itInstance) {
 | 
			
		||||
        if (object->instances.size() == 1) {
 | 
			
		||||
            Slic3r::GUI::show_error(nullptr, _(L("You can't delete the last intance from object.")));
 | 
			
		||||
            Slic3r::GUI::show_error(nullptr, _(L("From Object List You can't delete the last intance from object.")));
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2435,6 +2437,8 @@ void ObjectList::remove()
 | 
			
		|||
 | 
			
		||||
    for (auto& item : sels)
 | 
			
		||||
    {
 | 
			
		||||
        if (m_objects_model->InvalidItem(item)) // item can be deleted for this moment (like last 2 Instances or Volumes)
 | 
			
		||||
            continue;
 | 
			
		||||
        if (m_objects_model->GetParent(item) == wxDataViewItem(0))
 | 
			
		||||
            delete_from_model_and_list(itObject, m_objects_model->GetIdByItem(item), -1);
 | 
			
		||||
        else {
 | 
			
		||||
| 
						 | 
				
			
			@ -3181,33 +3185,6 @@ void ObjectList::last_volume_is_deleted(const int obj_idx)
 | 
			
		|||
    volume->config.set_key_value("extruder", new ConfigOptionInt(0));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* #lm_FIXME_delete_after_testing
 | 
			
		||||
void ObjectList::update_settings_items()
 | 
			
		||||
{
 | 
			
		||||
    m_prevent_canvas_selection_update = true;
 | 
			
		||||
    wxDataViewItemArray sel;
 | 
			
		||||
    GetSelections(sel); // stash selection
 | 
			
		||||
 | 
			
		||||
    wxDataViewItemArray items;
 | 
			
		||||
    m_objects_model->GetChildren(wxDataViewItem(0), items);
 | 
			
		||||
 | 
			
		||||
    for (auto& item : items) {        
 | 
			
		||||
        const wxDataViewItem& settings_item = m_objects_model->GetSettingsItem(item);
 | 
			
		||||
        select_item(settings_item ? settings_item : m_objects_model->AddSettingsChild(item));
 | 
			
		||||
 | 
			
		||||
        // If settings item was deleted from the list, 
 | 
			
		||||
        // it's need to be deleted from selection array, if it was there
 | 
			
		||||
        if (settings_item != m_objects_model->GetSettingsItem(item) && 
 | 
			
		||||
            sel.Index(settings_item) != wxNOT_FOUND) {
 | 
			
		||||
            sel.Remove(settings_item);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // restore selection:
 | 
			
		||||
    SetSelections(sel);
 | 
			
		||||
    m_prevent_canvas_selection_update = false;
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
void ObjectList::update_and_show_object_settings_item()
 | 
			
		||||
{
 | 
			
		||||
    const wxDataViewItem item = GetSelection();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -279,6 +279,18 @@ bool MainFrame::can_export_gcode() const
 | 
			
		|||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MainFrame::can_send_gcode() const
 | 
			
		||||
{
 | 
			
		||||
    if (m_plater == nullptr)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    if (m_plater->model().objects.empty())
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    const auto prin_host_opt =wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionString>("print_host");
 | 
			
		||||
    return prin_host_opt != nullptr && !prin_host_opt->value.empty();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MainFrame::can_slice() const
 | 
			
		||||
{
 | 
			
		||||
    bool bg_proc = wxGetApp().app_config->get("background_processing") == "1";
 | 
			
		||||
| 
						 | 
				
			
			@ -451,6 +463,10 @@ void MainFrame::init_menubar()
 | 
			
		|||
            [this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(); }, menu_icon("export_gcode"), nullptr,
 | 
			
		||||
            [this](){return can_export_gcode(); }, this);
 | 
			
		||||
        m_changeable_menu_items.push_back(item_export_gcode);
 | 
			
		||||
        wxMenuItem* item_send_gcode = append_menu_item(export_menu, wxID_ANY, _(L("S&end G-code")) + dots +"\tCtrl+Shift+G", _(L("Send to print current plate as G-code")),
 | 
			
		||||
            [this](wxCommandEvent&) { if (m_plater) m_plater->send_gcode(); }, menu_icon("export_gcode"), nullptr,
 | 
			
		||||
            [this](){return can_send_gcode(); }, this);
 | 
			
		||||
        m_changeable_menu_items.push_back(item_send_gcode);
 | 
			
		||||
        export_menu->AppendSeparator();
 | 
			
		||||
        append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &STL")) + dots, _(L("Export current plate as STL")),
 | 
			
		||||
            [this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, menu_icon("export_plater"), nullptr,
 | 
			
		||||
| 
						 | 
				
			
			@ -689,7 +705,8 @@ void MainFrame::update_menubar()
 | 
			
		|||
{
 | 
			
		||||
    const bool is_fff = plater()->printer_technology() == ptFFF;
 | 
			
		||||
 | 
			
		||||
    m_changeable_menu_items[miExport]       ->SetItemLabel((is_fff ? _(L("Export &G-code"))         : _(L("Export"))                    )   + dots + "\tCtrl+G");
 | 
			
		||||
    m_changeable_menu_items[miExport]       ->SetItemLabel((is_fff ? _(L("Export &G-code"))         : _(L("E&xport"))       ) + dots     + "\tCtrl+G");
 | 
			
		||||
    m_changeable_menu_items[miSend]         ->SetItemLabel((is_fff ? _(L("S&end G-code"))           : _(L("S&end to print"))) + dots    + "\tCtrl+Shift+G");
 | 
			
		||||
 | 
			
		||||
    m_changeable_menu_items[miMaterialTab]  ->SetItemLabel((is_fff ? _(L("&Filament Settings Tab")) : _(L("Mate&rial Settings Tab")))   + "\tCtrl+3");
 | 
			
		||||
    m_changeable_menu_items[miMaterialTab]  ->SetBitmap(create_scaled_bitmap(this, menu_icon(is_fff ? "spool": "resin")));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -67,6 +67,7 @@ class MainFrame : public DPIFrame
 | 
			
		|||
    bool can_export_model() const;
 | 
			
		||||
    bool can_export_supports() const;
 | 
			
		||||
    bool can_export_gcode() const;
 | 
			
		||||
    bool can_send_gcode() const;
 | 
			
		||||
    bool can_slice() const;
 | 
			
		||||
    bool can_change_view() const;
 | 
			
		||||
    bool can_select() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -79,6 +80,7 @@ class MainFrame : public DPIFrame
 | 
			
		|||
    enum MenuItems
 | 
			
		||||
    {                   //   FFF                  SLA
 | 
			
		||||
        miExport = 0,   // Export G-code        Export
 | 
			
		||||
        miSend,         // Send G-code          Send to print
 | 
			
		||||
        miMaterialTab,  // Filament Settings    Material Settings
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1175,10 +1175,10 @@ void Sidebar::show_sliced_info_sizer(const bool show)
 | 
			
		|||
                if (ps.estimated_silent_print_time != "N/A") {
 | 
			
		||||
                    new_label += wxString::Format("\n    - %s", _(L("stealth mode")));
 | 
			
		||||
                    info_text += wxString::Format("\n%s", ps.estimated_silent_print_time);
 | 
			
		||||
                    for (int i = (int)ps.estimated_normal_color_print_times.size() - 1; i >= 0; --i)
 | 
			
		||||
                    for (int i = (int)ps.estimated_silent_color_print_times.size() - 1; i >= 0; --i)
 | 
			
		||||
                    {
 | 
			
		||||
                        new_label += wxString::Format("\n      - %s%d", _(L("Color ")), i + 1);
 | 
			
		||||
                        info_text += wxString::Format("\n%s", ps.estimated_normal_color_print_times[i]);
 | 
			
		||||
                        info_text += wxString::Format("\n%s", ps.estimated_silent_color_print_times[i]);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                p->sliced_info->SetTextAndShow(siEstimatedTime,  info_text,      new_label);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -402,8 +402,10 @@ void Selection::remove_all()
 | 
			
		|||
 | 
			
		||||
    if (is_empty())
 | 
			
		||||
        return;
 | 
			
		||||
    
 | 
			
		||||
    if (!wxGetApp().plater()->can_redo())
 | 
			
		||||
  
 | 
			
		||||
// Not taking the snapshot with non-empty Redo stack will likely be more confusing than losing the Redo stack.
 | 
			
		||||
// Let's wait for user feedback.
 | 
			
		||||
//    if (!wxGetApp().plater()->can_redo())
 | 
			
		||||
        wxGetApp().plater()->take_snapshot(_(L("Selection-Remove All")));
 | 
			
		||||
 | 
			
		||||
    m_mode = Instance;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1385,6 +1385,18 @@ int ObjectDataViewModel::GetRowByItem(const wxDataViewItem& item) const
 | 
			
		|||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ObjectDataViewModel::InvalidItem(const wxDataViewItem& item)
 | 
			
		||||
{
 | 
			
		||||
    if (!item)
 | 
			
		||||
        return true;
 | 
			
		||||
 | 
			
		||||
    ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)item.GetID();
 | 
			
		||||
    if (!node || node->invalid()) 
 | 
			
		||||
        return true;
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
wxString ObjectDataViewModel::GetName(const wxDataViewItem &item) const
 | 
			
		||||
{
 | 
			
		||||
	ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -367,6 +367,7 @@ public:
 | 
			
		|||
#ifndef NDEBUG
 | 
			
		||||
	bool 		valid();
 | 
			
		||||
#endif /* NDEBUG */
 | 
			
		||||
    bool        invalid() const { return m_idx < -1; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    friend class ObjectDataViewModel;
 | 
			
		||||
| 
						 | 
				
			
			@ -430,6 +431,7 @@ public:
 | 
			
		|||
    void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx);
 | 
			
		||||
    int  GetRowByItem(const wxDataViewItem& item) const;
 | 
			
		||||
    bool IsEmpty() { return m_objects.empty(); }
 | 
			
		||||
    bool InvalidItem(const wxDataViewItem& item);
 | 
			
		||||
 | 
			
		||||
	// helper method for wxLog
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -353,6 +353,8 @@ void Serial::set_baud_rate(unsigned baud_rate)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
void Serial::set_DTR(bool on)
 | 
			
		||||
{
 | 
			
		||||
	auto handle = native_handle();
 | 
			
		||||
| 
						 | 
				
			
			@ -495,6 +497,7 @@ std::string Serial::printer_format_line(const std::string &line, unsigned line_n
 | 
			
		|||
 | 
			
		||||
	return (boost::format("N%1% %2%*%3%\n") % line_num_str % line % checksum).str();
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
} // namespace Utils
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,6 +46,17 @@ public:
 | 
			
		|||
	~Serial();
 | 
			
		||||
 | 
			
		||||
	void set_baud_rate(unsigned baud_rate);
 | 
			
		||||
 | 
			
		||||
	// The Serial implementation is currently in disarray and therefore commented out.
 | 
			
		||||
	// The boost implementation seems to have several problems, such as lack of support
 | 
			
		||||
	// for custom baud rates, few weird implementation bugs and a history of API breakages.
 | 
			
		||||
	// It's questionable whether it solves more problems than causes. Probably not.
 | 
			
		||||
	// TODO: Custom implementation not based on asio.
 | 
			
		||||
	//
 | 
			
		||||
	// As of now, this class is only kept for the purpose of rebooting AVR109,
 | 
			
		||||
	// see FirmwareDialog::priv::avr109_reboot()
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	void set_DTR(bool on);
 | 
			
		||||
 | 
			
		||||
	// Resets the line number both internally as well as with the firmware using M110
 | 
			
		||||
| 
						 | 
				
			
			@ -68,7 +79,7 @@ public:
 | 
			
		|||
 | 
			
		||||
	// Same as above, but with internally-managed line number
 | 
			
		||||
	size_t printer_write_line(const std::string &line);
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	// Toggles DTR to reset the printer
 | 
			
		||||
	void printer_reset();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -76,6 +87,7 @@ public:
 | 
			
		|||
	static std::string printer_format_line(const std::string &line, unsigned line_num);
 | 
			
		||||
private:
 | 
			
		||||
	unsigned m_line_num = 0;
 | 
			
		||||
*/
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue