mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-13 09:47:58 -06:00
Merge remote-tracking branch 'origin/master' into tm_colldetection_upgr
This commit is contained in:
commit
5b7a325983
14 changed files with 316 additions and 118 deletions
|
@ -487,7 +487,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
|
||||||
// starts analyzer calculations
|
// starts analyzer calculations
|
||||||
if (m_enable_analyzer) {
|
if (m_enable_analyzer) {
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Preparing G-code preview data";
|
BOOST_LOG_TRIVIAL(debug) << "Preparing G-code preview data";
|
||||||
m_analyzer.calc_gcode_preview_data(*preview_data);
|
m_analyzer.calc_gcode_preview_data(*preview_data, [print]() { print->throw_if_canceled(); });
|
||||||
m_analyzer.reset();
|
m_analyzer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,22 +137,22 @@ const std::string& GCodeAnalyzer::process_gcode(const std::string& gcode)
|
||||||
return m_process_output;
|
return m_process_output;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeAnalyzer::calc_gcode_preview_data(GCodePreviewData& preview_data)
|
void GCodeAnalyzer::calc_gcode_preview_data(GCodePreviewData& preview_data, std::function<void()> cancel_callback)
|
||||||
{
|
{
|
||||||
// resets preview data
|
// resets preview data
|
||||||
preview_data.reset();
|
preview_data.reset();
|
||||||
|
|
||||||
// calculates extrusion layers
|
// calculates extrusion layers
|
||||||
_calc_gcode_preview_extrusion_layers(preview_data);
|
_calc_gcode_preview_extrusion_layers(preview_data, cancel_callback);
|
||||||
|
|
||||||
// calculates travel
|
// calculates travel
|
||||||
_calc_gcode_preview_travel(preview_data);
|
_calc_gcode_preview_travel(preview_data, cancel_callback);
|
||||||
|
|
||||||
// calculates retractions
|
// calculates retractions
|
||||||
_calc_gcode_preview_retractions(preview_data);
|
_calc_gcode_preview_retractions(preview_data, cancel_callback);
|
||||||
|
|
||||||
// calculates unretractions
|
// calculates unretractions
|
||||||
_calc_gcode_preview_unretractions(preview_data);
|
_calc_gcode_preview_unretractions(preview_data, cancel_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GCodeAnalyzer::is_valid_extrusion_role(ExtrusionRole role)
|
bool GCodeAnalyzer::is_valid_extrusion_role(ExtrusionRole role)
|
||||||
|
@ -676,7 +676,7 @@ bool GCodeAnalyzer::_is_valid_extrusion_role(int value) const
|
||||||
return ((int)erNone <= value) && (value <= (int)erMixed);
|
return ((int)erNone <= value) && (value <= (int)erMixed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& preview_data)
|
void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& preview_data, std::function<void()> cancel_callback)
|
||||||
{
|
{
|
||||||
struct Helper
|
struct Helper
|
||||||
{
|
{
|
||||||
|
@ -725,9 +725,18 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
|
||||||
GCodePreviewData::Range feedrate_range;
|
GCodePreviewData::Range feedrate_range;
|
||||||
GCodePreviewData::Range volumetric_rate_range;
|
GCodePreviewData::Range volumetric_rate_range;
|
||||||
|
|
||||||
|
// to avoid to call the callback too often
|
||||||
|
unsigned int cancel_callback_threshold = (unsigned int)extrude_moves->second.size() / 25;
|
||||||
|
unsigned int cancel_callback_curr = 0;
|
||||||
|
|
||||||
// constructs the polylines while traversing the moves
|
// constructs the polylines while traversing the moves
|
||||||
for (const GCodeMove& move : extrude_moves->second)
|
for (const GCodeMove& move : extrude_moves->second)
|
||||||
{
|
{
|
||||||
|
// to avoid to call the callback too often
|
||||||
|
cancel_callback_curr = (cancel_callback_curr + 1) % cancel_callback_threshold;
|
||||||
|
if (cancel_callback_curr == 0)
|
||||||
|
cancel_callback();
|
||||||
|
|
||||||
if ((data != move.data) || (z != move.start_position.z()) || (position != move.start_position) || (volumetric_rate != move.data.feedrate * (float)move.data.mm3_per_mm))
|
if ((data != move.data) || (z != move.start_position.z()) || (position != move.start_position) || (volumetric_rate != move.data.feedrate * (float)move.data.mm3_per_mm))
|
||||||
{
|
{
|
||||||
// store current polyline
|
// store current polyline
|
||||||
|
@ -769,7 +778,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
|
||||||
preview_data.ranges.volumetric_rate.update_from(volumetric_rate_range);
|
preview_data.ranges.volumetric_rate.update_from(volumetric_rate_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data)
|
void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, std::function<void()> cancel_callback)
|
||||||
{
|
{
|
||||||
struct Helper
|
struct Helper
|
||||||
{
|
{
|
||||||
|
@ -797,9 +806,17 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data)
|
||||||
GCodePreviewData::Range width_range;
|
GCodePreviewData::Range width_range;
|
||||||
GCodePreviewData::Range feedrate_range;
|
GCodePreviewData::Range feedrate_range;
|
||||||
|
|
||||||
|
// to avoid to call the callback too often
|
||||||
|
unsigned int cancel_callback_threshold = (unsigned int)travel_moves->second.size() / 25;
|
||||||
|
unsigned int cancel_callback_curr = 0;
|
||||||
|
|
||||||
// constructs the polylines while traversing the moves
|
// constructs the polylines while traversing the moves
|
||||||
for (const GCodeMove& move : travel_moves->second)
|
for (const GCodeMove& move : travel_moves->second)
|
||||||
{
|
{
|
||||||
|
cancel_callback_curr = (cancel_callback_curr + 1) % cancel_callback_threshold;
|
||||||
|
if (cancel_callback_curr == 0)
|
||||||
|
cancel_callback();
|
||||||
|
|
||||||
GCodePreviewData::Travel::EType move_type = (move.delta_extruder < 0.0f) ? GCodePreviewData::Travel::Retract : ((move.delta_extruder > 0.0f) ? GCodePreviewData::Travel::Extrude : GCodePreviewData::Travel::Move);
|
GCodePreviewData::Travel::EType move_type = (move.delta_extruder < 0.0f) ? GCodePreviewData::Travel::Retract : ((move.delta_extruder > 0.0f) ? GCodePreviewData::Travel::Extrude : GCodePreviewData::Travel::Move);
|
||||||
GCodePreviewData::Travel::Polyline::EDirection move_direction = ((move.start_position.x() != move.end_position.x()) || (move.start_position.y() != move.end_position.y())) ? GCodePreviewData::Travel::Polyline::Generic : GCodePreviewData::Travel::Polyline::Vertical;
|
GCodePreviewData::Travel::Polyline::EDirection move_direction = ((move.start_position.x() != move.end_position.x()) || (move.start_position.y() != move.end_position.y())) ? GCodePreviewData::Travel::Polyline::Generic : GCodePreviewData::Travel::Polyline::Vertical;
|
||||||
|
|
||||||
|
@ -840,28 +857,44 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data)
|
||||||
preview_data.ranges.feedrate.update_from(feedrate_range);
|
preview_data.ranges.feedrate.update_from(feedrate_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_data)
|
void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_data, std::function<void()> cancel_callback)
|
||||||
{
|
{
|
||||||
TypeToMovesMap::iterator retraction_moves = m_moves_map.find(GCodeMove::Retract);
|
TypeToMovesMap::iterator retraction_moves = m_moves_map.find(GCodeMove::Retract);
|
||||||
if (retraction_moves == m_moves_map.end())
|
if (retraction_moves == m_moves_map.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// to avoid to call the callback too often
|
||||||
|
unsigned int cancel_callback_threshold = (unsigned int)retraction_moves->second.size() / 25;
|
||||||
|
unsigned int cancel_callback_curr = 0;
|
||||||
|
|
||||||
for (const GCodeMove& move : retraction_moves->second)
|
for (const GCodeMove& move : retraction_moves->second)
|
||||||
{
|
{
|
||||||
|
cancel_callback_curr = (cancel_callback_curr + 1) % cancel_callback_threshold;
|
||||||
|
if (cancel_callback_curr == 0)
|
||||||
|
cancel_callback();
|
||||||
|
|
||||||
// store position
|
// store position
|
||||||
Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()));
|
Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()));
|
||||||
preview_data.retraction.positions.emplace_back(position, move.data.width, move.data.height);
|
preview_data.retraction.positions.emplace_back(position, move.data.width, move.data.height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_data)
|
void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_data, std::function<void()> cancel_callback)
|
||||||
{
|
{
|
||||||
TypeToMovesMap::iterator unretraction_moves = m_moves_map.find(GCodeMove::Unretract);
|
TypeToMovesMap::iterator unretraction_moves = m_moves_map.find(GCodeMove::Unretract);
|
||||||
if (unretraction_moves == m_moves_map.end())
|
if (unretraction_moves == m_moves_map.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// to avoid to call the callback too often
|
||||||
|
unsigned int cancel_callback_threshold = (unsigned int)unretraction_moves->second.size() / 25;
|
||||||
|
unsigned int cancel_callback_curr = 0;
|
||||||
|
|
||||||
for (const GCodeMove& move : unretraction_moves->second)
|
for (const GCodeMove& move : unretraction_moves->second)
|
||||||
{
|
{
|
||||||
|
cancel_callback_curr = (cancel_callback_curr + 1) % cancel_callback_threshold;
|
||||||
|
if (cancel_callback_curr == 0)
|
||||||
|
cancel_callback();
|
||||||
|
|
||||||
// store position
|
// store position
|
||||||
Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()));
|
Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()));
|
||||||
preview_data.unretraction.positions.emplace_back(position, move.data.width, move.data.height);
|
preview_data.unretraction.positions.emplace_back(position, move.data.width, move.data.height);
|
||||||
|
|
|
@ -122,7 +122,8 @@ public:
|
||||||
const std::string& process_gcode(const std::string& gcode);
|
const std::string& process_gcode(const std::string& gcode);
|
||||||
|
|
||||||
// Calculates all data needed for gcode visualization
|
// Calculates all data needed for gcode visualization
|
||||||
void calc_gcode_preview_data(GCodePreviewData& preview_data);
|
// throws CanceledException through print->throw_if_canceled() (sent by the caller as callback).
|
||||||
|
void calc_gcode_preview_data(GCodePreviewData& preview_data, std::function<void()> cancel_callback = std::function<void()>());
|
||||||
|
|
||||||
// Return an estimate of the memory consumed by the time estimator.
|
// Return an estimate of the memory consumed by the time estimator.
|
||||||
size_t memory_used() const;
|
size_t memory_used() const;
|
||||||
|
@ -237,10 +238,11 @@ private:
|
||||||
// Checks if the given int is a valid extrusion role (contained into enum ExtrusionRole)
|
// Checks if the given int is a valid extrusion role (contained into enum ExtrusionRole)
|
||||||
bool _is_valid_extrusion_role(int value) const;
|
bool _is_valid_extrusion_role(int value) const;
|
||||||
|
|
||||||
void _calc_gcode_preview_extrusion_layers(GCodePreviewData& preview_data);
|
// All the following methods throw CanceledException through print->throw_if_canceled() (sent by the caller as callback).
|
||||||
void _calc_gcode_preview_travel(GCodePreviewData& preview_data);
|
void _calc_gcode_preview_extrusion_layers(GCodePreviewData& preview_data, std::function<void()> cancel_callback);
|
||||||
void _calc_gcode_preview_retractions(GCodePreviewData& preview_data);
|
void _calc_gcode_preview_travel(GCodePreviewData& preview_data, std::function<void()> cancel_callback);
|
||||||
void _calc_gcode_preview_unretractions(GCodePreviewData& preview_data);
|
void _calc_gcode_preview_retractions(GCodePreviewData& preview_data, std::function<void()> cancel_callback);
|
||||||
|
void _calc_gcode_preview_unretractions(GCodePreviewData& preview_data, std::function<void()> cancel_callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <boost/format.hpp>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
@ -88,7 +89,7 @@ static DWORD execute_process_winapi(const std::wstring &command_line)
|
||||||
// Run the script. If it is a perl script, run it through the bundled perl interpreter.
|
// Run the script. If it is a perl script, run it through the bundled perl interpreter.
|
||||||
// If it is a batch file, run it through the cmd.exe.
|
// If it is a batch file, run it through the cmd.exe.
|
||||||
// Otherwise run it directly.
|
// Otherwise run it directly.
|
||||||
static int run_script_win32(const std::string &script, const std::string &gcode)
|
static int run_script(const std::string &script, const std::string &gcode, std::string &/*std_err*/)
|
||||||
{
|
{
|
||||||
// Unpack the argument list provided by the user.
|
// Unpack the argument list provided by the user.
|
||||||
int nArgs;
|
int nArgs;
|
||||||
|
@ -132,9 +133,46 @@ static int run_script_win32(const std::string &script, const std::string &gcode)
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#include <sys/stat.h> //for getting filesystem UID/GID
|
// POSIX
|
||||||
#include <unistd.h> //for getting current UID/GID
|
|
||||||
#include <boost/process.hpp>
|
#include <cstdlib> // getenv()
|
||||||
|
#include <sstream>
|
||||||
|
#include <boost/process.hpp>
|
||||||
|
|
||||||
|
namespace process = boost::process;
|
||||||
|
|
||||||
|
static int run_script(const std::string &script, const std::string &gcode, std::string &std_err)
|
||||||
|
{
|
||||||
|
// Try to obtain user's default shell
|
||||||
|
const char *shell = ::getenv("SHELL");
|
||||||
|
if (shell == nullptr) { shell = "sh"; }
|
||||||
|
|
||||||
|
// Quote and escape the gcode path argument
|
||||||
|
std::string command { script };
|
||||||
|
command.append(" '");
|
||||||
|
for (char c : gcode) {
|
||||||
|
if (c == '\'') { command.append("'\\''"); }
|
||||||
|
else { command.push_back(c); }
|
||||||
|
}
|
||||||
|
command.push_back('\'');
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << boost::format("Executing script, shell: %1%, command: %2%") % shell % command;
|
||||||
|
|
||||||
|
process::ipstream istd_err;
|
||||||
|
process::child child(shell, "-c", command, process::std_err > istd_err);
|
||||||
|
|
||||||
|
std_err.clear();
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
while (child.running() && std::getline(istd_err, line)) {
|
||||||
|
std_err.append(line);
|
||||||
|
std_err.push_back('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
child.wait();
|
||||||
|
return child.exit_code();
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
@ -158,27 +196,15 @@ void run_post_process_scripts(const std::string &path, const PrintConfig &config
|
||||||
if (script.empty())
|
if (script.empty())
|
||||||
continue;
|
continue;
|
||||||
BOOST_LOG_TRIVIAL(info) << "Executing script " << script << " on file " << path;
|
BOOST_LOG_TRIVIAL(info) << "Executing script " << script << " on file " << path;
|
||||||
#ifdef WIN32
|
|
||||||
int result = run_script_win32(script, gcode_file.string());
|
std::string std_err;
|
||||||
#else
|
const int result = run_script(script, gcode_file.string(), std_err);
|
||||||
//FIXME testing existence of a script is risky, as the script line may contain the script and some additional command line parameters.
|
if (result != 0) {
|
||||||
// We would have to process the script line into parameters before testing for the existence of the command, the command may be looked up
|
const std::string msg = std_err.empty() ? (boost::format("Post-processing script %1% on file %2% failed.\nError code: %3%") % script % path % result).str()
|
||||||
// in the PATH etc.
|
: (boost::format("Post-processing script %1% on file %2% failed.\nError code: %3%\nOutput:\n%4%") % script % path % result % std_err).str();
|
||||||
if (! boost::filesystem::exists(boost::filesystem::path(script)))
|
BOOST_LOG_TRIVIAL(error) << msg;
|
||||||
throw std::runtime_error(std::string("The configured post-processing script does not exist: ") + script);
|
throw std::runtime_error(msg);
|
||||||
struct stat info;
|
}
|
||||||
if (stat(script.c_str(), &info))
|
|
||||||
throw std::runtime_error(std::string("Cannot read information for post-processing script: ") + script);
|
|
||||||
boost::filesystem::perms script_perms = boost::filesystem::status(script).permissions();
|
|
||||||
//if UID matches, check UID perm. else if GID matches, check GID perm. Otherwise check other perm.
|
|
||||||
if (!(script_perms & ((info.st_uid == geteuid()) ? boost::filesystem::perms::owner_exe
|
|
||||||
: ((info.st_gid == getegid()) ? boost::filesystem::perms::group_exe
|
|
||||||
: boost::filesystem::perms::others_exe))))
|
|
||||||
throw std::runtime_error(std::string("The configured post-processing script is not executable: check permissions. ") + script);
|
|
||||||
int result = boost::process::system(script, gcode_file);
|
|
||||||
if (result < 0)
|
|
||||||
BOOST_LOG_TRIVIAL(error) << "Script " << script << " on file " << path << " failed. Negative error code returned.";
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -834,6 +834,8 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
|
||||||
ModelInstance::EPrintVolumeState state = ModelInstance::PVS_Inside;
|
ModelInstance::EPrintVolumeState state = ModelInstance::PVS_Inside;
|
||||||
bool all_contained = true;
|
bool all_contained = true;
|
||||||
|
|
||||||
|
bool contained_min_one = false;
|
||||||
|
|
||||||
for (GLVolume* volume : this->volumes)
|
for (GLVolume* volume : this->volumes)
|
||||||
{
|
{
|
||||||
if ((volume == nullptr) || volume->is_modifier || (volume->is_wipe_tower && !volume->shader_outside_printer_detection_enabled) || ((volume->composite_id.volume_id < 0) && !volume->shader_outside_printer_detection_enabled))
|
if ((volume == nullptr) || volume->is_modifier || (volume->is_wipe_tower && !volume->shader_outside_printer_detection_enabled) || ((volume->composite_id.volume_id < 0) && !volume->shader_outside_printer_detection_enabled))
|
||||||
|
@ -843,6 +845,9 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
|
||||||
bool contained = print_volume.contains(bb);
|
bool contained = print_volume.contains(bb);
|
||||||
all_contained &= contained;
|
all_contained &= contained;
|
||||||
|
|
||||||
|
if (contained)
|
||||||
|
contained_min_one = true;
|
||||||
|
|
||||||
volume->is_outside = !contained;
|
volume->is_outside = !contained;
|
||||||
|
|
||||||
if ((state == ModelInstance::PVS_Inside) && volume->is_outside)
|
if ((state == ModelInstance::PVS_Inside) && volume->is_outside)
|
||||||
|
@ -855,7 +860,7 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
|
||||||
if (out_state != nullptr)
|
if (out_state != nullptr)
|
||||||
*out_state = state;
|
*out_state = state;
|
||||||
|
|
||||||
return all_contained;
|
return /*all_contained*/ contained_min_one; // #ys_FIXME_delete_after_testing
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLVolumeCollection::reset_outside_state()
|
void GLVolumeCollection::reset_outside_state()
|
||||||
|
|
|
@ -123,7 +123,7 @@ public:
|
||||||
// This "finished" flag does not account for the final export of the output file (.gcode or zipped PNGs),
|
// This "finished" flag does not account for the final export of the output file (.gcode or zipped PNGs),
|
||||||
// and it does not account for the OctoPrint scheduling.
|
// and it does not account for the OctoPrint scheduling.
|
||||||
bool finished() const { return m_print->finished(); }
|
bool finished() const { return m_print->finished(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void thread_proc();
|
void thread_proc();
|
||||||
void thread_proc_safe();
|
void thread_proc_safe();
|
||||||
|
|
|
@ -3272,7 +3272,7 @@ bool GLCanvas3D::Gizmos::generate_icons_texture() const
|
||||||
}
|
}
|
||||||
#endif // ENABLE_SVG_ICONS
|
#endif // ENABLE_SVG_ICONS
|
||||||
|
|
||||||
const unsigned char GLCanvas3D::WarningTexture::Background_Color[3] = { 9, 91, 134 };
|
const unsigned char GLCanvas3D::WarningTexture::Background_Color[3] = { 120, 120, 120 };//{ 9, 91, 134 };
|
||||||
const unsigned char GLCanvas3D::WarningTexture::Opacity = 255;
|
const unsigned char GLCanvas3D::WarningTexture::Opacity = 255;
|
||||||
|
|
||||||
GLCanvas3D::WarningTexture::WarningTexture()
|
GLCanvas3D::WarningTexture::WarningTexture()
|
||||||
|
@ -3306,16 +3306,23 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool
|
||||||
|
|
||||||
// Look at the end of our vector and generate proper texture.
|
// Look at the end of our vector and generate proper texture.
|
||||||
std::string text;
|
std::string text;
|
||||||
|
bool red_colored = false;
|
||||||
switch (m_warnings.back()) {
|
switch (m_warnings.back()) {
|
||||||
case ObjectOutside : text = L("Detected object outside print volume"); break;
|
case ObjectOutside : text = L("Detected object outside print volume"); break;
|
||||||
case ToolpathOutside : text = L("Detected toolpath outside print volume"); break;
|
case ToolpathOutside : text = L("Detected toolpath outside print volume"); break;
|
||||||
case SomethingNotShown : text = L("Some objects are not visible when editing supports"); break;
|
case SomethingNotShown : text = L("Some objects are not visible when editing supports"); break;
|
||||||
|
case ObjectClashed: {
|
||||||
|
text = L("Detected object outside print volume\n"
|
||||||
|
"Resolve a clash to continue slicing/export process correctly");
|
||||||
|
red_colored = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_generate(text, canvas); // GUI::GLTexture::reset() is called at the beginning of generate(...)
|
_generate(text, canvas, red_colored); // GUI::GLTexture::reset() is called at the beginning of generate(...)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLCanvas3D::WarningTexture::_generate(const std::string& msg, const GLCanvas3D& canvas)
|
bool GLCanvas3D::WarningTexture::_generate(const std::string& msg, const GLCanvas3D& canvas, const bool red_colored/* = false*/)
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
|
@ -3332,7 +3339,8 @@ bool GLCanvas3D::WarningTexture::_generate(const std::string& msg, const GLCanva
|
||||||
|
|
||||||
// calculates texture size
|
// calculates texture size
|
||||||
wxCoord w, h;
|
wxCoord w, h;
|
||||||
memDC.GetTextExtent(msg, &w, &h);
|
// memDC.GetTextExtent(msg, &w, &h);
|
||||||
|
memDC.GetMultiLineTextExtent(msg, &w, &h);
|
||||||
|
|
||||||
int pow_of_two_size = next_highest_power_of_2(std::max<unsigned int>(w, h));
|
int pow_of_two_size = next_highest_power_of_2(std::max<unsigned int>(w, h));
|
||||||
|
|
||||||
|
@ -3349,8 +3357,9 @@ bool GLCanvas3D::WarningTexture::_generate(const std::string& msg, const GLCanva
|
||||||
memDC.Clear();
|
memDC.Clear();
|
||||||
|
|
||||||
// draw message
|
// draw message
|
||||||
memDC.SetTextForeground(*wxWHITE);
|
memDC.SetTextForeground(red_colored ? wxColour(255,72,65/*204,204*/) : *wxWHITE);
|
||||||
memDC.DrawText(msg, 0, 0);
|
// memDC.DrawText(msg, 0, 0);
|
||||||
|
memDC.DrawLabel(msg, wxRect(0,0, m_original_width, m_original_height), wxALIGN_CENTER);
|
||||||
|
|
||||||
memDC.SelectObject(wxNullBitmap);
|
memDC.SelectObject(wxNullBitmap);
|
||||||
|
|
||||||
|
@ -4579,23 +4588,33 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||||
if (!m_volumes.empty())
|
if (!m_volumes.empty())
|
||||||
{
|
{
|
||||||
ModelInstance::EPrintVolumeState state;
|
ModelInstance::EPrintVolumeState state;
|
||||||
bool contained = m_volumes.check_outside_state(m_config, &state);
|
|
||||||
|
|
||||||
if (!contained)
|
const bool contained_min_one = m_volumes.check_outside_state(m_config, &state);
|
||||||
{
|
|
||||||
_set_warning_texture(WarningTexture::ObjectOutside, true);
|
_set_warning_texture(WarningTexture::ObjectClashed, state == ModelInstance::PVS_Partly_Outside);
|
||||||
post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, state == ModelInstance::PVS_Fully_Outside));
|
_set_warning_texture(WarningTexture::ObjectOutside, state == ModelInstance::PVS_Fully_Outside);
|
||||||
}
|
|
||||||
else
|
post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS,
|
||||||
{
|
contained_min_one && !m_model->objects.empty() && state != ModelInstance::PVS_Partly_Outside));
|
||||||
m_volumes.reset_outside_state();
|
|
||||||
_set_warning_texture(WarningTexture::ObjectOutside, false);
|
// #ys_FIXME_delete_after_testing
|
||||||
post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, !m_model->objects.empty()));
|
// bool contained = m_volumes.check_outside_state(m_config, &state);
|
||||||
}
|
// if (!contained)
|
||||||
|
// {
|
||||||
|
// _set_warning_texture(WarningTexture::ObjectOutside, true);
|
||||||
|
// post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, state == ModelInstance::PVS_Fully_Outside));
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// m_volumes.reset_outside_state();
|
||||||
|
// _set_warning_texture(WarningTexture::ObjectOutside, false);
|
||||||
|
// post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, !m_model->objects.empty()));
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_set_warning_texture(WarningTexture::ObjectOutside, false);
|
_set_warning_texture(WarningTexture::ObjectOutside, false);
|
||||||
|
_set_warning_texture(WarningTexture::ObjectClashed, false);
|
||||||
post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, false));
|
post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -794,7 +794,8 @@ private:
|
||||||
enum Warning {
|
enum Warning {
|
||||||
ObjectOutside,
|
ObjectOutside,
|
||||||
ToolpathOutside,
|
ToolpathOutside,
|
||||||
SomethingNotShown
|
SomethingNotShown,
|
||||||
|
ObjectClashed
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sets a warning of the given type to be active/inactive. If several warnings are active simultaneously,
|
// Sets a warning of the given type to be active/inactive. If several warnings are active simultaneously,
|
||||||
|
@ -813,7 +814,7 @@ private:
|
||||||
std::vector<Warning> m_warnings;
|
std::vector<Warning> m_warnings;
|
||||||
|
|
||||||
// Generates the texture with given text.
|
// Generates the texture with given text.
|
||||||
bool _generate(const std::string& msg, const GLCanvas3D& canvas);
|
bool _generate(const std::string& msg, const GLCanvas3D& canvas, const bool red_colored = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
class LegendTexture : public GUI::GLTexture
|
class LegendTexture : public GUI::GLTexture
|
||||||
|
|
|
@ -167,17 +167,6 @@ bool GUI_App::OnInit()
|
||||||
if (app_config->dirty() && app_config->get("autosave") == "1")
|
if (app_config->dirty() && app_config->get("autosave") == "1")
|
||||||
app_config->save();
|
app_config->save();
|
||||||
|
|
||||||
// ! Temporary workaround for the correct behavior of the Scrolled sidebar panel
|
|
||||||
// Do this "manipulations" only once ( after (re)create of the application )
|
|
||||||
if (sidebar().obj_list()->GetMinHeight() > 15 * wxGetApp().em_unit())
|
|
||||||
{
|
|
||||||
wxWindowUpdateLocker noUpdates_sidebar(&sidebar());
|
|
||||||
sidebar().obj_list()->SetMinSize(wxSize(-1, 15 * wxGetApp().em_unit()));
|
|
||||||
|
|
||||||
// !!! to correct later layouts
|
|
||||||
update_mode(); // update view mode after fix of the object_list size
|
|
||||||
}
|
|
||||||
|
|
||||||
this->obj_manipul()->update_if_dirty();
|
this->obj_manipul()->update_if_dirty();
|
||||||
|
|
||||||
// Preset updating & Configwizard are done after the above initializations,
|
// Preset updating & Configwizard are done after the above initializations,
|
||||||
|
@ -205,11 +194,12 @@ bool GUI_App::OnInit()
|
||||||
}
|
}
|
||||||
preset_updater->sync(preset_bundle);
|
preset_updater->sync(preset_bundle);
|
||||||
});
|
});
|
||||||
|
|
||||||
load_current_presets();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
load_current_presets();
|
||||||
|
update_mode(); // update view mode after fix of the object_list size
|
||||||
|
|
||||||
mainframe->Show(true);
|
mainframe->Show(true);
|
||||||
m_initialized = true;
|
m_initialized = true;
|
||||||
return true;
|
return true;
|
||||||
|
@ -534,20 +524,7 @@ void GUI_App::save_mode(const /*ConfigOptionMode*/int mode)
|
||||||
// Update view mode according to selected menu
|
// Update view mode according to selected menu
|
||||||
void GUI_App::update_mode()
|
void GUI_App::update_mode()
|
||||||
{
|
{
|
||||||
wxWindowUpdateLocker noUpdates(&sidebar());
|
sidebar().update_mode();
|
||||||
|
|
||||||
const ConfigOptionMode mode = wxGetApp().get_mode();
|
|
||||||
|
|
||||||
obj_list()->get_sizer()->Show(mode > comSimple);
|
|
||||||
sidebar().set_mode_value(mode);
|
|
||||||
// sidebar().show_buttons(mode == comExpert);
|
|
||||||
obj_list()->unselect_objects();
|
|
||||||
obj_list()->update_selections();
|
|
||||||
obj_list()->update_object_menu();
|
|
||||||
|
|
||||||
sidebar().update_mode_sizer(mode);
|
|
||||||
|
|
||||||
sidebar().Layout();
|
|
||||||
|
|
||||||
for (auto tab : tabs_list)
|
for (auto tab : tabs_list)
|
||||||
tab->update_visibility();
|
tab->update_visibility();
|
||||||
|
|
|
@ -115,10 +115,7 @@ ObjectList::~ObjectList()
|
||||||
|
|
||||||
void ObjectList::create_objects_ctrl()
|
void ObjectList::create_objects_ctrl()
|
||||||
{
|
{
|
||||||
// temporary workaround for the correct behavior of the Scrolled sidebar panel:
|
SetMinSize(wxSize(-1, 15 * wxGetApp().em_unit()));
|
||||||
// 1. set a height of the list to some big value
|
|
||||||
// 2. change it to the normal min value (200) after first whole App updating/layouting
|
|
||||||
SetMinSize(wxSize(-1, 3000)); // #ys_FIXME
|
|
||||||
|
|
||||||
m_sizer = new wxBoxSizer(wxVERTICAL);
|
m_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
m_sizer->Add(this, 1, wxGROW);
|
m_sizer->Add(this, 1, wxGROW);
|
||||||
|
|
|
@ -881,9 +881,10 @@ void MainFrame::on_config_changed(DynamicPrintConfig* config) const
|
||||||
// Update the UI based on the current preferences.
|
// Update the UI based on the current preferences.
|
||||||
void MainFrame::update_ui_from_settings()
|
void MainFrame::update_ui_from_settings()
|
||||||
{
|
{
|
||||||
bool bp_on = wxGetApp().app_config->get("background_processing") == "1";
|
const bool bp_on = wxGetApp().app_config->get("background_processing") == "1";
|
||||||
// m_menu_item_reslice_now->Enable(!bp_on);
|
// m_menu_item_reslice_now->Enable(!bp_on);
|
||||||
m_plater->sidebar().show_reslice(!bp_on);
|
m_plater->sidebar().show_reslice(!bp_on);
|
||||||
|
m_plater->sidebar().show_export(bp_on);
|
||||||
m_plater->sidebar().Layout();
|
m_plater->sidebar().Layout();
|
||||||
if (m_plater)
|
if (m_plater)
|
||||||
m_plater->update_ui_from_settings();
|
m_plater->update_ui_from_settings();
|
||||||
|
|
|
@ -513,6 +513,12 @@ ConfigOptionsGroup* FreqChangedParams::get_og(const bool is_fff)
|
||||||
|
|
||||||
// Sidebar / private
|
// Sidebar / private
|
||||||
|
|
||||||
|
enum class ActionButtonType : int {
|
||||||
|
abReslice,
|
||||||
|
abExport,
|
||||||
|
abSendGCode
|
||||||
|
};
|
||||||
|
|
||||||
struct Sidebar::priv
|
struct Sidebar::priv
|
||||||
{
|
{
|
||||||
Plater *plater;
|
Plater *plater;
|
||||||
|
@ -549,8 +555,6 @@ void Sidebar::priv::show_preset_comboboxes()
|
||||||
{
|
{
|
||||||
const bool showSLA = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA;
|
const bool showSLA = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA;
|
||||||
|
|
||||||
wxWindowUpdateLocker noUpdates_scrolled(scrolled->GetParent());
|
|
||||||
|
|
||||||
for (size_t i = 0; i < 4; ++i)
|
for (size_t i = 0; i < 4; ++i)
|
||||||
sizer_presets->Show(i, !showSLA);
|
sizer_presets->Show(i, !showSLA);
|
||||||
|
|
||||||
|
@ -574,6 +578,10 @@ Sidebar::Sidebar(Plater *parent)
|
||||||
p->scrolled = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(40 * wxGetApp().em_unit(), -1));
|
p->scrolled = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(40 * wxGetApp().em_unit(), -1));
|
||||||
p->scrolled->SetScrollbars(0, 20, 1, 2);
|
p->scrolled->SetScrollbars(0, 20, 1, 2);
|
||||||
|
|
||||||
|
#ifdef __WINDOWS__
|
||||||
|
p->scrolled->SetDoubleBuffered(true);
|
||||||
|
#endif //__WINDOWS__
|
||||||
|
|
||||||
// Sizer in the scrolled area
|
// Sizer in the scrolled area
|
||||||
auto *scrolled_sizer = new wxBoxSizer(wxVERTICAL);
|
auto *scrolled_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
p->scrolled->SetSizer(scrolled_sizer);
|
p->scrolled->SetSizer(scrolled_sizer);
|
||||||
|
@ -639,9 +647,7 @@ Sidebar::Sidebar(Plater *parent)
|
||||||
p->object_settings->Hide();
|
p->object_settings->Hide();
|
||||||
p->sizer_params->Add(p->object_settings->get_sizer(), 0, wxEXPAND | wxTOP, margin_5);
|
p->sizer_params->Add(p->object_settings->get_sizer(), 0, wxEXPAND | wxTOP, margin_5);
|
||||||
|
|
||||||
wxBitmap arrow_up(GUI::from_u8(Slic3r::var("brick_go.png")), wxBITMAP_TYPE_PNG);
|
|
||||||
p->btn_send_gcode = new wxButton(this, wxID_ANY, _(L("Send to printer")));
|
p->btn_send_gcode = new wxButton(this, wxID_ANY, _(L("Send to printer")));
|
||||||
p->btn_send_gcode->SetBitmap(arrow_up);
|
|
||||||
p->btn_send_gcode->SetFont(wxGetApp().bold_font());
|
p->btn_send_gcode->SetFont(wxGetApp().bold_font());
|
||||||
p->btn_send_gcode->Hide();
|
p->btn_send_gcode->Hide();
|
||||||
|
|
||||||
|
@ -675,7 +681,14 @@ Sidebar::Sidebar(Plater *parent)
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
p->btn_export_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->export_gcode(); });
|
p->btn_export_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->export_gcode(); });
|
||||||
p->btn_reslice->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->reslice(); });
|
p->btn_reslice->Bind(wxEVT_BUTTON, [this](wxCommandEvent&)
|
||||||
|
{
|
||||||
|
const bool export_gcode_after_slicing = wxGetKeyState(WXK_SHIFT);
|
||||||
|
if (export_gcode_after_slicing)
|
||||||
|
p->plater->export_gcode();
|
||||||
|
else
|
||||||
|
p->plater->reslice();
|
||||||
|
});
|
||||||
p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); });
|
p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -744,6 +757,8 @@ void Sidebar::update_presets(Preset::Type preset_type)
|
||||||
|
|
||||||
case Preset::TYPE_PRINTER:
|
case Preset::TYPE_PRINTER:
|
||||||
{
|
{
|
||||||
|
wxWindowUpdateLocker noUpdates_scrolled(p->scrolled);
|
||||||
|
|
||||||
// Update the print choosers to only contain the compatible presets, update the dirty flags.
|
// Update the print choosers to only contain the compatible presets, update the dirty flags.
|
||||||
if (print_tech == ptFFF)
|
if (print_tech == ptFFF)
|
||||||
preset_bundle.prints.update_platter_ui(p->combo_print);
|
preset_bundle.prints.update_platter_ui(p->combo_print);
|
||||||
|
@ -773,9 +788,15 @@ void Sidebar::update_presets(Preset::Type preset_type)
|
||||||
wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config);
|
wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sidebar::update_mode_sizer(const Slic3r::ConfigOptionMode& mode)
|
void Sidebar::update_mode_sizer() const
|
||||||
{
|
{
|
||||||
p->mode_sizer->SetMode(mode);
|
p->mode_sizer->SetMode(m_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sidebar::update_reslice_btn_tooltip() const
|
||||||
|
{
|
||||||
|
const wxString tooltip = m_mode == comSimple ? wxString("") : _(L("Hold Shift to Slice & Export G-code"));
|
||||||
|
p->btn_reslice->SetToolTip(tooltip);
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectManipulation* Sidebar::obj_manipul()
|
ObjectManipulation* Sidebar::obj_manipul()
|
||||||
|
@ -968,8 +989,9 @@ void Sidebar::enable_buttons(bool enable)
|
||||||
p->btn_send_gcode->Enable(enable);
|
p->btn_send_gcode->Enable(enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sidebar::show_reslice(bool show) { p->btn_reslice->Show(show); }
|
void Sidebar::show_reslice(bool show) const { p->btn_reslice->Show(show); }
|
||||||
void Sidebar::show_send(bool show) { p->btn_send_gcode->Show(show); }
|
void Sidebar::show_export(bool show) const { p->btn_export_gcode->Show(show); }
|
||||||
|
void Sidebar::show_send(bool show) const { p->btn_send_gcode->Show(show); }
|
||||||
|
|
||||||
bool Sidebar::is_multifilament()
|
bool Sidebar::is_multifilament()
|
||||||
{
|
{
|
||||||
|
@ -977,6 +999,24 @@ bool Sidebar::is_multifilament()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Sidebar::update_mode()
|
||||||
|
{
|
||||||
|
m_mode = wxGetApp().get_mode();
|
||||||
|
|
||||||
|
update_reslice_btn_tooltip();
|
||||||
|
update_mode_sizer();
|
||||||
|
|
||||||
|
wxWindowUpdateLocker noUpdates(this);
|
||||||
|
|
||||||
|
p->object_list->get_sizer()->Show(m_mode > comSimple);
|
||||||
|
|
||||||
|
p->object_list->unselect_objects();
|
||||||
|
p->object_list->update_selections();
|
||||||
|
p->object_list->update_object_menu();
|
||||||
|
|
||||||
|
Layout();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<PresetComboBox*>& Sidebar::combos_filament()
|
std::vector<PresetComboBox*>& Sidebar::combos_filament()
|
||||||
{
|
{
|
||||||
return p->combos_filament;
|
return p->combos_filament;
|
||||||
|
@ -1060,6 +1100,9 @@ struct Plater::priv
|
||||||
|
|
||||||
wxTimer background_process_timer;
|
wxTimer background_process_timer;
|
||||||
|
|
||||||
|
std::string label_btn_export;
|
||||||
|
std::string label_btn_send;
|
||||||
|
|
||||||
static const std::regex pattern_bundle;
|
static const std::regex pattern_bundle;
|
||||||
static const std::regex pattern_3mf;
|
static const std::regex pattern_3mf;
|
||||||
static const std::regex pattern_zip_amf;
|
static const std::regex pattern_zip_amf;
|
||||||
|
@ -1148,6 +1191,7 @@ struct Plater::priv
|
||||||
void on_3dcanvas_mouse_dragging_finished(SimpleEvent&);
|
void on_3dcanvas_mouse_dragging_finished(SimpleEvent&);
|
||||||
|
|
||||||
void update_object_menu();
|
void update_object_menu();
|
||||||
|
void show_action_buttons(const bool is_ready_to_slice) const;
|
||||||
|
|
||||||
// Set the bed shape to a single closed 2D polygon(array of two element arrays),
|
// Set the bed shape to a single closed 2D polygon(array of two element arrays),
|
||||||
// triangulate the bed and store the triangles into m_bed.m_triangles,
|
// triangulate the bed and store the triangles into m_bed.m_triangles,
|
||||||
|
@ -2110,13 +2154,36 @@ unsigned int Plater::priv::update_background_process(bool force_validation)
|
||||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, evt.Clone());
|
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, evt.Clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIXME update "Slice Now / Schedule background process"
|
if ((return_state & UPDATE_BACKGROUND_PROCESS_INVALID) != 0)
|
||||||
//background_process.is_export_scheduled() - byl zavolan "Export G-code", background processing ma jmeno export souboru
|
{
|
||||||
//background_process.is_upload_scheduled() - byl zavolan "Send to OctoPrint", jeste nebylo doslajsovano (pak se preda upload fronte a background process zapomene)
|
// Validation of the background data failed.
|
||||||
//background_process.empty() - prazdna plocha
|
const wxString invalid_str = _(L("Invalid data"));
|
||||||
// pokud (return_state & UPDATE_BACKGROUND_PROCESS_INVALID) != 0 -> doslo k chybe (gray out "Slice now") mozna "Invalid data"???
|
for (auto btn : {ActionButtonType::abReslice, ActionButtonType::abSendGCode, ActionButtonType::abExport})
|
||||||
// jinak background_process.running() -> Zobraz "Slicing ..."
|
sidebar->set_btn_label(btn, invalid_str);
|
||||||
// jinak pokud ! background_process.empty() && ! background_process.finished() -> je neco ke slajsovani (povol tlacitko) "Slice Now"
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Background data is valid.
|
||||||
|
if ((return_state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 ||
|
||||||
|
(return_state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) != 0 )
|
||||||
|
this->statusbar()->set_status_text(L("Ready to slice"));
|
||||||
|
|
||||||
|
sidebar->set_btn_label(ActionButtonType::abExport, _(label_btn_export));
|
||||||
|
sidebar->set_btn_label(ActionButtonType::abSendGCode, _(label_btn_send));
|
||||||
|
|
||||||
|
const wxString slice_string = background_process.running() && wxGetApp().get_mode() == comSimple ?
|
||||||
|
_(L("Slicing")) + dots : _(L("Slice now"));
|
||||||
|
sidebar->set_btn_label(ActionButtonType::abReslice, slice_string);
|
||||||
|
|
||||||
|
if (background_process.finished())
|
||||||
|
show_action_buttons(false);
|
||||||
|
else if (!background_process.empty() &&
|
||||||
|
!background_process.running()) /* Do not update buttons if background process is running
|
||||||
|
* This condition is important for SLA mode especially,
|
||||||
|
* when this function is called several times during calculations
|
||||||
|
* */
|
||||||
|
show_action_buttons(true);
|
||||||
|
}
|
||||||
|
|
||||||
return return_state;
|
return return_state;
|
||||||
}
|
}
|
||||||
|
@ -2398,14 +2465,17 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt)
|
||||||
this->statusbar()->reset_cancel_callback();
|
this->statusbar()->reset_cancel_callback();
|
||||||
this->statusbar()->stop_busy();
|
this->statusbar()->stop_busy();
|
||||||
|
|
||||||
bool canceled = evt.GetInt() < 0;
|
const bool canceled = evt.GetInt() < 0;
|
||||||
bool success = evt.GetInt() > 0;
|
const bool error = evt.GetInt() == 0;
|
||||||
|
const bool success = evt.GetInt() > 0;
|
||||||
// Reset the "export G-code path" name, so that the automatic background processing will be enabled again.
|
// Reset the "export G-code path" name, so that the automatic background processing will be enabled again.
|
||||||
this->background_process.reset_export();
|
this->background_process.reset_export();
|
||||||
if (! success) {
|
|
||||||
|
if (error) {
|
||||||
wxString message = evt.GetString();
|
wxString message = evt.GetString();
|
||||||
if (message.IsEmpty())
|
if (message.IsEmpty())
|
||||||
message = _(L("Export failed"));
|
message = _(L("Export failed"));
|
||||||
|
show_error(q, message);
|
||||||
this->statusbar()->set_status_text(message);
|
this->statusbar()->set_status_text(message);
|
||||||
}
|
}
|
||||||
if (canceled)
|
if (canceled)
|
||||||
|
@ -2430,6 +2500,14 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt)
|
||||||
this->update_sla_scene();
|
this->update_sla_scene();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (canceled) {
|
||||||
|
if (wxGetApp().get_mode() == comSimple)
|
||||||
|
sidebar->set_btn_label(ActionButtonType::abReslice, "Slice now");
|
||||||
|
show_action_buttons(true);
|
||||||
|
}
|
||||||
|
else if (wxGetApp().get_mode() == comSimple)
|
||||||
|
show_action_buttons(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::on_layer_editing_toggled(bool enable)
|
void Plater::priv::on_layer_editing_toggled(bool enable)
|
||||||
|
@ -2798,6 +2876,38 @@ void Plater::priv::update_object_menu()
|
||||||
view3D->update_toolbar_items_visibility();
|
view3D->update_toolbar_items_visibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const
|
||||||
|
{
|
||||||
|
wxWindowUpdateLocker noUpdater(sidebar);
|
||||||
|
const auto prin_host_opt = config->option<ConfigOptionString>("print_host");
|
||||||
|
const bool send_gcode_shown = prin_host_opt != nullptr && !prin_host_opt->value.empty();
|
||||||
|
|
||||||
|
// when a background processing is ON, export_btn and/or send_btn are showing
|
||||||
|
if (wxGetApp().app_config->get("background_processing") == "1")
|
||||||
|
{
|
||||||
|
sidebar->show_reslice(false);
|
||||||
|
sidebar->show_export(true);
|
||||||
|
sidebar->show_send(send_gcode_shown);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sidebar->show_reslice(is_ready_to_slice);
|
||||||
|
sidebar->show_export(!is_ready_to_slice);
|
||||||
|
sidebar->show_send(send_gcode_shown && !is_ready_to_slice);
|
||||||
|
}
|
||||||
|
sidebar->Layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& label) const
|
||||||
|
{
|
||||||
|
switch (btn_type)
|
||||||
|
{
|
||||||
|
case ActionButtonType::abReslice: p->btn_reslice->SetLabelText(label); break;
|
||||||
|
case ActionButtonType::abExport: p->btn_export_gcode->SetLabelText(label); break;
|
||||||
|
case ActionButtonType::abSendGCode: p->btn_send_gcode->SetLabelText(label); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Plater / Public
|
// Plater / Public
|
||||||
|
|
||||||
Plater::Plater(wxWindow *parent, MainFrame *main_frame)
|
Plater::Plater(wxWindow *parent, MainFrame *main_frame)
|
||||||
|
@ -3124,6 +3234,22 @@ void Plater::reslice()
|
||||||
this->p->background_process.set_task(PrintBase::TaskParams());
|
this->p->background_process.set_task(PrintBase::TaskParams());
|
||||||
// Only restarts if the state is valid.
|
// Only restarts if the state is valid.
|
||||||
this->p->restart_background_process(state | priv::UPDATE_BACKGROUND_PROCESS_FORCE_RESTART);
|
this->p->restart_background_process(state | priv::UPDATE_BACKGROUND_PROCESS_FORCE_RESTART);
|
||||||
|
|
||||||
|
if ((state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (p->background_process.running())
|
||||||
|
{
|
||||||
|
if (wxGetApp().get_mode() == comSimple)
|
||||||
|
p->sidebar->set_btn_label(ActionButtonType::abReslice, _(L("Slicing")) + dots);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p->sidebar->set_btn_label(ActionButtonType::abReslice, _(L("Slice now")));
|
||||||
|
p->show_action_buttons(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!p->background_process.empty() && !p->background_process.idle())
|
||||||
|
p->show_action_buttons(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::reslice_SLA_supports(const ModelObject &object)
|
void Plater::reslice_SLA_supports(const ModelObject &object)
|
||||||
|
@ -3322,6 +3448,9 @@ void Plater::set_printer_technology(PrinterTechnology printer_technology)
|
||||||
}
|
}
|
||||||
//FIXME for SLA synchronize
|
//FIXME for SLA synchronize
|
||||||
//p->background_process.apply(Model)!
|
//p->background_process.apply(Model)!
|
||||||
|
|
||||||
|
p->label_btn_export = printer_technology == ptFFF ? L("Export G-code") : L("Export");
|
||||||
|
p->label_btn_send = printer_technology == ptFFF ? L("Send G-code") : L("Send to printer");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::changed_object(int obj_idx)
|
void Plater::changed_object(int obj_idx)
|
||||||
|
|
|
@ -38,6 +38,7 @@ class GLCanvas3D;
|
||||||
using t_optgroups = std::vector <std::shared_ptr<ConfigOptionsGroup>>;
|
using t_optgroups = std::vector <std::shared_ptr<ConfigOptionsGroup>>;
|
||||||
|
|
||||||
class Plater;
|
class Plater;
|
||||||
|
enum class ActionButtonType : int;
|
||||||
|
|
||||||
class PresetComboBox : public wxBitmapComboBox
|
class PresetComboBox : public wxBitmapComboBox
|
||||||
{
|
{
|
||||||
|
@ -61,7 +62,7 @@ private:
|
||||||
|
|
||||||
class Sidebar : public wxPanel
|
class Sidebar : public wxPanel
|
||||||
{
|
{
|
||||||
/*ConfigOptionMode*/int m_mode;
|
ConfigOptionMode m_mode;
|
||||||
public:
|
public:
|
||||||
Sidebar(Plater *parent);
|
Sidebar(Plater *parent);
|
||||||
Sidebar(Sidebar &&) = delete;
|
Sidebar(Sidebar &&) = delete;
|
||||||
|
@ -73,7 +74,8 @@ public:
|
||||||
void init_filament_combo(PresetComboBox **combo, const int extr_idx);
|
void init_filament_combo(PresetComboBox **combo, const int extr_idx);
|
||||||
void remove_unused_filament_combos(const int current_extruder_count);
|
void remove_unused_filament_combos(const int current_extruder_count);
|
||||||
void update_presets(Slic3r::Preset::Type preset_type);
|
void update_presets(Slic3r::Preset::Type preset_type);
|
||||||
void update_mode_sizer(const Slic3r::ConfigOptionMode& mode);
|
void update_mode_sizer() const;
|
||||||
|
void update_reslice_btn_tooltip() const;
|
||||||
|
|
||||||
ObjectManipulation* obj_manipul();
|
ObjectManipulation* obj_manipul();
|
||||||
ObjectList* obj_list();
|
ObjectList* obj_list();
|
||||||
|
@ -86,10 +88,12 @@ public:
|
||||||
void show_info_sizer();
|
void show_info_sizer();
|
||||||
void show_sliced_info_sizer(const bool show);
|
void show_sliced_info_sizer(const bool show);
|
||||||
void enable_buttons(bool enable);
|
void enable_buttons(bool enable);
|
||||||
void show_reslice(bool show);
|
void set_btn_label(const ActionButtonType btn_type, const wxString& label) const;
|
||||||
void show_send(bool show);
|
void show_reslice(bool show) const;
|
||||||
|
void show_export(bool show) const;
|
||||||
|
void show_send(bool show) const;
|
||||||
bool is_multifilament();
|
bool is_multifilament();
|
||||||
void set_mode_value(const /*ConfigOptionMode*/int mode) { m_mode = mode; }
|
void update_mode();
|
||||||
|
|
||||||
std::vector<PresetComboBox*>& combos_filament();
|
std::vector<PresetComboBox*>& combos_filament();
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -751,6 +751,10 @@ void Tab::load_key_value(const std::string& opt_key, const boost::any& value, bo
|
||||||
|
|
||||||
void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||||
{
|
{
|
||||||
|
if (wxGetApp().plater() == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const bool is_fff = supports_printer_technology(ptFFF);
|
const bool is_fff = supports_printer_technology(ptFFF);
|
||||||
ConfigOptionsGroup* og_freq_chng_params = wxGetApp().sidebar().og_freq_chng_params(is_fff);
|
ConfigOptionsGroup* og_freq_chng_params = wxGetApp().sidebar().og_freq_chng_params(is_fff);
|
||||||
if (opt_key == "fill_density" || opt_key == "pad_enable")
|
if (opt_key == "fill_density" || opt_key == "pad_enable")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue