Merge remote-tracking branch 'remotes/origin/master' into lh_adaptive_infill_hooks

This commit is contained in:
Vojtech Bubnik 2020-11-16 10:54:19 +01:00
commit e77fc43159
135 changed files with 8427 additions and 6977 deletions

View file

@ -138,7 +138,6 @@ int CLI::run(int argc, char **argv)
m_print_config.apply(config);
}
#if ENABLE_GCODE_VIEWER
// are we starting as gcodeviewer ?
for (auto it = m_actions.begin(); it != m_actions.end(); ++it) {
if (*it == "gcodeviewer") {
@ -148,10 +147,8 @@ int CLI::run(int argc, char **argv)
break;
}
}
#endif // ENABLE_GCODE_VIEWER
// Read input file(s) if any.
#if ENABLE_GCODE_VIEWER
for (const std::string& file : m_input_files) {
std::string ext = boost::filesystem::path(file).extension().string();
if (ext == ".gcode" || ext == ".g") {
@ -162,7 +159,6 @@ int CLI::run(int argc, char **argv)
}
}
if (!start_as_gcodeviewer) {
#endif // ENABLE_GCODE_VIEWER
for (const std::string& file : m_input_files) {
if (!boost::filesystem::exists(file)) {
boost::nowide::cerr << "No such file: " << file << std::endl;
@ -195,9 +191,7 @@ int CLI::run(int argc, char **argv)
}
m_models.push_back(model);
}
#if ENABLE_GCODE_VIEWER
}
#endif // ENABLE_GCODE_VIEWER
// Apply command line options to a more specific DynamicPrintConfig which provides normalize()
// (command line options override --load files)
@ -504,11 +498,7 @@ int CLI::run(int argc, char **argv)
print->process();
if (printer_technology == ptFFF) {
// The outfile is processed by a PlaceholderParser.
#if ENABLE_GCODE_VIEWER
outfile = fff_print.export_gcode(outfile, nullptr, nullptr);
#else
outfile = fff_print.export_gcode(outfile, nullptr);
#endif // ENABLE_GCODE_VIEWER
outfile_final = fff_print.print_statistics().finalize_output_path(outfile);
} else {
outfile = sla_print.output_filepath(outfile);
@ -559,11 +549,6 @@ int CLI::run(int argc, char **argv)
<< " (" << print.total_extruded_volume()/1000 << "cm3)" << std::endl;
*/
}
#if !ENABLE_GCODE_VIEWER
} else if (opt_key == "gcodeviewer") {
start_gui = true;
start_as_gcodeviewer = true;
#endif // !ENABLE_GCODE_VIEWER
} else {
boost::nowide::cerr << "error: option not supported yet: " << opt_key << std::endl;
return 1;

View file

@ -7,4 +7,6 @@ THIS DIRECTORY CONTAINS THE imgui-1.75 58b3e02 SOURCE DISTRIBUTION.
Customized with the following commits:
042880ba2df913916b2cc77f7bb677e07bfd2c58
67c55c74901f1d337ef08f2090a87cfb4263bb0f
a94c952b40d36b1505fb77b87c0dd739e1034659
a94c952b40d36b1505fb77b87c0dd739e1034659
3ca3a544a87cc569b69351a77996c287763388a5
6586a46ea23e86d54d228c55c63ca55680d25d56

View file

@ -113,14 +113,16 @@ namespace ImGui
const char PrinterSlaIconMarker = 0x6;
const char FilamentIconMarker = 0x7;
const char MaterialIconMarker = 0x8;
const char CloseIconMarker = 0xB;
const char CloseIconHoverMarker = 0xC;
const char CloseNotifButton = 0xB;
const char CloseNotifHoverButton = 0xC;
// const char TimerDotMarker = 0xE;
// const char TimerDotEmptyMarker = 0xF;
const char MinimalizeMarker = 0xE;
const char MinimalizeHoverMarker = 0xF;
const char MinimalizeButton = 0xE;
const char MinimalizeHoverButton = 0xF;
const char WarningMarker = 0x10;
const char ErrorMarker = 0x11;
const char EjectButton = 0x12;
const char EjectHoverButton = 0x13;
// void MyFunction(const char* name, const MyMatrix44& v);
}

View file

@ -38,9 +38,7 @@ void AppConfig::reset()
// Override missing or keys with their defaults.
void AppConfig::set_defaults()
{
#if ENABLE_GCODE_VIEWER
if (m_mode == EAppMode::Editor) {
#endif // ENABLE_GCODE_VIEWER
// Reset the empty fields to defaults.
if (get("autocenter").empty())
set("autocenter", "0");
@ -57,6 +55,11 @@ void AppConfig::set_defaults()
if (get("show_incompatible_presets").empty())
set("show_incompatible_presets", "0");
if (get("show_drop_project_dialog").empty())
set("show_drop_project_dialog", "1");
if (get("drop_project_action").empty())
set("drop_project_action", "1");
if (get("version_check").empty())
set("version_check", "1");
if (get("preset_update").empty())
@ -98,17 +101,6 @@ void AppConfig::set_defaults()
if (get("auto_toolbar_size").empty())
set("auto_toolbar_size", "100");
#if !ENABLE_GCODE_VIEWER
if (get("use_perspective_camera").empty())
set("use_perspective_camera", "1");
if (get("use_free_camera").empty())
set("use_free_camera", "0");
if (get("reverse_mouse_wheel_zoom").empty())
set("reverse_mouse_wheel_zoom", "0");
#endif // !ENABLE_GCODE_VIEWER
#if ENABLE_ENVIRONMENT_MAP
if (get("use_environment_map").empty())
set("use_environment_map", "0");
@ -116,7 +108,6 @@ void AppConfig::set_defaults()
if (get("use_inches").empty())
set("use_inches", "0");
#if ENABLE_GCODE_VIEWER
}
if (get("seq_top_layer_only").empty())
@ -130,7 +121,6 @@ void AppConfig::set_defaults()
if (get("reverse_mouse_wheel_zoom").empty())
set("reverse_mouse_wheel_zoom", "0");
#endif // ENABLE_GCODE_VIEWER
if (get("show_splash_screen").empty())
set("show_splash_screen", "1");
@ -247,14 +237,10 @@ void AppConfig::save()
boost::nowide::ofstream c;
c.open(path_pid, std::ios::out | std::ios::trunc);
#if ENABLE_GCODE_VIEWER
if (m_mode == EAppMode::Editor)
c << "# " << Slic3r::header_slic3r_generated() << std::endl;
else
c << "# " << Slic3r::header_gcodeviewer_generated() << std::endl;
#else
c << "# " << Slic3r::header_slic3r_generated() << std::endl;
#endif // ENABLE_GCODE_VIEWER
// Make sure the "no" category is written first.
for (const std::pair<std::string, std::string> &kvp : m_storage[""])
c << kvp.first << " = " << kvp.second << std::endl;
@ -455,15 +441,11 @@ void AppConfig::reset_selections()
std::string AppConfig::config_path()
{
#if ENABLE_GCODE_VIEWER
std::string path = (m_mode == EAppMode::Editor) ?
(boost::filesystem::path(Slic3r::data_dir()) / (SLIC3R_APP_KEY ".ini")).make_preferred().string() :
(boost::filesystem::path(Slic3r::data_dir()) / (GCODEVIEWER_APP_KEY ".ini")).make_preferred().string();
return path;
#else
return (boost::filesystem::path(Slic3r::data_dir()) / (SLIC3R_APP_KEY ".ini")).make_preferred().string();
#endif // ENABLE_GCODE_VIEWER
}
std::string AppConfig::version_check_url() const
@ -474,11 +456,7 @@ std::string AppConfig::version_check_url() const
bool AppConfig::exists()
{
#if ENABLE_GCODE_VIEWER
return boost::filesystem::exists(config_path());
#else
return boost::filesystem::exists(AppConfig::config_path());
#endif // ENABLE_GCODE_VIEWER
}
}; // namespace Slic3r

View file

@ -15,7 +15,6 @@ namespace Slic3r {
class AppConfig
{
public:
#if ENABLE_GCODE_VIEWER
enum class EAppMode : unsigned char
{
Editor,
@ -23,14 +22,9 @@ public:
};
explicit AppConfig(EAppMode mode) :
#else
AppConfig() :
#endif // ENABLE_GCODE_VIEWER
m_dirty(false),
m_orig_version(Semver::invalid()),
#if ENABLE_GCODE_VIEWER
m_mode(mode),
#endif // ENABLE_GCODE_VIEWER
m_legacy_datadir(false)
{
this->reset();
@ -135,11 +129,7 @@ public:
void reset_selections();
// Get the default config path from Slic3r::data_dir().
#if ENABLE_GCODE_VIEWER
std::string config_path();
#else
static std::string config_path();
#endif // ENABLE_GCODE_VIEWER
// Returns true if the user's data directory comes from before Slic3r 1.40.0 (no updating)
bool legacy_datadir() const { return m_legacy_datadir; }
@ -154,11 +144,7 @@ public:
Semver orig_version() const { return m_orig_version; }
// Does the config file exist?
#if ENABLE_GCODE_VIEWER
bool exists();
#else
static bool exists();
#endif // ENABLE_GCODE_VIEWER
std::vector<std::string> get_recent_projects() const;
void set_recent_projects(const std::vector<std::string>& recent_projects);
@ -196,10 +182,8 @@ private:
return true;
}
#if ENABLE_GCODE_VIEWER
// Type of application: Editor or GCodeViewer
EAppMode m_mode { EAppMode::Editor };
#endif // ENABLE_GCODE_VIEWER
// Map of section, name -> value
std::map<std::string, std::map<std::string, std::string>> m_storage;
// Map of enabled vendors / models / variants

View file

@ -87,8 +87,6 @@ add_library(libslic3r STATIC
GCode/PostProcessor.hpp
# GCode/PressureEqualizer.cpp
# GCode/PressureEqualizer.hpp
GCode/PreviewData.cpp
GCode/PreviewData.hpp
GCode/PrintExtents.cpp
GCode/PrintExtents.hpp
GCode/SpiralVase.cpp

View file

@ -192,6 +192,23 @@ bool unescape_strings_cstyle(const std::string &str, std::vector<std::string> &o
}
}
std::string escape_ampersand(const std::string& str)
{
// Allocate a buffer 2 times the input string length,
// so the output will fit even if all input characters get escaped.
std::vector<char> out(str.size() * 6, 0);
char* outptr = out.data();
for (size_t i = 0; i < str.size(); ++i) {
char c = str[i];
if (c == '&') {
(*outptr++) = '&';
(*outptr++) = '&';
} else
(*outptr++) = c;
}
return std::string(out.data(), outptr - out.data());
}
std::vector<std::string> ConfigOptionDef::cli_args(const std::string &key) const
{
std::vector<std::string> args;

View file

@ -34,6 +34,8 @@ extern std::string escape_strings_cstyle(const std::vector<std::string> &strs);
extern bool unescape_string_cstyle(const std::string &str, std::string &out);
extern bool unescape_strings_cstyle(const std::string &str, std::vector<std::string> &out);
extern std::string escape_ampersand(const std::string& str);
/// Specialization of std::exception to indicate that an unknown config option has been encountered.
class UnknownOptionException : public Slic3r::RuntimeError {
public:

View file

@ -1,10 +1,6 @@
#include "CustomGCode.hpp"
#include "Config.hpp"
#if ENABLE_GCODE_VIEWER
#include "GCode.hpp"
#else
#include "GCode/PreviewData.hpp"
#endif // ENABLE_GCODE_VIEWER
#include "GCodeWriter.hpp"
namespace Slic3r {
@ -21,11 +17,7 @@ extern void update_custom_gcode_per_print_z_from_config(Info& info, DynamicPrint
return;
if (info.gcodes.empty() && ! colorprint_heights->values.empty()) {
// Convert the old colorprint_heighs only if there is no equivalent data in a new format.
#if ENABLE_GCODE_VIEWER
const std::vector<std::string>& colors = ColorPrintColors::get();
#else
const std::vector<std::string>& colors = GCodePreviewData::ColorPrintColors();
#endif // ENABLE_GCODE_VIEWER
const auto& colorprint_values = colorprint_heights->values;
info.gcodes.clear();
info.gcodes.reserve(colorprint_values.size());

View file

@ -20,6 +20,7 @@ SLIC3R_DERIVE_EXCEPTION(OutOfRange, LogicError);
SLIC3R_DERIVE_EXCEPTION(IOError, CriticalException);
SLIC3R_DERIVE_EXCEPTION(FileIOError, IOError);
SLIC3R_DERIVE_EXCEPTION(HostNetworkError, IOError);
SLIC3R_DERIVE_EXCEPTION(ExportError, CriticalException);
// Runtime exception produced by Slicer. Such exception cancels the slicing process and it shall be shown in notifications.
SLIC3R_DERIVE_EXCEPTION(SlicingError, Exception);
#undef SLIC3R_DERIVE_EXCEPTION

View file

@ -306,11 +306,7 @@ double ExtrusionLoop::min_mm3_per_mm() const
std::string ExtrusionEntity::role_to_string(ExtrusionRole role)
{
switch (role) {
#if ENABLE_GCODE_VIEWER
case erNone : return L("Unknown");
#else
case erNone : return L("None");
#endif // ENABLE_GCODE_VIEWER
case erPerimeter : return L("Perimeter");
case erExternalPerimeter : return L("External perimeter");
case erOverhangPerimeter : return L("Overhang perimeter");

View file

@ -546,9 +546,7 @@ namespace Slic3r {
return gcode;
}
#if ENABLE_GCODE_VIEWER
const std::vector<std::string> ColorPrintColors::Colors = { "#C0392B", "#E67E22", "#F1C40F", "#27AE60", "#1ABC9C", "#2980B9", "#9B59B6" };
#endif // ENABLE_GCODE_VIEWER
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.extruder()->id())
@ -687,7 +685,6 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
return layers_to_print;
}
#if ENABLE_GCODE_VIEWER
// free functions called by GCode::do_export()
namespace DoExport {
static void update_print_estimated_times_stats(const GCodeProcessor& processor, PrintStatistics& print_statistics)
@ -700,9 +697,6 @@ namespace DoExport {
} // namespace DoExport
void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb)
#else
void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
#endif // ENABLE_GCODE_VIEWER
{
PROFILE_CLEAR();
@ -724,10 +718,6 @@ void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_
if (file == nullptr)
throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
#if !ENABLE_GCODE_VIEWER
m_enable_analyzer = preview_data != nullptr;
#endif // !ENABLE_GCODE_VIEWER
try {
m_placeholder_parser_failed_templates.clear();
this->_do_export(*print, file, thumbnail_cb);
@ -759,35 +749,12 @@ void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_
throw Slic3r::RuntimeError(msg);
}
#if ENABLE_GCODE_VIEWER
BOOST_LOG_TRIVIAL(debug) << "Start processing gcode, " << log_memory_info();
m_processor.process_file(path_tmp, [print]() { print->throw_if_canceled(); });
m_processor.process_file(path_tmp, true, [print]() { print->throw_if_canceled(); });
DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics);
if (result != nullptr)
*result = std::move(m_processor.extract_result());
BOOST_LOG_TRIVIAL(debug) << "Finished processing gcode, " << log_memory_info();
#else
GCodeTimeEstimator::PostProcessData normal_data = m_normal_time_estimator.get_post_process_data();
GCodeTimeEstimator::PostProcessData silent_data = m_silent_time_estimator.get_post_process_data();
bool remaining_times_enabled = print->config().remaining_times.value;
BOOST_LOG_TRIVIAL(debug) << "Time estimator post processing" << log_memory_info();
GCodeTimeEstimator::post_process(path_tmp, 60.0f, remaining_times_enabled ? &normal_data : nullptr, (remaining_times_enabled && m_silent_time_estimator_enabled) ? &silent_data : nullptr);
if (remaining_times_enabled) {
m_normal_time_estimator.reset();
if (m_silent_time_estimator_enabled)
m_silent_time_estimator.reset();
}
// starts analyzer calculations
if (m_enable_analyzer) {
BOOST_LOG_TRIVIAL(debug) << "Preparing G-code preview data" << log_memory_info();
m_analyzer.calc_gcode_preview_data(*preview_data, [print]() { print->throw_if_canceled(); });
m_analyzer.reset();
}
#endif // ENABLE_GCODE_VIEWER
if (rename_file(path_tmp, path))
throw Slic3r::RuntimeError(
@ -804,88 +771,6 @@ void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_
// free functions called by GCode::_do_export()
namespace DoExport {
#if !ENABLE_GCODE_VIEWER
static void init_time_estimators(const PrintConfig &config, GCodeTimeEstimator &normal_time_estimator, GCodeTimeEstimator &silent_time_estimator, bool &silent_time_estimator_enabled)
{
// resets time estimators
normal_time_estimator.reset();
normal_time_estimator.set_dialect(config.gcode_flavor);
normal_time_estimator.set_extrusion_axis(config.get_extrusion_axis()[0]);
silent_time_estimator_enabled = (config.gcode_flavor == gcfMarlin) && config.silent_mode;
// Until we have a UI support for the other firmwares than the Marlin, use the hardcoded default values
// and let the user to enter the G-code limits into the start G-code.
// If the following block is enabled for other firmwares than the Marlin, then the function
// this->print_machine_envelope(file, print);
// shall be adjusted as well to produce a G-code block compatible with the particular firmware flavor.
if (config.gcode_flavor.value == gcfMarlin) {
if (config.machine_limits_usage.value != MachineLimitsUsage::Ignore) {
normal_time_estimator.set_max_acceleration((float)config.machine_max_acceleration_extruding.values[0]);
normal_time_estimator.set_retract_acceleration((float)config.machine_max_acceleration_retracting.values[0]);
normal_time_estimator.set_minimum_feedrate((float)config.machine_min_extruding_rate.values[0]);
normal_time_estimator.set_minimum_travel_feedrate((float)config.machine_min_travel_rate.values[0]);
normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)config.machine_max_acceleration_x.values[0]);
normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)config.machine_max_acceleration_y.values[0]);
normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)config.machine_max_acceleration_z.values[0]);
normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)config.machine_max_acceleration_e.values[0]);
normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)config.machine_max_feedrate_x.values[0]);
normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)config.machine_max_feedrate_y.values[0]);
normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)config.machine_max_feedrate_z.values[0]);
normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)config.machine_max_feedrate_e.values[0]);
normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)config.machine_max_jerk_x.values[0]);
normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)config.machine_max_jerk_y.values[0]);
normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)config.machine_max_jerk_z.values[0]);
normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)config.machine_max_jerk_e.values[0]);
}
if (silent_time_estimator_enabled)
{
silent_time_estimator.reset();
silent_time_estimator.set_dialect(config.gcode_flavor);
silent_time_estimator.set_extrusion_axis(config.get_extrusion_axis()[0]);
if (config.machine_limits_usage.value != MachineLimitsUsage::Ignore) {
/* "Stealth mode" values can be just a copy of "normal mode" values
* (when they aren't input for a printer preset).
* Thus, use back value from values, instead of second one, which could be absent
*/
silent_time_estimator.set_max_acceleration((float)config.machine_max_acceleration_extruding.values.back());
silent_time_estimator.set_retract_acceleration((float)config.machine_max_acceleration_retracting.values.back());
silent_time_estimator.set_minimum_feedrate((float)config.machine_min_extruding_rate.values.back());
silent_time_estimator.set_minimum_travel_feedrate((float)config.machine_min_travel_rate.values.back());
silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)config.machine_max_acceleration_x.values.back());
silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)config.machine_max_acceleration_y.values.back());
silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)config.machine_max_acceleration_z.values.back());
silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)config.machine_max_acceleration_e.values.back());
silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)config.machine_max_feedrate_x.values.back());
silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)config.machine_max_feedrate_y.values.back());
silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)config.machine_max_feedrate_z.values.back());
silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)config.machine_max_feedrate_e.values.back());
silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)config.machine_max_jerk_x.values.back());
silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)config.machine_max_jerk_y.values.back());
silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)config.machine_max_jerk_z.values.back());
silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)config.machine_max_jerk_e.values.back());
}
if (config.single_extruder_multi_material) {
// As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they
// are considered to be active for the single extruder multi-material printers only.
silent_time_estimator.set_filament_load_times(config.filament_load_time.values);
silent_time_estimator.set_filament_unload_times(config.filament_unload_time.values);
}
}
}
// Filament load / unload times are not specific to a firmware flavor. Let anybody use it if they find it useful.
if (config.single_extruder_multi_material) {
// As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they
// are considered to be active for the single extruder multi-material printers only.
normal_time_estimator.set_filament_load_times(config.filament_load_time.values);
normal_time_estimator.set_filament_unload_times(config.filament_unload_time.values);
}
}
#endif // !ENABLE_GCODE_VIEWER
#if ENABLE_GCODE_VIEWER
static void init_gcode_processor(const PrintConfig& config, GCodeProcessor& processor, bool& silent_time_estimator_enabled)
{
silent_time_estimator_enabled = (config.gcode_flavor == gcfMarlin) && config.silent_mode;
@ -893,33 +778,6 @@ namespace DoExport {
processor.apply_config(config);
processor.enable_stealth_time_estimator(silent_time_estimator_enabled);
}
#else
static void init_gcode_analyzer(const PrintConfig &config, GCodeAnalyzer &analyzer)
{
// resets analyzer
analyzer.reset();
// send extruder offset data to analyzer
GCodeAnalyzer::ExtruderOffsetsMap extruder_offsets;
unsigned int num_extruders = static_cast<unsigned int>(config.nozzle_diameter.values.size());
for (unsigned int extruder_id = 0; extruder_id < num_extruders; ++ extruder_id)
{
Vec2d offset = config.extruder_offset.get_at(extruder_id);
if (!offset.isApprox(Vec2d::Zero()))
extruder_offsets[extruder_id] = offset;
}
analyzer.set_extruder_offsets(extruder_offsets);
// tell analyzer about the extrusion axis
analyzer.set_extrusion_axis(config.get_extrusion_axis()[0]);
// send extruders count to analyzer to allow it to detect invalid extruder idxs
analyzer.set_extruders_count(num_extruders);
// tell analyzer about the gcode flavor
analyzer.set_gcode_flavor(config.gcode_flavor);
}
#endif // ENABLE_GCODE_VIEWER
static double autospeed_volumetric_limit(const Print &print)
{
@ -1043,11 +901,6 @@ namespace DoExport {
// Fill in print_statistics and return formatted string containing filament statistics to be inserted into G-code comment section.
static std::string update_print_stats_and_format_filament_stats(
#if !ENABLE_GCODE_VIEWER
const GCodeTimeEstimator &normal_time_estimator,
const GCodeTimeEstimator &silent_time_estimator,
const bool silent_time_estimator_enabled,
#endif // !ENABLE_GCODE_VIEWER
const bool has_wipe_tower,
const WipeTowerData &wipe_tower_data,
const std::vector<Extruder> &extruders,
@ -1056,13 +909,6 @@ namespace DoExport {
std::string filament_stats_string_out;
print_statistics.clear();
#if !ENABLE_GCODE_VIEWER
print_statistics.estimated_normal_print_time = normal_time_estimator.get_time_dhm/*s*/();
print_statistics.estimated_silent_print_time = silent_time_estimator_enabled ? silent_time_estimator.get_time_dhm/*s*/() : "N/A";
print_statistics.estimated_normal_custom_gcode_print_times = normal_time_estimator.get_custom_gcode_times_dhm(true);
if (silent_time_estimator_enabled)
print_statistics.estimated_silent_custom_gcode_print_times = silent_time_estimator.get_custom_gcode_times_dhm(true);
#endif // !ENABLE_GCODE_VIEWER
print_statistics.total_toolchanges = std::max(0, wipe_tower_data.number_of_toolchanges);
if (! extruders.empty()) {
std::pair<std::string, unsigned int> out_filament_used_mm ("; filament used [mm] = ", 0);
@ -1153,29 +999,16 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
{
PROFILE_FUNC();
#if ENABLE_GCODE_VIEWER
// modifies m_silent_time_estimator_enabled
DoExport::init_gcode_processor(print.config(), m_processor, m_silent_time_estimator_enabled);
#else
DoExport::init_time_estimators(print.config(),
// modifies the following:
m_normal_time_estimator, m_silent_time_estimator, m_silent_time_estimator_enabled);
DoExport::init_gcode_analyzer(print.config(), m_analyzer);
#endif // ENABLE_GCODE_VIEWER
// resets analyzer's tracking data
#if ENABLE_GCODE_VIEWER
m_last_height = 0.0f;
m_last_layer_z = 0.0f;
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_last_mm3_per_mm = 0.0;
m_last_width = 0.0f;
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
#else
m_last_mm3_per_mm = GCodeAnalyzer::Default_mm3_per_mm;
m_last_width = GCodeAnalyzer::Default_Width;
m_last_height = GCodeAnalyzer::Default_Height;
#endif // ENABLE_GCODE_VIEWER
// How many times will be change_layer() called?
// change_layer() in turn increments the progress bar status.
@ -1266,16 +1099,8 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
print.throw_if_canceled();
// adds tags for time estimators
#if ENABLE_GCODE_VIEWER
if (print.config().remaining_times.value)
_writeln(file, GCodeProcessor::First_Line_M73_Placeholder_Tag);
#else
if (print.config().remaining_times.value) {
_writeln(file, GCodeTimeEstimator::Normal_First_M73_Output_Placeholder_Tag);
if (m_silent_time_estimator_enabled)
_writeln(file, GCodeTimeEstimator::Silent_First_M73_Output_Placeholder_Tag);
}
#endif // ENABLE_GCODE_VIEWER
// Prepare the helper object for replacing placeholders in custom G-code and output filename.
m_placeholder_parser = print.placeholder_parser();
@ -1380,14 +1205,8 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// Set extruder(s) temperature before and after start G-code.
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false);
#if ENABLE_GCODE_VIEWER
// adds tag for processor
_write_format(file, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
#else
if (m_enable_analyzer)
// adds tag for analyzer
_write_format(file, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom);
#endif // ENABLE_GCODE_VIEWER
// Write the custom start G-code
_writeln(file, start_gcode);
@ -1541,14 +1360,8 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
_write(file, this->retract());
_write(file, m_writer.set_fan(false));
#if ENABLE_GCODE_VIEWER
// adds tag for processor
_write_format(file, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
#else
if (m_enable_analyzer)
// adds tag for analyzer
_write_format(file, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom);
#endif // ENABLE_GCODE_VIEWER
// Process filament-specific gcode in extruder order.
{
@ -1573,32 +1386,14 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
_write(file, m_writer.postamble());
// adds tags for time estimators
#if ENABLE_GCODE_VIEWER
if (print.config().remaining_times.value)
_writeln(file, GCodeProcessor::Last_Line_M73_Placeholder_Tag);
#else
if (print.config().remaining_times.value) {
_writeln(file, GCodeTimeEstimator::Normal_Last_M73_Output_Placeholder_Tag);
if (m_silent_time_estimator_enabled)
_writeln(file, GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag);
}
#endif // ENABLE_GCODE_VIEWER
print.throw_if_canceled();
// calculates estimated printing time
#if !ENABLE_GCODE_VIEWER
m_normal_time_estimator.calculate_time(false);
if (m_silent_time_estimator_enabled)
m_silent_time_estimator.calculate_time(false);
#endif // !ENABLE_GCODE_VIEWER
// Get filament stats.
_write(file, DoExport::update_print_stats_and_format_filament_stats(
// Const inputs
#if !ENABLE_GCODE_VIEWER
m_normal_time_estimator, m_silent_time_estimator, m_silent_time_estimator_enabled,
#endif // !ENABLE_GCODE_VIEWER
has_wipe_tower, print.wipe_tower_data(),
m_writer.extruders(),
// Modifies
@ -1608,13 +1403,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
_write_format(file, "; total filament cost = %.2lf\n", print.m_print_statistics.total_cost);
if (print.m_print_statistics.total_toolchanges > 0)
_write_format(file, "; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges);
#if ENABLE_GCODE_VIEWER
_writeln(file, GCodeProcessor::Estimated_Printing_Time_Placeholder_Tag);
#else
_write_format(file, "; estimated printing time (normal mode) = %s\n", m_normal_time_estimator.get_time_dhms().c_str());
if (m_silent_time_estimator_enabled)
_write_format(file, "; estimated printing time (silent mode) = %s\n", m_silent_time_estimator.get_time_dhms().c_str());
#endif // ENABLE_GCODE_VIEWER
// Append full config.
_write(file, "\n");
@ -1896,15 +1685,8 @@ namespace ProcessLayer
{
assert(m600_extruder_before_layer >= 0);
// Color Change or Tool Change as Color Change.
#if ENABLE_GCODE_VIEWER
// add tag for processor
gcode += "; " + GCodeProcessor::Color_Change_Tag + ",T" + std::to_string(m600_extruder_before_layer) + "\n";
#else
// add tag for analyzer
gcode += "; " + GCodeAnalyzer::Color_Change_Tag + ",T" + std::to_string(m600_extruder_before_layer) + "\n";
// add tag for time estimator
gcode += "; " + GCodeTimeEstimator::Color_Change_Tag + "\n";
#endif // ENABLE_GCODE_VIEWER
gcode += ";" + GCodeProcessor::Color_Change_Tag + ",T" + std::to_string(m600_extruder_before_layer) + "\n";
if (!single_extruder_printer && m600_extruder_before_layer >= 0 && first_extruder_id != (unsigned)m600_extruder_before_layer
// && !MMU1
@ -1923,33 +1705,17 @@ namespace ProcessLayer
{
if (gcode_type == CustomGCode::PausePrint) // Pause print
{
#if ENABLE_GCODE_VIEWER
// add tag for processor
gcode += "; " + GCodeProcessor::Pause_Print_Tag + "\n";
#else
// add tag for analyzer
gcode += "; " + GCodeAnalyzer::Pause_Print_Tag + "\n";
#endif // ENABLE_GCODE_VIEWER
gcode += ";" + GCodeProcessor::Pause_Print_Tag + "\n";
//! FIXME_in_fw show message during print pause
if (!pause_print_msg.empty())
gcode += "M117 " + pause_print_msg + "\n";
#if !ENABLE_GCODE_VIEWER
// add tag for time estimator
gcode += "; " + GCodeTimeEstimator::Pause_Print_Tag + "\n";
#endif // !ENABLE_GCODE_VIEWER
gcode += config.pause_print_gcode;
}
else
{
#if ENABLE_GCODE_VIEWER
// add tag for processor
gcode += "; " + GCodeProcessor::Custom_Code_Tag + "\n";
#else
// add tag for analyzer
gcode += "; " + GCodeAnalyzer::Custom_Code_Tag + "\n";
#endif // ENABLE_GCODE_VIEWER
// add tag for time estimator
//gcode += "; " + GCodeTimeEstimator::Custom_Code_Tag + "\n";
gcode += ";" + GCodeProcessor::Custom_Code_Tag + "\n";
if (gcode_type == CustomGCode::Template) // Template Cistom Gcode
gcode += config.template_custom_gcode;
else // custom Gcode
@ -2091,7 +1857,6 @@ void GCode::process_layer(
std::string gcode;
#if ENABLE_GCODE_VIEWER
// add tag for processor
gcode += "; " + GCodeProcessor::Layer_Change_Tag + "\n";
// export layer z
@ -2105,7 +1870,6 @@ void GCode::process_layer(
// update caches
m_last_layer_z = static_cast<float>(print_z);
m_last_height = height;
#endif // ENABLE_GCODE_VIEWER
// Set new layer - this will change Z and force a retraction if retract_layer_change is enabled.
if (! print.config().before_layer_gcode.value.empty()) {
@ -2320,15 +2084,9 @@ void GCode::process_layer(
m_wipe_tower->tool_change(*this, extruder_id, extruder_id == layer_tools.extruders.back()) :
this->set_extruder(extruder_id, print_z);
#if ENABLE_GCODE_VIEWER
// let analyzer tag generator aware of a role type change
if (layer_tools.has_wipe_tower && m_wipe_tower)
m_last_processor_extrusion_role = erWipeTower;
#else
// let analyzer tag generator aware of a role type change
if (m_enable_analyzer && layer_tools.has_wipe_tower && m_wipe_tower)
m_last_analyzer_extrusion_role = erWipeTower;
#endif // ENABLE_GCODE_VIEWER
if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) {
const std::pair<size_t, size_t> loops = loops_it->second;
@ -2432,14 +2190,6 @@ void GCode::process_layer(
if (m_cooling_buffer)
gcode = m_cooling_buffer->process_layer(gcode, layer.id());
#if !ENABLE_GCODE_VIEWER
// add tag for analyzer
if (gcode.find(GCodeAnalyzer::Pause_Print_Tag) != gcode.npos)
gcode += "\n; " + GCodeAnalyzer::End_Pause_Print_Or_Custom_Code_Tag + "\n";
else if (gcode.find(GCodeAnalyzer::Custom_Code_Tag) != gcode.npos)
gcode += "\n; " + GCodeAnalyzer::End_Pause_Print_Or_Custom_Code_Tag + "\n";
#endif // !ENABLE_GCODE_VIEWER
#ifdef HAS_PRESSURE_EQUALIZER
// Apply pressure equalization if enabled;
// printf("G-code before filter:\n%s\n", gcode.c_str());
@ -2449,17 +2199,8 @@ void GCode::process_layer(
#endif /* HAS_PRESSURE_EQUALIZER */
_write(file, gcode);
#if ENABLE_GCODE_VIEWER
BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
log_memory_info();
#else
BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
", time estimator memory: " <<
format_memsize_MB(m_normal_time_estimator.memory_used() + (m_silent_time_estimator_enabled ? m_silent_time_estimator.memory_used() : 0)) <<
", analyzer memory: " <<
format_memsize_MB(m_analyzer.memory_used()) <<
log_memory_info();
#endif // ENABLE_GCODE_VIEWER
}
void GCode::apply_print_config(const PrintConfig &print_config)
@ -2790,21 +2531,9 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
void GCode::_write(FILE* file, const char *what)
{
if (what != nullptr) {
#if ENABLE_GCODE_VIEWER
const char* gcode = what;
#else
// apply analyzer, if enabled
const char* gcode = m_enable_analyzer ? m_analyzer.process_gcode(what).c_str() : what;
#endif // !ENABLE_GCODE_VIEWER
// writes string to file
fwrite(gcode, 1, ::strlen(gcode), file);
#if !ENABLE_GCODE_VIEWER
// updates time estimator and gcode lines vector
m_normal_time_estimator.add_gcode_block(gcode);
if (m_silent_time_estimator_enabled)
m_silent_time_estimator.add_gcode_block(gcode);
#endif // !ENABLE_GCODE_VIEWER
}
}
@ -2944,70 +2673,36 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
}
// adds processor tags and updates processor tracking data
#if ENABLE_GCODE_VIEWER
// PrusaMultiMaterial::Writer may generate GCodeProcessor::Height_Tag lines without updating m_last_height
// so, if the last role was erWipeTower we force export of GCodeProcessor::Height_Tag lines
bool last_was_wipe_tower = (m_last_processor_extrusion_role == erWipeTower);
#else
if (m_enable_analyzer) {
// PrusaMultiMaterial::Writer may generate GCodeAnalyzer::Height_Tag and GCodeAnalyzer::Width_Tag lines without updating m_last_height and m_last_width
// so, if the last role was erWipeTower we force export of GCodeAnalyzer::Height_Tag and GCodeAnalyzer::Width_Tag lines
bool last_was_wipe_tower = (m_last_analyzer_extrusion_role == erWipeTower);
#endif // ENABLE_GCODE_VIEWER
char buf[64];
char buf[64];
#if ENABLE_GCODE_VIEWER
if (path.role() != m_last_processor_extrusion_role) {
m_last_processor_extrusion_role = path.role();
sprintf(buf, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(m_last_processor_extrusion_role).c_str());
gcode += buf;
}
if (path.role() != m_last_processor_extrusion_role) {
m_last_processor_extrusion_role = path.role();
sprintf(buf, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(m_last_processor_extrusion_role).c_str());
gcode += buf;
}
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
if (last_was_wipe_tower || (m_last_mm3_per_mm != path.mm3_per_mm)) {
m_last_mm3_per_mm = path.mm3_per_mm;
sprintf(buf, ";%s%f\n", GCodeProcessor::Mm3_Per_Mm_Tag.c_str(), m_last_mm3_per_mm);
gcode += buf;
}
if (last_was_wipe_tower || (m_last_mm3_per_mm != path.mm3_per_mm)) {
m_last_mm3_per_mm = path.mm3_per_mm;
sprintf(buf, ";%s%f\n", GCodeProcessor::Mm3_Per_Mm_Tag.c_str(), m_last_mm3_per_mm);
gcode += buf;
}
if (last_was_wipe_tower || m_last_width != path.width) {
m_last_width = path.width;
sprintf(buf, ";%s%g\n", GCodeProcessor::Width_Tag.c_str(), m_last_width);
gcode += buf;
}
if (last_was_wipe_tower || m_last_width != path.width) {
m_last_width = path.width;
sprintf(buf, ";%s%g\n", GCodeProcessor::Width_Tag.c_str(), m_last_width);
gcode += buf;
}
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
if (last_was_wipe_tower || std::abs(m_last_height - path.height) > EPSILON) {
m_last_height = path.height;
sprintf(buf, ";%s%g\n", GCodeProcessor::Height_Tag.c_str(), m_last_height);
gcode += buf;
}
#else
if (path.role() != m_last_analyzer_extrusion_role) {
m_last_analyzer_extrusion_role = path.role();
sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), int(m_last_analyzer_extrusion_role));
gcode += buf;
}
if (last_was_wipe_tower || (m_last_mm3_per_mm != path.mm3_per_mm)) {
m_last_mm3_per_mm = path.mm3_per_mm;
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Mm3_Per_Mm_Tag.c_str(), m_last_mm3_per_mm);
gcode += buf;
}
if (last_was_wipe_tower || m_last_width != path.width) {
m_last_width = path.width;
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Width_Tag.c_str(), m_last_width);
gcode += buf;
}
if (last_was_wipe_tower || m_last_height != path.height) {
m_last_height = path.height;
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Height_Tag.c_str(), m_last_height);
gcode += buf;
}
if (last_was_wipe_tower || std::abs(m_last_height - path.height) > EPSILON) {
m_last_height = path.height;
sprintf(buf, ";%s%g\n", GCodeProcessor::Height_Tag.c_str(), m_last_height);
gcode += buf;
}
#endif // ENABLE_GCODE_VIEWER
std::string comment;
if (m_enable_cooling_markers) {

View file

@ -14,12 +14,7 @@
#include "GCode/ToolOrdering.hpp"
#include "GCode/WipeTower.hpp"
#include "GCode/SeamPlacer.hpp"
#if ENABLE_GCODE_VIEWER
#include "GCode/GCodeProcessor.hpp"
#else
#include "GCode/Analyzer.hpp"
#include "GCodeTimeEstimator.hpp"
#endif // ENABLE_GCODE_VIEWER
#include "EdgeGrid.hpp"
#include "GCode/ThumbnailData.hpp"
@ -34,9 +29,6 @@ namespace Slic3r {
// Forward declarations.
class GCode;
#if !ENABLE_GCODE_VIEWER
class GCodePreviewData;
#endif // !ENABLE_GCODE_VIEWER
namespace { struct Item; }
struct PrintInstance;
@ -146,14 +138,12 @@ private:
double m_last_wipe_tower_print_z = 0.f;
};
#if ENABLE_GCODE_VIEWER
class ColorPrintColors
{
static const std::vector<std::string> Colors;
public:
static const std::vector<std::string>& get() { return Colors; }
};
#endif // ENABLE_GCODE_VIEWER
class GCode {
public:
@ -161,13 +151,8 @@ public:
m_origin(Vec2d::Zero()),
m_enable_loop_clipping(true),
m_enable_cooling_markers(false),
m_enable_extrusion_role_markers(false),
#if ENABLE_GCODE_VIEWER
m_enable_extrusion_role_markers(false),
m_last_processor_extrusion_role(erNone),
#else
m_enable_analyzer(false),
m_last_analyzer_extrusion_role(erNone),
#endif // ENABLE_GCODE_VIEWER
m_layer_count(0),
m_layer_index(-1),
m_layer(nullptr),
@ -178,17 +163,8 @@ public:
m_last_mm3_per_mm(0.0),
m_last_width(0.0f),
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
#if !ENABLE_GCODE_VIEWER
m_last_mm3_per_mm(GCodeAnalyzer::Default_mm3_per_mm),
m_last_width(GCodeAnalyzer::Default_Width),
m_last_height(GCodeAnalyzer::Default_Height),
#endif // !ENABLE_GCODE_VIEWER
m_brim_done(false),
m_second_layer_things_done(false),
#if !ENABLE_GCODE_VIEWER
m_normal_time_estimator(GCodeTimeEstimator::Normal),
m_silent_time_estimator(GCodeTimeEstimator::Silent),
#endif // !ENABLE_GCODE_VIEWER
m_silent_time_estimator_enabled(false),
m_last_obj_copy(nullptr, Point(std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max()))
{}
@ -196,11 +172,7 @@ public:
// throws std::runtime_exception on error,
// throws CanceledException through print->throw_if_canceled().
#if ENABLE_GCODE_VIEWER
void do_export(Print* print, const char* path, GCodeProcessor::Result* result = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
#else
void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
#endif // ENABLE_GCODE_VIEWER
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
const Vec2d& origin() const { return m_origin; }
@ -363,16 +335,8 @@ private:
// Markers for the Pressure Equalizer to recognize the extrusion type.
// The Pressure Equalizer removes the markers from the final G-code.
bool m_enable_extrusion_role_markers;
#if ENABLE_GCODE_VIEWER
// Keeps track of the last extrusion role passed to the processor
ExtrusionRole m_last_processor_extrusion_role;
#else
// Enableds the G-code Analyzer.
// Extended markers will be added during G-code generation.
// The G-code Analyzer will remove these comments from the final G-code.
bool m_enable_analyzer;
ExtrusionRole m_last_analyzer_extrusion_role;
#endif // ENABLE_GCODE_VIEWER
// How many times will change_layer() be called?
// change_layer() will update the progress bar.
unsigned int m_layer_count;
@ -384,7 +348,6 @@ private:
double m_volumetric_speed;
// Support for the extrusion role markers. Which marker is active?
ExtrusionRole m_last_extrusion_role;
#if ENABLE_GCODE_VIEWER
// Support for G-Code Processor
float m_last_height{ 0.0f };
float m_last_layer_z{ 0.0f };
@ -392,12 +355,6 @@ private:
double m_last_mm3_per_mm;
float m_last_width{ 0.0f };
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
#else
// Support for G-Code Analyzer
double m_last_mm3_per_mm;
float m_last_width;
float m_last_height;
#endif // ENABLE_GCODE_VIEWER
Point m_last_pos;
bool m_last_pos_defined;
@ -418,20 +375,10 @@ private:
// Index of a last object copy extruded.
std::pair<const PrintObject*, Point> m_last_obj_copy;
#if !ENABLE_GCODE_VIEWER
// Time estimators
GCodeTimeEstimator m_normal_time_estimator;
GCodeTimeEstimator m_silent_time_estimator;
#endif // !ENABLE_GCODE_VIEWER
bool m_silent_time_estimator_enabled;
#if ENABLE_GCODE_VIEWER
// Processor
GCodeProcessor m_processor;
#else
// Analyzer
GCodeAnalyzer m_analyzer;
#endif // ENABLE_GCODE_VIEWER
// Write a string into a file.
void _write(FILE* file, const std::string& what) { this->_write(file, what.c_str()); }

View file

@ -15,7 +15,6 @@
#include <utility>
#endif
#if ENABLE_GCODE_VIEWER
#include <chrono>
static const float INCHES_TO_MM = 25.4f;
@ -508,6 +507,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
m_flavor = config.gcode_flavor;
size_t extruders_count = config.nozzle_diameter.values.size();
m_result.extruders_count = extruders_count;
m_extruder_offsets.resize(extruders_count);
for (size_t i = 0; i < extruders_count; ++i) {
@ -561,9 +561,17 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
if (bed_shape != nullptr)
m_result.bed_shape = bed_shape->values;
const ConfigOptionString* print_settings_id = config.option<ConfigOptionString>("print_settings_id");
if (print_settings_id != nullptr)
m_result.settings_ids.print = print_settings_id->value;
const ConfigOptionStrings* filament_settings_id = config.option<ConfigOptionStrings>("filament_settings_id");
if (filament_settings_id != nullptr)
m_result.settings_ids.filament = filament_settings_id->values;
const ConfigOptionString* printer_settings_id = config.option<ConfigOptionString>("printer_settings_id");
if (printer_settings_id != nullptr)
m_result.printer_settings_id = printer_settings_id->value;
m_result.settings_ids.printer = printer_settings_id->value;
const ConfigOptionFloats* filament_diameters = config.option<ConfigOptionFloats>("filament_diameter");
if (filament_diameters != nullptr) {
@ -572,6 +580,8 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
}
}
m_result.extruders_count = config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
const ConfigOptionPoints* extruder_offset = config.option<ConfigOptionPoints>("extruder_offset");
if (extruder_offset != nullptr) {
m_extruder_offsets.resize(extruder_offset->values.size());
@ -750,7 +760,7 @@ void GCodeProcessor::reset()
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
}
void GCodeProcessor::process_file(const std::string& filename, std::function<void()> cancel_callback)
void GCodeProcessor::process_file(const std::string& filename, bool apply_postprocess, std::function<void()> cancel_callback)
{
auto last_cancel_callback_time = std::chrono::high_resolution_clock::now();
@ -808,7 +818,8 @@ void GCodeProcessor::process_file(const std::string& filename, std::function<voi
update_estimated_times_stats();
// post-process to add M73 lines into the gcode
m_time_processor.post_process(filename);
if (apply_postprocess)
m_time_processor.post_process(filename);
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
std::cout << "\n";
@ -2216,4 +2227,3 @@ void GCodeProcessor::update_estimated_times_stats()
} /* namespace Slic3r */
#endif // ENABLE_GCODE_VIEWER

View file

@ -1,7 +1,6 @@
#ifndef slic3r_GCodeProcessor_hpp_
#define slic3r_GCodeProcessor_hpp_
#if ENABLE_GCODE_VIEWER
#include "libslic3r/GCodeReader.hpp"
#include "libslic3r/Point.hpp"
#include "libslic3r/ExtrusionEntity.hpp"
@ -266,10 +265,24 @@ namespace Slic3r {
struct Result
{
struct SettingsIds
{
std::string print;
std::vector<std::string> filament;
std::string printer;
void reset()
{
print = "";
filament = std::vector<std::string>();
printer = "";
}
};
unsigned int id;
std::vector<MoveVertex> moves;
Pointfs bed_shape;
std::string printer_settings_id;
SettingsIds settings_ids;
size_t extruders_count;
std::vector<std::string> extruder_colors;
PrintEstimatedTimeStatistics time_statistics;
@ -281,6 +294,8 @@ namespace Slic3r {
moves = std::vector<MoveVertex>();
bed_shape = Pointfs();
extruder_colors = std::vector<std::string>();
extruders_count = 0;
settings_ids.reset();
}
#else
void reset()
@ -288,6 +303,8 @@ namespace Slic3r {
moves = std::vector<MoveVertex>();
bed_shape = Pointfs();
extruder_colors = std::vector<std::string>();
extruders_count = 0;
settings_ids.reset();
}
#endif // ENABLE_GCODE_VIEWER_STATISTICS
};
@ -433,7 +450,7 @@ namespace Slic3r {
// Process the gcode contained in the file with the given filename
// throws CanceledException through print->throw_if_canceled() (sent by the caller as callback).
void process_file(const std::string& filename, std::function<void()> cancel_callback = nullptr);
void process_file(const std::string& filename, bool apply_postprocess, std::function<void()> cancel_callback = nullptr);
float get_time(PrintEstimatedTimeStatistics::ETimeMode mode) const;
std::string get_time_dhm(PrintEstimatedTimeStatistics::ETimeMode mode) const;
@ -566,8 +583,6 @@ namespace Slic3r {
} /* namespace Slic3r */
#endif // ENABLE_GCODE_VIEWER
#endif /* slic3r_GCodeProcessor_hpp_ */

View file

@ -1,521 +0,0 @@
#include "PreviewData.hpp"
#include <I18N.hpp>
#include "Utils.hpp"
#include <boost/format.hpp>
#if !ENABLE_GCODE_VIEWER
//! macro used to mark string used at localization,
#define L(s) (s)
namespace Slic3r {
std::vector<unsigned char> Color::as_bytes() const
{
std::vector<unsigned char> ret;
for (unsigned int i = 0; i < 4; ++i)
{
ret.push_back((unsigned char)(255.0f * rgba[i]));
}
return ret;
}
GCodePreviewData::Extrusion::Layer::Layer(float z, const Paths& paths)
: z(z)
, paths(paths)
{
}
GCodePreviewData::Travel::Polyline::Polyline(EType type, EDirection direction, float feedrate, unsigned int extruder_id, const Polyline3& polyline)
: type(type)
, direction(direction)
, feedrate(feedrate)
, extruder_id(extruder_id)
, polyline(polyline)
{
}
GCodePreviewData::Range::Range()
{
reset();
}
void GCodePreviewData::Range::reset()
{
min_val = FLT_MAX;
max_val = -FLT_MAX;
}
bool GCodePreviewData::Range::empty() const
{
return min_val >= max_val;
}
void GCodePreviewData::Range::update_from(float value)
{
min_val = std::min(min_val, value);
max_val = std::max(max_val, value);
}
void GCodePreviewData::Range::update_from(const RangeBase& other)
{
min_val = std::min(min_val, other.min());
max_val = std::max(max_val, other.max());
}
float GCodePreviewData::RangeBase::step_size() const
{
return (max() - min()) / static_cast<float>(range_rainbow_colors.size() - 1);
}
Color GCodePreviewData::RangeBase::get_color_at(float value) const
{
// Input value scaled to the color range
float step = step_size();
const float global_t = (step != 0.0f) ? std::max(0.0f, value - min()) / step : 0.0f; // lower limit of 0.0f
constexpr std::size_t color_max_idx = range_rainbow_colors.size() - 1;
// Compute the two colors just below (low) and above (high) the input value
const std::size_t color_low_idx = std::clamp(static_cast<std::size_t>(global_t), std::size_t{ 0 }, color_max_idx);
const std::size_t color_high_idx = std::clamp(color_low_idx + 1, std::size_t{ 0 }, color_max_idx);
// Compute how far the value is between the low and high colors so that they can be interpolated
const float local_t = std::min(global_t - static_cast<float>(color_low_idx), 1.0f); // upper limit of 1.0f
// Interpolate between the low and high colors in RGB space to find exactly which color the input value should get
Color ret;
for (unsigned int i = 0; i < 4; ++i)
{
ret.rgba[i] = lerp(range_rainbow_colors[color_low_idx].rgba[i], range_rainbow_colors[color_high_idx].rgba[i], local_t);
}
return ret;
}
float GCodePreviewData::Range::min() const
{
return min_val;
}
float GCodePreviewData::Range::max() const
{
return max_val;
}
GCodePreviewData::LegendItem::LegendItem(const std::string& text, const Color& color)
: text(text)
, color(color)
{
}
const Color GCodePreviewData::Extrusion::Default_Extrusion_Role_Colors[erCount] =
{
Color(0.0f, 0.0f, 0.0f, 1.0f), // erNone
Color(1.0f, 0.0f, 0.0f, 1.0f), // erPerimeter
Color(0.0f, 1.0f, 0.0f, 1.0f), // erExternalPerimeter
Color(0.0f, 0.0f, 1.0f, 1.0f), // erOverhangPerimeter
Color(1.0f, 1.0f, 0.0f, 1.0f), // erInternalInfill
Color(1.0f, 0.0f, 1.0f, 1.0f), // erSolidInfill
Color(0.0f, 1.0f, 1.0f, 1.0f), // erTopSolidInfill
// Color(1.0f, 0.7f, 0.61f, 1.0f), // erIroning
Color(1.0f, 0.55f, 0.41f, 1.0f), // erIroning
Color(0.5f, 0.5f, 0.5f, 1.0f), // erBridgeInfill
Color(1.0f, 1.0f, 1.0f, 1.0f), // erGapFill
Color(0.5f, 0.0f, 0.0f, 1.0f), // erSkirt
Color(0.0f, 0.5f, 0.0f, 1.0f), // erSupportMaterial
Color(0.0f, 0.0f, 0.5f, 1.0f), // erSupportMaterialInterface
Color(0.7f, 0.89f, 0.67f, 1.0f), // erWipeTower
Color(1.0f, 1.0f, 0.0f, 1.0f), // erCustom
Color(0.0f, 0.0f, 0.0f, 1.0f) // erMixed
};
const GCodePreviewData::Extrusion::EViewType GCodePreviewData::Extrusion::Default_View_Type = GCodePreviewData::Extrusion::FeatureType;
void GCodePreviewData::Extrusion::set_default()
{
view_type = Default_View_Type;
::memcpy((void*)role_colors, (const void*)Default_Extrusion_Role_Colors, erCount * sizeof(Color));
for (unsigned int i = 0; i < erCount; ++i)
role_names[i] = ExtrusionEntity::role_to_string(ExtrusionRole(i));
role_flags = 0;
for (unsigned int i = 0; i < erCount; ++i)
role_flags |= 1 << i;
}
bool GCodePreviewData::Extrusion::is_role_flag_set(ExtrusionRole role) const
{
return is_role_flag_set(role_flags, role);
}
bool GCodePreviewData::Extrusion::is_role_flag_set(unsigned int flags, ExtrusionRole role)
{
return GCodeAnalyzer::is_valid_extrusion_role(role) && (flags & (1 << (role - erPerimeter))) != 0;
}
size_t GCodePreviewData::Extrusion::memory_used() const
{
size_t out = sizeof(*this);
out += SLIC3R_STDVEC_MEMSIZE(this->layers, Layer);
for (const Layer &layer : this->layers) {
out += SLIC3R_STDVEC_MEMSIZE(layer.paths, Path);
for (const Path &path : layer.paths)
out += SLIC3R_STDVEC_MEMSIZE(path.polyline.points, Point);
}
return out;
}
const float GCodePreviewData::Travel::Default_Width = 0.075f;
const float GCodePreviewData::Travel::Default_Height = 0.075f;
const Color GCodePreviewData::Travel::Default_Type_Colors[Num_Types] =
{
Color(0.0f, 0.0f, 0.75f, 1.0f), // Move
Color(0.0f, 0.75f, 0.0f, 1.0f), // Extrude
Color(0.75f, 0.0f, 0.0f, 1.0f), // Retract
};
void GCodePreviewData::Travel::set_default()
{
width = Default_Width;
height = Default_Height;
::memcpy((void*)type_colors, (const void*)Default_Type_Colors, Num_Types * sizeof(Color));
color_print_idx = 0;
is_visible = false;
}
size_t GCodePreviewData::Travel::memory_used() const
{
size_t out = sizeof(*this);
out += SLIC3R_STDVEC_MEMSIZE(this->polylines, Polyline);
for (const Polyline &polyline : this->polylines)
out += SLIC3R_STDVEC_MEMSIZE(polyline.polyline.points, Vec3crd);
return out;
}
const Color GCodePreviewData::Retraction::Default_Color = Color(1.0f, 1.0f, 1.0f, 1.0f);
GCodePreviewData::Retraction::Position::Position(const Vec3crd& position, float width, float height)
: position(position)
, width(width)
, height(height)
{
}
void GCodePreviewData::Retraction::set_default()
{
color = Default_Color;
is_visible = false;
}
size_t GCodePreviewData::Retraction::memory_used() const
{
return sizeof(*this) + SLIC3R_STDVEC_MEMSIZE(this->positions, Position);
}
void GCodePreviewData::Shell::set_default()
{
is_visible = false;
}
GCodePreviewData::GCodePreviewData()
{
set_default();
}
void GCodePreviewData::set_default()
{
extrusion.set_default();
travel.set_default();
retraction.set_default();
unretraction.set_default();
shell.set_default();
// Configure the color range for feedrate to match the default for travels and to enable extrusions since they are always visible
ranges.feedrate.set_mode(FeedrateKind::TRAVEL, travel.is_visible);
ranges.feedrate.set_mode(FeedrateKind::EXTRUSION, true);
}
void GCodePreviewData::reset()
{
ranges.width.reset();
ranges.height.reset();
ranges.feedrate.reset();
ranges.fan_speed.reset();
ranges.volumetric_rate.reset();
extrusion.layers.clear();
travel.polylines.clear();
retraction.positions.clear();
unretraction.positions.clear();
}
bool GCodePreviewData::empty() const
{
return extrusion.layers.empty() && travel.polylines.empty() && retraction.positions.empty() && unretraction.positions.empty();
}
Color GCodePreviewData::get_extrusion_role_color(ExtrusionRole role) const
{
return extrusion.role_colors[role];
}
Color GCodePreviewData::get_height_color(float height) const
{
return ranges.height.get_color_at(height);
}
Color GCodePreviewData::get_width_color(float width) const
{
return ranges.width.get_color_at(width);
}
Color GCodePreviewData::get_feedrate_color(float feedrate) const
{
return ranges.feedrate.get_color_at(feedrate);
}
Color GCodePreviewData::get_fan_speed_color(float fan_speed) const
{
return ranges.fan_speed.get_color_at(fan_speed);
}
Color GCodePreviewData::get_volumetric_rate_color(float rate) const
{
return ranges.volumetric_rate.get_color_at(rate);
}
void GCodePreviewData::set_extrusion_role_color(const std::string& role_name, float red, float green, float blue, float alpha)
{
for (unsigned int i = 0; i < erCount; ++i)
{
if (role_name == extrusion.role_names[i])
{
extrusion.role_colors[i] = Color(red, green, blue, alpha);
break;
}
}
}
void GCodePreviewData::set_extrusion_paths_colors(const std::vector<std::string>& colors)
{
unsigned int size = (unsigned int)colors.size();
if (size % 2 != 0)
return;
for (unsigned int i = 0; i < size; i += 2)
{
const std::string& color_str = colors[i + 1];
if (color_str.size() == 6)
{
bool valid = true;
for (int c = 0; c < 6; ++c)
{
if (::isxdigit(color_str[c]) == 0)
{
valid = false;
break;
}
}
if (valid)
{
unsigned int color;
std::stringstream ss;
ss << std::hex << color_str;
ss >> color;
float den = 1.0f / 255.0f;
float r = (float)((color & 0xFF0000) >> 16) * den;
float g = (float)((color & 0x00FF00) >> 8) * den;
float b = (float)(color & 0x0000FF) * den;
this->set_extrusion_role_color(colors[i], r, g, b, 1.0f);
}
}
}
}
std::string GCodePreviewData::get_legend_title() const
{
switch (extrusion.view_type)
{
case Extrusion::FeatureType:
return L("Feature type");
case Extrusion::Height:
return L("Height (mm)");
case Extrusion::Width:
return L("Width (mm)");
case Extrusion::Feedrate:
return L("Speed (mm/s)");
case Extrusion::FanSpeed:
return L("Fan Speed (%)");
case Extrusion::VolumetricRate:
return L("Volumetric flow rate (mm³/s)");
case Extrusion::Tool:
return L("Tool");
case Extrusion::ColorPrint:
return L("Color Print");
case Extrusion::Num_View_Types:
break; // just to supress warning about non-handled value
}
return "";
}
GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::vector<float>& tool_colors,
const std::vector<std::string>& cp_items) const
{
struct Helper
{
static void FillListFromRange(LegendItemsList& list, const RangeBase& range, unsigned int decimals, float scale_factor)
{
list.reserve(range_rainbow_colors.size());
float step = range.step_size();
if (step == 0.0f)
{
char buf[1024];
sprintf(buf, "%.*f", decimals, scale_factor * range.min());
list.emplace_back(buf, range_rainbow_colors[0]);
}
else
{
for (int i = static_cast<int>(range_rainbow_colors.size()) - 1; i >= 0; --i)
{
char buf[1024];
sprintf(buf, "%.*f", decimals, scale_factor * (range.min() + (float)i * step));
list.emplace_back(buf, range_rainbow_colors[i]);
}
}
}
};
LegendItemsList items;
switch (extrusion.view_type)
{
case Extrusion::FeatureType:
{
ExtrusionRole first_valid = erPerimeter;
ExtrusionRole last_valid = erCustom;
items.reserve(last_valid - first_valid + 1);
for (unsigned int i = (unsigned int)first_valid; i <= (unsigned int)last_valid; ++i)
{
items.emplace_back(Slic3r::I18N::translate(extrusion.role_names[i]), extrusion.role_colors[i]);
}
break;
}
case Extrusion::Height:
{
Helper::FillListFromRange(items, ranges.height, 3, 1.0f);
break;
}
case Extrusion::Width:
{
Helper::FillListFromRange(items, ranges.width, 3, 1.0f);
break;
}
case Extrusion::Feedrate:
{
Helper::FillListFromRange(items, ranges.feedrate, 1, 1.0f);
break;
}
case Extrusion::FanSpeed:
{
Helper::FillListFromRange(items, ranges.fan_speed, 0, 1.0f);
break;
}
case Extrusion::VolumetricRate:
{
Helper::FillListFromRange(items, ranges.volumetric_rate, 3, 1.0f);
break;
}
case Extrusion::Tool:
{
unsigned int tools_colors_count = (unsigned int)tool_colors.size() / 4;
items.reserve(tools_colors_count);
for (unsigned int i = 0; i < tools_colors_count; ++i)
{
Color color;
::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float));
items.emplace_back((boost::format(Slic3r::I18N::translate(L("Extruder %d"))) % (i + 1)).str(), color);
}
break;
}
case Extrusion::ColorPrint:
{
const int color_cnt = (int)tool_colors.size()/4;
const auto color_print_cnt = (int)cp_items.size();
if (color_print_cnt == 1) // means "Default print color"
{
Color color;
::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data()), 4 * sizeof(float));
items.emplace_back(cp_items[0], color);
break;
}
if (color_cnt != color_print_cnt)
break;
for (int i = 0 ; i < color_print_cnt; ++i)
{
Color color;
::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float));
items.emplace_back(cp_items[i], color);
}
break;
}
case Extrusion::Num_View_Types:
break; // just to supress warning about non-handled value
}
return items;
}
// Return an estimate of the memory consumed by the time estimator.
size_t GCodePreviewData::memory_used() const
{
return
this->extrusion.memory_used() +
this->travel.memory_used() +
this->retraction.memory_used() +
this->unretraction.memory_used() +
sizeof(shell) + sizeof(ranges);
}
const std::vector<std::string>& GCodePreviewData::ColorPrintColors()
{
static std::vector<std::string> color_print = {"#C0392B", "#E67E22", "#F1C40F", "#27AE60", "#1ABC9C", "#2980B9", "#9B59B6"};
return color_print;
}
Color operator + (const Color& c1, const Color& c2)
{
return Color(std::clamp(c1.rgba[0] + c2.rgba[0], 0.0f, 1.0f),
std::clamp(c1.rgba[1] + c2.rgba[1], 0.0f, 1.0f),
std::clamp(c1.rgba[2] + c2.rgba[2], 0.0f, 1.0f),
std::clamp(c1.rgba[3] + c2.rgba[3], 0.0f, 1.0f));
}
Color operator * (float f, const Color& color)
{
return Color(std::clamp(f * color.rgba[0], 0.0f, 1.0f),
std::clamp(f * color.rgba[1], 0.0f, 1.0f),
std::clamp(f * color.rgba[2], 0.0f, 1.0f),
std::clamp(f * color.rgba[3], 0.0f, 1.0f));
}
} // namespace Slic3r
#endif // !ENABLE_GCODE_VIEWER

View file

@ -1,398 +0,0 @@
#ifndef slic3r_GCode_PreviewData_hpp_
#define slic3r_GCode_PreviewData_hpp_
#if !ENABLE_GCODE_VIEWER
#include "../libslic3r.h"
#include "../ExtrusionEntity.hpp"
#include "../Point.hpp"
#include <tuple>
#include <array>
#include <vector>
#include <bitset>
#include <cstddef>
#include <algorithm>
#include <string>
#include <float.h>
namespace Slic3r {
// Represents an RGBA color
struct Color
{
std::array<float,4> rgba;
Color(const float *argba)
{
memcpy(this->rgba.data(), argba, sizeof(float) * 4);
}
constexpr Color(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f) : rgba{r,g,b,a}
{
// Intentionally empty
}
std::vector<unsigned char> as_bytes() const;
};
Color operator + (const Color& c1, const Color& c2);
Color operator * (float f, const Color& color);
// Default colors for Ranges
constexpr std::array<Color, 10> range_rainbow_colors{
Color{0.043f, 0.173f, 0.478f, 1.0f},
Color{0.075f, 0.349f, 0.522f, 1.0f},
Color{0.110f, 0.533f, 0.569f, 1.0f},
Color{0.016f, 0.839f, 0.059f, 1.0f},
Color{0.667f, 0.949f, 0.000f, 1.0f},
Color{0.988f, 0.975f, 0.012f, 1.0f},
Color{0.961f, 0.808f, 0.039f, 1.0f},
Color{0.890f, 0.533f, 0.125f, 1.0f},
Color{0.820f, 0.408f, 0.188f, 1.0f},
Color{0.761f, 0.322f, 0.235f, 1.0f}};
class GCodePreviewData
{
public:
// Color mapping to convert a float into a smooth rainbow of 10 colors.
class RangeBase
{
public:
virtual void reset() = 0;
virtual bool empty() const = 0;
virtual float min() const = 0;
virtual float max() const = 0;
// Gets the step size using min(), max() and colors
float step_size() const;
// Gets the color at a value using colors, min(), and max()
Color get_color_at(float value) const;
};
// Color mapping converting a float in a range between a min and a max into a smooth rainbow of 10 colors.
class Range : public RangeBase
{
public:
Range();
// RangeBase Overrides
void reset() override;
bool empty() const override;
float min() const override;
float max() const override;
// Range-specific methods
void update_from(float value);
void update_from(const RangeBase& other);
private:
float min_val;
float max_val;
};
// Like Range, but stores multiple ranges internally that are used depending on mode.
// Template param EnumRangeType must be an enum with values for each type of range that needs to be tracked in this MultiRange.
// The last enum value should be num_values. The numerical values of all enum values should range from 0 to num_values.
template <typename EnumRangeType>
class MultiRange : public RangeBase
{
public:
void reset() override
{
bounds = decltype(bounds){};
}
bool empty() const override
{
for (std::size_t i = 0; i < bounds.size(); ++i)
{
if (bounds[i].min != bounds[i].max)
return false;
}
return true;
}
float min() const override
{
float min = FLT_MAX;
for (std::size_t i = 0; i < bounds.size(); ++i)
{
// Only use bounds[i] if the current mode includes it
if (mode.test(i))
{
min = std::min(min, bounds[i].min);
}
}
return min;
}
float max() const override
{
float max = -FLT_MAX;
for (std::size_t i = 0; i < bounds.size(); ++i)
{
// Only use bounds[i] if the current mode includes it
if (mode.test(i))
{
max = std::max(max, bounds[i].max);
}
}
return max;
}
void update_from(const float value, EnumRangeType range_type_value)
{
bounds[static_cast<std::size_t>(range_type_value)].update_from(value);
}
void update_from(const MultiRange& other)
{
for (std::size_t i = 0; i < bounds.size(); ++i)
{
bounds[i].update_from(other.bounds[i]);
}
}
void set_mode(const EnumRangeType range_type_value, const bool enable)
{
mode.set(static_cast<std::size_t>(range_type_value), enable);
}
private:
// Interval bounds
struct Bounds
{
float min{FLT_MAX};
float max{-FLT_MAX};
void update_from(const float value)
{
min = std::min(min, value);
max = std::max(max, value);
}
void update_from(const Bounds other_bounds)
{
min = std::min(min, other_bounds.min);
max = std::max(max, other_bounds.max);
}
};
std::array<Bounds, static_cast<std::size_t>(EnumRangeType::num_values)> bounds;
std::bitset<static_cast<std::size_t>(EnumRangeType::num_values)> mode;
};
// Enum distinguishing different kinds of feedrate data
enum class FeedrateKind
{
EXTRUSION = 0, // values must go from 0 up to num_values
TRAVEL,
num_values //must be last in the list of values
};
struct Ranges
{
// Color mapping by layer height.
Range height;
// Color mapping by extrusion width.
Range width;
// Color mapping by feedrate.
MultiRange<FeedrateKind> feedrate;
// Color mapping by fan speed.
Range fan_speed;
// Color mapping by volumetric extrusion rate.
Range volumetric_rate;
};
struct LegendItem
{
std::string text;
Color color;
LegendItem(const std::string& text, const Color& color);
};
typedef std::vector<LegendItem> LegendItemsList;
struct Extrusion
{
enum EViewType : unsigned char
{
FeatureType,
Height,
Width,
Feedrate,
FanSpeed,
VolumetricRate,
Tool,
ColorPrint,
Num_View_Types
};
static const Color Default_Extrusion_Role_Colors[erCount];
static const std::string Default_Extrusion_Role_Names[erCount];
static const EViewType Default_View_Type;
class Path
{
public:
Polyline polyline;
ExtrusionRole extrusion_role;
// Volumetric velocity. mm^3 of plastic per mm of linear head motion. Used by the G-code generator.
float mm3_per_mm;
// Width of the extrusion, used for visualization purposes.
float width;
// Height of the extrusion, used for visualization purposes.
float height;
// Feedrate of the extrusion, used for visualization purposes.
float feedrate;
// Id of the extruder, used for visualization purposes.
uint32_t extruder_id;
// Id of the color, used for visualization purposes in the color printing case.
uint32_t cp_color_id;
// Fan speed for the extrusion, used for visualization purposes.
float fan_speed;
};
using Paths = std::vector<Path>;
struct Layer
{
float z;
Paths paths;
Layer(float z, const Paths& paths);
};
typedef std::vector<Layer> LayersList;
EViewType view_type;
Color role_colors[erCount];
std::string role_names[erCount];
LayersList layers;
unsigned int role_flags;
void set_default();
bool is_role_flag_set(ExtrusionRole role) const;
// Return an estimate of the memory consumed by the time estimator.
size_t memory_used() const;
static bool is_role_flag_set(unsigned int flags, ExtrusionRole role);
};
struct Travel
{
enum EType : unsigned char
{
Move,
Extrude,
Retract,
Num_Types
};
static const float Default_Width;
static const float Default_Height;
static const Color Default_Type_Colors[Num_Types];
struct Polyline
{
enum EDirection
{
Vertical,
Generic,
Num_Directions
};
EType type;
EDirection direction;
float feedrate;
unsigned int extruder_id;
Polyline3 polyline;
Polyline(EType type, EDirection direction, float feedrate, unsigned int extruder_id, const Polyline3& polyline);
};
typedef std::vector<Polyline> PolylinesList;
PolylinesList polylines;
float width;
float height;
Color type_colors[Num_Types];
bool is_visible;
size_t color_print_idx;
void set_default();
// Return an estimate of the memory consumed by the time estimator.
size_t memory_used() const;
};
struct Retraction
{
static const Color Default_Color;
struct Position
{
Vec3crd position;
float width;
float height;
Position(const Vec3crd& position, float width, float height);
};
typedef std::vector<Position> PositionsList;
PositionsList positions;
Color color;
bool is_visible;
void set_default();
// Return an estimate of the memory consumed by the time estimator.
size_t memory_used() const;
};
struct Shell
{
bool is_visible;
void set_default();
};
Extrusion extrusion;
Travel travel;
Retraction retraction;
Retraction unretraction;
Shell shell;
Ranges ranges;
GCodePreviewData();
void set_default();
void reset();
bool empty() const;
Color get_extrusion_role_color(ExtrusionRole role) const;
Color get_height_color(float height) const;
Color get_width_color(float width) const;
Color get_feedrate_color(float feedrate) const;
Color get_fan_speed_color(float fan_speed) const;
Color get_volumetric_rate_color(float rate) const;
void set_extrusion_role_color(const std::string& role_name, float red, float green, float blue, float alpha);
void set_extrusion_paths_colors(const std::vector<std::string>& colors);
std::string get_legend_title() const;
LegendItemsList get_legend_items(const std::vector<float>& tool_colors, const std::vector<std::string>& cp_items) const;
// Return an estimate of the memory consumed by the time estimator.
size_t memory_used() const;
static const std::vector<std::string>& ColorPrintColors();
};
} // namespace Slic3r
#endif // !ENABLE_GCODE_VIEWER
#endif /* slic3r_GCode_PreviewData_hpp_ */

View file

@ -5,11 +5,7 @@
#include <vector>
#include <numeric>
#if ENABLE_GCODE_VIEWER
#include "GCodeProcessor.hpp"
#else
#include "Analyzer.hpp"
#endif // ENABLE_GCODE_VIEWER
#include "BoundingBox.hpp"
@ -38,25 +34,18 @@ public:
m_extrusion_flow(0.f),
m_preview_suppressed(false),
m_elapsed_time(0.f),
#if !ENABLE_GCODE_VIEWER || ENABLE_GCODE_VIEWER_DATA_CHECKING
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_default_analyzer_line_width(line_width),
#endif // !ENABLE_GCODE_VIEWER || ENABLE_GCODE_VIEWER_DATA_CHECKING
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
m_gcode_flavor(flavor),
m_filpar(filament_parameters)
{
// adds tag for analyzer:
char buf[64];
#if ENABLE_GCODE_VIEWER
sprintf(buf, ";%s%f\n", GCodeProcessor::Height_Tag.c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming
m_gcode += buf;
sprintf(buf, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(erWipeTower).c_str());
m_gcode += buf;
#else
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Height_Tag.c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming
m_gcode += buf;
sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erWipeTower);
m_gcode += buf;
#endif // ENABLE_GCODE_VIEWER
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
change_analyzer_line_width(line_width);
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
@ -80,26 +69,6 @@ public:
m_gcode += buf;
return *this;
}
#else
#if !ENABLE_GCODE_VIEWER
WipeTowerWriter& change_analyzer_line_width(float line_width) {
// adds tag for analyzer:
char buf[64];
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Width_Tag.c_str(), line_width);
m_gcode += buf;
return *this;
}
WipeTowerWriter& change_analyzer_mm3_per_mm(float len, float e) {
static const float area = float(M_PI) * 1.75f * 1.75f / 4.f;
float mm3_per_mm = (len == 0.f ? 0.f : area * e / len);
// adds tag for analyzer:
char buf[64];
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Mm3_Per_Mm_Tag.c_str(), mm3_per_mm);
m_gcode += buf;
return *this;
}
#endif // !ENABLE_GCODE_VIEWER
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
WipeTowerWriter& set_initial_position(const Vec2f &pos, float width = 0.f, float depth = 0.f, float internal_angle = 0.f) {
@ -135,13 +104,13 @@ public:
// Suppress / resume G-code preview in Slic3r. Slic3r will have difficulty to differentiate the various
// filament loading and cooling moves from normal extrusion moves. Therefore the writer
// is asked to suppres output of some lines, which look like extrusions.
#if !ENABLE_GCODE_VIEWER || ENABLE_GCODE_VIEWER_DATA_CHECKING
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
WipeTowerWriter& suppress_preview() { change_analyzer_line_width(0.f); m_preview_suppressed = true; return *this; }
WipeTowerWriter& resume_preview() { change_analyzer_line_width(m_default_analyzer_line_width); m_preview_suppressed = false; return *this; }
#else
WipeTowerWriter& suppress_preview() { m_preview_suppressed = true; return *this; }
WipeTowerWriter& resume_preview() { m_preview_suppressed = false; return *this; }
#endif // !ENABLE_GCODE_VIEWER || ENABLE_GCODE_VIEWER_DATA_CHECKING
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
WipeTowerWriter& feedrate(float f)
{
@ -180,10 +149,6 @@ public:
if (! m_preview_suppressed && e > 0.f && len > 0.f) {
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
change_analyzer_mm3_per_mm(len, e);
#else
#if !ENABLE_GCODE_VIEWER
change_analyzer_mm3_per_mm(len, e);
#endif // !ENABLE_GCODE_VIEWER
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
// Width of a squished extrusion, corrected for the roundings of the squished extrusions.
// This is left zero if it is a travel move.
@ -463,9 +428,9 @@ private:
float m_wipe_tower_depth = 0.f;
unsigned m_last_fan_speed = 0;
int current_temp = -1;
#if !ENABLE_GCODE_VIEWER || ENABLE_GCODE_VIEWER_DATA_CHECKING
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
const float m_default_analyzer_line_width;
#endif // !ENABLE_GCODE_VIEWER || ENABLE_GCODE_VIEWER_DATA_CHECKING
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
float m_used_filament_length = 0.f;
GCodeFlavor m_gcode_flavor;
const std::vector<WipeTower::FilamentParameters>& m_filpar;

View file

@ -1,9 +1,7 @@
#include "GCodeReader.hpp"
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#if ENABLE_GCODE_VIEWER
#include <boost/nowide/fstream.hpp>
#endif // ENABLE_GCODE_VIEWER
#include <fstream>
#include <iostream>
#include <iomanip>
@ -116,18 +114,10 @@ void GCodeReader::update_coordinates(GCodeLine &gline, std::pair<const char*, co
void GCodeReader::parse_file(const std::string &file, callback_t callback)
{
#if ENABLE_GCODE_VIEWER
boost::nowide::ifstream f(file);
#else
std::ifstream f(file);
#endif // ENABLE_GCODE_VIEWER
std::string line;
#if ENABLE_GCODE_VIEWER
m_parsing_file = true;
while (m_parsing_file && std::getline(f, line))
#else
while (std::getline(f, line))
#endif // ENABLE_GCODE_VIEWER
this->parse_line(line, callback);
}

View file

@ -108,9 +108,7 @@ public:
{ GCodeLine gline; this->parse_line(line.c_str(), gline, callback); }
void parse_file(const std::string &file, callback_t callback);
#if ENABLE_GCODE_VIEWER
void quit_parsing_file() { m_parsing_file = false; }
#endif // ENABLE_GCODE_VIEWER
float& x() { return m_position[X]; }
float x() const { return m_position[X]; }
@ -149,9 +147,7 @@ private:
char m_extrusion_axis;
float m_position[NUM_AXES];
bool m_verbose;
#if ENABLE_GCODE_VIEWER
bool m_parsing_file{ false };
#endif // ENABLE_GCODE_VIEWER
};
} /* namespace Slic3r */

View file

@ -22,9 +22,6 @@
#include "SVG.hpp"
#include <Eigen/Dense>
#include "GCodeWriter.hpp"
#if !ENABLE_GCODE_VIEWER
#include "GCode/PreviewData.hpp"
#endif // !ENABLE_GCODE_VIEWER
namespace Slic3r {

View file

@ -1836,7 +1836,6 @@ namespace PresetUtils {
return out;
}
#if ENABLE_GCODE_VIEWER
std::string system_printer_bed_model(const Preset& preset)
{
std::string out;
@ -1854,7 +1853,6 @@ namespace PresetUtils {
out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_texture;
return out;
}
#endif // ENABLE_GCODE_VIEWER
} // namespace PresetUtils
} // namespace Slic3r

View file

@ -537,10 +537,8 @@ public:
namespace PresetUtils {
// PrinterModel of a system profile, from which this preset is derived, or null if it is not derived from a system profile.
const VendorProfile::PrinterModel* system_printer_model(const Preset &preset);
#if ENABLE_GCODE_VIEWER
std::string system_printer_bed_model(const Preset& preset);
std::string system_printer_bed_texture(const Preset& preset);
#endif // ENABLE_GCODE_VIEWER
} // namespace PresetUtils

View file

@ -1661,21 +1661,13 @@ void Print::process()
// The export_gcode may die for various reasons (fails to process output_filename_format,
// write error into the G-code, cannot execute post-processing scripts).
// It is up to the caller to show an error message.
#if ENABLE_GCODE_VIEWER
std::string Print::export_gcode(const std::string& path_template, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb)
#else
std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
#endif // ENABLE_GCODE_VIEWER
{
// output everything to a G-code file
// The following call may die if the output_filename_format template substitution fails.
std::string path = this->output_filepath(path_template);
std::string message;
#if ENABLE_GCODE_VIEWER
if (!path.empty() && result == nullptr) {
#else
if (! path.empty() && preview_data == nullptr) {
#endif // ENABLE_GCODE_VIEWER
// Only show the path if preview_data is not set -> running from command line.
message = L("Exporting G-code");
message += " to ";
@ -1686,11 +1678,7 @@ std::string Print::export_gcode(const std::string& path_template, GCodePreviewDa
// The following line may die for multiple reasons.
GCode gcode;
#if ENABLE_GCODE_VIEWER
gcode.do_export(this, path.c_str(), result, thumbnail_cb);
#else
gcode.do_export(this, path.c_str(), preview_data, thumbnail_cb);
#endif // ENABLE_GCODE_VIEWER
return path.c_str();
}

View file

@ -11,9 +11,7 @@
#include "GCode/ToolOrdering.hpp"
#include "GCode/WipeTower.hpp"
#include "GCode/ThumbnailData.hpp"
#if ENABLE_GCODE_VIEWER
#include "GCode/GCodeProcessor.hpp"
#endif // ENABLE_GCODE_VIEWER
#include "libslic3r.h"
@ -23,9 +21,6 @@ class Print;
class PrintObject;
class ModelObject;
class GCode;
#if !ENABLE_GCODE_VIEWER
class GCodePreviewData;
#endif // !ENABLE_GCODE_VIEWER
enum class SlicingMode : uint32_t;
class Layer;
class SupportLayer;
@ -312,10 +307,6 @@ struct PrintStatistics
PrintStatistics() { clear(); }
std::string estimated_normal_print_time;
std::string estimated_silent_print_time;
#if !ENABLE_GCODE_VIEWER
std::vector<std::pair<CustomGCode::Type, std::string>> estimated_normal_custom_gcode_print_times;
std::vector<std::pair<CustomGCode::Type, std::string>> estimated_silent_custom_gcode_print_times;
#endif // !ENABLE_GCODE_VIEWER
double total_used_filament;
double total_extruded_volume;
double total_cost;
@ -333,12 +324,6 @@ struct PrintStatistics
std::string finalize_output_path(const std::string &path_in) const;
void clear() {
#if !ENABLE_GCODE_VIEWER
estimated_normal_print_time.clear();
estimated_silent_print_time.clear();
estimated_normal_custom_gcode_print_times.clear();
estimated_silent_custom_gcode_print_times.clear();
#endif // !ENABLE_GCODE_VIEWER
total_used_filament = 0.;
total_extruded_volume = 0.;
total_cost = 0.;
@ -380,11 +365,7 @@ public:
void process() override;
// Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file.
// If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r).
#if ENABLE_GCODE_VIEWER
std::string export_gcode(const std::string& path_template, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
#else
std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
#endif // ENABLE_GCODE_VIEWER
// methods for handling state
bool is_step_done(PrintStep step) const { return Inherited::is_step_done(step); }

View file

@ -957,9 +957,9 @@ void PrintConfigDef::init_fff_params()
def = this->add("first_layer_temperature", coInts);
def->label = L("First layer");
def->full_label = L("First layer extruder temperature");
def->tooltip = L("Extruder temperature for first layer. If you want to control temperature manually "
"during print, set this to zero to disable temperature control commands in the output file.");
def->full_label = L("First layer nozzle temperature");
def->tooltip = L("Nozzle temperature for the first layer. If you want to control temperature manually "
"during print, set this to zero to disable temperature control commands in the output G-code.");
def->sidetext = L("°C");
def->min = 0;
def->max = max_temp;
@ -1180,9 +1180,9 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionFloat(0.1));
def = this->add("ironing_speed", coFloat);
def->label = L("Ironing speed");
def->label = L("Ironing");
def->category = L("Speed");
def->tooltip = L("Ironing speed");
def->tooltip = L("Ironing");
def->sidetext = L("mm/s");
def->min = 0;
def->mode = comAdvanced;
@ -1216,7 +1216,7 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionBool(true));
def = this->add("machine_limits_usage", coEnum);
def->label = L("How to apply");
def->label = L("How to apply limits");
def->full_label = L("Purpose of Machine Limits");
def->category = L("Machine limits");
def->tooltip = L("How to apply the Machine Limits");
@ -1224,9 +1224,9 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("emit_to_gcode");
def->enum_values.push_back("time_estimate_only");
def->enum_values.push_back("ignore");
def->enum_labels.push_back("Emit to G-code");
def->enum_labels.push_back("Use for time estimate");
def->enum_labels.push_back("Ignore");
def->enum_labels.push_back(L("Emit to G-code"));
def->enum_labels.push_back(L("Use for time estimate"));
def->enum_labels.push_back(L("Ignore"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<MachineLimitsUsage>(MachineLimitsUsage::EmitToGCode));
@ -2205,10 +2205,10 @@ void PrintConfigDef::init_fff_params()
def = this->add("temperature", coInts);
def->label = L("Other layers");
def->tooltip = L("Extruder temperature for layers after the first one. Set this to zero to disable "
"temperature control commands in the output.");
def->tooltip = L("Nozzle temperature for layers after the first one. Set this to zero to disable "
"temperature control commands in the output G-code.");
def->sidetext = L("°C");
def->full_label = L("Extruder temperature");
def->full_label = L("Nozzle temperature");
def->min = 0;
def->max = max_temp;
def->set_default_value(new ConfigOptionInts { 200 });
@ -3696,7 +3696,7 @@ CLIMiscConfigDef::CLIMiscConfigDef()
def->cli = "output|o";
def = this->add("single_instance", coBool);
def->label = L("Single Instance");
def->label = L("Single instance mode");
def->tooltip = L("If enabled, the command line arguments are sent to an existing instance of GUI PrusaSlicer, "
"or an existing PrusaSlicer window is activated. "
"Overrides the \"single_instance\" configuration value from application preferences.");

View file

@ -64,4 +64,13 @@
#define ENABLE_CTRL_M_ON_WINDOWS (0 && ENABLE_2_3_0_ALPHA3)
//===================
// 2.3.0.alpha4 techs
//===================
#define ENABLE_2_3_0_ALPHA4 1
#define ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS (1 && ENABLE_GCODE_VIEWER && ENABLE_2_3_0_ALPHA4)
#endif // _prusaslicer_technologies_h_

View file

@ -110,30 +110,13 @@ std::string string_printf(const char *format, ...);
// to be placed at the top of Slic3r generated files.
std::string header_slic3r_generated();
#if ENABLE_GCODE_VIEWER
// Standard "generated by PrusaGCodeViewer version xxx timestamp xxx" header string,
// to be placed at the top of Slic3r generated files.
std::string header_gcodeviewer_generated();
#endif // ENABLE_GCODE_VIEWER
// getpid platform wrapper
extern unsigned get_current_pid();
#if !ENABLE_GCODE_VIEWER
template <typename Real>
Real round_nearest(Real value, unsigned int decimals)
{
Real res = (Real)0;
if (decimals == 0)
res = ::round(value);
else {
Real power = ::pow((Real)10, (int)decimals);
res = ::round(value * power + (Real)0.5) / power;
}
return res;
}
#endif // !ENABLE_GCODE_VIEWER
// Compute the next highest power of 2 of 32-bit v
// http://graphics.stanford.edu/~seander/bithacks.html
inline uint16_t next_highest_power_of_2(uint16_t v)

View file

@ -25,12 +25,12 @@ public:
std::string formatted_errorstr() const
{
return L("Error with zip archive") + " " + m_zipname + ": " +
get_errorstr() + "!";
get_errorstr();
}
SLIC3R_NORETURN void blow_up() const
{
throw Slic3r::RuntimeError(formatted_errorstr());
throw Slic3r::ExportError(formatted_errorstr());
}
bool is_alive()

View file

@ -429,24 +429,20 @@ CopyFileResult copy_file_inner(const std::string& from, const std::string& to, s
// the copy_file() function will fail appropriately and we don't want the permission()
// calls to cause needless failures on permissionless filesystems (ie. FATs on SD cards etc.)
// or when the target file doesn't exist.
//This error code is ignored
boost::system::error_code ec;
boost::filesystem::permissions(target, perms, ec);
//if (ec)
// BOOST_LOG_TRIVIAL(error) << "Copy file permisions before copy error message: " << ec.message();
// This error code is passed up
if (ec)
BOOST_LOG_TRIVIAL(error) << "boost::filesystem::permisions before copy error message (this could be irrelevant message based on file system): " << ec.message();
ec.clear();
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
if (ec) {
error_message = ec.message();
return FAIL_COPY_FILE;
}
//ec.clear();
ec.clear();
boost::filesystem::permissions(target, perms, ec);
//if (ec)
// BOOST_LOG_TRIVIAL(error) << "Copy file permisions after copy error message: " << ec.message();
if (ec)
BOOST_LOG_TRIVIAL(error) << "boost::filesystem::permisions after copy error message (this could be irrelevant message based on file system): " << ec.message();
return SUCCESS;
}
@ -618,12 +614,10 @@ std::string header_slic3r_generated()
return std::string("generated by " SLIC3R_APP_NAME " " SLIC3R_VERSION " on " ) + Utils::utc_timestamp();
}
#if ENABLE_GCODE_VIEWER
std::string header_gcodeviewer_generated()
{
return std::string("generated by " GCODEVIEWER_APP_NAME " " SLIC3R_VERSION " on ") + Utils::utc_timestamp();
}
#endif // ENABLE_GCODE_VIEWER
unsigned get_current_pid()
{

View file

@ -16,15 +16,9 @@
#include "libslic3r/ExtrusionEntity.hpp"
#include "libslic3r/ExtrusionEntityCollection.hpp"
#include "libslic3r/Geometry.hpp"
#if !ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/PreviewData.hpp"
#endif // !ENABLE_GCODE_VIEWER
#include "libslic3r/Print.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "libslic3r/Slicing.hpp"
#if !ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/Analyzer.hpp"
#endif // !ENABLE_GCODE_VIEWER
#include "slic3r/GUI/BitmapCache.hpp"
#include "libslic3r/Format/STL.hpp"
#include "libslic3r/Utils.hpp"

View file

@ -38,12 +38,12 @@ void AboutDialogLogo::onRepaint(wxEvent &event)
// -----------------------------------------
CopyrightsDialog::CopyrightsDialog()
#if ENABLE_GCODE_VIEWER
: DPIDialog(NULL, wxID_ANY, from_u8((boost::format("%1% - %2%")
: DPIDialog((wxWindow*)wxGetApp().mainframe, wxID_ANY, from_u8((boost::format("%1% - %2%")
% (wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME)
% _utf8(L("Portions copyright"))).str()),
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
#else
: DPIDialog(NULL, wxID_ANY, from_u8((boost::format("%1% - %2%")
: DPIDialog((wxWindow*)wxGetApp().mainframe, wxID_ANY, from_u8((boost::format("%1% - %2%")
% SLIC3R_APP_NAME
% _utf8(L("Portions copyright"))).str()),
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
@ -209,10 +209,10 @@ void CopyrightsDialog::onCloseDialog(wxEvent &)
AboutDialog::AboutDialog()
#if ENABLE_GCODE_VIEWER
: DPIDialog(NULL, wxID_ANY, from_u8((boost::format(_utf8(L("About %s"))) % (wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME)).str()), wxDefaultPosition,
: DPIDialog((wxWindow*)wxGetApp().mainframe, wxID_ANY, from_u8((boost::format(_utf8(L("About %s"))) % (wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME)).str()), wxDefaultPosition,
wxDefaultSize, /*wxCAPTION*/wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
#else
: DPIDialog(NULL, wxID_ANY, from_u8((boost::format(_utf8(L("About %s"))) % SLIC3R_APP_NAME).str()), wxDefaultPosition,
: DPIDialog((wxWindow*)wxGetApp().mainframe, wxID_ANY, from_u8((boost::format(_utf8(L("About %s"))) % SLIC3R_APP_NAME).str()), wxDefaultPosition,
wxDefaultSize, /*wxCAPTION*/wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
#endif // ENABLE_GCODE_VIEWER
{

View file

@ -19,9 +19,6 @@
#include "libslic3r/SLAPrint.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/GCode/PostProcessor.hpp"
#if !ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/PreviewData.hpp"
#endif // !ENABLE_GCODE_VIEWER
#include "libslic3r/Format/SL1.hpp"
#include "libslic3r/Thread.hpp"
#include "libslic3r/libslic3r.h"
@ -53,6 +50,24 @@ bool SlicingProcessCompletedEvent::critical_error() const
return true;
}
bool SlicingProcessCompletedEvent::invalidate_plater() const
{
if (critical_error())
{
try {
this->rethrow_exception();
}
catch (const Slic3r::ExportError&) {
// Exception thrown by copying file does not ivalidate plater
return false;
}
catch (...) {
}
return true;
}
return false;
}
std::string SlicingProcessCompletedEvent::format_error_message() const
{
std::string error;
@ -142,19 +157,19 @@ void BackgroundSlicingProcess::process_fff()
switch (copy_ret_val) {
case SUCCESS: break; // no error
case FAIL_COPY_FILE:
throw Slic3r::RuntimeError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%"))) % error_message).str());
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%"))) % error_message).str());
break;
case FAIL_FILES_DIFFERENT:
throw Slic3r::RuntimeError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str());
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str());
break;
case FAIL_RENAMING:
throw Slic3r::RuntimeError((boost::format(_utf8(L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."))) % export_path).str());
throw Slic3r::ExportError((boost::format(_utf8(L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."))) % export_path).str());
break;
case FAIL_CHECK_ORIGIN_NOT_OPENED:
throw Slic3r::RuntimeError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."))) % m_temp_output_path % export_path).str());
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."))) % m_temp_output_path % export_path).str());
break;
case FAIL_CHECK_TARGET_NOT_OPENED:
throw Slic3r::RuntimeError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str());
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str());
break;
default:
throw Slic3r::RuntimeError(_utf8(L("Unknown error occured during exporting G-code.")));

View file

@ -57,6 +57,8 @@ public:
bool error() const { return m_status == Error; }
// Unhandled error produced by stdlib or a Win32 structured exception, or unhandled Slic3r's own critical exception.
bool critical_error() const;
// Critical errors does invalidate plater except CopyFileError.
bool invalidate_plater() const;
// Only valid if error()
void rethrow_exception() const { assert(this->error()); assert(m_exception); std::rethrow_exception(m_exception); }
// Produce a human readable message to be displayed by a notification or a message box.

View file

@ -127,7 +127,7 @@ public:
void look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up);
double max_zoom() const { return 100.0; }
double max_zoom() const { return 250.0; }
double min_zoom() const;
private:

View file

@ -109,7 +109,7 @@ static wxString generate_html_page(const Config::SnapshotDB &snapshot_db, const
}
ConfigSnapshotDialog::ConfigSnapshotDialog(const Config::SnapshotDB &snapshot_db, const wxString &on_snapshot)
: DPIDialog(NULL, wxID_ANY, _(L("Configuration Snapshots")), wxDefaultPosition,
: DPIDialog((wxWindow*)wxGetApp().mainframe, wxID_ANY, _(L("Configuration Snapshots")), wxDefaultPosition,
wxSize(45 * wxGetApp().em_unit(), 40 * wxGetApp().em_unit()),
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX)
{

View file

@ -27,6 +27,7 @@
#include <wx/debug.h>
#include "libslic3r/Utils.hpp"
#include "libslic3r/Config.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "GUI_Utils.hpp"
@ -191,10 +192,12 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt
wxBitmap bitmap;
int bitmap_width = 0;
int bitmap_height = 0;
const wxString bitmap_file = GUI::from_u8(Slic3r::resources_dir() + "/profiles/" + vendor.id + "/" + model.id + "_thumbnail.png");
if (wxFileExists(bitmap_file)) {
bitmap.LoadFile(bitmap_file, wxBITMAP_TYPE_PNG);
bitmap_width = bitmap.GetWidth();
bitmap_height = bitmap.GetHeight();
} else {
BOOST_LOG_TRIVIAL(warning) << boost::format("Can't find bitmap file `%1%` for vendor `%2%`, printer `%3%`, using placeholder icon instead")
% bitmap_file
@ -205,6 +208,7 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt
if (wxFileExists(placeholder_file)) {
bitmap.LoadFile(placeholder_file, wxBITMAP_TYPE_PNG);
bitmap_width = bitmap.GetWidth();
bitmap_height = bitmap.GetHeight();
}
}
@ -270,25 +274,22 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt
const size_t odd_items = titles.size() % cols;
for (size_t i = 0; i < titles.size() - odd_items; i += cols) {
for (size_t j = i; j < i + cols; j++) { printer_grid->Add(titles[j], 0, wxBOTTOM, 3); }
for (size_t j = i; j < i + cols; j++) { printer_grid->Add(bitmaps[j], 0, wxBOTTOM, 20); }
for (size_t j = i; j < i + cols; j++) { printer_grid->Add(titles[j], 0, wxBOTTOM, 3); }
for (size_t j = i; j < i + cols; j++) { printer_grid->Add(variants_panels[j]); }
// Add separator space
if (i > 0) {
for (size_t j = i; j < i + cols; j++) { printer_grid->Add(1, 100); }
// Add separator space to multiliners
if (titles.size() > cols) {
for (size_t j = i; j < i + cols; j++) { printer_grid->Add(1, 30); }
}
}
if (odd_items > 0) {
for (size_t i = 0; i < cols; i++) { printer_grid->Add(1, 100); }
const size_t rem = titles.size() - odd_items;
for (size_t i = rem; i < titles.size(); i++) { printer_grid->Add(titles[i], 0, wxBOTTOM, 3); }
for (size_t i = 0; i < cols - odd_items; i++) { printer_grid->AddSpacer(1); }
for (size_t i = rem; i < titles.size(); i++) { printer_grid->Add(bitmaps[i], 0, wxBOTTOM, 20); }
for (size_t i = 0; i < cols - odd_items; i++) { printer_grid->AddSpacer(1); }
for (size_t i = rem; i < titles.size(); i++) { printer_grid->Add(titles[i], 0, wxBOTTOM, 3); }
for (size_t i = 0; i < cols - odd_items; i++) { printer_grid->AddSpacer(1); }
for (size_t i = rem; i < titles.size(); i++) { printer_grid->Add(variants_panels[i]); }
}
}
@ -1389,7 +1390,7 @@ void PageDiameters::apply_custom_config(DynamicPrintConfig &config)
}
PageTemperatures::PageTemperatures(ConfigWizard *parent)
: ConfigWizardPage(parent, _(L("Extruder and Bed Temperatures")), _(L("Temperatures")), 1)
: ConfigWizardPage(parent, _(L("Nozzle and Bed Temperatures")), _(L("Temperatures")), 1)
, spin_extr(new wxSpinCtrlDouble(this, wxID_ANY))
, spin_bed(new wxSpinCtrlDouble(this, wxID_ANY))
{

View file

@ -4,7 +4,6 @@
#include "libslic3r/GCode.hpp"
#else
#include "wxExtensions.hpp"
#include "libslic3r/GCode/PreviewData.hpp"
#endif // ENABLE_GCODE_VIEWER
#include "GUI.hpp"
#include "GUI_App.hpp"
@ -53,11 +52,6 @@ static std::string gcode(Type type)
}
}
static bool is_lower_thumb_editable()
{
return Slic3r::GUI::get_app_config()->get("seq_top_layer_only") == "0";
}
Control::Control( wxWindow *parent,
wxWindowID id,
int lowerValue,
@ -299,6 +293,8 @@ wxSize Control::get_size() const
void Control::get_size(int* w, int* h) const
{
GetSize(w, h);
if (m_draw_mode == dmSequentialGCodeView)
return; // we have no more icons for drawing
is_horizontal() ? *w -= m_lock_icon_dim : *h -= m_lock_icon_dim;
}
@ -914,6 +910,10 @@ void Control::draw_revert_icon(wxDC& dc)
void Control::draw_cog_icon(wxDC& dc)
{
#if ENABLE_GCODE_VIEWER
if (m_draw_mode == dmSequentialGCodeView)
return;
#endif // ENABLE_GCODE_VIEWER
int width, height;
get_size(&width, &height);
@ -960,6 +960,13 @@ int Control::get_value_from_position(const wxCoord x, const wxCoord y)
return int(m_min_value + double(height - SLIDER_MARGIN - y) / step + 0.5);
}
bool Control::is_lower_thumb_editable()
{
if (m_draw_mode == dmSequentialGCodeView)
return Slic3r::GUI::get_app_config()->get("seq_top_layer_only") == "0";
return true;
}
bool Control::detect_selected_slider(const wxPoint& pt)
{
if (is_point_in_rect(pt, m_rect_lower_thumb))

View file

@ -293,6 +293,7 @@ protected:
void draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const;
void update_thumb_rect(const wxCoord begin_x, const wxCoord begin_y, const SelectedSlider& selection);
bool is_lower_thumb_editable();
bool detect_selected_slider(const wxPoint& pt);
void correct_lower_value();
void correct_higher_value();

View file

@ -20,7 +20,7 @@ namespace Slic3r {
namespace GUI {
ExtruderSequenceDialog::ExtruderSequenceDialog(const DoubleSlider::ExtrudersSequence& sequence)
: DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(L("Set extruder sequence")),
: DPIDialog((wxWindow*)wxGetApp().mainframe, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(L("Set extruder sequence")),
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
m_sequence(sequence)
{
@ -36,7 +36,7 @@ ExtruderSequenceDialog::ExtruderSequenceDialog(const DoubleSlider::ExtrudersSequ
auto option_sizer = new wxBoxSizer(wxVERTICAL);
auto intervals_box = new wxStaticBox(this, wxID_ANY, _(L("Set extruder change for every"))+ " : ");
auto intervals_box = new wxStaticBox(this, wxID_ANY, _(L("Set extruder change for every"))+ ": ");
auto intervals_box_sizer = new wxStaticBoxSizer(intervals_box, wxVERTICAL);
m_intervals_grid_sizer = new wxFlexGridSizer(3, 5, em);
@ -114,26 +114,26 @@ ExtruderSequenceDialog::ExtruderSequenceDialog(const DoubleSlider::ExtrudersSequ
rb_by_mm->SetValue(true);
});
m_interval_by_mm->Bind(wxEVT_KILL_FOCUS, [this, change_value](wxFocusEvent& event)
m_interval_by_mm->Bind(wxEVT_KILL_FOCUS, [change_value](wxFocusEvent& event)
{
change_value();
event.Skip();
});
m_interval_by_mm->Bind(wxEVT_TEXT_ENTER, [this, change_value](wxEvent&)
m_interval_by_mm->Bind(wxEVT_TEXT_ENTER, [change_value](wxEvent&)
{
change_value();
});
m_intervals_grid_sizer->Add(rb_by_mm, 0, wxALIGN_CENTER_VERTICAL);
m_intervals_grid_sizer->Add(m_interval_by_mm,0, wxALIGN_CENTER_VERTICAL);
m_intervals_grid_sizer->Add(m_interval_by_mm, 0, wxALIGN_CENTER_VERTICAL);
m_intervals_grid_sizer->Add(st_by_mm,0, wxALIGN_CENTER_VERTICAL);
intervals_box_sizer->Add(m_intervals_grid_sizer, 0, wxLEFT, em);
option_sizer->Add(intervals_box_sizer, 0, wxEXPAND);
auto extruders_box = new wxStaticBox(this, wxID_ANY, _(L("Set extruder(tool) sequence"))+ " : ");
auto extruders_box = new wxStaticBox(this, wxID_ANY, _(L("Set extruder(tool) sequence"))+ ": ");
auto extruders_box_sizer = new wxStaticBoxSizer(extruders_box, wxVERTICAL);
m_extruders_grid_sizer = new wxFlexGridSizer(3, 5, em);

View file

@ -693,6 +693,11 @@ void SpinCtrl::BUILD() {
auto temp = new wxSpinCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size,
0|wxTE_PROCESS_ENTER, min_val, max_val, default_value);
#ifdef __WXGTK3__
wxSize best_sz = temp->GetBestSize();
if (best_sz.x > size.x)
temp->SetSize(wxSize(size.x + 2 * best_sz.y, best_sz.y));
#endif //__WXGTK3__
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT);

View file

@ -112,16 +112,14 @@ bool GCodeViewer::Path::matches(const GCodeProcessor::MoveVertex& move) const
case EMoveType::Custom_GCode:
case EMoveType::Retract:
case EMoveType::Unretract:
case EMoveType::Extrude:
{
case EMoveType::Extrude: {
// use rounding to reduce the number of generated paths
return type == move.type && role == move.extrusion_role && height == round_to_nearest(move.height, 2) &&
return type == move.type && move.position[2] <= first.position[2] && role == move.extrusion_role && height == round_to_nearest(move.height, 2) &&
width == round_to_nearest(move.width, 2) && feedrate == move.feedrate && fan_speed == move.fan_speed &&
volumetric_rate == round_to_nearest(move.volumetric_rate(), 2) && extruder_id == move.extruder_id &&
cp_color_id == move.cp_color_id;
}
case EMoveType::Travel:
{
case EMoveType::Travel: {
return type == move.type && feedrate == move.feedrate && extruder_id == move.extruder_id && cp_color_id == move.cp_color_id;
}
default: { return false; }
@ -302,9 +300,11 @@ void GCodeViewer::load(const GCodeProcessor::Result& gcode_result, const Print&
reset();
load_toolpaths(gcode_result);
if (m_layers_zs.empty())
if (m_layers.empty())
return;
m_settings_ids = gcode_result.settings_ids;
if (wxGetApp().is_editor())
load_shells(print, initialized);
else {
@ -316,8 +316,8 @@ void GCodeViewer::load(const GCodeProcessor::Result& gcode_result, const Print&
// bed shape detected in the gcode
bed_shape = gcode_result.bed_shape;
auto bundle = wxGetApp().preset_bundle;
if (bundle != nullptr && !gcode_result.printer_settings_id.empty()) {
const Preset* preset = bundle->printers.find_preset(gcode_result.printer_settings_id);
if (bundle != nullptr && !m_settings_ids.printer.empty()) {
const Preset* preset = bundle->printers.find_preset(m_settings_ids.printer);
if (preset != nullptr) {
model = PresetUtils::system_printer_bed_model(*preset);
texture = PresetUtils::system_printer_bed_texture(*preset);
@ -412,6 +412,9 @@ void GCodeViewer::refresh(const GCodeProcessor::Result& gcode_result, const std:
void GCodeViewer::reset()
{
m_initialized = false;
m_gl_data_initialized = false;
m_moves_count = 0;
for (TBuffer& buffer : m_buffers) {
buffer.reset();
@ -420,12 +423,13 @@ void GCodeViewer::reset()
m_paths_bounding_box = BoundingBoxf3();
m_max_bounding_box = BoundingBoxf3();
m_tool_colors = std::vector<Color>();
m_extruders_count = 0;
m_extruder_ids = std::vector<unsigned char>();
m_extrusions.reset_role_visibility_flags();
m_extrusions.reset_ranges();
m_shells.volumes.clear();
m_layers_zs = std::vector<double>();
m_layers_z_range = { 0.0, 0.0 };
m_layers.reset();
m_layers_z_range = { 0, 0 };
m_roles = std::vector<ExtrusionRole>();
m_time_statistics.reset();
m_time_estimate_mode = PrintEstimatedTimeStatistics::ETimeMode::Normal;
@ -438,46 +442,39 @@ void GCodeViewer::reset()
void GCodeViewer::render() const
{
auto init_gl_data = [this]() {
static bool first_run = true;
if (first_run) {
// initializes opengl data of TBuffers
for (size_t i = 0; i < m_buffers.size(); ++i) {
TBuffer& buffer = m_buffers[i];
switch (buffer_type(i))
{
default: { break; }
case EMoveType::Tool_change:
case EMoveType::Color_change:
case EMoveType::Pause_Print:
case EMoveType::Custom_GCode:
case EMoveType::Retract:
case EMoveType::Unretract:
{
buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
break;
}
case EMoveType::Extrude:
{
buffer.shader = "gouraud_light";
break;
}
case EMoveType::Travel:
{
buffer.shader = "toolpaths_lines";
break;
}
}
// initializes opengl data of TBuffers
for (size_t i = 0; i < m_buffers.size(); ++i) {
TBuffer& buffer = m_buffers[i];
switch (buffer_type(i)) {
default: { break; }
case EMoveType::Tool_change:
case EMoveType::Color_change:
case EMoveType::Pause_Print:
case EMoveType::Custom_GCode:
case EMoveType::Retract:
case EMoveType::Unretract: {
buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
break;
}
case EMoveType::Extrude: {
buffer.shader = "gouraud_light";
break;
}
case EMoveType::Travel: {
buffer.shader = "toolpaths_lines";
break;
}
}
// initializes tool marker
m_sequential_view.marker.init();
// initializes point sizes
std::array<int, 2> point_sizes;
::glGetIntegerv(GL_ALIASED_POINT_SIZE_RANGE, point_sizes.data());
m_detected_point_sizes = { static_cast<float>(point_sizes[0]), static_cast<float>(point_sizes[1]) };
first_run = false;
}
// initializes tool marker
m_sequential_view.marker.init();
// initializes point sizes
std::array<int, 2> point_sizes;
::glGetIntegerv(GL_ALIASED_POINT_SIZE_RANGE, point_sizes.data());
m_detected_point_sizes = { static_cast<float>(point_sizes[0]), static_cast<float>(point_sizes[1]) };
m_gl_data_initialized = true;
};
#if ENABLE_GCODE_VIEWER_STATISTICS
@ -486,7 +483,8 @@ void GCodeViewer::render() const
// OpenGL data must be initialized after the glContext has been created.
// This is ensured when this method is called by GLCanvas3D::_render_gcode().
init_gl_data();
if (!m_gl_data_initialized)
init_gl_data();
if (m_roles.empty())
return;
@ -601,7 +599,7 @@ void GCodeViewer::set_options_visibility_from_flags(unsigned int flags)
enable_legend(is_flag_set(static_cast<unsigned int>(Preview::OptionType::Legend)));
}
void GCodeViewer::set_layers_z_range(const std::array<double, 2>& layers_z_range)
void GCodeViewer::set_layers_z_range(const std::array<unsigned int, 2>& layers_z_range)
{
bool keep_sequential_current_first = layers_z_range[0] >= m_layers_z_range[0];
bool keep_sequential_current_last = layers_z_range[1] <= m_layers_z_range[1];
@ -967,6 +965,8 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
new wxProgressDialog(_L("Generating toolpaths"), "...",
100, wxGetApp().plater(), wxPD_AUTO_HIDE | wxPD_APP_MODAL) : nullptr;
m_extruders_count = gcode_result.extruders_count;
for (size_t i = 0; i < m_moves_count; ++i) {
const GCodeProcessor::MoveVertex& move = gcode_result.moves[i];
if (wxGetApp().is_gcode_viewer())
@ -1532,36 +1532,35 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
std::vector<MultiIndexBuffer>().swap(indices);
// layers zs / roles / extruder ids / cp color ids -> extract from result
size_t last_travel_s_id = 0;
for (size_t i = 0; i < m_moves_count; ++i) {
const GCodeProcessor::MoveVertex& move = gcode_result.moves[i];
if (move.type == EMoveType::Extrude)
m_layers_zs.emplace_back(static_cast<double>(move.position[2]));
if (move.type == EMoveType::Extrude) {
// layers zs
const double* const last_z = m_layers.empty() ? nullptr : &m_layers.get_zs().back();
double z = static_cast<double>(move.position[2]);
if (last_z == nullptr || z < *last_z - EPSILON || *last_z + EPSILON < z)
m_layers.append(z, { last_travel_s_id, i });
else
m_layers.get_endpoints().back().last = i;
// extruder ids
m_extruder_ids.emplace_back(move.extruder_id);
// roles
if (i > 0)
m_roles.emplace_back(move.extrusion_role);
}
else if (move.type == EMoveType::Travel) {
if (i - last_travel_s_id > 1 && !m_layers.empty())
m_layers.get_endpoints().back().last = i;
m_extruder_ids.emplace_back(move.extruder_id);
if (i > 0)
m_roles.emplace_back(move.extrusion_role);
}
// layers zs -> replace intervals of layers with similar top positions with their average value.
std::sort(m_layers_zs.begin(), m_layers_zs.end());
int n = int(m_layers_zs.size());
int k = 0;
for (int i = 0; i < n;) {
int j = i + 1;
double zmax = m_layers_zs[i] + EPSILON;
for (; j < n && m_layers_zs[j] <= zmax; ++j);
m_layers_zs[k++] = (j > i + 1) ? (0.5 * (m_layers_zs[i] + m_layers_zs[j - 1])) : m_layers_zs[i];
i = j;
}
if (k < n) {
m_layers_zs.erase(m_layers_zs.begin() + k, m_layers_zs.end());
m_layers_zs.shrink_to_fit();
last_travel_s_id = i;
}
}
// set layers z range
if (!m_layers_zs.empty())
m_layers_z_range = { m_layers_zs.front(), m_layers_zs.back() };
if (!m_layers.empty()) {
m_layers_z_range = { 0, static_cast<unsigned int>(m_layers.size() - 1) };
}
// roles -> remove duplicates
std::sort(m_roles.begin(), m_roles.end());
@ -1670,34 +1669,46 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
Travel_Colors[0] /* Move */);
};
auto is_in_z_range = [](const Path& path, double min_z, double max_z) {
auto in_z_range = [min_z, max_z](double z) {
return z > min_z - EPSILON && z < max_z + EPSILON;
auto is_in_layers_range = [this](const Path& path, size_t min_id, size_t max_id) {
auto in_layers_range = [this, min_id, max_id](size_t id) {
return m_layers.get_endpoints_at(min_id).first <= id && id <= m_layers.get_endpoints_at(max_id).last;
};
return in_z_range(path.first.position[2]) || in_z_range(path.last.position[2]);
return in_layers_range(path.first.s_id) || in_layers_range(path.last.s_id);
};
auto is_travel_in_z_range = [this, is_in_z_range](size_t path_id, double min_z, double max_z) {
auto is_travel_in_layers_range = [this](size_t path_id, size_t min_id, size_t max_id) {
auto is_in_z_range = [](const Path& path, double min_z, double max_z) {
auto in_z_range = [min_z, max_z](double z) {
return min_z - EPSILON < z&& z < max_z + EPSILON;
};
return in_z_range(path.first.position[2]) || in_z_range(path.last.position[2]);
};
const TBuffer& buffer = m_buffers[buffer_id(EMoveType::Travel)];
if (path_id >= buffer.paths.size())
return false;
Path path = buffer.paths[path_id];
int first = static_cast<int>(path_id);
unsigned int last = static_cast<unsigned int>(path_id);
size_t first = path_id;
size_t last = path_id;
// check adjacent paths
while (first > 0 && path.first.position.isApprox(buffer.paths[first - 1].last.position)) {
--first;
path.first = buffer.paths[first].first;
}
while (last < static_cast<unsigned int>(buffer.paths.size() - 1) && path.last.position.isApprox(buffer.paths[last + 1].first.position)) {
while (last < buffer.paths.size() - 1 && path.last.position.isApprox(buffer.paths[last + 1].first.position)) {
++last;
path.last = buffer.paths[last].last;
}
return is_in_z_range(path, min_z, max_z);
size_t min_s_id = m_layers.get_endpoints_at(min_id).first;
size_t max_s_id = m_layers.get_endpoints_at(max_id).last;
return (min_s_id <= path.first.s_id && path.first.s_id <= max_s_id) ||
(min_s_id <= path.last.s_id && path.last.s_id <= max_s_id);
};
#if ENABLE_GCODE_VIEWER_STATISTICS
@ -1723,10 +1734,10 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
for (size_t i = 0; i < buffer.paths.size(); ++i) {
const Path& path = buffer.paths[i];
if (path.type == EMoveType::Travel) {
if (!is_travel_in_z_range(i, m_layers_z_range[0], m_layers_z_range[1]))
if (!is_travel_in_layers_range(i, m_layers_z_range[0], m_layers_z_range[1]))
continue;
}
else if (!is_in_z_range(path, m_layers_z_range[0], m_layers_z_range[1]))
else if (!is_in_layers_range(path, m_layers_z_range[0], m_layers_z_range[1]))
continue;
if (path.type == EMoveType::Extrude && !is_visible(path))
@ -1740,12 +1751,12 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
if (top_layer_only) {
if (path.type == EMoveType::Travel) {
if (is_travel_in_z_range(i, m_layers_z_range[1], m_layers_z_range[1])) {
if (is_travel_in_layers_range(i, m_layers_z_range[1], m_layers_z_range[1])) {
top_layer_endpoints.first = std::min(top_layer_endpoints.first, path.first.s_id);
top_layer_endpoints.last = std::max(top_layer_endpoints.last, path.last.s_id);
}
}
else if (is_in_z_range(path, m_layers_z_range[1], m_layers_z_range[1])) {
else if (is_in_layers_range(path, m_layers_z_range[1], m_layers_z_range[1])) {
top_layer_endpoints.first = std::min(top_layer_endpoints.first, path.first.s_id);
top_layer_endpoints.last = std::max(top_layer_endpoints.last, path.last.s_id);
}
@ -1802,7 +1813,9 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
switch (path.type)
{
case EMoveType::Extrude: {
if (!top_layer_only || m_sequential_view.current.last == global_endpoints.last || is_in_z_range(path, m_layers_z_range[1], m_layers_z_range[1]))
if (!top_layer_only ||
m_sequential_view.current.last == global_endpoints.last ||
is_in_layers_range(path, m_layers_z_range[1], m_layers_z_range[1]))
color = extrusion_color(path);
else
color = { 0.25f, 0.25f, 0.25f };
@ -1810,7 +1823,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
break;
}
case EMoveType::Travel: {
if (!top_layer_only || m_sequential_view.current.last == global_endpoints.last || is_travel_in_z_range(path_id, m_layers_z_range[1], m_layers_z_range[1]))
if (!top_layer_only || m_sequential_view.current.last == global_endpoints.last || is_travel_in_layers_range(path_id, m_layers_z_range[1], m_layers_z_range[1]))
color = (m_view_type == EViewType::Feedrate || m_view_type == EViewType::Tool || m_view_type == EViewType::ColorPrint) ? extrusion_color(path) : travel_color(path);
else
color = { 0.25f, 0.25f, 0.25f };
@ -1870,7 +1883,11 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
void GCodeViewer::render_toolpaths() const
{
#if ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS
float point_size = 20.0f;
#else
float point_size = 0.8f;
#endif // ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS
std::array<float, 4> light_intensity = { 0.25f, 0.70f, 0.75f, 0.75f };
const Camera& camera = wxGetApp().plater()->get_camera();
double zoom = camera.get_zoom();
@ -1886,6 +1903,11 @@ void GCodeViewer::render_toolpaths() const
auto render_as_points = [this, zoom, point_size, near_plane_height, set_uniform_color]
(const TBuffer& buffer, unsigned int index_buffer_id, EOptionsColors color_id, GLShaderProgram& shader) {
set_uniform_color(Options_Colors[static_cast<unsigned int>(color_id)], shader);
#if ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS
shader.set_uniform("use_fixed_screen_size", 1);
#else
shader.set_uniform("use_fixed_screen_size", 0);
#endif // ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS
shader.set_uniform("zoom", zoom);
shader.set_uniform("percent_outline_radius", 0.0f);
shader.set_uniform("percent_center_radius", 0.33f);
@ -2057,17 +2079,14 @@ void GCodeViewer::render_legend() const
if (!visible)
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.3333f);
ImVec2 pos = ImGui::GetCursorScreenPos();
switch (type)
{
switch (type) {
default:
case EItemType::Rect:
{
case EItemType::Rect: {
draw_list->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f },
ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }));
break;
}
case EItemType::Circle:
{
case EItemType::Circle: {
ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size));
if (m_buffers[buffer_id(EMoveType::Retract)].shader == "options_120") {
draw_list->AddCircleFilled(center, 0.5f * icon_size,
@ -2082,14 +2101,12 @@ void GCodeViewer::render_legend() const
break;
}
case EItemType::Hexagon:
{
case EItemType::Hexagon: {
ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size));
draw_list->AddNgonFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 6);
break;
}
case EItemType::Line:
{
case EItemType::Line: {
draw_list->AddLine({ pos.x + 1, pos.y + icon_size - 1 }, { pos.x + icon_size - 1, pos.y + 1 }, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 3.0f);
break;
}
@ -2201,13 +2218,13 @@ void GCodeViewer::render_legend() const
if (item.type != ColorChange)
continue;
auto lower_b = std::lower_bound(m_layers_zs.begin(), m_layers_zs.end(), item.print_z - Slic3r::DoubleSlider::epsilon());
if (lower_b == m_layers_zs.end())
const std::vector<double> zs = m_layers.get_zs();
auto lower_b = std::lower_bound(zs.begin(), zs.end(), item.print_z - Slic3r::DoubleSlider::epsilon());
if (lower_b == zs.end())
continue;
double current_z = *lower_b;
double previous_z = lower_b == m_layers_zs.begin() ? 0.0 : *(--lower_b);
double previous_z = (lower_b == zs.begin()) ? 0.0 : *(--lower_b);
// to avoid duplicate values, check adding values
if (ret.empty() || !(ret.back().second.first == previous_z && ret.back().second.second == current_z))
@ -2322,8 +2339,7 @@ void GCodeViewer::render_legend() const
case EViewType::ColorPrint:
{
const std::vector<CustomGCode::Item>& custom_gcode_per_print_z = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes;
const int extruders_count = wxGetApp().extruders_edited_cnt();
if (extruders_count == 1) { // single extruder use case
if (m_extruders_count == 1) { // single extruder use case
std::vector<std::pair<Color, std::pair<double, double>>> cp_values = color_print_ranges(0, custom_gcode_per_print_z);
const int items_cnt = static_cast<int>(cp_values.size());
if (items_cnt == 0) { // There are no color changes, but there are some pause print or custom Gcode
@ -2415,28 +2431,26 @@ void GCodeViewer::render_legend() const
for (const auto& time_rec : times) {
switch (time_rec.first)
{
case CustomGCode::PausePrint:
{
case CustomGCode::PausePrint: {
auto it = std::find_if(custom_gcode_per_print_z.begin(), custom_gcode_per_print_z.end(), [time_rec](const CustomGCode::Item& item) { return item.type == time_rec.first; });
if (it != custom_gcode_per_print_z.end()) {
items.push_back({ PartialTime::EType::Print, it->extruder, Color(), Color(), time_rec.second });
items.push_back({ PartialTime::EType::Print, it->extruder, last_color[it->extruder - 1], Color(), time_rec.second });
items.push_back({ PartialTime::EType::Pause, it->extruder, Color(), Color(), time_rec.second });
custom_gcode_per_print_z.erase(it);
}
break;
}
case CustomGCode::ColorChange:
{
case CustomGCode::ColorChange: {
auto it = std::find_if(custom_gcode_per_print_z.begin(), custom_gcode_per_print_z.end(), [time_rec](const CustomGCode::Item& item) { return item.type == time_rec.first; });
if (it != custom_gcode_per_print_z.end()) {
items.push_back({ PartialTime::EType::Print, it->extruder, Color(), Color(), time_rec.second });
items.push_back({ PartialTime::EType::Print, it->extruder, last_color[it->extruder - 1], Color(), time_rec.second });
items.push_back({ PartialTime::EType::ColorChange, it->extruder, last_color[it->extruder - 1], decode_color(it->color), time_rec.second });
last_color[it->extruder - 1] = decode_color(it->color);
last_extruder_id = it->extruder;
custom_gcode_per_print_z.erase(it);
}
else
items.push_back({ PartialTime::EType::Print, last_extruder_id, Color(), Color(), time_rec.second });
items.push_back({ PartialTime::EType::Print, last_extruder_id, last_color[last_extruder_id - 1], Color(), time_rec.second });
break;
}
@ -2447,7 +2461,7 @@ void GCodeViewer::render_legend() const
return items;
};
auto append_color = [this, &imgui](const Color& color1, const Color& color2, std::array<float, 2>& offsets, const Times& times) {
auto append_color_change = [this, &imgui](const Color& color1, const Color& color2, const std::array<float, 2>& offsets, const Times& times) {
imgui.text(_u8L("Color change"));
ImGui::SameLine();
@ -2466,6 +2480,24 @@ void GCodeViewer::render_legend() const
imgui.text(short_time(get_time_dhms(times.second - times.first)));
};
auto append_print = [this, &imgui](const Color& color, const std::array<float, 2>& offsets, const Times& times) {
imgui.text(_u8L("Print"));
ImGui::SameLine();
float icon_size = ImGui::GetTextLineHeight();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
ImVec2 pos = ImGui::GetCursorScreenPos();
pos.x -= 0.5f * ImGui::GetStyle().ItemSpacing.x;
draw_list->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f },
ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }));
ImGui::SameLine(offsets[0]);
imgui.text(short_time(get_time_dhms(times.second)));
ImGui::SameLine(offsets[1]);
imgui.text(short_time(get_time_dhms(times.first)));
};
PartialTimes partial_times = generate_partial_times(time_mode.custom_gcode_times);
if (!partial_times.empty()) {
labels.clear();
@ -2474,8 +2506,8 @@ void GCodeViewer::render_legend() const
for (const PartialTime& item : partial_times) {
switch (item.type)
{
case PartialTime::EType::Print: { labels.push_back(_u8L("Print")); break; }
case PartialTime::EType::Pause: { labels.push_back(_u8L("Pause")); break; }
case PartialTime::EType::Print: { labels.push_back(_u8L("Print")); break; }
case PartialTime::EType::Pause: { labels.push_back(_u8L("Pause")); break; }
case PartialTime::EType::ColorChange: { labels.push_back(_u8L("Color change")); break; }
}
times.push_back(short_time(get_time_dhms(item.times.second)));
@ -2487,25 +2519,18 @@ void GCodeViewer::render_legend() const
for (const PartialTime& item : partial_times) {
switch (item.type)
{
case PartialTime::EType::Print:
{
imgui.text(_u8L("Print"));
ImGui::SameLine(offsets[0]);
imgui.text(short_time(get_time_dhms(item.times.second)));
ImGui::SameLine(offsets[1]);
imgui.text(short_time(get_time_dhms(item.times.first)));
case PartialTime::EType::Print: {
append_print(item.color1, offsets, item.times);
break;
}
case PartialTime::EType::Pause:
{
case PartialTime::EType::Pause: {
imgui.text(_u8L("Pause"));
ImGui::SameLine(offsets[0]);
imgui.text(short_time(get_time_dhms(item.times.second - item.times.first)));
break;
}
case PartialTime::EType::ColorChange:
{
append_color(item.color1, item.color2, offsets, item.times);
case PartialTime::EType::ColorChange: {
append_color_change(item.color1, item.color2, offsets, item.times);
break;
}
}
@ -2519,12 +2544,10 @@ void GCodeViewer::render_legend() const
{
case EViewType::Feedrate:
case EViewType::Tool:
case EViewType::ColorPrint:
{
case EViewType::ColorPrint: {
break;
}
default:
{
default: {
// title
ImGui::Spacing();
imgui.title(_u8L("Travel"));
@ -2570,8 +2593,58 @@ void GCodeViewer::render_legend() const
add_option(EMoveType::Unretract, EOptionsColors::Unretractions, _u8L("Deretractions"));
add_option(EMoveType::Tool_change, EOptionsColors::ToolChanges, _u8L("Tool changes"));
add_option(EMoveType::Color_change, EOptionsColors::ColorChanges, _u8L("Color changes"));
add_option(EMoveType::Pause_Print, EOptionsColors::PausePrints, _u8L("Pause prints"));
add_option(EMoveType::Custom_GCode, EOptionsColors::CustomGCodes, _u8L("Custom GCodes"));
add_option(EMoveType::Pause_Print, EOptionsColors::PausePrints, _u8L("Print pauses"));
add_option(EMoveType::Custom_GCode, EOptionsColors::CustomGCodes, _u8L("Custom G-codes"));
}
// settings section
if (wxGetApp().is_gcode_viewer() &&
(m_view_type == EViewType::FeatureType || m_view_type == EViewType::Tool) &&
(!m_settings_ids.print.empty() || !m_settings_ids.filament.empty() || !m_settings_ids.printer.empty())) {
auto calc_offset = [this]() {
float ret = 0.0f;
if (!m_settings_ids.printer.empty())
ret = std::max(ret, ImGui::CalcTextSize((_u8L("Printer") + std::string(":")).c_str()).x);
if (!m_settings_ids.print.empty())
ret = std::max(ret, ImGui::CalcTextSize((_u8L("Print settings") + std::string(":")).c_str()).x);
if (!m_settings_ids.filament.empty()) {
for (unsigned char i : m_extruder_ids) {
ret = std::max(ret, ImGui::CalcTextSize((_u8L("Filament") + " " + std::to_string(i + 1) + ":").c_str()).x);
}
}
if (ret > 0.0f)
ret += 2.0f * ImGui::GetStyle().ItemSpacing.x;
return ret;
};
ImGui::Spacing();
ImGui::Spacing();
ImGui::PushStyleColor(ImGuiCol_Separator, { 1.0f, 1.0f, 1.0f, 1.0f });
ImGui::Separator();
ImGui::PopStyleColor();
ImGui::Spacing();
float offset = calc_offset();
if (!m_settings_ids.printer.empty()) {
imgui.text(_u8L("Printer") + ":");
ImGui::SameLine(offset);
imgui.text(m_settings_ids.printer);
}
if (!m_settings_ids.print.empty()) {
imgui.text(_u8L("Print settings") + ":");
ImGui::SameLine(offset);
imgui.text(m_settings_ids.print);
}
if (!m_settings_ids.filament.empty()) {
for (unsigned char i : m_extruder_ids) {
imgui.text(_u8L("Filament") + " " + std::to_string(i + 1) + ":");
ImGui::SameLine(offset);
imgui.text(m_settings_ids.filament[i]);
}
}
}
// total estimated printing time section
@ -2620,15 +2693,12 @@ void GCodeViewer::render_legend() const
}
};
switch (m_time_estimate_mode)
{
case PrintEstimatedTimeStatistics::ETimeMode::Normal:
{
switch (m_time_estimate_mode) {
case PrintEstimatedTimeStatistics::ETimeMode::Normal: {
show_mode_button(_u8L("Show stealth mode"), PrintEstimatedTimeStatistics::ETimeMode::Stealth);
break;
}
case PrintEstimatedTimeStatistics::ETimeMode::Stealth:
{
case PrintEstimatedTimeStatistics::ETimeMode::Stealth: {
show_mode_button(_u8L("Show normal mode"), PrintEstimatedTimeStatistics::ETimeMode::Normal);
break;
}
@ -2745,9 +2815,10 @@ void GCodeViewer::log_memory_used(const std::string& label, long long additional
render_paths_size += SLIC3R_STDVEC_MEMSIZE(path.offsets, size_t);
}
}
long long layers_zs_size = SLIC3R_STDVEC_MEMSIZE(m_layers_zs, double);
long long layers_size = SLIC3R_STDVEC_MEMSIZE(m_layers.get_zs(), double);
layers_size += SLIC3R_STDVEC_MEMSIZE(m_layers.get_endpoints(), Layers::Endpoints);
BOOST_LOG_TRIVIAL(trace) << label
<< format_memsize_MB(additional + paths_size + render_paths_size + layers_zs_size)
<< format_memsize_MB(additional + paths_size + render_paths_size + layers_size)
<< log_memory_info();
}
}

View file

@ -272,6 +272,41 @@ class GCodeViewer
void reset_ranges() { ranges.reset(); }
};
class Layers
{
public:
struct Endpoints
{
size_t first{ 0 };
size_t last{ 0 };
};
private:
std::vector<double> m_zs;
std::vector<Endpoints> m_endpoints;
public:
void append(double z, Endpoints endpoints)
{
m_zs.emplace_back(z);
m_endpoints.emplace_back(endpoints);
}
void reset()
{
m_zs = std::vector<double>();
m_endpoints = std::vector<Endpoints>();
}
size_t size() const { return m_zs.size(); }
bool empty() const { return m_zs.empty(); }
const std::vector<double>& get_zs() const { return m_zs; }
const std::vector<Endpoints>& get_endpoints() const { return m_endpoints; }
std::vector<Endpoints>& get_endpoints() { return m_endpoints; }
double get_z_at(unsigned int id) const { return (id < m_zs.size()) ? m_zs[id] : 0.0; }
Endpoints get_endpoints_at(unsigned int id) const { return (id < m_endpoints.size()) ? m_endpoints[id] : Endpoints(); }
};
#if ENABLE_GCODE_VIEWER_STATISTICS
struct Statistics
{
@ -388,6 +423,7 @@ public:
private:
bool m_initialized{ false };
mutable bool m_gl_data_initialized{ false };
unsigned int m_last_result_id{ 0 };
size_t m_moves_count{ 0 };
mutable std::vector<TBuffer> m_buffers{ static_cast<size_t>(EMoveType::Extrude) };
@ -396,9 +432,10 @@ private:
// bounding box of toolpaths + marker tools
BoundingBoxf3 m_max_bounding_box;
std::vector<Color> m_tool_colors;
std::vector<double> m_layers_zs;
std::array<double, 2> m_layers_z_range;
Layers m_layers;
std::array<unsigned int, 2> m_layers_z_range;
std::vector<ExtrusionRole> m_roles;
size_t m_extruders_count;
std::vector<unsigned char> m_extruder_ids;
mutable Extrusions m_extrusions;
mutable SequentialView m_sequential_view;
@ -411,6 +448,7 @@ private:
mutable Statistics m_statistics;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
mutable std::array<float, 2> m_detected_point_sizes = { 0.0f, 0.0f };
GCodeProcessor::Result::SettingsIds m_settings_ids;
public:
GCodeViewer() = default;
@ -428,7 +466,7 @@ public:
const BoundingBoxf3& get_paths_bounding_box() const { return m_paths_bounding_box; }
const BoundingBoxf3& get_max_bounding_box() const { return m_max_bounding_box; }
const std::vector<double>& get_layers_zs() const { return m_layers_zs; };
const std::vector<double>& get_layers_zs() const { return m_layers.get_zs(); };
const SequentialView& get_sequential_view() const { return m_sequential_view; }
void update_sequential_view_current(unsigned int first, unsigned int last);
@ -447,7 +485,7 @@ public:
void set_toolpath_role_visibility_flags(unsigned int flags) { m_extrusions.role_visibility_flags = flags; }
unsigned int get_options_visibility_flags() const;
void set_options_visibility_from_flags(unsigned int flags);
void set_layers_z_range(const std::array<double, 2>& layers_z_range);
void set_layers_z_range(const std::array<unsigned int, 2>& layers_z_range);
bool is_legend_enabled() const { return m_legend_enabled; }
void enable_legend(bool enable) { m_legend_enabled = enable; }

View file

@ -5,9 +5,6 @@
#include "polypartition.h"
#include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/PrintConfig.hpp"
#if !ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/PreviewData.hpp"
#endif // !ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/ThumbnailData.hpp"
#include "libslic3r/Geometry.hpp"
#include "libslic3r/ExtrusionEntity.hpp"
@ -1415,7 +1412,7 @@ void GLCanvas3D::Tooltip::render(const Vec2d& mouse_position, GLCanvas3D& canvas
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha);
imgui.set_next_window_pos(position(0), position(1), ImGuiCond_Always, 0.0f, 0.0f);
imgui.begin(_L("canvas_tooltip"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoFocusOnAppearing);
imgui.begin(wxString("canvas_tooltip"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoFocusOnAppearing);
ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow());
ImGui::TextUnformatted(m_text.c_str());
@ -1457,6 +1454,7 @@ wxDEFINE_EVENT(EVT_GLCANVAS_MOVE_LAYERS_SLIDER, wxKeyEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent);
#endif // ENABLE_GCODE_VIEWER
wxDEFINE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_JUMP_TO, wxKeyEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_COLLAPSE_SIDEBAR, SimpleEvent);
@ -2178,9 +2176,13 @@ void GLCanvas3D::set_toolpath_view_type(GCodeViewer::EViewType type)
m_gcode_viewer.set_view_type(type);
}
void GLCanvas3D::set_toolpaths_z_range(const std::array<double, 2>& range)
void GLCanvas3D::set_volumes_z_range(const std::array<double, 2>& range)
{
m_volumes.set_range(range[0] - 1e-6, range[1] + 1e-6);
}
void GLCanvas3D::set_toolpaths_z_range(const std::array<unsigned int, 2>& range)
{
if (m_gcode_viewer.has_data())
m_gcode_viewer.set_layers_z_range(range);
}
@ -2899,6 +2901,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
// see include/wx/defs.h enum wxKeyCode
int keyCode = evt.GetKeyCode();
int ctrlMask = wxMOD_CONTROL;
int shiftMask = wxMOD_SHIFT;
auto imgui = wxGetApp().imgui();
if (imgui->update_key_data(evt)) {
@ -2996,6 +2999,18 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE_ALL)); break;
default: evt.Skip();
}
}
else if ((evt.GetModifiers() & shiftMask) != 0) {
switch (keyCode) {
case 'g':
case 'G': {
if (dynamic_cast<Preview*>(m_canvas->GetParent()) != nullptr)
post_event(wxKeyEvent(EVT_GLCANVAS_JUMP_TO, evt));
break;
}
default:
evt.Skip();
}
} else if (evt.HasModifiers()) {
evt.Skip();
} else {
@ -4385,7 +4400,7 @@ bool GLCanvas3D::_render_search_list(float pos_x) const
std::string& search_line = sidebar.get_search_line();
char *s = new char[255];
strcpy(s, search_line.empty() ? _u8L("Type here to search").c_str() : search_line.c_str());
strcpy(s, search_line.empty() ? _u8L("Enter a search term").c_str() : search_line.c_str());
imgui->search_list(ImVec2(45 * em, 30 * em), &search_string_getter, s,
sidebar.get_searcher().view_params,
@ -4393,7 +4408,7 @@ bool GLCanvas3D::_render_search_list(float pos_x) const
search_line = s;
delete [] s;
if (search_line == _u8L("Type here to search"))
if (search_line == _u8L("Enter a search term"))
search_line.clear();
if (edited)

View file

@ -114,6 +114,7 @@ wxDECLARE_EVENT(EVT_GLCANVAS_MOVE_LAYERS_SLIDER, wxKeyEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent);
#endif // ENABLE_GCODE_VIEWER
wxDECLARE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_JUMP_TO, wxKeyEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_COLLAPSE_SIDEBAR, SimpleEvent);
@ -650,7 +651,8 @@ public:
unsigned int get_toolpath_role_visibility_flags() const { return m_gcode_viewer.get_toolpath_role_visibility_flags(); }
void set_toolpath_role_visibility_flags(unsigned int flags);
void set_toolpath_view_type(GCodeViewer::EViewType type);
void set_toolpaths_z_range(const std::array<double, 2>& range);
void set_volumes_z_range(const std::array<double, 2>& range);
void set_toolpaths_z_range(const std::array<unsigned int, 2>& range);
#else
std::vector<double> get_current_print_zs(bool active_only) const;
#endif // ENABLE_GCODE_VIEWER

View file

@ -86,7 +86,7 @@ class SplashScreen : public wxSplashScreen
{
public:
SplashScreen(const wxBitmap& bitmap, long splashStyle, int milliseconds, wxPoint pos = wxDefaultPosition)
: wxSplashScreen(bitmap, splashStyle, milliseconds, nullptr, wxID_ANY, wxDefaultPosition, wxDefaultSize,
: wxSplashScreen(bitmap, splashStyle, milliseconds, (wxWindow*)wxGetApp().mainframe, wxID_ANY, wxDefaultPosition, wxDefaultSize,
#ifdef __APPLE__
wxSIMPLE_BORDER | wxFRAME_NO_TASKBAR | wxSTAY_ON_TOP
#else
@ -892,7 +892,7 @@ bool GUI_App::on_init_inner()
#else
if (scrn)
#endif // ENABLE_GCODE_VIEWER
scrn->SetText(_L("Creating settings tabs..."));
scrn->SetText(_L("Preparing settings tabs..."));
mainframe = new MainFrame();
// hide settings tabs after first Layout
@ -1149,8 +1149,8 @@ void GUI_App::check_printer_presets()
for (const std::string& preset_name : preset_names)
msg_text += "\n \"" + from_u8(preset_name) + "\",";
msg_text.RemoveLast();
msg_text += "\n\n" + _L("But from this version of PrusaSlicer we don't show/use this information in Printer Settings.\n"
"Now, this information will be exposed in physical printers settings.") + "\n\n" +
msg_text += "\n\n" + _L("But since this version of PrusaSlicer we don't show this information in Printer Settings anymore.\n"
"Settings will be available in physical printers settings.") + "\n\n" +
_L("By default new Printer devices will be named as \"Printer N\" during its creation.\n"
"Note: This name can be changed later from the physical printers settings");

View file

@ -1,7 +1,4 @@
#include "libslic3r/libslic3r.h"
#if !ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/PreviewData.hpp"
#endif // !ENABLE_GCODE_VIEWER
#include "GUI_Preview.hpp"
#include "GUI_App.hpp"
#include "GUI.hpp"
@ -557,6 +554,16 @@ void Preview::msw_rescale()
refresh_print();
}
void Preview::jump_layers_slider(wxKeyEvent& evt)
{
#if ENABLE_GCODE_VIEWER
if (m_layers_slider) m_layers_slider->OnChar(evt);
#else
if (m_slider)
m_slider->OnKeyDown(evt);
#endif // ENABLE_GCODE_VIEWER
}
#if ENABLE_GCODE_VIEWER
void Preview::move_layers_slider(wxKeyEvent& evt)
{
@ -1282,13 +1289,12 @@ void Preview::load_print_as_fff(bool keep_z_range)
// set color print values, if it si selected "ColorPrint" view type
#if ENABLE_GCODE_VIEWER
if (gcode_view_type == GCodeViewer::EViewType::ColorPrint) {
colors = wxGetApp().plater()->get_colors_for_color_print(m_gcode_result);
#else
if (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::ColorPrint) {
#endif // ENABLE_GCODE_VIEWER
colors = wxGetApp().plater()->get_colors_for_color_print();
#if !ENABLE_GCODE_VIEWER
colors.push_back("#808080"); // gray color for pause print or custom G-code
#endif // !ENABLE_GCODE_VIEWER
#endif // ENABLE_GCODE_VIEWER
if (!gcode_preview_data_valid) {
color_print_values = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes;
@ -1299,10 +1305,11 @@ void Preview::load_print_as_fff(bool keep_z_range)
}
#if ENABLE_GCODE_VIEWER
else if (gcode_preview_data_valid || gcode_view_type == GCodeViewer::EViewType::Tool) {
colors = wxGetApp().plater()->get_extruder_colors_from_plater_config(m_gcode_result);
#else
else if (gcode_preview_data_valid || (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::Tool) ) {
#endif // ENABLE_GCODE_VIEWER
colors = wxGetApp().plater()->get_extruder_colors_from_plater_config();
#endif // ENABLE_GCODE_VIEWER
color_print_values.clear();
}
@ -1417,13 +1424,12 @@ void Preview::on_layers_slider_scroll_changed(wxCommandEvent& event)
void Preview::on_sliders_scroll_changed(wxCommandEvent& event)
#endif // ENABLE_GCODE_VIEWER
{
if (IsShown())
{
if (IsShown()) {
PrinterTechnology tech = m_process->current_printer_technology();
if (tech == ptFFF)
{
if (tech == ptFFF) {
#if ENABLE_GCODE_VIEWER
m_canvas->set_toolpaths_z_range({ m_layers_slider->GetLowerValueD(), m_layers_slider->GetHigherValueD() });
m_canvas->set_volumes_z_range({ m_layers_slider->GetLowerValueD(), m_layers_slider->GetHigherValueD() });
m_canvas->set_toolpaths_z_range({ static_cast<unsigned int>(m_layers_slider->GetLowerValue()), static_cast<unsigned int>(m_layers_slider->GetHigherValue()) });
m_canvas->set_as_dirty();
#else
m_canvas->set_toolpaths_range(m_slider->GetLowerValueD() - 1e-6, m_slider->GetHigherValueD() + 1e-6);
@ -1431,8 +1437,7 @@ void Preview::on_sliders_scroll_changed(wxCommandEvent& event)
m_canvas->set_use_clipping_planes(false);
#endif // ENABLE_GCODE_VIEWER
}
else if (tech == ptSLA)
{
else if (tech == ptSLA) {
#if ENABLE_GCODE_VIEWER
m_canvas->set_clipping_plane(0, ClippingPlane(Vec3d::UnitZ(), -m_layers_slider->GetLowerValueD()));
m_canvas->set_clipping_plane(1, ClippingPlane(-Vec3d::UnitZ(), m_layers_slider->GetHigherValueD()));
@ -1463,8 +1468,8 @@ wxString Preview::get_option_type_string(OptionType type) const
case OptionType::Unretractions: { return _L("Deretractions"); }
case OptionType::ToolChanges: { return _L("Tool changes"); }
case OptionType::ColorChanges: { return _L("Color changes"); }
case OptionType::PausePrints: { return _L("Pause prints"); }
case OptionType::CustomGCodes: { return _L("Custom GCodes"); }
case OptionType::PausePrints: { return _L("Print pauses"); }
case OptionType::CustomGCodes: { return _L("Custom G-codes"); }
case OptionType::Shells: { return _L("Shells"); }
case OptionType::ToolMarker: { return _L("Tool marker"); }
case OptionType::Legend: { return _L("Legend/Estimated printing time"); }

View file

@ -179,6 +179,7 @@ Preview(wxWindow* parent, Model* model, DynamicPrintConfig* config,
void refresh_print();
void msw_rescale();
void jump_layers_slider(wxKeyEvent& evt);
#if ENABLE_GCODE_VIEWER
void move_layers_slider(wxKeyEvent& evt);
void edit_layers_slider(wxKeyEvent& evt);

View file

@ -95,6 +95,7 @@ public:
#ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList
this->SetFont(m_normal_font);
#endif
this->CenterOnParent();
// Linux specific issue : get_dpi_for_window(this) still doesn't responce to the Display's scale in new wxWidgets(3.1.3).
// So, calculate the m_em_unit value from the font size, as before

View file

@ -41,8 +41,8 @@ bool GLGizmoFdmSupports::on_init()
m_desc["clipping_of_view"] = _L("Clipping of view") + ": ";
m_desc["reset_direction"] = _L("Reset direction");
m_desc["cursor_size"] = _L("Cursor size") + ": ";
m_desc["cursor_type"] = _L("Cursor type") + ": ";
m_desc["cursor_size"] = _L("Brush size") + ": ";
m_desc["cursor_type"] = _L("Brush shape") + ": ";
m_desc["enforce_caption"] = _L("Left mouse button") + ": ";
m_desc["enforce"] = _L("Enforce supports");
m_desc["block_caption"] = _L("Right mouse button") + " ";
@ -126,7 +126,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
m_imgui->text("");
if (m_imgui->button("Autoset by angle...")) {
if (m_imgui->button(_L("Autoset by angle") + "...")) {
m_setting_angle = true;
}
@ -232,9 +232,12 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
else {
m_imgui->begin(_L("Autoset custom supports"), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
ImGui::AlignTextToFramePadding();
m_imgui->text(_L("Threshold:") + " " + _L("deg"));
m_imgui->text(_L("Threshold:"));
std::string format_str = std::string("%.f") + I18N::translate_utf8("°",
"Degree sign to use in the respective slider in FDM supports gizmo,"
"placed after the number with no whitespace in between.");
ImGui::SameLine();
if (m_imgui->slider_float("", &m_angle_threshold_deg, 0.f, 90.f, "%.f"))
if (m_imgui->slider_float("", &m_angle_threshold_deg, 0.f, 90.f, format_str.data()))
m_parent.set_slope_normal_angle(90.f - m_angle_threshold_deg);
if (m_imgui->button(_L("Enforce")))
select_facets_by_angle(m_angle_threshold_deg, false);

View file

@ -36,16 +36,16 @@ void GLGizmoPainterBase::activate_internal_undo_redo_stack(bool activate)
{
if (activate && ! m_internal_stack_active) {
wxString str = get_painter_type() == PainterGizmoType::FDM_SUPPORTS
? _L("Supports gizmo turned on")
: _L("Seam gizmo turned on");
? _L("Entering Paint-on supports")
: _L("Entering Seam painting");
Plater::TakeSnapshot(wxGetApp().plater(), str);
wxGetApp().plater()->enter_gizmos_stack();
m_internal_stack_active = true;
}
if (! activate && m_internal_stack_active) {
wxString str = get_painter_type() == PainterGizmoType::SEAM
? _L("Seam gizmo turned off")
: _L("Supports gizmo turned off");
? _L("Leaving Seam painting")
: _L("Leaving Paint-on supports");
wxGetApp().plater()->leave_gizmos_stack();
Plater::TakeSnapshot(wxGetApp().plater(), str);
m_internal_stack_active = false;

View file

@ -200,62 +200,10 @@ void GLGizmoRotate::on_render_for_picking() const
glsafe(::glPopMatrix());
}
GLGizmoRotate3D::RotoptimzeWindow::RotoptimzeWindow(ImGuiWrapper * imgui,
State & state,
const Alignment &alignment)
: m_imgui{imgui}
{
imgui->begin(_L("Rotation"), ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_AlwaysAutoResize |
ImGuiWindowFlags_NoCollapse);
// adjust window position to avoid overlap the view toolbar
float win_h = ImGui::GetWindowHeight();
float x = alignment.x, y = alignment.y;
y = std::min(y, alignment.bottom_limit - win_h);
ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always);
static constexpr const char * button_txt = L("Optimize orientation");
static constexpr const char * slider_txt = L("Accuracy");
float button_width = imgui->calc_text_size(_(button_txt)).x;
ImGui::PushItemWidth(100.);
//if (imgui->button(_(button_txt))) {
if (ImGui::ArrowButton(_(button_txt).c_str(), ImGuiDir_Down)){
std::cout << "Blip" << std::endl;
}
ImGui::SliderFloat(_(slider_txt).c_str(), &state.accuracy, 0.01f, 1.f, "%.1f");
static const std::vector<std::string> options = {
_L("Least supports").ToStdString(),
_L("Suface quality").ToStdString()
};
// if (imgui->combo(_L("Choose method"), options, state.method) ) {
// std::cout << "method: " << state.method << std::endl;
// }
}
GLGizmoRotate3D::RotoptimzeWindow::~RotoptimzeWindow()
{
m_imgui->end();
}
void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limit)
{
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
return;
// TODO:
// m_rotoptimizewin_state.mobj = ?;
// RotoptimzeWindow popup{m_imgui, m_rotoptimizewin_state, {x, y, bottom_limit}};
}
void GLGizmoRotate::render_circle() const

View file

@ -136,37 +136,6 @@ protected:
}
void on_render_input_window(float x, float y, float bottom_limit) override;
private:
class RotoptimzeWindow {
ImGuiWrapper *m_imgui = nullptr;
public:
struct State {
enum Metods { mMinSupportPoints, mLegacy };
float accuracy = 1.f;
int method = mMinSupportPoints;
ModelObject *mobj = nullptr;
};
struct Alignment { float x, y, bottom_limit; };
RotoptimzeWindow(ImGuiWrapper * imgui,
State & state,
const Alignment &bottom_limit);
~RotoptimzeWindow();
RotoptimzeWindow(const RotoptimzeWindow&) = delete;
RotoptimzeWindow(RotoptimzeWindow &&) = delete;
RotoptimzeWindow& operator=(const RotoptimzeWindow &) = delete;
RotoptimzeWindow& operator=(RotoptimzeWindow &&) = delete;
};
RotoptimzeWindow::State m_rotoptimizewin_state = {};
};
} // namespace GUI

View file

@ -24,8 +24,8 @@ bool GLGizmoSeam::on_init()
m_desc["clipping_of_view"] = _L("Clipping of view") + ": ";
m_desc["reset_direction"] = _L("Reset direction");
m_desc["cursor_size"] = _L("Cursor size") + ": ";
m_desc["cursor_type"] = _L("Cursor type") + ": ";
m_desc["cursor_size"] = _L("Brush size") + ": ";
m_desc["cursor_type"] = _L("Brush shape") + ": ";
m_desc["enforce_caption"] = _L("Left mouse button") + ": ";
m_desc["enforce"] = _L("Enforce seam");
m_desc["block_caption"] = _L("Right mouse button") + " ";

View file

@ -42,14 +42,16 @@ static const std::map<const char, std::string> font_icons = {
{ImGui::PrinterSlaIconMarker , "sla_printer" },
{ImGui::FilamentIconMarker , "spool" },
{ImGui::MaterialIconMarker , "resin" },
{ImGui::CloseIconMarker , "notification_close" },
{ImGui::CloseIconHoverMarker , "notification_close_hover" },
//{ImGui::TimerDotMarker , "timer_dot" },
//{ImGui::TimerDotEmptyMarker , "timer_dot_empty" },
{ImGui::MinimalizeMarker , "notification_minimalize" },
{ImGui::MinimalizeHoverMarker , "notification_minimalize_hover" },
{ImGui::WarningMarker , "notification_warning" },
{ImGui::ErrorMarker , "notification_error" }
{ImGui::MinimalizeButton , "notification_minimalize" },
{ImGui::MinimalizeHoverButton , "notification_minimalize_hover" }
};
static const std::map<const char, std::string> font_icons_large = {
{ImGui::CloseNotifButton , "notification_close" },
{ImGui::CloseNotifHoverButton , "notification_close_hover" },
{ImGui::EjectButton , "notification_eject_sd" },
{ImGui::EjectHoverButton , "notification_eject_sd_hover" },
{ImGui::WarningMarker , "notification_warning" },
{ImGui::ErrorMarker , "notification_error" }
};
const ImVec4 ImGuiWrapper::COL_GREY_DARK = { 0.333f, 0.333f, 0.333f, 1.0f };
@ -718,7 +720,7 @@ void ImGuiWrapper::search_list(const ImVec2& size_, bool (*items_getter)(int, co
// The press on Esc key invokes editing of InputText (removes last changes)
// So we should save previous value...
std::string str = search_str;
ImGui::InputTextEx("", NULL, search_str, 20, search_size, ImGuiInputTextFlags_AutoSelectAll, NULL, NULL);
ImGui::InputTextEx("", NULL, search_str, 40, search_size, ImGuiInputTextFlags_AutoSelectAll, NULL, NULL);
edited = ImGui::IsItemEdited();
if (edited)
hovered_id = 0;
@ -796,6 +798,8 @@ void ImGuiWrapper::search_list(const ImVec2& size_, bool (*items_getter)(int, co
}
};
ImGui::AlignTextToFramePadding();
// add checkboxes for show/hide Categories and Groups
text(_L("Use for search")+":");
check_box(_L("Category"), view_params.category);
@ -948,6 +952,8 @@ void ImGuiWrapper::init_font(bool compress)
// add rectangles for the icons to the font atlas
for (auto& icon : font_icons)
io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz, icon_sz, 3.0 * font_scale + icon_sz);
for (auto& icon : font_icons_large)
io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz * 2, icon_sz * 2, 3.0 * font_scale + icon_sz * 2);
// Build texture atlas
unsigned char* pixels;
@ -967,6 +973,20 @@ void ImGuiWrapper::init_font(bool compress)
}
rect_id++;
}
icon_sz = lround(32 * font_scale); // default size of large icon is 32 px
for (auto icon : font_icons_large) {
if (const ImFontAtlas::CustomRect* rect = io.Fonts->GetCustomRectByIndex(rect_id)) {
std::vector<unsigned char> raw_data = load_svg(icon.second, icon_sz, icon_sz);
const ImU32* pIn = (ImU32*)raw_data.data();
for (int y = 0; y < icon_sz; y++) {
ImU32* pOut = (ImU32*)pixels + (rect->Y + y) * width + (rect->X);
for (int x = 0; x < icon_sz; x++)
*pOut++ = *pIn++;
}
}
rect_id++;
}
// Upload texture to graphics system
GLint last_texture;

View file

@ -34,9 +34,9 @@ namespace GUI {
KBShortcutsDialog::KBShortcutsDialog()
#if ENABLE_GCODE_VIEWER
: DPIDialog(NULL, wxID_ANY, wxString(wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME) + " - " + _L("Keyboard Shortcuts"),
: DPIDialog((wxWindow*)wxGetApp().mainframe, wxID_ANY, wxString(wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME) + " - " + _L("Keyboard Shortcuts"),
#else
: DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _L("Keyboard Shortcuts"),
: DPIDialog((wxWindow*)wxGetApp().mainframe, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _L("Keyboard Shortcuts"),
#endif // ENABLE_GCODE_VIEWER
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
@ -194,7 +194,7 @@ void KBShortcutsDialog::fill_shortcuts()
m_full_shortcuts.push_back(std::make_pair(_L("Plater"), plater_shortcuts));
Shortcuts gizmos_shortcuts = {
{ ctrl, L("All gizmos: Press to rotate view with mouse left or to pan view with mouse right") },
{ ctrl, L("All gizmos: Rotate - left mouse button; Pan - right mouse button") },
{ "Shift+", L("Gizmo move: Press to snap by 1mm") },
{ "Shift+", L("Gizmo scale: Press to snap by 5%") },
{ "F", L("Gizmo scale: Scale selection to fit print volume") },
@ -213,7 +213,7 @@ void KBShortcutsDialog::fill_shortcuts()
{ L("Arrow Down"), L("Lower Layer") },
{ "U", L("Upper Layer") },
{ "D", L("Lower Layer") },
{ "L", L("Show/Hide Legend/Estimated printing time") },
{ "L", L("Show/Hide Legend & Estimated printing time") },
};
m_full_shortcuts.push_back(std::make_pair(_L("Preview"), preview_shortcuts));

View file

@ -238,6 +238,17 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
event.Skip();
});
// OSX specific issue:
// When we move application between Retina and non-Retina displays, The legend on a canvas doesn't redraw
// So, redraw explicitly canvas, when application is moved
#if ENABLE_RETINA_GL
Bind(wxEVT_MOVE, [this](wxMoveEvent& event) {
wxGetApp().plater()->get_current_canvas3D()->set_as_dirty();
wxGetApp().plater()->get_current_canvas3D()->request_extra_frame();
event.Skip();
});
#endif
wxGetApp().persist_window_geometry(this, true);
wxGetApp().persist_window_geometry(&m_settings_dialog, true);
@ -418,6 +429,10 @@ void MainFrame::update_layout()
// m_tabpanel->SetMinSize(size);
// }
//#endif
#ifdef __APPLE__
m_plater->sidebar().change_top_border_for_mode_sizer(m_layout != ESettingsLayout::Old);
#endif
Layout();
Thaw();
@ -1044,7 +1059,7 @@ void MainFrame::init_menubar()
[this](wxCommandEvent&) { if (m_plater) m_plater->add_model(true); }, "import_plater", nullptr,
[this](){return m_plater != nullptr; }, this);
append_menu_item(import_menu, wxID_ANY, _L("Import SL1 archive") + dots, _L("Load an SL1 output archive"),
append_menu_item(import_menu, wxID_ANY, _L("Import SL1 archive") + dots, _L("Load an SL1 archive"),
[this](wxCommandEvent&) { if (m_plater) m_plater->import_sl1_archive(); }, "import_plater", nullptr,
[this](){return m_plater != nullptr; }, this);
@ -1202,7 +1217,7 @@ void MainFrame::init_menubar()
editMenu->AppendSeparator();
append_menu_item(editMenu, wxID_ANY, _L("Searc&h") + "\tCtrl+F",
_L("Find option"), [this](wxCommandEvent&) { m_plater->search(/*m_tabpanel->GetCurrentPage() == */m_plater->IsShown()); },
_L("Search in settings"), [this](wxCommandEvent&) { m_plater->search(/*m_tabpanel->GetCurrentPage() == */m_plater->IsShown()); },
"search", nullptr, []() {return true; }, this);
}

View file

@ -100,6 +100,165 @@ void Mouse3DController::State::append_button(unsigned int id, size_t /* input_qu
}
#ifdef WIN32
#if ENABLE_CTRL_M_ON_WINDOWS
static std::string format_device_string(int vid, int pid)
{
std::string ret;
switch (vid)
{
case 0x046d: { ret = "LOGITECH"; break; }
case 0x256F: { ret = "3DCONNECTION"; break; }
default: { ret = "UNKNOWN"; break; }
}
ret += "::";
switch (pid)
{
case 0xc603: { ret += "spacemouse plus XT"; break; }
case 0xc605: { ret += "cadman"; break; }
case 0xc606: { ret += "spacemouse classic"; break; }
case 0xc621: { ret += "spaceball 5000"; break; }
case 0xc623: { ret += "space traveller"; break; }
case 0xc625: { ret += "space pilot"; break; }
case 0xc626: { ret += "space navigator"; break; }
case 0xc627: { ret += "space explorer"; break; }
case 0xc628: { ret += "space navigator for notebooks"; break; }
case 0xc629: { ret += "space pilot pro"; break; }
case 0xc62b: { ret += "space mouse pro"; break; }
case 0xc62e: { ret += "spacemouse wireless (USB cable)"; break; }
case 0xc62f: { ret += "spacemouse wireless receiver"; break; }
case 0xc631: { ret += "spacemouse pro wireless"; break; }
case 0xc632: { ret += "spacemouse pro wireless receiver"; break; }
case 0xc633: { ret += "spacemouse enterprise"; break; }
case 0xc635: { ret += "spacemouse compact"; break; }
case 0xc636: { ret += "spacemouse module"; break; }
case 0xc640: { ret += "nulooq"; break; }
case 0xc652: { ret += "3Dconnexion universal receiver"; break; }
default: { ret += "UNKNOWN"; break; }
}
return ret;
}
static std::string detect_attached_device()
{
std::string ret;
// Initialize the hidapi library
int res = hid_init();
if (res != 0)
BOOST_LOG_TRIVIAL(error) << "Unable to initialize hidapi library";
else {
// Enumerates devices
hid_device_info* devices = hid_enumerate(0, 0);
if (devices == nullptr)
BOOST_LOG_TRIVIAL(trace) << "detect_attached_device() - no HID device enumerated.";
else {
// Searches for 1st connected 3Dconnexion device
struct DeviceData
{
unsigned short usage_page{ 0 };
unsigned short usage{ 0 };
DeviceData(unsigned short usage_page, unsigned short usage)
: usage_page(usage_page), usage(usage)
{}
// https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
// Usage page 1 - Generic Desktop Controls
// Usage page 1, usage 8 - Multi-axis Controller
bool has_valid_usage() const { return usage_page == 1 && usage == 8; }
};
// When using 3Dconnexion universal receiver, multiple devices are detected sharing the same vendor_id and product_id.
// To choose from them the right one we use: usage_page == 1 and usage == 8
// When only a single device is detected, as for wired connections, vendor_id and product_id are enough
// First we count all the valid devices from the enumerated list,
hid_device_info* current = devices;
typedef std::pair<unsigned short, unsigned short> DeviceIds;
typedef std::vector<DeviceData> DeviceDataList;
typedef std::map<DeviceIds, DeviceDataList> DetectedDevices;
DetectedDevices detected_devices;
while (current != nullptr) {
unsigned short vendor_id = 0;
unsigned short product_id = 0;
for (size_t i = 0; i < _3DCONNEXION_VENDORS.size(); ++i) {
if (_3DCONNEXION_VENDORS[i] == current->vendor_id) {
vendor_id = current->vendor_id;
break;
}
}
if (vendor_id != 0) {
for (size_t i = 0; i < _3DCONNEXION_DEVICES.size(); ++i) {
if (_3DCONNEXION_DEVICES[i] == current->product_id) {
product_id = current->product_id;
DeviceIds detected_device(vendor_id, product_id);
DetectedDevices::iterator it = detected_devices.find(detected_device);
if (it == detected_devices.end())
it = detected_devices.insert(DetectedDevices::value_type(detected_device, DeviceDataList())).first;
it->second.emplace_back(current->usage_page, current->usage);
}
}
}
current = current->next;
}
// Free enumerated devices
hid_free_enumeration(devices);
unsigned short vendor_id = 0;
unsigned short product_id = 0;
if (!detected_devices.empty()) {
// Then we'll decide the choosing logic to apply in dependence of the device count and operating system
for (const DetectedDevices::value_type& device : detected_devices) {
if (device.second.size() == 1) {
if (device.second.front().has_valid_usage()) {
vendor_id = device.first.first;
product_id = device.first.second;
break;
}
}
else {
bool found = false;
for (const DeviceData& data : device.second) {
if (data.has_valid_usage()) {
vendor_id = device.first.first;
product_id = device.first.second;
found = true;
break;
}
}
if (found)
break;
}
}
}
if (vendor_id != 0 && product_id != 0) {
ret = format_device_string(static_cast<int>(vendor_id), static_cast<int>(product_id));
BOOST_LOG_TRIVIAL(trace) << "Detected device: " << std::hex << vendor_id << std::dec << "::" << std::hex << product_id << std::dec << " " << ret;
}
else
BOOST_LOG_TRIVIAL(trace) << "No 3DConnexion device detected";
}
// Finalize the hidapi library
hid_exit();
}
return ret;
}
#endif // ENABLE_CTRL_M_ON_WINDOWS
// Called by Win32 HID enumeration callback.
void Mouse3DController::device_attached(const std::string &device)
{
@ -116,6 +275,13 @@ void Mouse3DController::device_attached(const std::string &device)
m_wakeup = true;
m_stop_condition.notify_all();
#if ENABLE_CTRL_M_ON_WINDOWS
m_device_str = format_device_string(vid, pid);
if (auto it_params = m_params_by_device.find(m_device_str); it_params != m_params_by_device.end()) {
tbb::mutex::scoped_lock lock(m_params_ui_mutex);
m_params = m_params_ui = it_params->second;
}
else
m_params_by_device[format_device_string(vid, pid)] = Params();
m_connected = true;
#endif // ENABLE_CTRL_M_ON_WINDOWS
}
@ -125,6 +291,15 @@ void Mouse3DController::device_attached(const std::string &device)
#if ENABLE_CTRL_M_ON_WINDOWS
void Mouse3DController::device_detached(const std::string& device)
{
int vid = 0;
int pid = 0;
if (sscanf(device.c_str(), "\\\\?\\HID#VID_%x&PID_%x&", &vid, &pid) == 2) {
if (std::find(_3DCONNEXION_VENDORS.begin(), _3DCONNEXION_VENDORS.end(), vid) != _3DCONNEXION_VENDORS.end()) {
tbb::mutex::scoped_lock lock(m_params_ui_mutex);
m_params_by_device[format_device_string(vid, pid)] = m_params_ui;
}
}
m_device_str = "";
m_connected = false;
}
#endif // ENABLE_CTRL_M_ON_WINDOWS
@ -222,6 +397,7 @@ void Mouse3DController::save_config(AppConfig &appconfig) const
{
// We do not synchronize m_params_by_device with the background thread explicitely
// as there should be a full memory barrier executed once the background thread is stopped.
for (const std::pair<std::string, Params> &key_value_pair : m_params_by_device) {
const std::string &device_name = key_value_pair.first;
const Params &params = key_value_pair.second;
@ -239,6 +415,19 @@ bool Mouse3DController::apply(Camera& camera)
m_show_settings_dialog = false;
m_settings_dialog_closed_by_user = false;
}
#if ENABLE_CTRL_M_ON_WINDOWS
#ifdef _WIN32
{
tbb::mutex::scoped_lock lock(m_params_ui_mutex);
if (m_params_ui_changed) {
m_params = m_params_ui;
m_params_ui_changed = false;
}
}
#endif // _WIN32
#endif // ENABLE_CTRL_M_ON_WINDOWS
return m_state.apply(m_params, camera);
}
@ -376,7 +565,7 @@ void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
imgui.end();
if (params_changed) {
// Synchronize front end parameters to back end.
// Synchronize front end parameters to back end.
tbb::mutex::scoped_lock lock(m_params_ui_mutex);
auto pthis = const_cast<Mouse3DController*>(this);
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
@ -473,6 +662,17 @@ bool Mouse3DController::handle_input(const DataPacketAxis& packet)
// Initialize the application.
void Mouse3DController::init()
{
#if ENABLE_CTRL_M_ON_WINDOWS
#ifdef _WIN32
m_device_str = detect_attached_device();
if (!m_device_str.empty()) {
m_connected = true;
if (auto it_params = m_params_by_device.find(m_device_str); it_params != m_params_by_device.end())
m_params = m_params_ui = it_params->second;
}
#endif // _WIN32
#endif // ENABLE_CTRL_M_ON_WINDOWS
assert(! m_thread.joinable());
if (! m_thread.joinable()) {
m_stop = false;
@ -498,6 +698,13 @@ void Mouse3DController::shutdown()
m_thread.join();
m_stop = false;
}
#if ENABLE_CTRL_M_ON_WINDOWS
#ifdef WIN32
if (!m_device_str.empty())
m_params_by_device[m_device_str] = m_params_ui;
#endif // WIN32
#endif // ENABLE_CTRL_M_ON_WINDOWS
}
// Main routine of the worker thread.
@ -531,7 +738,7 @@ void Mouse3DController::run()
if (m_stop)
break;
if (m_params_ui_changed) {
m_params = m_params_ui;
m_params = m_params_ui;
m_params_ui_changed = false;
}
}
@ -571,8 +778,7 @@ bool Mouse3DController::connect_device()
// Enumerates devices
hid_device_info* devices = hid_enumerate(0, 0);
if (devices == nullptr)
{
if (devices == nullptr) {
BOOST_LOG_TRIVIAL(trace) << "Mouse3DController::connect_device() - no HID device enumerated.";
return false;
}
@ -605,8 +811,7 @@ bool Mouse3DController::connect_device()
hid_device_info* cur = devices;
std::cout << std::endl << "======================================================================================================================================" << std::endl;
std::cout << "Detected devices:" << std::endl;
while (cur != nullptr)
{
while (cur != nullptr) {
std::cout << "\"";
std::wcout << ((cur->manufacturer_string != nullptr) ? cur->manufacturer_string : L"Unknown");
std::cout << "/";
@ -636,26 +841,20 @@ bool Mouse3DController::connect_device()
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
std::cout << std::endl << "Detected 3D connexion devices:" << std::endl;
#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
while (current != nullptr)
{
while (current != nullptr) {
unsigned short vendor_id = 0;
unsigned short product_id = 0;
for (size_t i = 0; i < _3DCONNEXION_VENDORS.size(); ++i)
{
if (_3DCONNEXION_VENDORS[i] == current->vendor_id)
{
for (size_t i = 0; i < _3DCONNEXION_VENDORS.size(); ++i) {
if (_3DCONNEXION_VENDORS[i] == current->vendor_id) {
vendor_id = current->vendor_id;
break;
}
}
if (vendor_id != 0)
{
for (size_t i = 0; i < _3DCONNEXION_DEVICES.size(); ++i)
{
if (_3DCONNEXION_DEVICES[i] == current->product_id)
{
if (vendor_id != 0) {
for (size_t i = 0; i < _3DCONNEXION_DEVICES.size(); ++i) {
if (_3DCONNEXION_DEVICES[i] == current->product_id) {
product_id = current->product_id;
DeviceIds detected_device(vendor_id, product_id);
DetectedDevices::iterator it = detected_devices.find(detected_device);
@ -692,40 +891,33 @@ bool Mouse3DController::connect_device()
// Then we'll decide the choosing logic to apply in dependence of the device count and operating system
for (const DetectedDevices::value_type& device : detected_devices)
{
if (device.second.size() == 1)
{
for (const DetectedDevices::value_type& device : detected_devices) {
if (device.second.size() == 1) {
#if defined(__linux__)
hid_device* test_device = hid_open(device.first.first, device.first.second, nullptr);
if (test_device != nullptr)
{
if (test_device != nullptr) {
hid_close(test_device);
#else
if (device.second.front().has_valid_usage())
{
if (device.second.front().has_valid_usage()) {
#endif // __linux__
vendor_id = device.first.first;
product_id = device.first.second;
break;
}
}
else
{
else {
bool found = false;
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
std::cout << std::endl;
#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
for (const DeviceData& data : device.second)
{
for (const DeviceData& data : device.second) {
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
std::cout << "Test device: " << std::hex << device.first.first << std::dec << "/" << std::hex << device.first.second << std::dec << " \"" << data.path << "\"";
#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
#ifdef __linux__
hid_device* test_device = hid_open_path(data.path.c_str());
if (test_device != nullptr)
{
if (test_device != nullptr) {
path = data.path;
vendor_id = device.first.first;
product_id = device.first.second;
@ -737,8 +929,7 @@ bool Mouse3DController::connect_device()
break;
}
#else // !__linux__
if (data.has_valid_usage())
{
if (data.has_valid_usage()) {
path = data.path;
vendor_id = device.first.first;
product_id = device.first.second;
@ -760,10 +951,8 @@ bool Mouse3DController::connect_device()
}
}
if (path.empty())
{
if ((vendor_id != 0) && (product_id != 0))
{
if (path.empty()) {
if ((vendor_id != 0) && (product_id != 0)) {
// Open the 3Dconnexion device using vendor_id and product_id
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
std::cout << std::endl << "Opening device: " << std::hex << vendor_id << std::dec << "/" << std::hex << product_id << std::dec << " using hid_open()" << std::endl;
@ -773,8 +962,7 @@ bool Mouse3DController::connect_device()
else
return false;
}
else
{
else {
// Open the 3Dconnexion device using the device path
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
std::cout << std::endl << "Opening device: " << std::hex << vendor_id << std::dec << "/" << std::hex << product_id << std::dec << "\"" << path << "\" using hid_open_path()" << std::endl;
@ -782,8 +970,7 @@ bool Mouse3DController::connect_device()
m_device = hid_open_path(path.c_str());
}
if (m_device != nullptr)
{
if (m_device != nullptr) {
wchar_t buffer[1024];
hid_get_manufacturer_string(m_device, buffer, 1024);
m_device_str = boost::nowide::narrow(buffer);
@ -811,8 +998,7 @@ bool Mouse3DController::connect_device()
}
}
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
else
{
else {
std::cout << std::endl << "Unable to connect to device:" << std::endl;
std::cout << "Manufacturer/product: " << m_device_str << std::endl;
std::cout << "Manufacturer id.....: " << vendor_id << " (" << std::hex << vendor_id << std::dec << ")" << std::endl;

View file

@ -33,12 +33,12 @@ class Mouse3DController
struct Params
{
static constexpr double DefaultTranslationScale = 2.5;
static constexpr double MaxTranslationDeadzone = 0.0;
static constexpr double DefaultTranslationDeadzone = 0.5 * MaxTranslationDeadzone;
static constexpr float DefaultRotationScale = 1.0f;
static constexpr float MaxRotationDeadzone = 0.0f;
static constexpr float DefaultRotationDeadzone = 0.5f * MaxRotationDeadzone;
static constexpr double DefaultZoomScale = 0.1;
static constexpr double MaxTranslationDeadzone = 0.2;
static constexpr double DefaultTranslationDeadzone = 0.0;
static constexpr float DefaultRotationScale = 1.0f;
static constexpr float MaxRotationDeadzone = 0.2f;
static constexpr float DefaultRotationDeadzone = 0.0f;
static constexpr double DefaultZoomScale = 0.1;
template <typename Number>
struct CustomParameters

View file

@ -1,6 +1,7 @@
#include "NotificationManager.hpp"
#include "GUI_App.hpp"
#include "GUI.hpp"
#include "Plater.hpp"
#include "GLCanvas3D.hpp"
#include "ImGuiWrapper.hpp"
@ -26,6 +27,17 @@ wxDEFINE_EVENT(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, ExportGcodeNotificationClic
wxDEFINE_EVENT(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, PresetUpdateAvailableClickedEvent);
namespace Notifications_Internal{
ImFont* add_default_font(float pixel_size)
{
ImGuiIO& io = ImGui::GetIO();
ImFontConfig config;
config.SizePixels = pixel_size;
config.OversampleH = config.OversampleV = 1;
config.PixelSnapH = true;
ImFont* font = io.Fonts->AddFontDefault(&config);
return font;
}
static inline void push_style_color(ImGuiCol idx, const ImVec4& col, bool fading_out, float current_fade_opacity)
{
if (fading_out)
@ -33,6 +45,56 @@ namespace Notifications_Internal{
else
ImGui::PushStyleColor(idx, col);
}
void open_folder(const std::string& path)
{
// Code taken from desktop_open_datadir_folder()
// Execute command to open a file explorer, platform dependent.
// FIXME: The const_casts aren't needed in wxWidgets 3.1, remove them when we upgrade.
#ifdef _WIN32
const wxString widepath = from_u8(path);
const wchar_t* argv[] = { L"explorer", widepath.GetData(), nullptr };
::wxExecute(const_cast<wchar_t**>(argv), wxEXEC_ASYNC, nullptr);
#elif __APPLE__
const char* argv[] = { "open", path.data(), nullptr };
::wxExecute(const_cast<char**>(argv), wxEXEC_ASYNC, nullptr);
#else
const char* argv[] = { "xdg-open", path.data(), nullptr };
// Check if we're running in an AppImage container, if so, we need to remove AppImage's env vars,
// because they may mess up the environment expected by the file manager.
// Mostly this is about LD_LIBRARY_PATH, but we remove a few more too for good measure.
if (wxGetEnv("APPIMAGE", nullptr)) {
// We're running from AppImage
wxEnvVariableHashMap env_vars;
wxGetEnvMap(&env_vars);
env_vars.erase("APPIMAGE");
env_vars.erase("APPDIR");
env_vars.erase("LD_LIBRARY_PATH");
env_vars.erase("LD_PRELOAD");
env_vars.erase("UNION_PRELOAD");
wxExecuteEnv exec_env;
exec_env.env = std::move(env_vars);
wxString owd;
if (wxGetEnv("OWD", &owd)) {
// This is the original work directory from which the AppImage image was run,
// set it as CWD for the child process:
exec_env.cwd = std::move(owd);
}
::wxExecute(const_cast<char**>(argv), wxEXEC_ASYNC, nullptr, &exec_env);
}
else {
// Looks like we're NOT running from AppImage, we'll make no changes to the environment.
::wxExecute(const_cast<char**>(argv), wxEXEC_ASYNC, nullptr, nullptr);
}
#endif
}
}
#if 1
@ -183,6 +245,7 @@ NotificationManager::PopNotification::RenderResult NotificationManager::PopNotif
render_left_sign(imgui);
render_text(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y);
render_close_button(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y);
m_minimize_b_visible = false;
if (m_multiline && m_lines_count > 3)
render_minimize_button(imgui, win_pos.x, win_pos.y);
} else {
@ -205,12 +268,8 @@ NotificationManager::PopNotification::RenderResult NotificationManager::PopNotif
ImGui::PopStyleColor();
return ret_val;
}
void NotificationManager::PopNotification::init()
void NotificationManager::PopNotification::count_spaces()
{
std::string text = m_text1 + " " + m_hypertext;
int last_end = 0;
m_lines_count = 0;
//determine line width
m_line_height = ImGui::CalcTextSize("A").y;
@ -221,8 +280,16 @@ void NotificationManager::PopNotification::init()
float picture_width = ImGui::CalcTextSize(text.c_str()).x;
m_left_indentation = picture_width + m_line_height / 2;
}
m_window_width_offset = m_left_indentation + m_line_height * 2;
m_window_width_offset = m_left_indentation + m_line_height * 3.f;
m_window_width = m_line_height * 25;
}
void NotificationManager::PopNotification::init()
{
std::string text = m_text1 + " " + m_hypertext;
int last_end = 0;
m_lines_count = 0;
count_spaces();
// count lines
m_endlines.clear();
@ -233,10 +300,9 @@ void NotificationManager::PopNotification::init()
//next line is ended by '/n'
m_endlines.push_back(next_hard_end);
last_end = next_hard_end + 1;
}
else {
} else {
// find next suitable endline
if (ImGui::CalcTextSize(text.substr(last_end).c_str()).x >= m_window_width - 3.5f * m_line_height) {// m_window_width_offset) {
if (ImGui::CalcTextSize(text.substr(last_end).c_str()).x >= m_window_width - m_window_width_offset) {
// more than one line till end
int next_space = text.find_first_of(' ', last_end);
if (next_space > 0) {
@ -245,8 +311,19 @@ void NotificationManager::PopNotification::init()
next_space = next_space_candidate;
next_space_candidate = text.find_first_of(' ', next_space + 1);
}
m_endlines.push_back(next_space);
last_end = next_space + 1;
// when one word longer than line.
if (ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x > m_window_width - m_window_width_offset) {
float width_of_a = ImGui::CalcTextSize("a").x;
int letter_count = (int)((m_window_width - m_window_width_offset) / width_of_a);
while (last_end + letter_count < text.size() && ImGui::CalcTextSize(text.substr(last_end, letter_count).c_str()).x < m_window_width - m_window_width_offset) {
letter_count++;
}
m_endlines.push_back(last_end + letter_count);
last_end += letter_count;
} else {
m_endlines.push_back(next_space);
last_end = next_space + 1;
}
}
}
else {
@ -257,6 +334,8 @@ void NotificationManager::PopNotification::init()
}
m_lines_count++;
}
if (m_lines_count == 3)
m_multiline = true;
m_initialized = true;
}
void NotificationManager::PopNotification::set_next_window_size(ImGuiWrapper& imgui)
@ -285,7 +364,8 @@ void NotificationManager::PopNotification::render_text(ImGuiWrapper& imgui, cons
float shift_y = m_line_height;// -m_line_height / 20;
for (size_t i = 0; i < m_lines_count; i++) {
std::string line = m_text1.substr(last_end , m_endlines[i] - last_end);
last_end = m_endlines[i] + 1;
if(i < m_lines_count - 1)
last_end = m_endlines[i] + (m_text1[m_endlines[i]] == '\n' || m_text1[m_endlines[i]] == ' ' ? 1 : 0);
ImGui::SetCursorPosX(x_offset);
ImGui::SetCursorPosY(starting_y + i * shift_y);
imgui.text(line.c_str());
@ -303,7 +383,7 @@ void NotificationManager::PopNotification::render_text(ImGuiWrapper& imgui, cons
ImGui::SetCursorPosY(win_size.y / 2 - win_size.y / 6 - m_line_height / 2);
imgui.text(m_text1.substr(0, m_endlines[0]).c_str());
// line2
std::string line = m_text1.substr(m_endlines[0] + 1, m_endlines[1] - m_endlines[0] - 1);
std::string line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0), m_endlines[1] - m_endlines[0] - (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0));
if (ImGui::CalcTextSize(line.c_str()).x > m_window_width - m_window_width_offset - ImGui::CalcTextSize((".." + _u8L("More")).c_str()).x)
{
line = line.substr(0, line.length() - 6);
@ -326,7 +406,7 @@ void NotificationManager::PopNotification::render_text(ImGuiWrapper& imgui, cons
ImGui::SetCursorPosY(win_size.y / 2 - win_size.y / 6 - m_line_height / 2);
imgui.text(m_text1.substr(0, m_endlines[0]).c_str());
// line2
std::string line = m_text1.substr(m_endlines[0] + 1);
std::string line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0));
cursor_y = win_size.y / 2 + win_size.y / 6 - m_line_height / 2;
ImGui::SetCursorPosX(x_offset);
ImGui::SetCursorPosY(cursor_y);
@ -375,8 +455,7 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui,
set_next_window_size(imgui);
}
else {
on_text_click();
m_close_pending = true;
m_close_pending = on_text_click();
}
}
ImGui::PopStyleColor();
@ -407,7 +486,7 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui,
void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
ImVec2 win_size(win_size_x, win_size_y);
ImVec2 win_pos(win_pos_x, win_pos_y);
ImVec2 win_pos(win_pos_x, win_pos_y);
ImVec4 orange_color = ImGui::GetStyleColorVec4(ImGuiCol_Button);
orange_color.w = 0.8f;
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f));
@ -419,27 +498,27 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img
//button - if part if treggered
std::string button_text;
button_text = ImGui::CloseIconMarker;
button_text = ImGui::CloseNotifButton;
if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - win_size.x / 10.f, win_pos.y),
ImVec2(win_pos.x, win_pos.y + win_size.y - (m_multiline? 2 * m_line_height : 0)),
ImVec2(win_pos.x, win_pos.y + win_size.y - ( m_minimize_b_visible ? 2 * m_line_height : 0)),
true))
{
button_text = ImGui::CloseIconHoverMarker;
button_text = ImGui::CloseNotifHoverButton;
}
ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str());
ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f);
ImGui::SetCursorPosX(win_size.x - m_line_height * 2.25f);
ImGui::SetCursorPosY(win_size.y / 2 - button_size.y/2);
ImGui::SetCursorPosX(win_size.x - m_line_height * 2.75f);
ImGui::SetCursorPosY(win_size.y / 2 - button_size.y);
if (imgui.button(button_text.c_str(), button_size.x, button_size.y))
{
m_close_pending = true;
}
//invisible large button
ImGui::SetCursorPosX(win_size.x - win_size.x / 10.f);
ImGui::SetCursorPosX(win_size.x - m_line_height * 2.35f);
ImGui::SetCursorPosY(0);
if (imgui.button(" ", win_size.x / 10.f, win_size.y - (m_multiline ? 2 * m_line_height : 0)))
if (imgui.button(" ", m_line_height * 2.125, win_size.y - ( m_minimize_b_visible ? 2 * m_line_height : 0)))
{
m_close_pending = true;
}
@ -502,14 +581,12 @@ void NotificationManager::PopNotification::render_left_sign(ImGuiWrapper& imgui)
std::string text;
text = (m_data.level == NotificationLevel::ErrorNotification ? ImGui::ErrorMarker : ImGui::WarningMarker);
ImGui::SetCursorPosX(m_line_height / 3);
ImGui::SetCursorPosY(m_window_height / 2 - m_line_height / 2);
ImGui::SetCursorPosY(m_window_height / 2 - m_line_height);
imgui.text(text.c_str());
}
}
void NotificationManager::PopNotification::render_minimize_button(ImGuiWrapper& imgui, const float win_pos_x, const float win_pos_y)
{
ImVec4 orange_color = ImGui::GetStyleColorVec4(ImGuiCol_Button);
orange_color.w = 0.8f;
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f));
Notifications_Internal::push_style_color(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_fading_out, m_current_fade_opacity);
@ -519,16 +596,16 @@ void NotificationManager::PopNotification::render_minimize_button(ImGuiWrapper&
//button - if part if treggered
std::string button_text;
button_text = ImGui::MinimalizeMarker;
button_text = ImGui::MinimalizeButton;
if (ImGui::IsMouseHoveringRect(ImVec2(win_pos_x - m_window_width / 10.f, win_pos_y + m_window_height - 2 * m_line_height + 1),
ImVec2(win_pos_x, win_pos_y + m_window_height),
true))
{
button_text = ImGui::MinimalizeHoverMarker;
button_text = ImGui::MinimalizeHoverButton;
}
ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str());
ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f);
ImGui::SetCursorPosX(m_window_width - m_line_height * 2.25f);
ImGui::SetCursorPosX(m_window_width - m_line_height * 1.8f);
ImGui::SetCursorPosY(m_window_height - button_size.y - 5);
if (imgui.button(button_text.c_str(), button_size.x, button_size.y))
{
@ -540,33 +617,13 @@ void NotificationManager::PopNotification::render_minimize_button(ImGuiWrapper&
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
m_minimize_b_visible = true;
}
void NotificationManager::PopNotification::on_text_click()
bool NotificationManager::PopNotification::on_text_click()
{
switch (m_data.type) {
case NotificationType::ExportToRemovableFinished :
assert(m_evt_handler != nullptr);
if (m_evt_handler != nullptr)
wxPostEvent(m_evt_handler, EjectDriveNotificationClickedEvent(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED));
break;
case NotificationType::SlicingComplete :
//wxGetApp().plater()->export_gcode(false);
assert(m_evt_handler != nullptr);
if (m_evt_handler != nullptr)
wxPostEvent(m_evt_handler, ExportGcodeNotificationClickedEvent(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED));
break;
case NotificationType::PresetUpdateAvailable :
//wxGetApp().plater()->export_gcode(false);
assert(m_evt_handler != nullptr);
if (m_evt_handler != nullptr)
wxPostEvent(m_evt_handler, PresetUpdateAvailableClickedEvent(EVT_PRESET_UPDATE_AVAILABLE_CLICKED));
break;
case NotificationType::NewAppAvailable:
wxLaunchDefaultBrowser("https://github.com/prusa3d/PrusaSlicer/releases");
break;
default:
break;
}
if(m_data.callback != nullptr)
return m_data.callback(m_evt_handler);
return false;
}
void NotificationManager::PopNotification::update(const NotificationData& n)
{
@ -633,6 +690,160 @@ void NotificationManager::SlicingCompleteLargeNotification::set_large(bool l)
m_hypertext = l ? _u8L("Export G-Code.") : std::string();
m_hidden = !l;
}
//---------------ExportFinishedNotification-----------
void NotificationManager::ExportFinishedNotification::count_spaces()
{
//determine line width
m_line_height = ImGui::CalcTextSize("A").y;
m_left_indentation = m_line_height;
if (m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification) {
std::string text;
text = (m_data.level == NotificationLevel::ErrorNotification ? ImGui::ErrorMarker : ImGui::WarningMarker);
float picture_width = ImGui::CalcTextSize(text.c_str()).x;
m_left_indentation = picture_width + m_line_height / 2;
}
//TODO count this properly
m_window_width_offset = m_left_indentation + m_line_height * (m_to_removable ? 6.f : 3.f);
m_window_width = m_line_height * 25;
}
void NotificationManager::ExportFinishedNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
ImVec2 win_size(win_size_x, win_size_y);
ImVec2 win_pos(win_pos_x, win_pos_y);
float x_offset = m_left_indentation;
std::string fulltext = m_text1 + m_hypertext; //+ m_text2;
ImVec2 text_size = ImGui::CalcTextSize(fulltext.c_str());
// Lines are always at least two and m_multiline is always true for ExportFinishedNotification.
// First line has "Export Finished" text and than hyper text open folder.
// Following lines are path to gcode.
int last_end = 0;
float starting_y = m_line_height / 2;//10;
float shift_y = m_line_height;// -m_line_height / 20;
for (size_t i = 0; i < m_lines_count; i++) {
std::string line = m_text1.substr(last_end, m_endlines[i] - last_end);
if (i < m_lines_count - 1)
last_end = m_endlines[i] + (m_text1[m_endlines[i]] == '\n' || m_text1[m_endlines[i]] == ' ' ? 1 : 0);
ImGui::SetCursorPosX(x_offset);
ImGui::SetCursorPosY(starting_y + i * shift_y);
imgui.text(line.c_str());
//hyperlink text
if ( i == 0 ) {
render_hypertext(imgui, x_offset + ImGui::CalcTextSize(m_text1.substr(0, last_end).c_str()).x + ImGui::CalcTextSize(" ").x, starting_y, _u8L("Open Folder."));
}
}
}
void NotificationManager::ExportFinishedNotification::render_close_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
PopNotification::render_close_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
if(m_to_removable)
render_eject_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
}
void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
ImVec2 win_size(win_size_x, win_size_y);
ImVec2 win_pos(win_pos_x, win_pos_y);
ImVec4 orange_color = ImGui::GetStyleColorVec4(ImGuiCol_Button);
orange_color.w = 0.8f;
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f));
Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_fading_out, m_current_fade_opacity);
Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_fading_out, m_current_fade_opacity);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f));
std::string button_text;
button_text = ImGui::EjectButton;
if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - m_line_height * 5.f, win_pos.y),
ImVec2(win_pos.x - m_line_height * 2.5f, win_pos.y + win_size.y),
true))
{
button_text = ImGui::EjectHoverButton;
// tooltip
long time_now = wxGetLocalTime();
if (m_hover_time > 0 && m_hover_time < time_now) {
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND);
ImGui::BeginTooltip();
imgui.text(_u8L("Eject drive"));
ImGui::EndTooltip();
ImGui::PopStyleColor();
}
if (m_hover_time == 0)
m_hover_time = time_now;
} else
m_hover_time = 0;
ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str());
ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f);
ImGui::SetCursorPosX(win_size.x - m_line_height * 5.0f);
ImGui::SetCursorPosY(win_size.y / 2 - button_size.y);
if (imgui.button(button_text.c_str(), button_size.x, button_size.y))
{
assert(m_evt_handler != nullptr);
if (m_evt_handler != nullptr)
wxPostEvent(m_evt_handler, EjectDriveNotificationClickedEvent(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED));
m_close_pending = true;
}
//invisible large button
ImGui::SetCursorPosX(win_size.x - m_line_height * 4.625f);
ImGui::SetCursorPosY(0);
if (imgui.button(" ", m_line_height * 2.f, win_size.y))
{
assert(m_evt_handler != nullptr);
if (m_evt_handler != nullptr)
wxPostEvent(m_evt_handler, EjectDriveNotificationClickedEvent(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED));
m_close_pending = true;
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
}
bool NotificationManager::ExportFinishedNotification::on_text_click()
{
Notifications_Internal::open_folder(m_export_dir_path);
return false;
}
//------ProgressBar----------------
void NotificationManager::ProgressBarNotification::init()
{
PopNotification::init();
m_lines_count++;
m_endlines.push_back(m_endlines.back());
}
void NotificationManager::ProgressBarNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
PopNotification::render_text(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
}
void NotificationManager::ProgressBarNotification::render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
float bar_y = win_size_y / 2 - win_size_y / 6 + m_line_height;
ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f);
float invisible_length = 0;//((float)(m_data.duration - m_remaining_time) / (float)m_data.duration * win_size_x);
//invisible_length -= win_size_x / ((float)m_data.duration * 60.f) * (60 - m_countdown_frame);
ImVec2 lineEnd = ImVec2(win_pos_x - invisible_length - m_window_width_offset, win_pos_y + win_size_y/2 + m_line_height / 2);
ImVec2 lineStart = ImVec2(win_pos_x - win_size_x + m_left_indentation, win_pos_y + win_size_y/2 + m_line_height / 2);
ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (1.0f * 255.f)), m_line_height * 0.7f);
/*
//countdown line
ImVec4 orange_color = ImGui::GetStyleColorVec4(ImGuiCol_Button);
float invisible_length = ((float)(m_data.duration - m_remaining_time) / (float)m_data.duration * win_size_x);
invisible_length -= win_size_x / ((float)m_data.duration * 60.f) * (60 - m_countdown_frame);
ImVec2 lineEnd = ImVec2(win_pos_x - invisible_length, win_pos_y + win_size_y - 5);
ImVec2 lineStart = ImVec2(win_pos_x - win_size_x, win_pos_y + win_size_y - 5);
ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (int)(orange_color.picture_width * 255.f * (m_fading_out ? m_current_fade_opacity : 1.f))), 2.f);
if (!m_paused)
m_countdown_frame++;
*/
}
//------NotificationManager--------
NotificationManager::NotificationManager(wxEvtHandler* evt_handler) :
m_evt_handler(evt_handler)
@ -750,7 +961,8 @@ void NotificationManager::push_slicing_complete_notification(GLCanvas3D& canvas,
hypertext = _u8L("Export G-Code.");
time = 0;
}
NotificationData data{ NotificationType::SlicingComplete, NotificationLevel::RegularNotification, time, _u8L("Slicing finished."), hypertext };
NotificationData data{ NotificationType::SlicingComplete, NotificationLevel::RegularNotification, time, _u8L("Slicing finished."), hypertext, [](wxEvtHandler* evnthndlr){
if (evnthndlr != nullptr) wxPostEvent(evnthndlr, ExportGcodeNotificationClickedEvent(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED)); return true; } };
push_notification_data(std::make_unique<NotificationManager::SlicingCompleteLargeNotification>(data, m_id_provider, m_evt_handler, large),
canvas, timestamp);
}
@ -789,6 +1001,32 @@ void NotificationManager::remove_slicing_warnings_of_released_objects(const std:
notification->close();
}
}
void NotificationManager::push_exporting_finished_notification(GLCanvas3D& canvas, std::string path, std::string dir_path, bool on_removable)
{
close_notification_of_type(NotificationType::ExportFinished);
NotificationData data{ NotificationType::ExportFinished, NotificationLevel::RegularNotification, 0, _u8L("Exporting finished.") +"\n"+ path };
push_notification_data(std::make_unique<NotificationManager::ExportFinishedNotification>(data, m_id_provider, m_evt_handler, on_removable, path, dir_path),
canvas, 0);
}
void NotificationManager::push_progress_bar_notification(const std::string& text, GLCanvas3D& canvas, float percentage)
{
NotificationData data{ NotificationType::ProgressBar, NotificationLevel::ProgressBarNotification, 0, text };
push_notification_data(std::make_unique<NotificationManager::ProgressBarNotification>(data, m_id_provider, m_evt_handler, 0),canvas, 0);
}
void NotificationManager::set_progress_bar_percentage(const std::string& text, float percentage, GLCanvas3D& canvas)
{
bool found = false;
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->get_type() == NotificationType::ProgressBar && notification->compare_text(text)) {
dynamic_cast<ProgressBarNotification*>(notification.get())->set_percentage(percentage);
canvas.request_extra_frame();
found = true;
}
}
if (!found) {
push_progress_bar_notification(text, canvas, percentage);
}
}
bool NotificationManager::push_notification_data(const NotificationData &notification_data, GLCanvas3D& canvas, int timestamp)
{
return push_notification_data(std::make_unique<PopNotification>(notification_data, m_id_provider, m_evt_handler), canvas, timestamp);
@ -822,7 +1060,7 @@ void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay
bool hovered = false;
sort_notifications();
// iterate thru notifications and render them / erease them
for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) {
for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) {
if ((*it)->get_finished()) {
it = m_pop_notifications.erase(it);
} else {
@ -931,5 +1169,31 @@ bool NotificationManager::has_slicing_error_notification()
});
}
void NotificationManager::new_export_began(bool on_removable)
{
close_notification_of_type(NotificationType::ExportFinished);
// If we want to hold information of ejecting removable on later export finished notifications
/*
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->get_type() == NotificationType::ExportToRemovableFinished) {
if (!on_removable) {
const NotificationData old_data = notification->get_data();
notification->update( {old_data.type, old_data.level ,old_data.duration, std::string(), old_data.hypertext} );
} else {
notification->close();
}
return;
}
}
*/
}
void NotificationManager::device_ejected()
{
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->get_type() == NotificationType::ExportFinished && dynamic_cast<ExportFinishedNotification*>(notification.get())->m_to_removable)
notification->close();
}
}
}//namespace GUI
}//namespace Slic3r

View file

@ -32,7 +32,11 @@ enum class NotificationType
SlicingComplete,
// SlicingNotPossible,
// Notification on end of export to a removable media, with hyperling to eject the external media.
ExportToRemovableFinished,
// Obsolete by ExportFinished
// ExportToRemovableFinished,
// Notification on end of export, with hyperling to see folder and eject if export was to external media.
// Own subclass.
ExportFinished,
// Works on OSX only.
//FIXME Do we want to have it on Linux and Windows? Is it possible to get the Disconnect event on Windows?
Mouse3dDisconnected,
@ -56,7 +60,9 @@ enum class NotificationType
// Object partially outside the print volume. Cannot slice.
PlaterError,
// Object fully outside the print volume, or extrusion outside the print volume. Slicing is not disabled.
PlaterWarning
PlaterWarning,
// Progress bar instead of text.
ProgressBar
};
class NotificationManager
@ -70,6 +76,8 @@ public:
RegularNotification = 1,
// Information notification without a fade-out or with a longer fade-out.
ImportantNotification,
// Important notification with progress bar, no fade-out, might appear again after closing.
ProgressBarNotification,
// Warning, no fade-out.
WarningNotification,
// Error, no fade-out.
@ -115,25 +123,36 @@ public:
// Called when the side bar changes its visibility, as the "slicing complete" notification supplements
// the "slicing info" normally shown at the side bar.
void set_slicing_complete_large(bool large);
// Exporting finished, show this information with path, button to open containing folder and if ejectable - eject button
void push_exporting_finished_notification(GLCanvas3D& canvas, std::string path, std::string dir_path, bool on_removable);
// notification with progress bar
void push_progress_bar_notification(const std::string& text, GLCanvas3D& canvas, float percentage = 0);
void set_progress_bar_percentage(const std::string& text, float percentage, GLCanvas3D& canvas);
// Close old notification ExportFinished.
void new_export_began(bool on_removable);
// finds ExportFinished notification and closes it if it was to removable device
void device_ejected();
// renders notifications in queue and deletes expired ones
void render_notifications(GLCanvas3D& canvas, float overlay_width);
// finds and closes all notifications of given type
void close_notification_of_type(const NotificationType type);
// Which view is active? Plater or G-code preview? Hide warnings in G-code preview.
void set_in_preview(bool preview);
// Move to left to avoid colision with variable layer height gizmo
// Move to left to avoid colision with variable layer height gizmo.
void set_move_from_overlay(bool move) { m_move_from_overlay = move; }
private:
// duration 0 means not disapearing
struct NotificationData {
NotificationType type;
NotificationLevel level;
NotificationType type;
NotificationLevel level;
// Fade out time
const int duration;
const std::string text1;
const std::string hypertext;
const std::string text2;
const int duration;
const std::string text1;
const std::string hypertext;
// Callback for hypertext - returns if notif shall close.
std::function<bool(wxEvtHandler*)> callback { nullptr };
const std::string text2;
};
// Cache of IDs to identify and reuse ImGUI windows.
@ -169,7 +188,7 @@ private:
void close() { m_close_pending = true; }
// data from newer notification of same type
void update(const NotificationData& n);
bool get_finished() const { return m_finished; }
bool get_finished() const { return m_finished || m_close_pending; }
// returns top after movement
float get_top() const { return m_top_y; }
//returns top in actual frame
@ -187,25 +206,29 @@ private:
protected:
// Call after every size change
void init();
// Part of init()
virtual void count_spaces();
// Calculetes correct size but not se it in imgui!
virtual void set_next_window_size(ImGuiWrapper& imgui);
virtual void render_text(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x , const float win_pos_y);
void render_close_button(ImGuiWrapper& imgui,
virtual void render_close_button(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x , const float win_pos_y);
void render_countdown(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x , const float win_pos_y);
void render_hypertext(ImGuiWrapper& imgui,
virtual void render_hypertext(ImGuiWrapper& imgui,
const float text_x, const float text_y,
const std::string text,
bool more = false);
// Left sign could be error or warning sign
void render_left_sign(ImGuiWrapper& imgui);
void render_minimize_button(ImGuiWrapper& imgui,
virtual void render_minimize_button(ImGuiWrapper& imgui,
const float win_pos_x, const float win_pos_y);
void on_text_click();
// Hypertext action, returns if close notification
virtual bool on_text_click();
const NotificationData m_data;
@ -236,7 +259,9 @@ private:
// Will go to m_finished next render
bool m_close_pending { false };
// variables to count positions correctly
// all space without text
float m_window_width_offset;
// Space on left side without text
float m_left_indentation;
// Total size of notification window - varies based on monitor
float m_window_height { 56.0f };
@ -252,6 +277,8 @@ private:
bool m_is_gray { false };
//if multiline = true, notification is showing all lines(>2)
bool m_multiline { false };
// True if minimized button is rendered, helps to decide where is area for invisible close button
bool m_minimize_b_visible { false };
int m_lines_count{ 1 };
// Target for wxWidgets events sent by clicking on the hyperlink available at some notifications.
wxEvtHandler* m_evt_handler;
@ -270,7 +297,6 @@ private:
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y)
override;
bool m_is_large;
bool m_has_print_info { false };
std::string m_print_info { std::string() };
@ -284,6 +310,57 @@ private:
int warning_step;
};
class ProgressBarNotification : public PopNotification
{
public:
ProgressBarNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, float percentage) : PopNotification(n, id_provider, evt_handler) { set_percentage(percentage); }
void set_percentage(float percent) { m_percentage = percent; if (percent >= 1.0f) m_progress_complete = true; else m_progress_complete = false; }
protected:
virtual void init();
virtual void render_text(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y);
void render_bar(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y);
bool m_progress_complete{ false };
float m_percentage;
};
class ExportFinishedNotification : public PopNotification
{
public:
ExportFinishedNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, bool to_removable,const std::string& export_path,const std::string& export_dir_path)
: PopNotification(n, id_provider, evt_handler)
, m_to_removable(to_removable)
, m_export_path(export_path)
, m_export_dir_path(export_dir_path)
{
m_multiline = true;
}
bool m_to_removable;
std::string m_export_path;
std::string m_export_dir_path;
protected:
// Reserves space on right for more buttons
virtual void count_spaces() override;
virtual void render_text(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y) override;
// Renders also button to open directory with exported path and eject removable media
virtual void render_close_button(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y) override;
void render_eject_button(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y);
virtual void render_minimize_button(ImGuiWrapper& imgui, const float win_pos_x, const float win_pos_y) override
{ m_minimize_b_visible = false; }
virtual bool on_text_click() override;
// local time of last hover for showing tooltip
long m_hover_time { 0 };
};
//pushes notification into the queue of notifications that are rendered
//can be used to create custom notification
bool push_notification_data(const NotificationData& notification_data, GLCanvas3D& canvas, int timestamp);
@ -314,12 +391,14 @@ private:
//prepared (basic) notifications
const std::vector<NotificationData> basic_notifications = {
// {NotificationType::SlicingNotPossible, NotificationLevel::RegularNotification, 10, _u8L("Slicing is not possible.")},
{NotificationType::ExportToRemovableFinished, NotificationLevel::ImportantNotification, 0, _u8L("Exporting finished."), _u8L("Eject drive.") },
// {NotificationType::ExportToRemovableFinished, NotificationLevel::ImportantNotification, 0, _u8L("Exporting finished."), _u8L("Eject drive.") },
{NotificationType::Mouse3dDisconnected, NotificationLevel::RegularNotification, 10, _u8L("3D Mouse disconnected.") },
// {NotificationType::Mouse3dConnected, NotificationLevel::RegularNotification, 5, _u8L("3D Mouse connected.") },
// {NotificationType::NewPresetsAviable, NotificationLevel::ImportantNotification, 20, _u8L("New Presets are available."), _u8L("See here.") },
{NotificationType::PresetUpdateAvailable, NotificationLevel::ImportantNotification, 20, _u8L("Configuration update is available."), _u8L("See more.")},
{NotificationType::NewAppAvailable, NotificationLevel::ImportantNotification, 20, _u8L("New version is available."), _u8L("See Releases page.")},
{NotificationType::PresetUpdateAvailable, NotificationLevel::ImportantNotification, 20, _u8L("Configuration update is available."), _u8L("See more."), [](wxEvtHandler* evnthndlr){
if (evnthndlr != nullptr) wxPostEvent(evnthndlr, PresetUpdateAvailableClickedEvent(EVT_PRESET_UPDATE_AVAILABLE_CLICKED)); return true; }},
{NotificationType::NewAppAvailable, NotificationLevel::ImportantNotification, 20, _u8L("New version is available."), _u8L("See Releases page."), [](wxEvtHandler* evnthndlr){
wxLaunchDefaultBrowser("https://github.com/prusa3d/PrusaSlicer/releases"); return true; }},
//{NotificationType::NewAppAvailable, NotificationLevel::ImportantNotification, 20, _u8L("New vesion of PrusaSlicer is available.", _u8L("Download page.") },
//{NotificationType::LoadingFailed, NotificationLevel::RegularNotification, 20, _u8L("Loading of model has Failed") },
//{NotificationType::DeviceEjected, NotificationLevel::RegularNotification, 10, _u8L("Removable device has been safely ejected")} // if we want changeble text (like here name of device), we need to do it as CustomNotification

View file

@ -114,7 +114,15 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/)
{
wxCoord v_pos = 0;
wxCoord h_pos = 0;
for (auto ctrl_line : ctrl_lines) {
auto correct_line_height = [](int& line_height, wxWindow* win)
{
int win_height = win->GetSize().GetHeight();
if (line_height < win_height)
line_height = win_height;
};
for (CtrlLine& ctrl_line : ctrl_lines) {
if (&ctrl_line.og_line == &line)
{
h_pos = m_bmp_mode_sz.GetWidth() + m_h_gap;
@ -134,6 +142,10 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/)
if (line.widget) {
h_pos += blinking_button_width;
for (auto child : line.widget_sizer->GetChildren())
if (child->IsWindow())
correct_line_height(ctrl_line.height, child->GetWindow());
break;
}
@ -144,11 +156,15 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/)
option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0)
{
h_pos += 3 * blinking_button_width;
Field* field = opt_group->get_field(option_set.front().opt_id);
correct_line_height(ctrl_line.height, field->getWindow());
break;
}
for (auto opt : option_set) {
Field* field = opt_group->get_field(opt.opt_id);
correct_line_height(ctrl_line.height, field->getWindow());
ConfigOptionDef option = opt.opt;
// add label if any
if (!option.label.empty()) {
@ -157,9 +173,9 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/)
_CTX(option.label, "Layers") : _(option.label);
label += ":";
wxPaintDC dc(this);
dc.SetFont(m_font);
h_pos += dc.GetMultiLineTextExtent(label).x + m_h_gap;
wxCoord label_w, label_h;
GetTextExtent(label, &label_w, &label_h, 0, 0, &m_font);
h_pos += label_w + 1 + m_h_gap;
}
h_pos += 3 * blinking_button_width;
@ -189,12 +205,6 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/)
void OG_CustomCtrl::OnPaint(wxPaintEvent&)
{
#ifdef _WIN32
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
#else
SetBackgroundColour(GetParent()->GetBackgroundColour());
#endif // _WIN32
// case, when custom controll is destroyed but doesn't deleted from the evet loop
if(!this->opt_group->custom_ctrl)
return;
@ -408,12 +418,6 @@ void OG_CustomCtrl::CtrlLine::msw_rescale()
wxSize label_sz = ctrl->GetTextExtent(og_line.label);
height = label_sz.y * (label_sz.GetWidth() > int(ctrl->opt_group->label_width * ctrl->m_em_unit) ? 2 : 1) + ctrl->m_v_gap;
}
if (og_line.get_options().front().opt.full_width) {
Field* field = ctrl->opt_group->get_field(og_line.get_options().front().opt_id);
if (field->getWindow())
field->getWindow()->SetSize(wxSize(3 * Field::def_width_wider() * ctrl->m_em_unit, -1));
}
correct_items_positions();
}
@ -493,7 +497,10 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos)
option_set.front().side_widget == nullptr && og_line.get_extra_widgets().size() == 0)
{
if (field && field->undo_to_sys_bitmap())
draw_act_bmps(dc, wxPoint(h_pos, v_pos), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp(), field->blink());
h_pos = draw_act_bmps(dc, wxPoint(h_pos, v_pos), field->undo_to_sys_bitmap()->bmp(), field->undo_bitmap()->bmp(), field->blink()) + ctrl->m_h_gap;
// update width for full_width fields
if (option_set.front().opt.full_width && field->getWindow())
field->getWindow()->SetSize(ctrl->GetSize().x - h_pos, -1);
return;
}
@ -611,7 +618,7 @@ wxCoord OG_CustomCtrl::CtrlLine::draw_text(wxDC& dc, wxPoint pos, const wxStr
return pos.x + width + ctrl->m_h_gap;
}
wxPoint OG_CustomCtrl::CtrlLine::draw_blinking_bmp(wxDC& dc, wxPoint pos, bool is_blinking, size_t rect_id)
wxPoint OG_CustomCtrl::CtrlLine::draw_blinking_bmp(wxDC& dc, wxPoint pos, bool is_blinking)
{
wxBitmap bmp_blinking = create_scaled_bitmap(is_blinking ? "search_blink" : "empty", ctrl);
wxCoord h_pos = pos.x;
@ -627,7 +634,7 @@ wxPoint OG_CustomCtrl::CtrlLine::draw_blinking_bmp(wxDC& dc, wxPoint pos, bool i
wxCoord OG_CustomCtrl::CtrlLine::draw_act_bmps(wxDC& dc, wxPoint pos, const wxBitmap& bmp_undo_to_sys, const wxBitmap& bmp_undo, bool is_blinking, size_t rect_id)
{
pos = draw_blinking_bmp(dc, pos, is_blinking, rect_id);
pos = draw_blinking_bmp(dc, pos, is_blinking);
wxCoord h_pos = pos.x;
wxCoord v_pos = pos.y;

View file

@ -55,7 +55,7 @@ class OG_CustomCtrl :public wxPanel
void render(wxDC& dc, wxCoord v_pos);
wxCoord draw_mode_bmp(wxDC& dc, wxCoord v_pos);
wxCoord draw_text (wxDC& dc, wxPoint pos, const wxString& text, const wxColour* color, int width, bool is_url = false);
wxPoint draw_blinking_bmp(wxDC& dc, wxPoint pos, bool is_blinking, size_t rect_id = 0);
wxPoint draw_blinking_bmp(wxDC& dc, wxPoint pos, bool is_blinking);
wxCoord draw_act_bmps(wxDC& dc, wxPoint pos, const wxBitmap& bmp_undo_to_sys, const wxBitmap& bmp_undo, bool is_blinking, size_t rect_id = 0);
bool launch_browser() const;

View file

@ -115,10 +115,15 @@ void ObjectDataViewModelNode::set_action_and_extruder_icons()
m_type & (itVolume | itLayer) ? "cog" : /*m_type & itInstance*/ "set_separate_obj";
m_action_icon = create_scaled_bitmap(m_action_icon_name); // FIXME: pass window ptr
// set extruder bitmap
set_extruder_icon();
}
void ObjectDataViewModelNode::set_extruder_icon()
{
if (m_type & itInstance)
return; // don't set colored bitmap for Instance
// set extruder bitmap
int extruder_idx = atoi(m_extruder.c_str());
if (extruder_idx > 0) --extruder_idx;
m_extruder_bmp = get_extruder_color_icon(extruder_idx);
@ -180,6 +185,8 @@ void ObjectDataViewModelNode::msw_rescale()
if (!m_opt_categories.empty())
update_settings_digest_bitmaps();
set_extruder_icon();
}
bool ObjectDataViewModelNode::SetValue(const wxVariant& variant, unsigned col)

View file

@ -209,8 +209,10 @@ public:
return true;
}
// Set action icons for node
// Set action and extruder(if any exist) icons for node
void set_action_and_extruder_icons();
// set extruder icon for node
void set_extruder_icon();
// Set printable icon for node
void set_printable_icon(PrintIndicator printable);

View file

@ -296,11 +296,7 @@ void OptionsGroup::activate_line(Line& line)
const auto& option = option_set.front();
const auto& field = build_field(option);
if (custom_ctrl) {
if (is_window_field(field) && option.opt.full_width)
field->getWindow()->SetSize(wxSize(3 * Field::def_width_wider() * wxGetApp().em_unit(), -1));
}
else {
if (!custom_ctrl) {
if (is_window_field(field))
sizer->Add(field->getWindow(), option.opt.full_width ? 1 : 0,
wxBOTTOM | wxTOP | (option.opt.full_width ? wxEXPAND : wxALIGN_CENTER_VERTICAL), (wxOSX || !staticbox) ? 0 : 2);

View file

@ -151,8 +151,8 @@ void PresetForPrinter::msw_rescale()
// PhysicalPrinterDialog
//------------------------------------------
PhysicalPrinterDialog::PhysicalPrinterDialog(wxString printer_name) :
DPIDialog(NULL, wxID_ANY, _L("Physical Printer"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), -1), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
PhysicalPrinterDialog::PhysicalPrinterDialog(wxWindow* parent, wxString printer_name) :
DPIDialog(parent, wxID_ANY, _L("Physical Printer"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), -1), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
m_printer("", wxGetApp().preset_bundle->physical_printers.default_config())
{
SetFont(wxGetApp().normal_font());
@ -169,7 +169,7 @@ PhysicalPrinterDialog::PhysicalPrinterDialog(wxString printer_name) :
new_printer = false;
}
wxStaticText* label_top = new wxStaticText(this, wxID_ANY, _L("Descriptive name for the printer device") + ":");
wxStaticText* label_top = new wxStaticText(this, wxID_ANY, _L("Descriptive name for the printer") + ":");
m_add_preset_btn = new ScalableButton(this, wxID_ANY, "add_copies", "", wxDefaultSize, wxDefaultPosition, /*wxBU_LEFT | */wxBU_EXACTFIT);
m_add_preset_btn->SetFont(wxGetApp().normal_font());
@ -257,7 +257,7 @@ void PhysicalPrinterDialog::update_printers()
printers.clear();
} catch (const HostNetworkError &err) {
printers.clear();
show_error(this, _L("Querying printers connected to a print host failed.") + "\n\n" + from_u8(err.what()));
show_error(this, _L("Connection to printers connected via the print host failed.") + "\n\n" + from_u8(err.what()));
}
Choice *choice = dynamic_cast<Choice*>(rs);
choice->set_values(printers);
@ -269,6 +269,8 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr
m_optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
if (opt_key == "host_type" || opt_key == "printhost_authorization_type")
this->update();
if (opt_key == "print_host")
this->update_printhost_buttons();
};
m_optgroup->append_single_option_line("host_type");
@ -413,6 +415,23 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr
m_optgroup->activate();
Field* printhost_field = m_optgroup->get_field("print_host");
if (printhost_field)
{
wxTextCtrl* temp = dynamic_cast<wxTextCtrl*>(printhost_field->getWindow());
if (temp)
temp->Bind(wxEVT_TEXT, ([this, printhost_field, temp](wxEvent& e)
{
#ifndef __WXGTK__
e.Skip();
temp->GetToolTip()->Enable(true);
#endif // __WXGTK__
TextCtrl* field = dynamic_cast<TextCtrl*>(printhost_field);
if (field)
field->propagate_value();
}), temp->GetId());
}
// Always fill in the "printhost_port" combo box from the config and select it.
{
Choice* choice = dynamic_cast<Choice*>(m_optgroup->get_field("printhost_port"));
@ -423,6 +442,13 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr
update();
}
void PhysicalPrinterDialog::update_printhost_buttons()
{
std::unique_ptr<PrintHost> host(PrintHost::get_print_host(m_config));
m_printhost_test_btn->Enable(!m_config->opt_string("print_host").empty() && host->can_test());
m_printhost_browse_btn->Enable(host->has_auto_discovery());
}
void PhysicalPrinterDialog::update()
{
m_optgroup->reload_config();
@ -455,9 +481,7 @@ void PhysicalPrinterDialog::update()
m_optgroup->show_field("printhost_port", supports_multiple_printers);
m_printhost_port_browse_btn->Show(supports_multiple_printers);
std::unique_ptr<PrintHost> host(PrintHost::get_print_host(m_config));
m_printhost_test_btn->Enable(!m_config->opt_string("print_host").empty() && host->can_test());
m_printhost_browse_btn->Enable(host->has_auto_discovery());
update_printhost_buttons();
this->SetSize(this->GetBestSize());
this->Layout();
@ -552,10 +576,10 @@ void PhysicalPrinterDialog::OnOK(wxEvent& event)
repeatable_presets += " " + from_u8(preset_name) + "\n";
repeatable_presets += "\n";
wxString msg_text = from_u8((boost::format(_u8L("Next printer preset(s) is(are) duplicated:%1%"
"Should I add it(they) just once for the printer \"%2%\" and close the Editing Dialog?")) % repeatable_presets % printer_name).str());
wxMessageDialog dialog(nullptr, msg_text, _L("Warning"), wxICON_WARNING | wxYES | wxNO);
if (dialog.ShowModal() == wxID_NO)
wxString msg_text = from_u8((boost::format(_u8L("Following printer preset(s) is duplicated:%1%"
"The above preset for printer \"%2%\" will be used just once.")) % repeatable_presets % printer_name).str());
wxMessageDialog dialog(nullptr, msg_text, _L("Warning"), wxICON_WARNING | wxOK | wxCANCEL);
if (dialog.ShowModal() == wxID_CANCEL)
return;
}
@ -598,7 +622,7 @@ void PhysicalPrinterDialog::AddPreset(wxEvent& event)
void PhysicalPrinterDialog::DeletePreset(PresetForPrinter* preset_for_printer)
{
if (m_presets.size() == 1) {
wxString msg_text = _L("It's not possible to delete last related preset for the printer.");
wxString msg_text = _L("It's not possible to delete the last related preset for the printer.");
wxMessageDialog dialog(nullptr, msg_text, _L("Infornation"), wxICON_INFORMATION | wxOK);
dialog.ShowModal();
return;

View file

@ -82,10 +82,11 @@ class PhysicalPrinterDialog : public DPIDialog
void AddPreset(wxEvent& event);
public:
PhysicalPrinterDialog(wxString printer_name);
PhysicalPrinterDialog(wxWindow* parent, wxString printer_name);
~PhysicalPrinterDialog();
void update();
void update_printhost_buttons();
void update_printers();
wxString get_printer_name();
void update_full_printer_names();

View file

@ -32,11 +32,6 @@
#include "libslic3r/Format/STL.hpp"
#include "libslic3r/Format/AMF.hpp"
#include "libslic3r/Format/3mf.hpp"
#if ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/GCodeProcessor.hpp"
#else
#include "libslic3r/GCode/PreviewData.hpp"
#endif // ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/ThumbnailData.hpp"
#include "libslic3r/Model.hpp"
#include "libslic3r/SLA/Hollowing.hpp"
@ -578,7 +573,7 @@ struct Sidebar::priv
wxButton *btn_export_gcode;
wxButton *btn_reslice;
ScalableButton *btn_send_gcode;
ScalableButton *btn_eject_device;
//ScalableButton *btn_eject_device;
ScalableButton* btn_export_gcode_removable; //exports to removable drives (appears only if removable drive is connected)
bool is_collapsed {false};
@ -750,13 +745,14 @@ Sidebar::Sidebar(Plater *parent)
(*btn)->Hide();
};
init_scalable_btn(&p->btn_send_gcode , "export_gcode", _L("Send to printer") + "\tCtrl+Shift+G");
init_scalable_btn(&p->btn_eject_device, "eject_sd" , _L("Remove device") + "\tCtrl+T");
init_scalable_btn(&p->btn_export_gcode_removable, "export_to_sd", _L("Export to SD card / Flash drive") + "\tCtrl+U");
init_scalable_btn(&p->btn_send_gcode , "export_gcode", _L("Send to printer ") + GUI::shortkey_ctrl_prefix() + "Shift+G");
// init_scalable_btn(&p->btn_eject_device, "eject_sd" , _L("Remove device ") + GUI::shortkey_ctrl_prefix() + "T");
init_scalable_btn(&p->btn_export_gcode_removable, "export_to_sd", _L("Export to SD card / Flash drive ") + GUI::shortkey_ctrl_prefix() + "U");
// regular buttons "Slice now" and "Export G-code"
const int scaled_height = p->btn_eject_device->GetBitmapHeight() + 4;
// const int scaled_height = p->btn_eject_device->GetBitmapHeight() + 4;
const int scaled_height = p->btn_export_gcode_removable->GetBitmapHeight() + 4;
auto init_btn = [this](wxButton **btn, wxString label, const int button_height) {
*btn = new wxButton(this, wxID_ANY, label, wxDefaultPosition,
wxSize(-1, button_height), wxBU_EXACTFIT);
@ -774,7 +770,7 @@ Sidebar::Sidebar(Plater *parent)
complect_btns_sizer->Add(p->btn_export_gcode, 1, wxEXPAND);
complect_btns_sizer->Add(p->btn_send_gcode);
complect_btns_sizer->Add(p->btn_export_gcode_removable);
complect_btns_sizer->Add(p->btn_eject_device);
// complect_btns_sizer->Add(p->btn_eject_device);
btns_sizer->Add(p->btn_reslice, 0, wxEXPAND | wxTOP, margin_5);
@ -797,7 +793,7 @@ Sidebar::Sidebar(Plater *parent)
p->plater->select_view_3D("Preview");
});
p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); });
p->btn_eject_device->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->eject_drive(); });
// p->btn_eject_device->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->eject_drive(); });
p->btn_export_gcode_removable->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->export_gcode(true); });
}
@ -909,6 +905,12 @@ void Sidebar::update_mode_sizer() const
p->mode_sizer->SetMode(m_mode);
}
void Sidebar::change_top_border_for_mode_sizer(bool increase_border)
{
p->mode_sizer->set_items_flag(increase_border ? wxTOP : 0);
p->mode_sizer->set_items_border(increase_border ? int(0.5 * wxGetApp().em_unit()) : 0);
}
void Sidebar::update_reslice_btn_tooltip() const
{
wxString tooltip = wxString("Slice") + " [" + GUI::shortkey_ctrl_prefix() + "R]";
@ -940,9 +942,9 @@ void Sidebar::msw_rescale()
p->object_info->msw_rescale();
p->btn_send_gcode->msw_rescale();
p->btn_eject_device->msw_rescale();
// p->btn_eject_device->msw_rescale();
p->btn_export_gcode_removable->msw_rescale();
const int scaled_height = p->btn_eject_device->GetBitmap().GetHeight() + 4;
const int scaled_height = p->btn_export_gcode_removable->GetBitmap().GetHeight() + 4;
p->btn_export_gcode->SetMinSize(wxSize(-1, scaled_height));
p->btn_reslice ->SetMinSize(wxSize(-1, scaled_height));
@ -965,7 +967,7 @@ void Sidebar::sys_color_changed()
// btn...->msw_rescale() updates icon on button, so use it
p->btn_send_gcode->msw_rescale();
p->btn_eject_device->msw_rescale();
// p->btn_eject_device->msw_rescale();
p->btn_export_gcode_removable->msw_rescale();
p->scrolled->Layout();
@ -1268,7 +1270,7 @@ void Sidebar::enable_buttons(bool enable)
p->btn_reslice->Enable(enable);
p->btn_export_gcode->Enable(enable);
p->btn_send_gcode->Enable(enable);
p->btn_eject_device->Enable(enable);
// p->btn_eject_device->Enable(enable);
p->btn_export_gcode_removable->Enable(enable);
}
@ -1276,8 +1278,8 @@ bool Sidebar::show_reslice(bool show) const { return p->btn_reslice->Sh
bool Sidebar::show_export(bool show) const { return p->btn_export_gcode->Show(show); }
bool Sidebar::show_send(bool show) const { return p->btn_send_gcode->Show(show); }
bool Sidebar::show_export_removable(bool show) const { return p->btn_export_gcode_removable->Show(show); }
bool Sidebar::show_eject(bool show) const { return p->btn_eject_device->Show(show); }
bool Sidebar::get_eject_shown() const { return p->btn_eject_device->IsShown(); }
//bool Sidebar::show_eject(bool show) const { return p->btn_eject_device->Show(show); }
//bool Sidebar::get_eject_shown() const { return p->btn_eject_device->IsShown(); }
bool Sidebar::is_multifilament()
{
@ -1383,6 +1385,70 @@ const std::regex PlaterDropTarget::pattern_drop(".*[.](stl|obj|amf|3mf|prusa)",
const std::regex PlaterDropTarget::pattern_gcode_drop(".*[.](gcode|g)", std::regex::icase);
#endif // ENABLE_GCODE_VIEWER
enum class LoadType : unsigned char
{
Unknown,
OpenProject,
LoadGeometry,
LoadConfig
};
class ProjectDropDialog : public DPIDialog
{
wxRadioBox* m_action{ nullptr };
public:
ProjectDropDialog(const std::string& filename);
int get_action() const { return m_action->GetSelection() + 1; }
protected:
void on_dpi_changed(const wxRect& suggested_rect) override;
};
ProjectDropDialog::ProjectDropDialog(const std::string& filename)
: DPIDialog((wxWindow*)wxGetApp().mainframe, wxID_ANY,
from_u8((boost::format(_utf8(L("%s - Drop project file"))) % SLIC3R_APP_NAME).str()), wxDefaultPosition,
wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
{
SetFont(wxGetApp().normal_font());
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
const wxString choices[] = { _L("Open as project"),
_L("Import geometry only"),
_L("Import config only") };
main_sizer->Add(new wxStaticText(this, wxID_ANY,
_L("Select an action to apply to the file") + ": " + from_u8(filename)), 0, wxEXPAND | wxALL, 10);
m_action = new wxRadioBox(this, wxID_ANY, _L("Action"), wxDefaultPosition, wxDefaultSize,
WXSIZEOF(choices), choices, 0, wxRA_SPECIFY_ROWS);
int action = std::clamp(std::stoi(wxGetApp().app_config->get("drop_project_action")),
static_cast<int>(LoadType::OpenProject), static_cast<int>(LoadType::LoadConfig)) - 1;
m_action->SetSelection(action);
main_sizer->Add(m_action, 1, wxEXPAND | wxRIGHT | wxLEFT, 10);
wxBoxSizer* bottom_sizer = new wxBoxSizer(wxHORIZONTAL);
wxCheckBox* check = new wxCheckBox(this, wxID_ANY, _L("Don't show again"));
check->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& evt) {
wxGetApp().app_config->set("show_drop_project_dialog", evt.IsChecked() ? "0" : "1");
});
bottom_sizer->Add(check, 0, wxEXPAND | wxRIGHT, 5);
bottom_sizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT, 5);
main_sizer->Add(bottom_sizer, 0, wxEXPAND | wxALL, 10);
SetSizer(main_sizer);
main_sizer->SetSizeHints(this);
}
void ProjectDropDialog::on_dpi_changed(const wxRect& suggested_rect)
{
const int em = em_unit();
SetMinSize(wxSize(65 * em, 30 * em));
Fit();
Refresh();
}
bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &filenames)
{
std::vector<fs::path> paths;
@ -1393,8 +1459,8 @@ bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &fi
this->MSWUpdateDragImageOnLeave();
#endif // WIN32
// gcode viewer section
if (wxGetApp().is_gcode_viewer()) {
// gcode section
for (const auto& filename : filenames) {
fs::path path(into_path(filename));
if (std::regex_match(path.string(), pattern_gcode_drop))
@ -1430,44 +1496,62 @@ bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &fi
// Likely all paths processed were gcodes, for which a G-code viewer instance has hopefully been started.
return false;
wxString snapshot_label;
assert(! paths.empty());
if (paths.size() == 1) {
snapshot_label = _L("Load File");
snapshot_label += ": ";
snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str());
} else {
snapshot_label = _L("Load Files");
snapshot_label += ": ";
snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str());
for (size_t i = 1; i < paths.size(); ++ i) {
snapshot_label += ", ";
snapshot_label += wxString::FromUTF8(paths[i].filename().string().c_str());
}
}
Plater::TakeSnapshot snapshot(plater, snapshot_label);
for (std::vector<fs::path>::const_reverse_iterator it = paths.rbegin(); it != paths.rend(); ++it) {
std::string filename = (*it).filename().string();
if (boost::algorithm::iends_with(filename, ".3mf") || boost::algorithm::iends_with(filename, ".amf")) {
LoadType load_type = LoadType::Unknown;
if (!plater->model().objects.empty()) {
if (wxGetApp().app_config->get("show_drop_project_dialog") == "1") {
ProjectDropDialog dlg(filename);
if (dlg.ShowModal() == wxID_OK) {
int choice = dlg.get_action();
load_type = static_cast<LoadType>(choice);
wxGetApp().app_config->set("drop_project_action", std::to_string(choice));
}
}
else
load_type = static_cast<LoadType>(std::clamp(std::stoi(wxGetApp().app_config->get("drop_project_action")),
static_cast<int>(LoadType::OpenProject), static_cast<int>(LoadType::LoadConfig)));
}
else
load_type = LoadType::OpenProject;
// FIXME: when drag and drop is done on a .3mf or a .amf file we should clear the plater for consistence with the open project command
// (the following call to plater->load_files() will load the config data, if present)
if (load_type == LoadType::Unknown)
return false;
std::vector<size_t> res = plater->load_files(paths);
// because right now the plater is not cleared, we set the project file (from the latest imported .3mf or .amf file)
// only if not set yet
// if res is empty no data has been loaded
if (!res.empty() && plater->get_project_filename().empty()) {
for (std::vector<fs::path>::const_reverse_iterator it = paths.rbegin(); it != paths.rend(); ++it) {
std::string filename = (*it).filename().string();
if (boost::algorithm::iends_with(filename, ".3mf") || boost::algorithm::iends_with(filename, ".amf")) {
plater->set_project_filename(from_path(*it));
switch (load_type) {
case LoadType::OpenProject: {
plater->load_project(from_path(*it));
break;
}
case LoadType::LoadGeometry: {
Plater::TakeSnapshot snapshot(plater, _L("Import Object"));
std::vector<fs::path> in_paths;
in_paths.emplace_back(*it);
plater->load_files(in_paths, true, false);
break;
}
case LoadType::LoadConfig: {
std::vector<fs::path> in_paths;
in_paths.emplace_back(*it);
plater->load_files(in_paths, false, true);
break;
}
}
break;
}
}
return true;
}
// State to manage showing after export notifications and device ejecting
enum ExportingStatus{
NOT_EXPORTING,
EXPORTING_TO_REMOVABLE,
EXPORTING_TO_LOCAL
};
// Plater / private
struct Plater::priv
{
@ -1770,8 +1854,9 @@ struct Plater::priv
// Caching last value of show_action_buttons parameter for show_action_buttons(), so that a callback which does not know this state will not override it.
mutable bool ready_to_slice = { false };
// Flag indicating that the G-code export targets a removable device, therefore the show_action_buttons() needs to be called at any case when the background processing finishes.
bool writing_to_removable_device { false };
bool show_ExportToRemovableFinished_notification { false };
ExportingStatus exporting_status { NOT_EXPORTING };
std::string last_output_path;
std::string last_output_dir_path;
bool inside_snapshot_capture() { return m_prevent_snapshots != 0; }
bool process_completed_with_error { false };
private:
@ -1969,6 +2054,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_UPDATE_BED_SHAPE, [q](SimpleEvent&) { q->set_bed_shape(); });
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_TAB, [this](SimpleEvent&) { select_next_view_3D(); });
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_COLLAPSE_SIDEBAR, [this](SimpleEvent&) { this->q->collapse_sidebar(!this->q->is_sidebar_collapsed()); });
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_JUMP_TO, [this](wxKeyEvent& evt) { preview->jump_layers_slider(evt); });
#if ENABLE_GCODE_VIEWER
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_MOVE_LAYERS_SLIDER, [this](wxKeyEvent& evt) { preview->move_layers_slider(evt); });
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_EDIT_COLOR_CHANGE, [this](wxKeyEvent& evt) { preview->edit_layers_slider(evt); });
@ -2043,9 +2129,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
});
this->q->Bind(EVT_REMOVABLE_DRIVES_CHANGED, [this, q](RemovableDrivesChangedEvent &) {
this->show_action_buttons(this->ready_to_slice);
if (!this->sidebar->get_eject_shown()) {
notification_manager->close_notification_of_type(NotificationType::ExportToRemovableFinished);
}
// Close notification ExportingFinished but only if last export was to removable
notification_manager->device_ejected();
});
// Start the background thread and register this window as a target for update events.
wxGetApp().removable_drive_manager()->init(this->q);
@ -2314,7 +2399,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
wxMessageDialog msg_dlg(q, format_wxstr(_L(
"Some object(s) in file %s looks like saved in inches.\n"
"Should I consider them as a saved in inches and convert them?"), from_path(filename)) + "\n",
_L("Saved in inches object detected"), wxICON_WARNING | wxYES | wxNO);
_L("The object appears to be saved in inches"), wxICON_WARNING | wxYES | wxNO);
if (msg_dlg.ShowModal() == wxID_YES)
convert_from_imperial_units(model);
}
@ -2912,6 +2997,7 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
const wxString invalid_str = _L("Invalid data");
for (auto btn : {ActionButtonType::abReslice, ActionButtonType::abSendGCode, ActionButtonType::abExport})
sidebar->set_btn_label(btn, invalid_str);
process_completed_with_error = true;
}
else
{
@ -3442,6 +3528,7 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
this->statusbar()->set_progress(evt.status.percent);
this->statusbar()->set_status_text(_(evt.status.text) + wxString::FromUTF8(""));
//notification_manager->set_progress_bar_percentage("Slicing progress", (float)evt.status.percent / 100.0f, *q->get_current_canvas3D());
}
if (evt.status.flags & (PrintBase::SlicingStatus::RELOAD_SCENE | PrintBase::SlicingStatus::RELOAD_SLA_SUPPORT_POINTS)) {
switch (this->printer_technology) {
@ -3493,7 +3580,6 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
void Plater::priv::on_slicing_completed(wxCommandEvent & evt)
{
notification_manager->push_slicing_complete_notification(*q->get_current_canvas3D(), evt.GetInt(), is_sidebar_collapsed());
switch (this->printer_technology) {
case ptFFF:
this->update_fff_scene();
@ -3511,9 +3597,7 @@ void Plater::priv::on_slicing_completed(wxCommandEvent & evt)
void Plater::priv::on_export_began(wxCommandEvent& evt)
{
if (show_warning_dialog)
warnings_dialog();
if (this->writing_to_removable_device)
this->show_ExportToRemovableFinished_notification = true;
warnings_dialog();
}
void Plater::priv::on_slicing_began()
{
@ -3551,7 +3635,7 @@ bool Plater::priv::warnings_dialog()
{
if (current_warnings.empty())
return true;
std::string text = _u8L("There are active warnings concerning sliced models:\n");
std::string text = _u8L("There are active warnings concerning sliced models:") + "\n";
bool empt = true;
for (auto const& it : current_warnings) {
int next_n = it.first.message.find_first_of('\n', 0);
@ -3591,10 +3675,14 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
} else
notification_manager->push_slicing_error_notification(message, *q->get_current_canvas3D());
this->statusbar()->set_status_text(from_u8(message));
const wxString invalid_str = _L("Invalid data");
for (auto btn : { ActionButtonType::abReslice, ActionButtonType::abSendGCode, ActionButtonType::abExport })
sidebar->set_btn_label(btn, invalid_str);
process_completed_with_error = true;
if (evt.invalidate_plater())
{
const wxString invalid_str = _L("Invalid data");
for (auto btn : { ActionButtonType::abReslice, ActionButtonType::abSendGCode, ActionButtonType::abExport })
sidebar->set_btn_label(btn, invalid_str);
process_completed_with_error = true;
}
}
if (evt.cancelled())
this->statusbar()->set_status_text(_L("Cancelled"));
@ -3629,13 +3717,14 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
show_action_buttons(false);
}
// If writing to removable drive was scheduled, show notification with eject button
if (this->writing_to_removable_device && this->show_ExportToRemovableFinished_notification) {
if (exporting_status == ExportingStatus::EXPORTING_TO_REMOVABLE && !this->process_completed_with_error) {
show_action_buttons(false);
notification_manager->push_notification(NotificationType::ExportToRemovableFinished, *q->get_current_canvas3D());
}
notification_manager->push_exporting_finished_notification(*q->get_current_canvas3D(), last_output_path, last_output_dir_path, true);
wxGetApp().removable_drive_manager()->set_exporting_finished(true);
}else if (exporting_status == ExportingStatus::EXPORTING_TO_LOCAL && !this->process_completed_with_error)
notification_manager->push_exporting_finished_notification(*q->get_current_canvas3D(), last_output_path, last_output_dir_path, false);
}
this->show_ExportToRemovableFinished_notification = false;
this->writing_to_removable_device = false;
exporting_status = ExportingStatus::NOT_EXPORTING;
}
void Plater::priv::on_layer_editing_toggled(bool enable)
@ -4306,8 +4395,8 @@ void Plater::priv::show_action_buttons(const bool ready_to_slice) const
if (sidebar->show_reslice(false) |
sidebar->show_export(true) |
sidebar->show_send(send_gcode_shown) |
sidebar->show_export_removable(removable_media_status.has_removable_drives) |
sidebar->show_eject(removable_media_status.has_eject))
sidebar->show_export_removable(removable_media_status.has_removable_drives))
// sidebar->show_eject(removable_media_status.has_eject))
sidebar->Layout();
}
else
@ -4318,8 +4407,8 @@ void Plater::priv::show_action_buttons(const bool ready_to_slice) const
if (sidebar->show_reslice(ready_to_slice) |
sidebar->show_export(!ready_to_slice) |
sidebar->show_send(send_gcode_shown && !ready_to_slice) |
sidebar->show_export_removable(!ready_to_slice && removable_media_status.has_removable_drives) |
sidebar->show_eject(!ready_to_slice && removable_media_status.has_eject))
sidebar->show_export_removable(!ready_to_slice && removable_media_status.has_removable_drives))
// sidebar->show_eject(!ready_to_slice && removable_media_status.has_eject))
sidebar->Layout();
}
}
@ -4727,7 +4816,7 @@ void Plater::load_gcode(const wxString& filename)
GCodeProcessor processor;
processor.enable_producers(true);
processor.enable_machine_envelope_processing(true);
processor.process_file(filename.ToUTF8().data());
processor.process_file(filename.ToUTF8().data(), false);
p->gcode_result = std::move(processor.extract_result());
// show results
@ -4958,7 +5047,7 @@ void Plater::export_gcode(bool prefer_removable)
if (p->model.objects.empty())
return;
if (p->process_completed_with_error)//here
if (p->process_completed_with_error)
return;
// If possible, remove accents from accented latin characters.
@ -5003,7 +5092,10 @@ void Plater::export_gcode(bool prefer_removable)
if (! output_path.empty()) {
bool path_on_removable_media = removable_drive_manager.set_and_verify_last_save_path(output_path.string());
p->writing_to_removable_device = path_on_removable_media;
p->notification_manager->new_export_began(path_on_removable_media);
p->exporting_status = path_on_removable_media ? ExportingStatus::EXPORTING_TO_REMOVABLE : ExportingStatus::EXPORTING_TO_LOCAL;
p->last_output_path = output_path.string();
p->last_output_dir_path = output_path.parent_path().string();
p->export_gcode(output_path, path_on_removable_media, PrintHostJob());
// Storing a path to AppConfig either as path to removable media or a path to internal media.
// is_path_on_removable_drive() is called with the "true" parameter to update its internal database as the user may have shuffled the external drives
@ -5223,6 +5315,10 @@ void Plater::export_toolpaths_to_obj() const
void Plater::reslice()
{
// There is "invalid data" button instead "slice now"
if (p->process_completed_with_error)
return;
// Stop arrange and (or) optimize rotation tasks.
this->stop_jobs();
@ -5606,31 +5702,49 @@ void Plater::on_activate()
}
// Get vector of extruder colors considering filament color, if extruder color is undefined.
#if ENABLE_GCODE_VIEWER
std::vector<std::string> Plater::get_extruder_colors_from_plater_config(const GCodeProcessor::Result* const result) const
#else
std::vector<std::string> Plater::get_extruder_colors_from_plater_config() const
#endif // ENABLE_GCODE_VIEWER
{
const Slic3r::DynamicPrintConfig* config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
std::vector<std::string> extruder_colors;
if (!config->has("extruder_colour")) // in case of a SLA print
#if ENABLE_GCODE_VIEWER
if (wxGetApp().is_gcode_viewer() && result != nullptr)
return result->extruder_colors;
else {
#endif // ENABLE_GCODE_VIEWER
const Slic3r::DynamicPrintConfig* config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
std::vector<std::string> extruder_colors;
if (!config->has("extruder_colour")) // in case of a SLA print
return extruder_colors;
extruder_colors = (config->option<ConfigOptionStrings>("extruder_colour"))->values;
if (!wxGetApp().plater())
return extruder_colors;
const std::vector<std::string>& filament_colours = (p->config->option<ConfigOptionStrings>("filament_colour"))->values;
for (size_t i = 0; i < extruder_colors.size(); ++i)
if (extruder_colors[i] == "" && i < filament_colours.size())
extruder_colors[i] = filament_colours[i];
return extruder_colors;
extruder_colors = (config->option<ConfigOptionStrings>("extruder_colour"))->values;
if (!wxGetApp().plater())
return extruder_colors;
const std::vector<std::string>& filament_colours = (p->config->option<ConfigOptionStrings>("filament_colour"))->values;
for (size_t i = 0; i < extruder_colors.size(); ++i)
if (extruder_colors[i] == "" && i < filament_colours.size())
extruder_colors[i] = filament_colours[i];
return extruder_colors;
#if ENABLE_GCODE_VIEWER
}
#endif // ENABLE_GCODE_VIEWER
}
/* Get vector of colors used for rendering of a Preview scene in "Color print" mode
* It consists of extruder colors and colors, saved in model.custom_gcode_per_print_z
*/
#if ENABLE_GCODE_VIEWER
std::vector<std::string> Plater::get_colors_for_color_print(const GCodeProcessor::Result* const result) const
{
std::vector<std::string> colors = get_extruder_colors_from_plater_config(result);
#else
std::vector<std::string> Plater::get_colors_for_color_print() const
{
std::vector<std::string> colors = get_extruder_colors_from_plater_config();
#endif // ENABLE_GCODE_VIEWER
colors.reserve(colors.size() + p->model.custom_gcode_per_print_z.gcodes.size());
for (const CustomGCode::Item& code : p->model.custom_gcode_per_print_z.gcodes)

View file

@ -11,6 +11,9 @@
#include "libslic3r/Preset.hpp"
#include "libslic3r/BoundingBox.hpp"
#if ENABLE_GCODE_VIEWER
#include "libslic3r/GCode/GCodeProcessor.hpp"
#endif // ENABLE_GCODE_VIEWER
#include "Jobs/Job.hpp"
#include "Search.hpp"
@ -72,6 +75,7 @@ public:
void update_all_preset_comboboxes();
void update_presets(Slic3r::Preset::Type preset_type);
void update_mode_sizer() const;
void change_top_border_for_mode_sizer(bool increase_border);
void update_reslice_btn_tooltip() const;
void msw_rescale();
void sys_color_changed();
@ -232,8 +236,13 @@ public:
void force_print_bed_update();
// On activating the parent window.
void on_activate();
#if ENABLE_GCODE_VIEWER
std::vector<std::string> get_extruder_colors_from_plater_config(const GCodeProcessor::Result* const result = nullptr) const;
std::vector<std::string> get_colors_for_color_print(const GCodeProcessor::Result* const result = nullptr) const;
#else
std::vector<std::string> get_extruder_colors_from_plater_config() const;
std::vector<std::string> get_colors_for_color_print() const;
#endif // ENABLE_GCODE_VIEWER
void update_object_menu();
void show_action_buttons(const bool is_ready_to_slice) const;

View file

@ -117,12 +117,19 @@ void PreferencesDialog::build()
option = Option(def, "show_incompatible_presets");
m_optgroup_general->append_single_option_line(option);
def.label = L("Single Instance");
def.label = L("Show drop project dialog");
def.type = coBool;
def.tooltip = L("When checked, whenever dragging and dropping a project file on the application, shows a dialog asking to select the action to take on the file to load.");
def.set_default_value(new ConfigOptionBool{ app_config->get("show_drop_project_dialog") == "1" });
option = Option(def, "show_drop_project_dialog");
m_optgroup_general->append_single_option_line(option);
def.label = L("Single instance mode");
def.type = coBool;
#if __APPLE__
def.tooltip = L("On OSX there is always only one instance of app running by default. However it is allowed to run multiple instances of same app from the command line. In such case this settings will allow only one instance.");
#else
def.tooltip = L("If this is enabled, when staring PrusaSlicer and another instance of same PrusaSlicer is running, that instance will be reactivated instead.");
def.tooltip = L("If this is enabled, when starting PrusaSlicer and another instance of the same PrusaSlicer is already running, that instance will be reactivated instead.");
#endif
def.set_default_value(new ConfigOptionBool{ app_config->has("single_instance") ? app_config->get("single_instance") == "1" : false });
option = Option(def, "single_instance");
@ -153,7 +160,7 @@ void PreferencesDialog::build()
def.label = L("Ask for unsaved changes when closing application");
def.type = coBool;
def.tooltip = L("Always ask for unsaved changes when closing application");
def.tooltip = L("When closing the application, always ask for unsaved changes");
def.set_default_value(new ConfigOptionBool{ app_config->get("default_action_on_close_application") == "none" });
option = Option(def, "default_action_on_close_application");
m_optgroup_general->append_single_option_line(option);
@ -235,8 +242,8 @@ void PreferencesDialog::build()
def.label = L("Sequential slider applied only to top layer");
def.type = coBool;
def.tooltip = L("If enabled, changes made using the sequential slider, in preview, apply only to gcode top layer, "
"if disabled, changes made using the sequential slider, in preview, apply to the whole gcode.");
def.tooltip = L("If enabled, changes made using the sequential slider, in preview, apply only to gcode top layer. "
"If disabled, changes made using the sequential slider, in preview, apply to the whole gcode.");
def.set_default_value(new ConfigOptionBool{ app_config->get("seq_top_layer_only") == "1" });
option = Option(def, "seq_top_layer_only");
m_optgroup_gui->append_single_option_line(option);
@ -427,8 +434,8 @@ void PreferencesDialog::create_icon_size_slider()
void PreferencesDialog::create_settings_mode_widget()
{
wxString choices[] = { _L("Old regular layout with the tab bar"),
_L("New layout without the tab bar on the plater"),
_L("Settings will be shown in the non-modal dialog") };
_L("New layout, access via settings button in the top menu"),
_L("Settings in non-modal window") };
auto app_config = get_app_config();
int selection = app_config->get("old_settings_layout_mode") == "1" ? 0 :
@ -437,7 +444,7 @@ void PreferencesDialog::create_settings_mode_widget()
wxWindow* parent = m_optgroup_gui->ctrl_parent();
m_layout_mode_box = new wxRadioBox(parent, wxID_ANY, _L("Settings layout mode"), wxDefaultPosition, wxDefaultSize, WXSIZEOF(choices), choices,
m_layout_mode_box = new wxRadioBox(parent, wxID_ANY, _L("Layout Options"), wxDefaultPosition, wxDefaultSize, WXSIZEOF(choices), choices,
3, wxRA_SPECIFY_ROWS);
m_layout_mode_box->SetFont(wxGetApp().normal_font());
m_layout_mode_box->SetSelection(selection);

View file

@ -253,14 +253,14 @@ void PresetComboBox::edit_physical_printer()
if (!m_preset_bundle->physical_printers.has_selection())
return;
PhysicalPrinterDialog dlg(this->GetString(this->GetSelection()));
PhysicalPrinterDialog dlg(this->GetParent(),this->GetString(this->GetSelection()));
if (dlg.ShowModal() == wxID_OK)
update();
}
void PresetComboBox::add_physical_printer()
{
if (PhysicalPrinterDialog(wxEmptyString).ShowModal() == wxID_OK)
if (PhysicalPrinterDialog(this->GetParent(), wxEmptyString).ShowModal() == wxID_OK)
update();
}
@ -675,7 +675,7 @@ void PlaterPresetComboBox::show_add_menu()
append_menu_item(menu, wxID_ANY, _L("Add physical printer"), "",
[this](wxCommandEvent&) {
PhysicalPrinterDialog dlg(wxEmptyString);
PhysicalPrinterDialog dlg(this->GetParent(), wxEmptyString);
if (dlg.ShowModal() == wxID_OK)
update();
}, "edit_uni", menu, []() { return true; }, wxGetApp().plater());

View file

@ -391,7 +391,6 @@ bool RemovableDriveManager::set_and_verify_last_save_path(const std::string &pat
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this->update();
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
m_last_save_path = this->get_removable_drive_from_path(path);
m_exporting_finished = false;
return ! m_last_save_path.empty();

View file

@ -130,15 +130,16 @@ void SavePresetDialog::Item::update()
if (m_valid_type == Valid && existing && m_preset_name != m_presets->get_selected_preset_name())
{
info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists.")) % m_preset_name).str());
if (!existing->is_compatible)
info_line += "\n" + _L("And selected preset is imcopatible with selected printer.");
if (existing->is_compatible)
info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists.")) % m_preset_name).str());
else
info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists and is imcopatible with selected printer.")) % m_preset_name).str());
info_line += "\n" + _L("Note: This preset will be replaced after saving");
m_valid_type = Warning;
}
if (m_valid_type == Valid && m_preset_name.empty()) {
info_line = _L("The empty name is not available.");
info_line = _L("The name cannot be empty.");
m_valid_type = NoValid;
}
@ -171,14 +172,14 @@ void SavePresetDialog::Item::accept()
// SavePresetDialog
//-----------------------------------------------
SavePresetDialog::SavePresetDialog(Preset::Type type, std::string suffix)
: DPIDialog(nullptr, wxID_ANY, _L("Save preset"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), 5 * wxGetApp().em_unit()), wxDEFAULT_DIALOG_STYLE | wxICON_WARNING | wxRESIZE_BORDER)
SavePresetDialog::SavePresetDialog(wxWindow* parent, Preset::Type type, std::string suffix)
: DPIDialog(parent, wxID_ANY, _L("Save preset"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), 5 * wxGetApp().em_unit()), wxDEFAULT_DIALOG_STYLE | wxICON_WARNING | wxRESIZE_BORDER)
{
build(std::vector<Preset::Type>{type}, suffix);
}
SavePresetDialog::SavePresetDialog(std::vector<Preset::Type> types, std::string suffix)
: DPIDialog(nullptr, wxID_ANY, _L("Save preset"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), 5 * wxGetApp().em_unit()), wxDEFAULT_DIALOG_STYLE | wxICON_WARNING | wxRESIZE_BORDER)
SavePresetDialog::SavePresetDialog(wxWindow* parent, std::vector<Preset::Type> types, std::string suffix)
: DPIDialog(parent, wxID_ANY, _L("Save preset"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), 5 * wxGetApp().em_unit()), wxDEFAULT_DIALOG_STYLE | wxICON_WARNING | wxRESIZE_BORDER)
{
build(types, suffix);
}

View file

@ -73,8 +73,8 @@ class SavePresetDialog : public DPIDialog
public:
SavePresetDialog(Preset::Type type, std::string suffix = "");
SavePresetDialog(std::vector<Preset::Type> types, std::string suffix = "");
SavePresetDialog(wxWindow* parent, Preset::Type type, std::string suffix = "");
SavePresetDialog(wxWindow* parent, std::vector<Preset::Type> types, std::string suffix = "");
~SavePresetDialog();
void AddItem(Preset::Type type, const std::string& suffix);

View file

@ -430,7 +430,7 @@ SearchDialog::SearchDialog(OptionsSearcher* searcher)
wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
SetBackgroundColour(bgr_clr);
default_string = _L("Type here to search");
default_string = _L("Enter a search term");
int border = 10;
int em = em_unit();

View file

@ -87,9 +87,9 @@ std::string get_mem_info(bool format_as_html)
SysInfoDialog::SysInfoDialog()
#if ENABLE_GCODE_VIEWER
: DPIDialog(NULL, wxID_ANY, (wxGetApp().is_editor() ? wxString(SLIC3R_APP_NAME) : wxString(GCODEVIEWER_APP_NAME)) + " - " + _L("System Information"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
: DPIDialog((wxWindow*)wxGetApp().mainframe, wxID_ANY, (wxGetApp().is_editor() ? wxString(SLIC3R_APP_NAME) : wxString(GCODEVIEWER_APP_NAME)) + " - " + _L("System Information"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
#else
: DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _L("System Information"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
: DPIDialog((wxWindow*)wxGetApp().mainframe, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _L("System Information"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
#endif // ENABLE_GCODE_VIEWER
{
wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);

View file

@ -219,7 +219,7 @@ void Tab::create_preset_tab()
"or click this button.")));
add_scaled_button(panel, &m_search_btn, "search");
m_search_btn->SetToolTip(format_wxstr(_L("Click to start a search or use %1% shortcut"), "Ctrl+F"));
m_search_btn->SetToolTip(format_wxstr(_L("Search in settings [%1%]"), "Ctrl+F"));
// Bitmaps to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
add_scaled_bitmap(this, m_bmp_value_lock , "lock_closed");
@ -1788,7 +1788,7 @@ void TabFilament::build()
// optgroup = page->new_optgroup(_(L("Temperature")) + wxString(" °C", wxConvUTF8));
optgroup = page->new_optgroup(L("Temperature"));
Line line = { L("Extruder"), "" };
Line line = { L("Nozzle"), "" };
line.append_option(optgroup->get_option("first_layer_temperature"));
line.append_option(optgroup->get_option("temperature"));
optgroup->append_line(line);
@ -2040,7 +2040,7 @@ void TabPrinter::build_print_host_upload_group(Page* page)
wxString description_line_text = _L(""
"Note: All parameters from this group are moved to the Physical Printer settings (see changelog).\n\n"
"A new Physical Printer profile is created by clicking on the \"cog\" icon right of the Printer profiles combo box, "
"by selecting the \"add or remove printers\" item in the Printer combo box. The Physical Printer profile editor opens "
"by selecting the \"Add physical printer\" item in the Printer combo box. The Physical Printer profile editor opens "
"also when clicking on the \"cog\" icon in the Printer settings tab. The Physical Printer profiles are being stored "
"into PrusaSlicer/physical_printer directory.");
@ -3339,7 +3339,7 @@ void Tab::save_preset(std::string name /*= ""*/, bool detach)
//! m_treectrl->OnSetFocus();
if (name.empty()) {
SavePresetDialog dlg(m_type, detach ? _u8L("Detached") : "");
SavePresetDialog dlg(m_parent, m_type, detach ? _u8L("Detached") : "");
if (dlg.ShowModal() != wxID_OK)
return;
name = dlg.get_name();
@ -3428,7 +3428,7 @@ void Tab::delete_preset()
std::vector<std::string> ph_printers_only = physical_printers.get_printers_with_only_preset(current_preset.name);
if (!ph_printers.empty()) {
msg += _L("Next physical printer(s) has/have selected preset") + ":";
msg += _L("The physical printer(s) below is based on the preset, you are going to delete.");
for (const std::string& printer : ph_printers)
msg += "\n \"" + from_u8(printer) + "\",";
msg.RemoveLast();
@ -3436,7 +3436,7 @@ void Tab::delete_preset()
}
if (!ph_printers_only.empty()) {
msg += _L("Next physical printer(s) has/have one and only selected preset") + ":";
msg += _L("The physical printer(s) below is based only on the preset, you are going to delete.");
for (const std::string& printer : ph_printers_only)
msg += "\n \"" + from_u8(printer) + "\",";
msg.RemoveLast();

View file

@ -522,7 +522,7 @@ void UnsavedChangesModel::Rescale()
//------------------------------------------
UnsavedChangesDialog::UnsavedChangesDialog(const wxString& header)
: DPIDialog(nullptr, wxID_ANY, _L("Closing PrusaSlicer: Unsaved Changes"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
: DPIDialog((wxWindow*)wxGetApp().mainframe , wxID_ANY, _L("PrusaSlicer is closing: Unsaved Changes"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
m_app_config_key = "default_action_on_close_application";
@ -539,7 +539,7 @@ UnsavedChangesDialog::UnsavedChangesDialog(const wxString& header)
}
UnsavedChangesDialog::UnsavedChangesDialog(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset)
: DPIDialog(nullptr, wxID_ANY, _L("Switching Presets: Unsaved Changes"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
: DPIDialog((wxWindow*)wxGetApp().mainframe, wxID_ANY, _L("Switching Presets: Unsaved Changes"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
m_app_config_key = "default_action_on_select_preset";
@ -734,10 +734,10 @@ void UnsavedChangesDialog::show_info_line(Action action, std::string preset_name
if (action == Action::Undef)
text = _L("Some fields are too long to fit. Right mouse click reveals the full text.");
else if (action == Action::Discard)
text = _L("All modified options will be reverted.");
text = _L("All settings changes will be discarded.");
else {
if (preset_name.empty())
text = action == Action::Save ? _L("Save the selected options.") : _L("Transfer the selected options to the newly selected presets.");
text = action == Action::Save ? _L("Save the selected options.") : _L("Transfer the selected settings to the newly selected preset.");
else
text = format_wxstr(
action == Action::Save ?
@ -781,7 +781,7 @@ bool UnsavedChangesDialog::save(PresetCollection* dependent_presets)
// for system/default/external presets we should take an edited name
if (preset.is_system || preset.is_default || preset.is_external) {
SavePresetDialog save_dlg(preset.type);
SavePresetDialog save_dlg(this, preset.type);
if (save_dlg.ShowModal() != wxID_OK) {
m_exit_action = Action::Discard;
return false;
@ -809,7 +809,7 @@ bool UnsavedChangesDialog::save(PresetCollection* dependent_presets)
if (!types_for_save.empty()) {
SavePresetDialog save_dlg(types_for_save);
SavePresetDialog save_dlg(this, types_for_save);
if (save_dlg.ShowModal() != wxID_OK) {
m_exit_action = Action::Discard;
return false;

View file

@ -696,6 +696,17 @@ void ModeSizer::SetMode(const int mode)
m_mode_btns[m]->SetState(int(m) == mode);
}
void ModeSizer::set_items_flag(int flag)
{
for (wxSizerItem* item : this->GetChildren())
item->SetFlag(flag);
}
void ModeSizer::set_items_border(int border)
{
for (wxSizerItem* item : this->GetChildren())
item->SetBorder(border);
}
void ModeSizer::msw_rescale()
{

View file

@ -298,6 +298,9 @@ public:
void SetMode(const /*ConfigOptionMode*/int mode);
void set_items_flag(int flag);
void set_items_border(int border);
void msw_rescale();
private:

View file

@ -203,7 +203,7 @@ bool Repetier::get_groups(wxArrayString& groups) const
groups.push_back(_utf8(L("Default")));
} else {
// Is it safe to assume that the data are utf-8 encoded?
groups.push_back(wxString::FromUTF8(v.second.data()));
groups.push_back(GUI::from_u8(v.second.data()));
}
}
}