mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-22 14:50:59 +00:00
Merge remote-tracking branch 'upstream/main' into feedback
This commit is contained in:
commit
357fcb374d
140 files changed
+2283
-1850
No files matched your search
@@ -523,6 +523,11 @@ void AppConfig::set_defaults()
|
||||
set_bool("installed_networking", false);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
if (get("window_buttons_on_left").empty())
|
||||
set_bool("window_buttons_on_left", false);
|
||||
#endif
|
||||
|
||||
// Remove legacy window positions/sizes
|
||||
erase("app", "main_frame_maximized");
|
||||
erase("app", "main_frame_pos");
|
||||
|
||||
@@ -2559,6 +2559,21 @@ void priv::create_face_types(FaceTypeMap &map,
|
||||
bool priv::clip_cut(SurfacePatch &cut, CutMesh clipper)
|
||||
{
|
||||
CutMesh& tm = cut.mesh;
|
||||
auto is_mesh_usable_for_clip = [](const CutMesh &mesh) {
|
||||
return !mesh.is_empty() &&
|
||||
mesh.number_of_vertices() >= 3 &&
|
||||
mesh.number_of_faces() > 0 &&
|
||||
mesh.is_valid(false);
|
||||
};
|
||||
|
||||
if (!is_mesh_usable_for_clip(tm) || !is_mesh_usable_for_clip(clipper))
|
||||
return false;
|
||||
|
||||
// Hard-stop pathological inputs before entering corefinement internals.
|
||||
if (CGAL::Polygon_mesh_processing::does_self_intersect(tm) ||
|
||||
CGAL::Polygon_mesh_processing::does_self_intersect(clipper))
|
||||
return false;
|
||||
|
||||
// create backup for case that there is no intersection
|
||||
CutMesh backup_copy = tm;
|
||||
|
||||
|
||||
@@ -808,8 +808,10 @@ void split_solid_surface(size_t layer_id, const SurfaceFill &fill, ExPolygons &n
|
||||
return;
|
||||
}
|
||||
|
||||
// Expand the normal infills a little bit to avoid gaps between normal and narrow infills
|
||||
normal_infill = intersection_ex(offset_ex(normal_fill_areas_ex, scaled_spacing * 0.1), fill.expolygons);
|
||||
// Expand the normal infills to avoid gaps between normal and narrow infills.
|
||||
// The inner_area was shrunk by scaled_spacing * 0.5, so we need to expand
|
||||
// by at least that amount to ensure proper coverage and avoid gaps.
|
||||
normal_infill = intersection_ex(offset_ex(normal_fill_areas_ex, scaled_spacing * 0.5), fill.expolygons);
|
||||
narrow_infill = narrow_fill_areas;
|
||||
|
||||
#ifdef DEBUG_SURFACE_SPLIT
|
||||
|
||||
@@ -173,7 +173,10 @@ const std::string BBL_LICENSE_TAG = "License";
|
||||
const std::string BBL_REGION_TAG = "Region";
|
||||
const std::string BBL_MODIFICATION_TAG = "ModificationDate";
|
||||
const std::string BBL_CREATION_DATE_TAG = "CreationDate";
|
||||
// Orca: BBL current version
|
||||
const std::string BBL_APPLICATION_TAG = "Application";
|
||||
// OrcaSlicer version tag
|
||||
const std::string ORCASLICER_TAG = "OrcaSlicer";
|
||||
const std::string BBL_MAKERLAB_TAG = "MakerLab";
|
||||
const std::string BBL_MAKERLAB_VERSION_TAG = "MakerLabVersion";
|
||||
|
||||
@@ -1034,6 +1037,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
std::string m_origin_file;
|
||||
// Semantic version of Orca Slicer, that generated this 3MF.
|
||||
boost::optional<Semver> m_bambuslicer_generator_version;
|
||||
// Semantic version from the OrcaSlicer metadata tag (if present).
|
||||
boost::optional<Semver> m_orca_slicer_version;
|
||||
unsigned int m_fdm_supports_painting_version = 0;
|
||||
unsigned int m_seam_painting_version = 0;
|
||||
unsigned int m_mm_painting_version = 0;
|
||||
@@ -1105,7 +1110,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
//BBS: add plate data related logic
|
||||
// add backup & restore logic
|
||||
bool load_model_from_file(const std::string& filename, Model& model, PlateDataPtrs& plate_data_list, std::vector<Preset*>& project_presets, DynamicPrintConfig& config,
|
||||
ConfigSubstitutionContext& config_substitutions, LoadStrategy strategy, bool* is_bbl_3mf, Semver& file_version, Import3mfProgressFn proFn = nullptr, BBLProject *project = nullptr, int plate_id = 0);
|
||||
ConfigSubstitutionContext& config_substitutions, LoadStrategy strategy, bool* is_bbl_3mf, bool* is_orca_3mf, Semver& file_version, Import3mfProgressFn proFn = nullptr, BBLProject *project = nullptr, int plate_id = 0);
|
||||
bool get_thumbnail(const std::string &filename, std::string &data);
|
||||
bool load_gcode_3mf_from_stream(std::istream & data, Model& model, PlateDataPtrs& plate_data_list, DynamicPrintConfig& config, Semver& file_version);
|
||||
unsigned int version() const { return m_version; }
|
||||
@@ -1313,7 +1318,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
//BBS: add plate data related logic
|
||||
// add backup & restore logic
|
||||
bool _BBS_3MF_Importer::load_model_from_file(const std::string& filename, Model& model, PlateDataPtrs& plate_data_list, std::vector<Preset*>& project_presets, DynamicPrintConfig& config,
|
||||
ConfigSubstitutionContext& config_substitutions, LoadStrategy strategy, bool* is_bbl_3mf, Semver& file_version, Import3mfProgressFn proFn, BBLProject *project, int plate_id)
|
||||
ConfigSubstitutionContext& config_substitutions, LoadStrategy strategy, bool* is_bbl_3mf, bool* is_orca_3mf, Semver& file_version, Import3mfProgressFn proFn, BBLProject *project, int plate_id)
|
||||
{
|
||||
m_version = 0;
|
||||
m_fdm_supports_painting_version = 0;
|
||||
@@ -1369,8 +1374,18 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
if (is_bbl_3mf) {
|
||||
*is_bbl_3mf = m_is_bbl_3mf;
|
||||
}
|
||||
if (m_bambuslicer_generator_version)
|
||||
file_version = *m_bambuslicer_generator_version;
|
||||
// If the OrcaSlicer tag is present, use it as file_version (ignoring the Bambu Application version).
|
||||
// Otherwise fall back to the version parsed from the Application tag.
|
||||
if (m_orca_slicer_version) {
|
||||
file_version = *m_orca_slicer_version;
|
||||
if (is_orca_3mf)
|
||||
*is_orca_3mf = true;
|
||||
} else {
|
||||
if (m_bambuslicer_generator_version)
|
||||
file_version = *m_bambuslicer_generator_version;
|
||||
if (is_orca_3mf)
|
||||
*is_orca_3mf = false;
|
||||
}
|
||||
// save for restore
|
||||
if (result && m_load_aux && !m_load_restore) {
|
||||
save_string_file(model.get_backup_path() + "/origin.txt", filename);
|
||||
@@ -3821,6 +3836,12 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
m_is_bbl_3mf = true;
|
||||
m_bambuslicer_generator_version = Semver::parse(m_curr_characters.substr(11));
|
||||
}
|
||||
} else if (m_curr_metadata_name == ORCASLICER_TAG) {
|
||||
// OrcaSlicer version tag (written from OrcaSlicer 2.3.2 onwards)
|
||||
m_orca_slicer_version = Semver::parse(m_curr_characters);
|
||||
if (m_orca_slicer_version) {
|
||||
m_is_bbl_3mf = true;
|
||||
}
|
||||
//TODO: currently use version 0, no need to load&&save this string
|
||||
/*} else if (m_curr_metadata_name == BBS_FDM_SUPPORTS_PAINTING_VERSION) {
|
||||
m_fdm_supports_painting_version = (unsigned int) atoi(m_curr_characters.c_str());
|
||||
@@ -6667,8 +6688,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
// Orca: PRIVACY: do not store creation & modification date in 3mf
|
||||
metadata_item_map[BBL_CREATION_DATE_TAG] = "";
|
||||
metadata_item_map[BBL_MODIFICATION_TAG] = "";
|
||||
//SoftFever: write BambuStudio tag to keep it compatible
|
||||
metadata_item_map[BBL_APPLICATION_TAG] = (boost::format("%1%-%2%") % "BambuStudio" % SoftFever_VERSION).str();
|
||||
// Orca: Write the BambuStudio compatibility version string using SLIC3R_VERSION
|
||||
metadata_item_map[BBL_APPLICATION_TAG] = (boost::format("%1%-%2%") % "BambuStudio" % SLIC3R_VERSION).str();
|
||||
}
|
||||
metadata_item_map[BBS_3MF_VERSION] = std::to_string(VERSION_BBS_3MF);
|
||||
|
||||
@@ -6693,6 +6714,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
BOOST_LOG_TRIVIAL(info) << "bbs_3mf: save key= " << item.first << ", value = " << item.second;
|
||||
stream << " <" << METADATA_TAG << " name=\"" << item.first << "\">"
|
||||
<< xml_escape(item.second) << "</" << METADATA_TAG << ">\n";
|
||||
if (item.first == BBL_APPLICATION_TAG) {
|
||||
stream << " <" << METADATA_TAG << " name=\"" << ORCASLICER_TAG << "\">"
|
||||
<< xml_escape(SoftFever_VERSION) << "</" << METADATA_TAG << ">\n";
|
||||
}
|
||||
}
|
||||
|
||||
stream << " <" << RESOURCES_TAG << ">\n";
|
||||
@@ -7552,7 +7577,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
{
|
||||
const std::string& temp_path = model.get_backup_path();
|
||||
std::string temp_file = temp_path + std::string("/") + "_temp_1.config";
|
||||
config.save_to_json(temp_file, std::string("project_settings"), std::string("project"), std::string(SoftFever_VERSION));
|
||||
config.save_to_json(temp_file, std::string("project_settings"), std::string("project"), std::string(SLIC3R_VERSION));
|
||||
return _add_file_to_archive(archive, BBS_PROJECT_CONFIG_FILE, temp_file);
|
||||
}
|
||||
|
||||
@@ -7958,7 +7983,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
// save slice header for debug
|
||||
stream << " <" << SLICE_HEADER_TAG << ">\n";
|
||||
stream << " <" << SLICE_HEADER_ITEM_TAG << " " << KEY_ATTR << "=\"" << "X-BBL-Client-Type" << "\" " << VALUE_ATTR << "=\"" << "slicer" << "\"/>\n";
|
||||
stream << " <" << SLICE_HEADER_ITEM_TAG << " " << KEY_ATTR << "=\"" << "X-BBL-Client-Version" << "\" " << VALUE_ATTR << "=\"" << convert_to_full_version(SoftFever_VERSION) << "\"/>\n";
|
||||
stream << " <" << SLICE_HEADER_ITEM_TAG << " " << KEY_ATTR << "=\"" << "X-BBL-Client-Version" << "\" " << VALUE_ATTR << "=\"" << convert_to_full_version(SLIC3R_VERSION) << "\"/>\n";
|
||||
stream << " <" << SLICE_HEADER_ITEM_TAG << " " << KEY_ATTR << "=\"" << "OrcaSlicer-Version" << "\" " << VALUE_ATTR << "=\"" << SoftFever_VERSION << "\"/>\n";
|
||||
stream << " </" << SLICE_HEADER_TAG << ">\n";
|
||||
|
||||
for (unsigned int i = 0; i < (unsigned int)plate_data_list.size(); ++i)
|
||||
@@ -8654,7 +8680,7 @@ private:
|
||||
|
||||
//BBS: add plate data list related logic
|
||||
bool load_bbs_3mf(const char* path, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions, Model* model, PlateDataPtrs* plate_data_list, std::vector<Preset*>* project_presets,
|
||||
bool* is_bbl_3mf, Semver* file_version, Import3mfProgressFn proFn, LoadStrategy strategy, BBLProject *project, int plate_id)
|
||||
bool* is_bbl_3mf, bool* is_orca_3mf, Semver* file_version, Import3mfProgressFn proFn, LoadStrategy strategy, BBLProject *project, int plate_id)
|
||||
{
|
||||
if (path == nullptr || config == nullptr || model == nullptr)
|
||||
return false;
|
||||
@@ -8662,7 +8688,7 @@ bool load_bbs_3mf(const char* path, DynamicPrintConfig* config, ConfigSubstituti
|
||||
// All import should use "C" locales for number formatting.
|
||||
CNumericLocalesSetter locales_setter;
|
||||
_BBS_3MF_Importer importer;
|
||||
bool res = importer.load_model_from_file(path, *model, *plate_data_list, *project_presets, *config, *config_substitutions, strategy, is_bbl_3mf, *file_version, proFn, project, plate_id);
|
||||
bool res = importer.load_model_from_file(path, *model, *plate_data_list, *project_presets, *config, *config_substitutions, strategy, is_bbl_3mf, is_orca_3mf, *file_version, proFn, project, plate_id);
|
||||
importer.log_errors();
|
||||
//BBS: remove legacy project logic currently
|
||||
//handle_legacy_project_loaded(importer.version(), *config);
|
||||
|
||||
@@ -248,7 +248,7 @@ struct StoreParams
|
||||
// add restore logic
|
||||
// Load the content of a 3mf file into the given model and preset bundle.
|
||||
extern bool load_bbs_3mf(const char* path, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions, Model* model, PlateDataPtrs* plate_data_list, std::vector<Preset*>* project_presets,
|
||||
bool* is_bbl_3mf, Semver* file_version, Import3mfProgressFn proFn = nullptr, LoadStrategy strategy = LoadStrategy::Default, BBLProject *project = nullptr, int plate_id = 0);
|
||||
bool* is_bbl_3mf, bool* is_orca_3mf, Semver* file_version, Import3mfProgressFn proFn = nullptr, LoadStrategy strategy = LoadStrategy::Default, BBLProject *project = nullptr, int plate_id = 0);
|
||||
|
||||
extern std::string bbs_3mf_get_thumbnail(const char * path);
|
||||
|
||||
|
||||
+90
-35
@@ -1948,6 +1948,7 @@ namespace DoExport {
|
||||
//if (ret.size() < MAX_TAGS_COUNT) check(_(L("Color Change G-code")), config.color_change_gcode.value);
|
||||
//Orca
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Change extrusion role G-code")), config.change_extrusion_role_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Process change extrusion role G-code")), config.process_change_extrusion_role_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Pause G-code")), config.machine_pause_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Template Custom G-code")), config.template_custom_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) {
|
||||
@@ -1964,6 +1965,13 @@ namespace DoExport {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret.size() < MAX_TAGS_COUNT) {
|
||||
for (const std::string& value : config.filament_change_extrusion_role_gcode.values) {
|
||||
check(_(L("Filament change extrusion role G-code")), value);
|
||||
if (ret.size() == MAX_TAGS_COUNT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
//BBS: no custom_gcode_per_print_z, don't need to check
|
||||
//if (ret.size() < MAX_TAGS_COUNT) {
|
||||
// const CustomGCode::Info& custom_gcode_per_print_z = print.model().custom_gcode_per_print_z;
|
||||
@@ -2513,7 +2521,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
} else
|
||||
m_enable_extrusion_role_markers = false;
|
||||
|
||||
if (!print.config().small_area_infill_flow_compensation_model.empty())
|
||||
if (m_config.small_area_infill_flow_compensation.value && !m_config.small_area_infill_flow_compensation_model.empty())
|
||||
m_small_area_infill_flow_compensator = make_unique<SmallAreaInfillFlowCompensator>(print.config());
|
||||
|
||||
// Process file_start_gcode - written at the very top of the file, before any header
|
||||
@@ -3188,15 +3196,16 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
this->_print_first_layer_extruder_temperatures(file, print, machine_start_gcode, initial_extruder_id, true);
|
||||
}
|
||||
// Orca: when activate_air_filtration is set on any extruder, find and set the highest during_print_exhaust_fan_speed
|
||||
bool activate_air_filtration = false;
|
||||
bool activate_air_filtration_during_print = false;
|
||||
int during_print_exhaust_fan_speed = 0;
|
||||
for (const auto &extruder : m_writer.extruders()) {
|
||||
activate_air_filtration |= m_config.activate_air_filtration.get_at(extruder.id());
|
||||
if (m_config.activate_air_filtration.get_at(extruder.id()))
|
||||
if (m_config.activate_air_filtration.get_at(extruder.id()) && m_config.activate_air_filtration_during_print.get_at(extruder.id())) {
|
||||
activate_air_filtration_during_print = true;
|
||||
during_print_exhaust_fan_speed = std::max(during_print_exhaust_fan_speed,
|
||||
m_config.during_print_exhaust_fan_speed.get_at(extruder.id()));
|
||||
}
|
||||
}
|
||||
if (activate_air_filtration)
|
||||
if (activate_air_filtration_during_print)
|
||||
file.write(m_writer.set_exhaust_fan(during_print_exhaust_fan_speed, true));
|
||||
|
||||
print.throw_if_canceled();
|
||||
@@ -3519,13 +3528,16 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
if (activate_chamber_temp_control && max_chamber_temp > 0)
|
||||
file.write(m_writer.set_chamber_temperature(0, false)); //close chamber_temperature
|
||||
|
||||
if (activate_air_filtration) {
|
||||
int complete_print_exhaust_fan_speed = 0;
|
||||
for (const auto& extruder : m_writer.extruders())
|
||||
if (m_config.activate_air_filtration.get_at(extruder.id()))
|
||||
complete_print_exhaust_fan_speed = std::max(complete_print_exhaust_fan_speed, m_config.complete_print_exhaust_fan_speed.get_at(extruder.id()));
|
||||
file.write(m_writer.set_exhaust_fan(complete_print_exhaust_fan_speed, true));
|
||||
bool activate_air_filtration_on_completion = false;
|
||||
int complete_print_exhaust_fan_speed = 0;
|
||||
for (const auto& extruder : m_writer.extruders()) {
|
||||
if (m_config.activate_air_filtration.get_at(extruder.id()) && m_config.activate_air_filtration_on_completion.get_at(extruder.id())) {
|
||||
activate_air_filtration_on_completion = true;
|
||||
complete_print_exhaust_fan_speed = std::max(complete_print_exhaust_fan_speed, m_config.complete_print_exhaust_fan_speed.get_at(extruder.id()));
|
||||
}
|
||||
}
|
||||
if (activate_air_filtration_on_completion)
|
||||
file.write(m_writer.set_exhaust_fan(complete_print_exhaust_fan_speed, true));
|
||||
// adds tags for time estimators
|
||||
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Last_Line_M73_Placeholder).c_str());
|
||||
file.write_format("; EXECUTABLE_BLOCK_END\n\n");
|
||||
@@ -5560,6 +5572,7 @@ void GCode::apply_print_config(const PrintConfig &print_config)
|
||||
&m_config.time_lapse_gcode,
|
||||
&m_config.change_filament_gcode,
|
||||
&m_config.change_extrusion_role_gcode,
|
||||
&m_config.process_change_extrusion_role_gcode,
|
||||
&m_config.printing_by_object_gcode,
|
||||
&m_config.machine_pause_gcode,
|
||||
&m_config.template_custom_gcode,
|
||||
@@ -5569,7 +5582,8 @@ void GCode::apply_print_config(const PrintConfig &print_config)
|
||||
}
|
||||
for (auto opt : std::initializer_list<ConfigOptionStrings*>{
|
||||
&m_config.filament_start_gcode,
|
||||
&m_config.filament_end_gcode
|
||||
&m_config.filament_end_gcode,
|
||||
&m_config.filament_change_extrusion_role_gcode
|
||||
}) {
|
||||
if (opt->empty())
|
||||
for (int i = 0; i < opt->size(); ++i)
|
||||
@@ -6336,11 +6350,13 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
"move to first " + description + " point",
|
||||
sloped == nullptr ? DBL_MAX : get_sloped_z(sloped->slope_begin.z_ratio)
|
||||
);
|
||||
m_need_change_layer_lift_z = false;
|
||||
// Orca: ensure Z matches planned layer height
|
||||
if (_last_pos_undefined && !slope_need_z_travel) {
|
||||
gcode += this->writer().travel_to_z(m_nominal_z, "ensure Z matches planned layer height", true);
|
||||
if (!slope_need_z_travel && (_last_pos_undefined || m_need_change_layer_lift_z)) {
|
||||
const std::string z_sync_comment = _last_pos_undefined ?
|
||||
"ensure Z matches planned layer height" : ""; // no comment for normal layer-Z lift
|
||||
gcode += this->writer().travel_to_z(m_nominal_z, z_sync_comment, true);
|
||||
}
|
||||
m_need_change_layer_lift_z = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -6420,6 +6436,8 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
_mm3_per_mm *= m_config.bottom_solid_infill_flow_ratio;
|
||||
} else if (path.role() == erInternalBridgeInfill) {
|
||||
_mm3_per_mm *= m_config.internal_bridge_flow;
|
||||
} else if (path.role() == erBrim) {
|
||||
_mm3_per_mm *= m_config.brim_flow_ratio;
|
||||
} else if (sloped) {
|
||||
_mm3_per_mm *= m_config.scarf_joint_flow_ratio;
|
||||
}
|
||||
@@ -6502,14 +6520,17 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
|
||||
if (speed == 0)
|
||||
speed = filament_max_volumetric_speed / _mm3_per_mm;
|
||||
if (this->on_first_layer()) {
|
||||
|
||||
const auto _layer = layer_id();
|
||||
if (this->on_first_layer() || object_layer_over_raft()) {
|
||||
//BBS: for solid infill of first layer, speed can be higher as long as
|
||||
//wall lines have be attached
|
||||
if (path.role() != erBottomSurface)
|
||||
speed = m_config.get_abs_value("initial_layer_speed");
|
||||
}
|
||||
else if(m_config.slow_down_layers > 1){
|
||||
const auto _layer = layer_id();
|
||||
if (path.role() != erBottomSurface) {
|
||||
speed = is_perimeter(path.role()) ? m_config.get_abs_value("initial_layer_speed") :
|
||||
m_config.get_abs_value("initial_layer_infill_speed");
|
||||
}
|
||||
} else if (m_config.slow_down_layers > 1 && !m_config.raft_layers > 0) {
|
||||
|
||||
if (_layer > 0 && _layer < m_config.slow_down_layers) {
|
||||
const auto first_layer_speed =
|
||||
is_perimeter(path.role())
|
||||
@@ -6519,7 +6540,18 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
speed = std::min(
|
||||
speed,
|
||||
Slic3r::lerp(first_layer_speed, speed,
|
||||
(double)_layer / m_config.slow_down_layers));
|
||||
(double) (_layer) / m_config.slow_down_layers));
|
||||
}
|
||||
}
|
||||
} else if (m_config.slow_down_layers > 1 && m_config.raft_layers > 0 ) {
|
||||
|
||||
if (_layer > m_config.raft_layers && (_layer - m_config.raft_layers) < m_config.slow_down_layers) {
|
||||
const auto first_layer_speed
|
||||
= is_perimeter(path.role()) ? m_config.get_abs_value("initial_layer_speed") :
|
||||
m_config.get_abs_value("initial_layer_infill_speed");
|
||||
if (first_layer_speed < speed) {
|
||||
speed = std::min(speed, Slic3r::lerp(first_layer_speed, speed,
|
||||
(double) (_layer - m_config.raft_layers) / m_config.slow_down_layers));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6582,7 +6614,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
bool variable_speed = false;
|
||||
std::vector<ProcessedPoint> new_points {};
|
||||
|
||||
if (m_config.enable_overhang_speed && !this->on_first_layer() &&
|
||||
if (m_config.enable_overhang_speed && !this->on_first_layer() && !object_layer_over_raft() &&
|
||||
(is_bridge(path.role()) || is_perimeter(path.role()))) {
|
||||
bool is_external = is_external_perimeter(path.role());
|
||||
double ref_speed = is_external ? m_config.get_abs_value("outer_wall_speed") : m_config.get_abs_value("inner_wall_speed");
|
||||
@@ -6670,15 +6702,29 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
// Orca: End of dynamic PA trigger flag segment
|
||||
|
||||
//Orca: process custom gcode for extrusion role change
|
||||
if (path.role() != m_last_extrusion_role && !m_config.change_extrusion_role_gcode.value.empty()) {
|
||||
if (path.role() != m_last_extrusion_role) {
|
||||
const auto current_filament_id = m_writer.filament()->id();
|
||||
const std::string& machine_role_change_gcode = m_config.change_extrusion_role_gcode.value;
|
||||
const std::string& filament_role_change_gcode = m_config.filament_change_extrusion_role_gcode.get_at(current_filament_id);
|
||||
const std::string& process_role_change_gcode = m_config.process_change_extrusion_role_gcode.value;
|
||||
|
||||
if (!machine_role_change_gcode.empty() || !filament_role_change_gcode.empty() || !process_role_change_gcode.empty()) {
|
||||
DynamicConfig config;
|
||||
config.set_key_value("extrusion_role", new ConfigOptionString(extrusion_role_to_string_for_parser(path.role())));
|
||||
config.set_key_value("last_extrusion_role", new ConfigOptionString(extrusion_role_to_string_for_parser(m_last_extrusion_role)));
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index + 1));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(m_layer == nullptr ? m_last_height : m_layer->print_z));
|
||||
gcode += this->placeholder_parser_process("change_extrusion_role_gcode",
|
||||
m_config.change_extrusion_role_gcode.value, m_writer.filament()->id(), &config)
|
||||
+ "\n";
|
||||
|
||||
const auto append_role_gcode = [this, current_filament_id, &config, &gcode](const std::string& key, const std::string& templ) {
|
||||
if (templ.empty())
|
||||
return;
|
||||
gcode += this->placeholder_parser_process(key, templ, current_filament_id, &config) + "\n";
|
||||
};
|
||||
|
||||
append_role_gcode("change_extrusion_role_gcode", machine_role_change_gcode);
|
||||
append_role_gcode("filament_change_extrusion_role_gcode", filament_role_change_gcode);
|
||||
append_role_gcode("process_change_extrusion_role_gcode", process_role_change_gcode);
|
||||
}
|
||||
}
|
||||
|
||||
// extrude arc or line
|
||||
@@ -7225,16 +7271,25 @@ std::string GCode::travel_to(const Point& point, ExtrusionRole role, std::string
|
||||
unsigned int acceleration_to_set = 0;
|
||||
|
||||
if (this->on_first_layer()) {
|
||||
if (m_config.default_acceleration.value > 0 && m_config.initial_layer_acceleration.value > 0) {
|
||||
acceleration_to_set = (unsigned int) floor(m_config.initial_layer_acceleration.value + 0.5);
|
||||
unsigned int initial_layer_travel_acceleration = m_config.get_abs_value("initial_layer_travel_acceleration");
|
||||
double initial_layer_travel_jerk = m_config.get_abs_value("initial_layer_travel_jerk");
|
||||
|
||||
if (m_config.default_acceleration.value > 0 && initial_layer_travel_acceleration > 0) {
|
||||
acceleration_to_set = (unsigned int) floor(initial_layer_travel_acceleration + 0.5);
|
||||
}
|
||||
|
||||
if (m_config.default_jerk.value > 0 && m_config.initial_layer_jerk.value > 0) {
|
||||
jerk_to_set = m_config.initial_layer_jerk.value;
|
||||
if (m_config.default_jerk.value > 0 && initial_layer_travel_jerk > 0) {
|
||||
jerk_to_set = initial_layer_travel_jerk;
|
||||
}
|
||||
} else {
|
||||
} else { // ORCA: Handle short-travel acceleration and jerk for outer perimeters (if applicable)
|
||||
const bool is_short_travel = travel.length() < scale_(EXTRUDER_CONFIG(retraction_minimum_travel));
|
||||
|
||||
if (m_config.default_acceleration.value > 0) {
|
||||
if (role == erExternalPerimeter && travel.length() < scale_(EXTRUDER_CONFIG(retraction_minimum_travel))) {
|
||||
if (role == erOverhangPerimeter && is_short_travel) {
|
||||
const double bridge_acceleration = m_config.get_abs_value("bridge_acceleration");
|
||||
|
||||
if (bridge_acceleration > 0)
|
||||
acceleration_to_set = (unsigned int) floor(bridge_acceleration + 0.5);
|
||||
} else if (role == erExternalPerimeter && is_short_travel) {
|
||||
if (m_config.outer_wall_acceleration.value > 0)
|
||||
acceleration_to_set = (unsigned int) floor(m_config.outer_wall_acceleration.value + 0.5);
|
||||
} else {
|
||||
@@ -7244,7 +7299,7 @@ std::string GCode::travel_to(const Point& point, ExtrusionRole role, std::string
|
||||
}
|
||||
|
||||
if (m_config.default_jerk.value > 0) {
|
||||
if (role == erExternalPerimeter && travel.length() < scale_(EXTRUDER_CONFIG(retraction_minimum_travel))) {
|
||||
if ((role == erExternalPerimeter || role == erOverhangPerimeter) && is_short_travel) {
|
||||
if (m_config.outer_wall_jerk.value > 0)
|
||||
jerk_to_set = m_config.outer_wall_jerk.value;
|
||||
} else {
|
||||
|
||||
@@ -5480,6 +5480,37 @@ void GCodeProcessor::process_filament_change(int id)
|
||||
void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type, bool internal_only)
|
||||
{
|
||||
int filament_id = get_filament_id();
|
||||
const auto normal_mode = PrintEstimatedStatistics::ETimeMode::Normal;
|
||||
const size_t normal_mode_id = static_cast<size_t>(normal_mode);
|
||||
const float delta_x = std::abs(m_end_position[X] - m_start_position[X]);
|
||||
const float delta_y = std::abs(m_end_position[Y] - m_start_position[Y]);
|
||||
const float delta_z = std::abs(m_end_position[Z] - m_start_position[Z]);
|
||||
const float delta_e = std::abs(m_end_position[E] - m_start_position[E]);
|
||||
const bool has_x = delta_x > 0.0f;
|
||||
const bool has_y = delta_y > 0.0f;
|
||||
const bool has_z = delta_z > 0.0f;
|
||||
const bool has_e = delta_e > 0.0f;
|
||||
const float move_acceleration =
|
||||
(type == EMoveType::Travel) ? get_travel_acceleration(normal_mode) :
|
||||
((type == EMoveType::Retract || type == EMoveType::Unretract) ? get_retract_acceleration(normal_mode) :
|
||||
get_acceleration(normal_mode));
|
||||
const float junction_deviation = get_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, normal_mode_id);
|
||||
const bool use_jd_jerk = (m_flavor == gcfMarlinFirmware && junction_deviation > 0.0f);
|
||||
const auto axis_jerk_for_preview = [this, normal_mode, use_jd_jerk, move_acceleration](Axis axis) {
|
||||
return use_jd_jerk ? get_axis_max_jerk_with_jd(normal_mode, axis, move_acceleration) : get_axis_max_jerk(normal_mode, axis);
|
||||
};
|
||||
const float jerk_x = axis_jerk_for_preview(X);
|
||||
const float jerk_y = axis_jerk_for_preview(Y);
|
||||
const float jerk_z = axis_jerk_for_preview(Z);
|
||||
const float jerk_e = axis_jerk_for_preview(E);
|
||||
const float move_jerk =
|
||||
(has_e && !has_x && !has_y && !has_z) ? jerk_e :
|
||||
(has_z && !has_x && !has_y) ? jerk_z :
|
||||
(has_x && has_y) ? std::min(jerk_x, jerk_y) :
|
||||
has_x ? jerk_x :
|
||||
has_y ? jerk_y :
|
||||
has_z ? jerk_z :
|
||||
std::min(jerk_x, jerk_y);
|
||||
m_last_line_id = (type == EMoveType::Color_change || type == EMoveType::Pause_Print || type == EMoveType::Custom_GCode) ?
|
||||
m_line_id + 1 :
|
||||
((type == EMoveType::Seam) ? m_last_line_id : m_line_id);
|
||||
@@ -5503,6 +5534,10 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type,
|
||||
m_extruder_temps[filament_id],
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
m_pressure_advance,
|
||||
// ORCA: Add Acceleration visualization support
|
||||
move_acceleration,
|
||||
// ORCA: Add Jerk visualization support
|
||||
move_jerk,
|
||||
{ 0.0f, 0.0f }, // time
|
||||
static_cast<float>(m_layer_id), //layer_duration: set later
|
||||
std::max<unsigned int>(1, m_layer_id) - 1,
|
||||
@@ -5578,7 +5613,7 @@ float GCodeProcessor::get_axis_max_acceleration(PrintEstimatedStatistics::ETimeM
|
||||
}
|
||||
}
|
||||
|
||||
float GCodeProcessor::get_axis_max_jerk_with_jd(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
|
||||
float GCodeProcessor::get_axis_max_jerk_with_jd(PrintEstimatedStatistics::ETimeMode mode, Axis axis, float acceleration) const
|
||||
{
|
||||
if (axis != X && axis != Y && axis != Z && axis != E)
|
||||
return 0.0f;
|
||||
@@ -5589,12 +5624,22 @@ float GCodeProcessor::get_axis_max_jerk_with_jd(PrintEstimatedStatistics::ETimeM
|
||||
return 0.0f;
|
||||
|
||||
const float axis_max_acc = get_axis_max_acceleration(mode, axis);
|
||||
const float generic_acc = get_acceleration(mode);
|
||||
const float effective_acc = axis_max_acc > 0.0f ? axis_max_acc : generic_acc;
|
||||
float effective_acc = acceleration;
|
||||
if (effective_acc <= 0.0f)
|
||||
effective_acc = get_acceleration(mode);
|
||||
if (axis_max_acc > 0.0f)
|
||||
effective_acc = effective_acc > 0.0f ? std::min(effective_acc, axis_max_acc) : axis_max_acc;
|
||||
if (effective_acc <= 0.0f)
|
||||
return 0.0f;
|
||||
|
||||
return std::sqrt(jd * effective_acc * 2.5f);
|
||||
}
|
||||
|
||||
float GCodeProcessor::get_axis_max_jerk_with_jd(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
|
||||
{
|
||||
return get_axis_max_jerk_with_jd(mode, axis, get_acceleration(mode));
|
||||
}
|
||||
|
||||
float GCodeProcessor::get_axis_max_jerk(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
|
||||
{
|
||||
const size_t id = static_cast<size_t>(mode);
|
||||
|
||||
@@ -186,6 +186,10 @@ class Print;
|
||||
float temperature{ 0.0f }; // Celsius degrees
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
float pressure_advance{ 0.0f };
|
||||
// ORCA: Add Acceleration visualization support
|
||||
float acceleration{ 0.0f }; // mm/s^2
|
||||
// ORCA: Add Jerk visualization support
|
||||
float jerk{ 0.0f }; // mm/s
|
||||
std::array<float, static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count)> time{ 0.0f, 0.0f }; // s
|
||||
float layer_duration{ 0.0f }; // s
|
||||
unsigned int layer_id{ 0 };
|
||||
@@ -1074,6 +1078,7 @@ class Print;
|
||||
// per-nozzle machine limits (filament_map_2 / get_config_idx_for_filament).
|
||||
float get_axis_max_feedrate(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
|
||||
float get_axis_max_acceleration(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
|
||||
float get_axis_max_jerk_with_jd(PrintEstimatedStatistics::ETimeMode mode, Axis axis, float acceleration) const;
|
||||
float get_axis_max_jerk_with_jd(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
|
||||
float get_axis_max_jerk(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
|
||||
Vec3f get_xyz_max_jerk(PrintEstimatedStatistics::ETimeMode mode) const;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include <CGAL/Polygon_mesh_processing/orient_polygon_soup.h>
|
||||
#include <CGAL/Polygon_mesh_processing/repair.h>
|
||||
#include <CGAL/Polygon_mesh_processing/remesh.h>
|
||||
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||
#include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h>
|
||||
#include <CGAL/Polygon_mesh_processing/orientation.h>
|
||||
// BBS: for segment
|
||||
#include <CGAL/mesh_segmentation.h>
|
||||
@@ -475,6 +475,92 @@ bool empty(const CGALMesh &mesh)
|
||||
return mesh.m.is_empty();
|
||||
}
|
||||
|
||||
bool repair(TriangleMesh& mesh, RepairedMeshErrors* repaired_errors, std::string* error)
|
||||
{
|
||||
using namespace CGAL;
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
if (mesh.empty())
|
||||
return true;
|
||||
|
||||
try {
|
||||
// 1) Convert to polygon soup
|
||||
std::vector<_EpicMesh::Point> points;
|
||||
std::vector<std::vector<std::size_t>> polygons;
|
||||
|
||||
points.reserve(mesh.its.vertices.size());
|
||||
polygons.reserve(mesh.its.indices.size());
|
||||
|
||||
for (const auto& v : mesh.its.vertices)
|
||||
points.emplace_back(v.x(), v.y(), v.z());
|
||||
|
||||
for (const auto& f : mesh.its.indices)
|
||||
polygons.push_back({size_t(f[0]), size_t(f[1]), size_t(f[2])});
|
||||
|
||||
// 2) Aggressive soup cleanup
|
||||
PMP::repair_polygon_soup(points, polygons);
|
||||
|
||||
// 3) Convert soup → mesh
|
||||
_EpicMesh cgal_mesh;
|
||||
PMP::polygon_soup_to_polygon_mesh(points, polygons, cgal_mesh);
|
||||
|
||||
// 4) Remove degenerate geometry
|
||||
PMP::remove_degenerate_faces(cgal_mesh);
|
||||
PMP::remove_isolated_vertices(cgal_mesh);
|
||||
|
||||
// 5) Fix remaining non-manifold vertices
|
||||
PMP::duplicate_non_manifold_vertices(cgal_mesh);
|
||||
|
||||
// 6) Boolean union (keeps only outer shell)
|
||||
_EpicMesh tmp;
|
||||
if (PMP::corefine_and_compute_union(cgal_mesh, cgal_mesh, tmp)) {
|
||||
cgal_mesh = std::move(tmp);
|
||||
}
|
||||
// If it fails, continue anyway with previous mesh
|
||||
|
||||
// 7) Fill holes
|
||||
if (!CGAL::is_closed(cgal_mesh)) {
|
||||
using halfedge_descriptor = boost::graph_traits<_EpicMesh>::halfedge_descriptor;
|
||||
|
||||
std::vector<halfedge_descriptor> borders;
|
||||
PMP::extract_boundary_cycles(cgal_mesh, std::back_inserter(borders));
|
||||
|
||||
for (halfedge_descriptor h : borders) {
|
||||
PMP::triangulate_and_refine_hole(cgal_mesh, h);
|
||||
}
|
||||
}
|
||||
|
||||
// 8) Final validity check
|
||||
if (!CGAL::is_closed(cgal_mesh)) {
|
||||
if (error)
|
||||
*error = "Repair failed: mesh still open after hole filling.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// 9) Ensure outward orientation
|
||||
if (!PMP::does_bound_a_volume(cgal_mesh))
|
||||
PMP::orient_to_bound_a_volume(cgal_mesh);
|
||||
|
||||
// 10) Convert back
|
||||
indexed_triangle_set its = cgal_to_indexed_triangle_set(cgal_mesh);
|
||||
|
||||
RepairedMeshErrors errs{};
|
||||
errs.facets_removed = 0;
|
||||
errs.edges_fixed = 0;
|
||||
|
||||
mesh = TriangleMesh(std::move(its), errs);
|
||||
|
||||
if (repaired_errors)
|
||||
*repaired_errors = errs;
|
||||
|
||||
return true;
|
||||
} catch (const std::exception& e) {
|
||||
if (error)
|
||||
*error = e.what();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CGALMeshPtr clone(const CGALMesh &m)
|
||||
{
|
||||
return CGALMeshPtr{new CGALMesh{m}};
|
||||
|
||||
@@ -70,6 +70,9 @@ TriangleMesh merge(std::vector<TriangleMesh> meshes);
|
||||
|
||||
bool does_bound_a_volume(const CGALMesh &mesh);
|
||||
bool empty(const CGALMesh &mesh);
|
||||
|
||||
// Repair a mesh using CGAL. Returns true on success. Optionally returns a summary of repairs and an error string.
|
||||
bool repair(TriangleMesh &mesh, RepairedMeshErrors *repaired_errors = nullptr, std::string *error = nullptr);
|
||||
}
|
||||
|
||||
namespace mcut {
|
||||
|
||||
@@ -323,7 +323,7 @@ Model Model::read_from_file(const std::string&
|
||||
// BBS: backup & restore
|
||||
//FIXME options & LoadStrategy::CheckVersion ?
|
||||
//BBS: is_xxx is used for is_bbs_3mf when load 3mf
|
||||
result = load_bbs_3mf(input_file.c_str(), config, config_substitutions, &model, plate_data, project_presets, is_xxx, file_version, proFn, options, project, plate_id);
|
||||
result = load_bbs_3mf(input_file.c_str(), config, config_substitutions, &model, plate_data, project_presets, is_xxx, nullptr, file_version, proFn, options, project, plate_id);
|
||||
#ifdef __APPLE__
|
||||
else if (boost::algorithm::iends_with(input_file, ".usd") || boost::algorithm::iends_with(input_file, ".usda") ||
|
||||
boost::algorithm::iends_with(input_file, ".usdc") || boost::algorithm::iends_with(input_file, ".usdz") ||
|
||||
@@ -382,7 +382,8 @@ Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig
|
||||
Model model;
|
||||
|
||||
bool result = false;
|
||||
bool is_bbl_3mf;
|
||||
bool is_bbl_3mf = false;
|
||||
bool is_orca_3mf = false;
|
||||
if (boost::algorithm::iends_with(input_file, ".3mf")) {
|
||||
PrusaFileParser prusa_file_parser;
|
||||
if (prusa_file_parser.check_3mf_from_prusa(input_file)) {
|
||||
@@ -392,7 +393,7 @@ Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig
|
||||
} else {
|
||||
// BBS: add part plate related logic
|
||||
// BBS: backup & restore
|
||||
result = load_bbs_3mf(input_file.c_str(), config, config_substitutions, &model, plate_data, project_presets, &is_bbl_3mf, file_version, proFn, options, project);
|
||||
result = load_bbs_3mf(input_file.c_str(), config, config_substitutions, &model, plate_data, project_presets, &is_bbl_3mf, &is_orca_3mf, file_version, proFn, options, project);
|
||||
}
|
||||
}
|
||||
else if (boost::algorithm::iends_with(input_file, ".zip.amf"))
|
||||
@@ -401,7 +402,10 @@ Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig
|
||||
throw Slic3r::RuntimeError(_L("Unknown file format. Input file must have .3mf or .zip.amf extension."));
|
||||
|
||||
if (out_file_type != En3mfType::From_Prusa) {
|
||||
out_file_type = is_bbl_3mf ? En3mfType::From_BBS : En3mfType::From_Other;
|
||||
if (is_orca_3mf)
|
||||
out_file_type = En3mfType::From_Orca;
|
||||
else
|
||||
out_file_type = is_bbl_3mf ? En3mfType::From_BBS : En3mfType::From_Other;
|
||||
}
|
||||
|
||||
if (!result)
|
||||
|
||||
@@ -719,6 +719,7 @@ enum class ConversionType : int {
|
||||
};
|
||||
|
||||
enum class En3mfType : int {
|
||||
From_Orca,
|
||||
From_BBS,
|
||||
From_Prusa,
|
||||
From_Other
|
||||
|
||||
@@ -1562,9 +1562,9 @@ void PerimeterGenerator::process_classic()
|
||||
} // for each loop of an island
|
||||
|
||||
// fill gaps
|
||||
if (! gaps.empty()) {
|
||||
// collapse
|
||||
double min = 0.2 * perimeter_width * (1 - INSET_OVERLAP_TOLERANCE);
|
||||
if (! gaps.empty()) { // collapse
|
||||
// ORCA: Use the smaller width as the lower bound to avoid overestimating safe overlap
|
||||
double min = 0.2 * std::min(perimeter_width, ext_perimeter_width) * (1 - INSET_OVERLAP_TOLERANCE);
|
||||
double max = 2. * perimeter_spacing;
|
||||
ExPolygons gaps_ex = diff_ex(
|
||||
//FIXME offset2 would be enough and cheaper.
|
||||
@@ -1870,6 +1870,20 @@ void PerimeterGenerator::process_no_bridge(Surfaces& all_surfaces, coord_t perim
|
||||
bridges_temp = diff_ex(bridges_temp, unbridgeable);
|
||||
unsupported_filtered = offset_ex(bridges_temp, offset_to_do);
|
||||
unsupported_filtered = intersection_ex(unsupported_filtered, reference);
|
||||
|
||||
// Normalize anchor size for partial bridges:
|
||||
// derive the bridge core first, then add a fixed overlap into support.
|
||||
const coordf_t anchor_overlap = bridged_infill_margin;
|
||||
ExPolygons bridge_core = diff_ex(unsupported_filtered, support, ApplySafetyOffset::Yes);
|
||||
if (bridge_core.empty()) {
|
||||
bridge_core = unsupported_filtered;
|
||||
}
|
||||
ExPolygons anchor_overlap_area = intersection_ex(
|
||||
offset_ex(bridge_core, anchor_overlap),
|
||||
support,
|
||||
ApplySafetyOffset::Yes);
|
||||
unsupported_filtered = union_ex(bridge_core, anchor_overlap_area);
|
||||
unsupported_filtered = intersection_ex(unsupported_filtered, reference);
|
||||
// } else {
|
||||
// ExPolygons unbridgeable = intersection_ex(unsupported, diff_ex(unsupported_filtered, offset_ex(bridgeable_simplified, ext_perimeter_width / 2)));
|
||||
// unbridgeable = offset2_ex(unbridgeable, -ext_perimeter_width, ext_perimeter_width);
|
||||
|
||||
@@ -910,7 +910,7 @@ static std::vector<std::string> s_Preset_print_options {
|
||||
"top_surface_speed", "support_speed", "support_object_xy_distance", "support_object_first_layer_gap", "support_interface_speed",
|
||||
"bridge_speed", "internal_bridge_speed", "gap_infill_speed", "travel_speed", "travel_speed_z", "initial_layer_speed",
|
||||
"outer_wall_acceleration", "initial_layer_acceleration", "top_surface_acceleration", "default_acceleration", "skirt_type", "skirt_loops", "skirt_speed","min_skirt_length", "skirt_distance", "skirt_start_angle", "skirt_height","single_loop_draft_shield", "draft_shield",
|
||||
"brim_width", "brim_object_gap", "brim_use_efc_outline", "combine_brims", "brim_type", "brim_ears_max_angle", "brim_ears_detection_length", "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap","enforce_support_layers",
|
||||
"brim_width", "brim_object_gap", "brim_flow_ratio", "brim_use_efc_outline", "combine_brims", "brim_type", "brim_ears_max_angle", "brim_ears_detection_length", "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap","enforce_support_layers",
|
||||
"raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion",
|
||||
"support_base_pattern", "support_base_pattern_spacing", "support_expansion", "support_style",
|
||||
// BBS
|
||||
@@ -940,8 +940,8 @@ static std::vector<std::string> s_Preset_print_options {
|
||||
"support_bottom_interface_spacing", "enable_overhang_speed", "slowdown_for_curled_perimeters", "overhang_1_4_speed", "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed",
|
||||
"initial_layer_infill_speed", "only_one_wall_top",
|
||||
"timelapse_type",
|
||||
"wall_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle",
|
||||
"wall_distribution_count", "min_feature_size", "min_bead_width", "post_process", "min_length_factor",
|
||||
"wall_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle",
|
||||
"wall_distribution_count", "min_feature_size", "min_bead_width", "post_process", "process_change_extrusion_role_gcode", "min_length_factor",
|
||||
"small_perimeter_speed", "small_perimeter_threshold","bridge_angle","internal_bridge_angle", "filter_out_gap_fill", "travel_acceleration","inner_wall_acceleration", "min_width_top_surface",
|
||||
"default_jerk", "outer_wall_jerk", "inner_wall_jerk", "infill_jerk", "top_surface_jerk", "initial_layer_jerk","travel_jerk","default_junction_deviation",
|
||||
"top_solid_infill_flow_ratio","bottom_solid_infill_flow_ratio","only_one_wall_first_layer", "print_flow_ratio", "seam_gap",
|
||||
@@ -950,7 +950,7 @@ static std::vector<std::string> s_Preset_print_options {
|
||||
"bridge_density","internal_bridge_density", "precise_outer_wall", "bridge_acceleration",
|
||||
"sparse_infill_acceleration", "internal_solid_infill_acceleration", "tree_support_auto_brim",
|
||||
"tree_support_brim_width", "gcode_comments", "gcode_label_objects",
|
||||
"initial_layer_travel_speed", "exclude_object", "slow_down_layers", "infill_anchor", "infill_anchor_max","initial_layer_min_bead_width",
|
||||
"initial_layer_travel_speed", "initial_layer_travel_acceleration", "initial_layer_travel_jerk", "exclude_object", "slow_down_layers", "infill_anchor", "infill_anchor_max","initial_layer_min_bead_width",
|
||||
"make_overhang_printable", "make_overhang_printable_angle", "make_overhang_printable_hole_size" ,"notes",
|
||||
"wipe_tower_cone_angle", "wipe_tower_extra_spacing","wipe_tower_max_purge_speed",
|
||||
"wipe_tower_wall_type", "wipe_tower_extra_rib_length", "wipe_tower_rib_width", "wipe_tower_fillet_wall",
|
||||
@@ -979,9 +979,9 @@ static std::vector<std::string> s_Preset_filament_options {/*"filament_colour",
|
||||
//BBS:temperature_vitrification
|
||||
"temperature_vitrification", "reduce_fan_stop_start_freq","dont_slow_down_outer_wall", "slow_down_for_layer_cooling", "fan_min_speed",
|
||||
"fan_max_speed", "enable_overhang_bridge_fan", "overhang_fan_speed", "overhang_fan_threshold", "close_fan_the_first_x_layers", "full_fan_speed_layer", "fan_cooling_layer_time", "slow_down_layer_time", "slow_down_min_speed",
|
||||
"filament_start_gcode", "filament_end_gcode",
|
||||
"filament_start_gcode", "filament_end_gcode", "filament_change_extrusion_role_gcode",
|
||||
//exhaust fan control
|
||||
"activate_air_filtration","during_print_exhaust_fan_speed","complete_print_exhaust_fan_speed",
|
||||
"activate_air_filtration","activate_air_filtration_during_print","activate_air_filtration_on_completion","during_print_exhaust_fan_speed","complete_print_exhaust_fan_speed",
|
||||
// Retract overrides
|
||||
"filament_retraction_length", "filament_z_hop", "filament_z_hop_types", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_lift_enforce", "filament_retraction_speed", "filament_deretraction_speed", "filament_retract_restart_extra", "filament_retraction_minimum_travel",
|
||||
"filament_retract_when_changing_layer", "filament_wipe", "filament_retract_before_wipe",
|
||||
|
||||
@@ -2205,16 +2205,32 @@ void PresetBundle::set_num_filaments(unsigned int n, std::vector<std::string> ne
|
||||
filament_presets.resize(n);
|
||||
}
|
||||
ConfigOptionStrings* filament_color = project_config.option<ConfigOptionStrings>("filament_colour");
|
||||
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
||||
ConfigOptionStrings* filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
||||
ConfigOptionInts* filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
||||
|
||||
|
||||
filament_color->resize(n);
|
||||
// Sync filament multi colour
|
||||
filament_multi_color->values.resize(n);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
filament_multi_color->values[i] = filament_color->values[i];
|
||||
}
|
||||
filament_color_type->resize(n);
|
||||
filament_map->values.resize(n, 1);
|
||||
ams_multi_color_filment.resize(n);
|
||||
|
||||
// BBS set new filament color to new_color
|
||||
if (old_filament_count < n) {
|
||||
if (!new_colors.empty()) {
|
||||
for (int i = old_filament_count; i < n; i++) {
|
||||
filament_color->values[i] = new_colors[i - old_filament_count];
|
||||
filament_multi_color->values[i] = new_colors[i - old_filament_count];
|
||||
filament_color_type->values[i] = "1"; // default color type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_multi_material_filament_presets();
|
||||
}
|
||||
void PresetBundle::set_num_filaments(unsigned int n, std::string new_color)
|
||||
|
||||
@@ -219,6 +219,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
"ironing_fan_speed",
|
||||
"single_extruder_multi_material_priming",
|
||||
"activate_air_filtration",
|
||||
"activate_air_filtration_during_print",
|
||||
"activate_air_filtration_on_completion",
|
||||
"during_print_exhaust_fan_speed",
|
||||
"complete_print_exhaust_fan_speed",
|
||||
"activate_chamber_temp_control",
|
||||
@@ -343,6 +345,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
|| opt_key == "travel_speed_z"
|
||||
|| opt_key == "initial_layer_speed"
|
||||
|| opt_key == "initial_layer_travel_speed"
|
||||
|| opt_key == "initial_layer_travel_acceleration"
|
||||
|| opt_key == "initial_layer_travel_jerk"
|
||||
|| opt_key == "slow_down_layers"
|
||||
|| opt_key == "idle_temperature"
|
||||
|| opt_key == "wipe_tower_cone_angle"
|
||||
|
||||
@@ -1584,6 +1584,17 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.));
|
||||
|
||||
def = this->add("brim_flow_ratio", coFloat);
|
||||
def->label = L("Brim flow ratio");
|
||||
def->category = L("Support");
|
||||
def->tooltip = L("This factor affects the amount of material for brims.\n\n"
|
||||
"The actual brim flow used is calculated by multiplying this value by the filament flow ratio, and if set, the object's flow ratio.\n\n"
|
||||
"Note: The resulting value will not be affected by the first-layer flow ratio.");
|
||||
def->min = 0;
|
||||
def->max = 2;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(1));
|
||||
|
||||
def = this->add("brim_use_efc_outline", coBool);
|
||||
def->label = L("Brim follows compensated outline");
|
||||
def->category = L("Support");
|
||||
@@ -1741,6 +1752,19 @@ void PrintConfigDef::init_fff_params()
|
||||
def->tooltip = L("Activate for better air filtration. G-code command: M106 P3 S(0-255)");
|
||||
def->mode = comSimple;
|
||||
def->set_default_value(new ConfigOptionBools{false});
|
||||
|
||||
|
||||
def = this->add("activate_air_filtration_during_print", coBools);
|
||||
def->full_label = L("During print");
|
||||
def->tooltip=L("Enable this to override the fan speed set in custom G-code during print.");
|
||||
def->mode = comSimple;
|
||||
def->set_default_value(new ConfigOptionBools{true});
|
||||
|
||||
def = this->add("activate_air_filtration_on_completion", coBools);
|
||||
def->full_label = L("On completion");
|
||||
def->tooltip=L("Enable this to override the fan speed set in custom G-code after print completion.");
|
||||
def->mode = comSimple;
|
||||
def->set_default_value(new ConfigOptionBools{true});
|
||||
|
||||
def = this->add("during_print_exhaust_fan_speed", coInts);
|
||||
def->label = L("Fan speed");
|
||||
@@ -3032,6 +3056,15 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(300));
|
||||
|
||||
def = this->add("initial_layer_travel_acceleration", coFloatOrPercent);
|
||||
def->label = L("First layer travel");
|
||||
def->tooltip = L("Travel acceleration of first layer.\nThe percentage value is relative to Travel Acceleration.");
|
||||
def->sidetext = L("mm/s² or %");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->ratio_over = "travel_acceleration";
|
||||
def->set_default_value(new ConfigOptionFloatOrPercent(100, true));
|
||||
|
||||
def = this->add("accel_to_decel_enable", coBool);
|
||||
def->label = L("Enable accel_to_decel");
|
||||
def->category = L("Speed");
|
||||
@@ -3122,6 +3155,15 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(12));
|
||||
|
||||
def = this->add("initial_layer_travel_jerk", coFloatOrPercent);
|
||||
def->label = L("First layer travel");
|
||||
def->tooltip = L("Travel jerk of first layer.\nThe percentage value is relative to Travel Jerk.");
|
||||
def->sidetext = L("mm/s or %");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->ratio_over = "travel_jerk";
|
||||
def->set_default_value(new ConfigOptionFloatOrPercent(100, true));
|
||||
|
||||
def = this->add("initial_layer_line_width", coFloatOrPercent);
|
||||
def->label = L("First layer");
|
||||
def->category = L("Quality");
|
||||
@@ -4633,6 +4675,15 @@ void PrintConfigDef::init_fff_params()
|
||||
def->height = 6;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionStrings());
|
||||
|
||||
def = this->add("process_change_extrusion_role_gcode", coString);
|
||||
def->label = L("Change extrusion role G-code (process)");
|
||||
def->tooltip = L("This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code.");
|
||||
def->multiline = true;
|
||||
def->full_width = true;
|
||||
def->height = 5;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionString());
|
||||
|
||||
def = this->add("printer_model", coString);
|
||||
def->label = L("Printer type");
|
||||
@@ -6286,6 +6337,15 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionString());
|
||||
|
||||
def = this->add("filament_change_extrusion_role_gcode", coStrings);
|
||||
def->label = L("Change extrusion role G-code (filament)");
|
||||
def->tooltip = L("This G-code is inserted when the extrusion role is changed for the active filament.");
|
||||
def->multiline = true;
|
||||
def->full_width = true;
|
||||
def->height = 5;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionStrings{ "" });
|
||||
|
||||
def = this->add("top_surface_line_width", coFloatOrPercent);
|
||||
def->label = L("Top surface");
|
||||
def->category = L("Quality");
|
||||
@@ -7938,7 +7998,12 @@ std::set<std::string> filament_options_with_variant = {
|
||||
"filament_ironing_flow",
|
||||
"filament_ironing_spacing",
|
||||
"filament_ironing_inset",
|
||||
"filament_ironing_speed"
|
||||
"filament_ironing_speed",
|
||||
"activate_air_filtration",
|
||||
"activate_air_filtration_during_print",
|
||||
"activate_air_filtration_on_completion",
|
||||
"during_print_exhaust_fan_speed",
|
||||
"complete_print_exhaust_fan_speed"
|
||||
};
|
||||
|
||||
// Parameters that are the same as the number of extruders
|
||||
@@ -10773,6 +10838,8 @@ static std::map<t_custom_gcode_key, t_config_option_keys> s_CustomGcodeSpecificP
|
||||
"travel_point_1_x", "travel_point_1_y", "travel_point_2_x", "travel_point_2_y", "travel_point_3_x",
|
||||
"travel_point_3_y", "x_after_toolchange", "y_after_toolchange", "z_after_toolchange"}},
|
||||
{"change_extrusion_role_gcode", {"layer_num", "layer_z", "extrusion_role", "last_extrusion_role"}},
|
||||
{"filament_change_extrusion_role_gcode", {"layer_num", "layer_z", "extrusion_role", "last_extrusion_role"}},
|
||||
{"process_change_extrusion_role_gcode", {"layer_num", "layer_z", "extrusion_role", "last_extrusion_role"}},
|
||||
{"printing_by_object_gcode", {}},
|
||||
{"machine_pause_gcode", {}},
|
||||
{"template_custom_gcode", {}},
|
||||
|
||||
@@ -888,6 +888,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
PrintObjectConfig,
|
||||
|
||||
((ConfigOptionFloat, brim_object_gap))
|
||||
((ConfigOptionFloat, brim_flow_ratio))
|
||||
((ConfigOptionBool, brim_use_efc_outline))
|
||||
((ConfigOptionEnum<BrimType>, brim_type))
|
||||
((ConfigOptionFloat, brim_width))
|
||||
@@ -1351,6 +1352,8 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionBool, wipe_tower_no_sparse_layers))
|
||||
((ConfigOptionString, change_filament_gcode))
|
||||
((ConfigOptionString, change_extrusion_role_gcode))
|
||||
((ConfigOptionString, process_change_extrusion_role_gcode))
|
||||
((ConfigOptionStrings, filament_change_extrusion_role_gcode))
|
||||
((ConfigOptionFloat, travel_speed))
|
||||
((ConfigOptionFloat, travel_speed_z))
|
||||
((ConfigOptionBool, silent_mode))
|
||||
@@ -1377,6 +1380,8 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionBool, accel_to_decel_enable))
|
||||
((ConfigOptionPercent, accel_to_decel_factor))
|
||||
((ConfigOptionFloatOrPercent, initial_layer_travel_speed))
|
||||
((ConfigOptionFloatOrPercent, initial_layer_travel_acceleration))
|
||||
((ConfigOptionFloatOrPercent, initial_layer_travel_jerk))
|
||||
((ConfigOptionBool, bbl_calib_mark_logo))
|
||||
((ConfigOptionBool, disable_m73))
|
||||
|
||||
@@ -1471,6 +1476,8 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
||||
((ConfigOptionBools, dont_slow_down_outer_wall))
|
||||
((ConfigOptionFloats, fan_cooling_layer_time))
|
||||
((ConfigOptionBools, activate_air_filtration))
|
||||
((ConfigOptionBools, activate_air_filtration_during_print))
|
||||
((ConfigOptionBools, activate_air_filtration_on_completion))
|
||||
((ConfigOptionInts, during_print_exhaust_fan_speed))
|
||||
((ConfigOptionInts, complete_print_exhaust_fan_speed))
|
||||
((ConfigOptionFloatOrPercent, initial_layer_line_width))
|
||||
|
||||
@@ -1300,7 +1300,6 @@ bool PrintObject::invalidate_state_by_config_options(
|
||||
|| opt_key == "scarf_angle_threshold"
|
||||
|| opt_key == "scarf_overhang_threshold"
|
||||
|| opt_key == "scarf_joint_speed"
|
||||
|| opt_key == "scarf_joint_flow_ratio"
|
||||
|| opt_key == "seam_slope_start_height"
|
||||
|| opt_key == "seam_slope_entire_loop"
|
||||
|| opt_key == "seam_slope_min_length"
|
||||
@@ -1324,7 +1323,24 @@ bool PrintObject::invalidate_state_by_config_options(
|
||||
|| opt_key == "bed_mesh_min"
|
||||
|| opt_key == "bed_mesh_max"
|
||||
|| opt_key == "adaptive_bed_mesh_margin"
|
||||
|| opt_key == "bed_mesh_probe_distance") {
|
||||
|| opt_key == "bed_mesh_probe_distance"
|
||||
|| opt_key == "print_flow_ratio"
|
||||
|| opt_key == "first_layer_flow_ratio"
|
||||
|| opt_key == "top_solid_infill_flow_ratio"
|
||||
|| opt_key == "bottom_solid_infill_flow_ratio"
|
||||
|| opt_key == "outer_wall_flow_ratio"
|
||||
|| opt_key == "inner_wall_flow_ratio"
|
||||
|| opt_key == "overhang_flow_ratio"
|
||||
|| opt_key == "sparse_infill_flow_ratio"
|
||||
|| opt_key == "internal_solid_infill_flow_ratio"
|
||||
|| opt_key == "gap_fill_flow_ratio"
|
||||
|| opt_key == "support_flow_ratio"
|
||||
|| opt_key == "support_interface_flow_ratio"
|
||||
|| opt_key == "brim_flow_ratio"
|
||||
|| opt_key == "filament_flow_ratio"
|
||||
|| opt_key == "scarf_joint_flow_ratio"
|
||||
|| opt_key == "spiral_starting_flow_ratio"
|
||||
|| opt_key == "spiral_finishing_flow_ratio") {
|
||||
invalidated |= m_print->invalidate_step(psGCodeExport);
|
||||
} else if (
|
||||
opt_key == "flush_into_infill"
|
||||
|
||||
@@ -2882,8 +2882,9 @@ SupportGeneratorLayersPtr PrintObjectSupportMaterial::raft_and_intermediate_supp
|
||||
intermediate_layers.push_back(&layer_new);
|
||||
}
|
||||
} else {
|
||||
// Insert intermediate layers.
|
||||
size_t n_layers_extra = size_t(ceil(dist / m_slicing_params.max_suport_layer_height));
|
||||
// ORCA: Bias by EPSILON so a gap effectively equal to
|
||||
// max_suport_layer_height is not split by floating-point noise.
|
||||
size_t n_layers_extra = size_t(ceil((dist - EPSILON) / m_slicing_params.max_suport_layer_height));
|
||||
assert(n_layers_extra > 0);
|
||||
coordf_t step = dist / coordf_t(n_layers_extra);
|
||||
if (extr1 != nullptr && extr1->layer_type == SupporLayerType::TopContact &&
|
||||
@@ -2898,7 +2899,9 @@ SupportGeneratorLayersPtr PrintObjectSupportMaterial::raft_and_intermediate_supp
|
||||
layer_new.height = extr1->height;
|
||||
intermediate_layers.push_back(&layer_new);
|
||||
dist = extr2z - extr1z;
|
||||
n_layers_extra = size_t(ceil(dist / m_slicing_params.max_suport_layer_height));
|
||||
// ORCA: Recalculate with the same EPSILON bias after re-anchoring at the top
|
||||
// contact layer so near-equal gaps do not gain an extra split here either.
|
||||
n_layers_extra = size_t(ceil((dist - EPSILON) / m_slicing_params.max_suport_layer_height));
|
||||
if (n_layers_extra == 0)
|
||||
continue;
|
||||
// Continue printing the other layers up to extr2z.
|
||||
|
||||
@@ -1157,12 +1157,17 @@ void TreeSupport::create_tree_support_layers()
|
||||
|
||||
// Layers between the raft contacts and bottom of the object.
|
||||
double dist_to_go = m_slicing_params.object_print_z_min - raft_print_z;
|
||||
auto nsteps = int(ceil(dist_to_go / m_slicing_params.max_suport_layer_height));
|
||||
double height = dist_to_go / nsteps;
|
||||
for (int i = 0; i < nsteps; ++i) {
|
||||
raft_print_z += height;
|
||||
raft_slice_z = raft_print_z - height / 2;
|
||||
m_object->add_tree_support_layer(layer_id++, height, raft_print_z, raft_slice_z);
|
||||
// ORCA: Guard tiny residual raft-to-object gaps so the EPSILON-biased ceil()
|
||||
// below cannot turn them into zero steps after floating-point accumulation.
|
||||
if (dist_to_go > EPSILON) {
|
||||
// ORCA: Bias by EPSILON so near-equal gaps do not get an extra split from FP noise.
|
||||
auto nsteps = int(ceil((dist_to_go - EPSILON) / m_slicing_params.max_suport_layer_height));
|
||||
double height = dist_to_go / nsteps;
|
||||
for (int i = 0; i < nsteps; ++i) {
|
||||
raft_print_z += height;
|
||||
raft_slice_z = raft_print_z - height / 2;
|
||||
m_object->add_tree_support_layer(layer_id++, height, raft_print_z, raft_slice_z);
|
||||
}
|
||||
}
|
||||
m_raft_layers = layer_id;
|
||||
}
|
||||
|
||||
@@ -343,7 +343,8 @@ public:
|
||||
}
|
||||
if (double dist_to_go = slicing_params.object_print_z_min - z; dist_to_go > EPSILON) {
|
||||
// Layers between the raft contacts and bottom of the object.
|
||||
auto nsteps = int(ceil(dist_to_go / slicing_params.max_suport_layer_height));
|
||||
// ORCA: Bias by EPSILON so near-equal gaps do not get an extra split from FP noise.
|
||||
auto nsteps = int(ceil((dist_to_go - EPSILON) / slicing_params.max_suport_layer_height));
|
||||
double step = dist_to_go / nsteps;
|
||||
for (int i = 0; i < nsteps; ++ i) {
|
||||
z += step;
|
||||
@@ -754,4 +755,4 @@ enum class LineStatus
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_TreeSupportCommon_hpp
|
||||
#endif // slic3r_TreeSupportCommon_hpp
|
||||
@@ -71,8 +71,8 @@ namespace Timing {
|
||||
static TimeLimitAlarm new_nanos(uint64_t time_limit_nanoseconds, std::string_view limit_exceeded_message) {
|
||||
return TimeLimitAlarm(time_limit_nanoseconds, limit_exceeded_message);
|
||||
}
|
||||
static TimeLimitAlarm new_milis(uint64_t time_limit_milis, std::string_view limit_exceeded_message) {
|
||||
return TimeLimitAlarm(uint64_t(time_limit_milis) * 1000000l, limit_exceeded_message);
|
||||
static TimeLimitAlarm new_millis(uint64_t time_limit_millis, std::string_view limit_exceeded_message) {
|
||||
return TimeLimitAlarm(uint64_t(time_limit_millis) * 1000000l, limit_exceeded_message);
|
||||
}
|
||||
static TimeLimitAlarm new_seconds(uint64_t time_limit_seconds, std::string_view limit_exceeded_message) {
|
||||
return TimeLimitAlarm(uint64_t(time_limit_seconds) * 1000000000l, limit_exceeded_message);
|
||||
|
||||
@@ -91,6 +91,16 @@ struct PathVertex
|
||||
// Pressure advance value
|
||||
//
|
||||
float pressure_advance{ 0.0f };
|
||||
//
|
||||
// ORCA: Add Acceleration visualization support
|
||||
// Acceleration value
|
||||
//
|
||||
float acceleration{ 0.0f };
|
||||
//
|
||||
// ORCA: Add Jerk visualization support
|
||||
// Jerk value
|
||||
//
|
||||
float jerk{ 0.0f };
|
||||
|
||||
//
|
||||
// Return true if the segment is an extrusion move
|
||||
|
||||
@@ -94,6 +94,10 @@ enum class EViewType : uint8_t
|
||||
Temperature,
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
PressureAdvance,
|
||||
// ORCA: Add Acceleration visualization support
|
||||
Acceleration,
|
||||
// ORCA: Add Jerk visualization support
|
||||
Jerk,
|
||||
Tool,
|
||||
COUNT
|
||||
};
|
||||
|
||||
@@ -171,6 +171,10 @@ public:
|
||||
// EViewType::Temperature
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
// EViewType::PressureAdvance
|
||||
// ORCA: Add Acceleration visualization support
|
||||
// EViewType::Acceleration
|
||||
// ORCA: Add Jerk visualization support
|
||||
// EViewType::Jerk
|
||||
// EViewType::VolumetricFlowRate
|
||||
// EViewType::ActualVolumetricFlowRate
|
||||
// EViewType::LayerTimeLinear
|
||||
@@ -189,6 +193,10 @@ public:
|
||||
// EViewType::Temperature
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
// EViewType::PressureAdvance
|
||||
// ORCA: Add Acceleration visualization support
|
||||
// EViewType::Acceleration
|
||||
// ORCA: Add Jerk visualization support
|
||||
// EViewType::Jerk
|
||||
// EViewType::VolumetricFlowRate
|
||||
// EViewType::ActualVolumetricFlowRate
|
||||
// EViewType::LayerTimeLinear
|
||||
|
||||
@@ -1469,7 +1469,7 @@ Color ViewerImpl::get_vertex_color(const PathVertex& v) const
|
||||
if (v.type == EMoveType::Noop)
|
||||
return DUMMY_COLOR;
|
||||
|
||||
if ((v.is_wipe() && (m_settings.view_type != EViewType::Speed && m_settings.view_type != EViewType::ActualSpeed)) || v.is_option())
|
||||
if ((v.is_wipe() && (m_settings.view_type != EViewType::Speed && m_settings.view_type != EViewType::ActualSpeed && m_settings.view_type != EViewType::Acceleration && m_settings.view_type != EViewType::Jerk)) || v.is_option())
|
||||
return get_option_color(move_type_to_option(v.type));
|
||||
|
||||
switch (m_settings.view_type)
|
||||
@@ -1507,6 +1507,16 @@ Color ViewerImpl::get_vertex_color(const PathVertex& v) const
|
||||
{
|
||||
return v.is_travel() ? get_option_color(move_type_to_option(v.type)) : m_pressure_advance_range.get_color_at(v.pressure_advance);
|
||||
}
|
||||
// ORCA: Add Acceleration visualization support
|
||||
case EViewType::Acceleration:
|
||||
{
|
||||
return m_acceleration_range.get_color_at(v.acceleration);
|
||||
}
|
||||
// ORCA: Add Jerk visualization support
|
||||
case EViewType::Jerk:
|
||||
{
|
||||
return m_jerk_range.get_color_at(v.jerk);
|
||||
}
|
||||
case EViewType::VolumetricFlowRate:
|
||||
{
|
||||
return v.is_travel() ? get_option_color(move_type_to_option(v.type)) : m_volumetric_rate_range.get_color_at(v.volumetric_rate());
|
||||
@@ -1598,6 +1608,10 @@ const ColorRange& ViewerImpl::get_color_range(EViewType type) const
|
||||
case EViewType::Temperature: { return m_temperature_range; }
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
case EViewType::PressureAdvance: { return m_pressure_advance_range; }
|
||||
// ORCA: Add Acceleration visualization support
|
||||
case EViewType::Acceleration: { return m_acceleration_range; }
|
||||
// ORCA: Add Jerk visualization support
|
||||
case EViewType::Jerk: { return m_jerk_range; }
|
||||
case EViewType::VolumetricFlowRate: { return m_volumetric_rate_range; }
|
||||
case EViewType::ActualVolumetricFlowRate: { return m_actual_volumetric_rate_range; }
|
||||
case EViewType::LayerTimeLinear: { return m_layer_time_range[0]; }
|
||||
@@ -1618,6 +1632,10 @@ void ViewerImpl::set_color_range_palette(EViewType type, const Palette& palette)
|
||||
case EViewType::Temperature: { m_temperature_range.set_palette(palette); break; }
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
case EViewType::PressureAdvance: { m_pressure_advance_range.set_palette(palette); break; }
|
||||
// ORCA: Add Acceleration visualization support
|
||||
case EViewType::Acceleration: { m_acceleration_range.set_palette(palette); break; }
|
||||
// ORCA: Add Jerk visualization support
|
||||
case EViewType::Jerk: { m_jerk_range.set_palette(palette); break; }
|
||||
case EViewType::VolumetricFlowRate: { m_volumetric_rate_range.set_palette(palette); break; }
|
||||
case EViewType::ActualVolumetricFlowRate: { m_actual_volumetric_rate_range.set_palette(palette); break; }
|
||||
case EViewType::LayerTimeLinear: { m_layer_time_range[0].set_palette(palette); break; }
|
||||
@@ -1657,6 +1675,10 @@ size_t ViewerImpl::get_used_cpu_memory() const
|
||||
ret += m_temperature_range.size_in_bytes_cpu();
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
ret += m_pressure_advance_range.size_in_bytes_cpu();
|
||||
// ORCA: Add Acceleration visualization support
|
||||
ret += m_acceleration_range.size_in_bytes_cpu();
|
||||
// ORCA: Add Jerk visualization support
|
||||
ret += m_jerk_range.size_in_bytes_cpu();
|
||||
ret += m_volumetric_rate_range.size_in_bytes_cpu();
|
||||
ret += m_actual_volumetric_rate_range.size_in_bytes_cpu();
|
||||
for (size_t i = 0; i < COLOR_RANGE_TYPES_COUNT; ++i) {
|
||||
@@ -1809,6 +1831,10 @@ void ViewerImpl::update_color_ranges()
|
||||
m_temperature_range.reset();
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
m_pressure_advance_range.reset();
|
||||
// ORCA: Add Acceleration visualization support
|
||||
m_acceleration_range.reset();
|
||||
// ORCA: Add Jerk visualization support
|
||||
m_jerk_range.reset();
|
||||
m_volumetric_rate_range.reset();
|
||||
m_actual_volumetric_rate_range.reset();
|
||||
m_layer_time_range[0].reset(); // ColorRange::EType::Linear
|
||||
@@ -1834,6 +1860,10 @@ void ViewerImpl::update_color_ranges()
|
||||
v.is_extrusion()) {
|
||||
m_speed_range.update(v.feedrate);
|
||||
m_actual_speed_range.update(v.actual_feedrate);
|
||||
// ORCA: Add Acceleration visualization support
|
||||
m_acceleration_range.update(v.acceleration);
|
||||
// ORCA: Add Jerk visualization support
|
||||
m_jerk_range.update(v.jerk);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -291,6 +291,10 @@ private:
|
||||
ColorRange m_temperature_range;
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
ColorRange m_pressure_advance_range;
|
||||
// ORCA: Add Acceleration visualization support
|
||||
ColorRange m_acceleration_range;
|
||||
// ORCA: Add Jerk visualization support
|
||||
ColorRange m_jerk_range;
|
||||
ColorRange m_volumetric_rate_range;
|
||||
ColorRange m_actual_volumetric_rate_range;
|
||||
std::array<ColorRange, COLOR_RANGE_TYPES_COUNT> m_layer_time_range{
|
||||
|
||||
@@ -170,6 +170,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/Gizmos/GLGizmosManager.hpp
|
||||
GUI/Gizmos/GLGizmoSVG.cpp
|
||||
GUI/Gizmos/GLGizmoSVG.hpp
|
||||
GUI/Gizmos/GLGizmoUtils.cpp
|
||||
GUI/Gizmos/GLGizmoUtils.hpp
|
||||
#GUI/Gizmos/GLGizmoText.cpp
|
||||
#GUI/Gizmos/GLGizmoText.hpp
|
||||
GUI/GLCanvas3D.cpp
|
||||
@@ -580,8 +582,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
Utils/ESP3D.hpp
|
||||
Utils/FileHelp.cpp
|
||||
Utils/FileHelp.hpp
|
||||
Utils/FixModelByWin10.cpp
|
||||
Utils/FixModelByWin10.hpp
|
||||
Utils/FixModelByCgal.cpp
|
||||
Utils/FixModelByCgal.hpp
|
||||
Utils/FlashAir.cpp
|
||||
Utils/FlashAir.hpp
|
||||
Utils/Flashforge.cpp
|
||||
|
||||
@@ -236,7 +236,37 @@ void BBLTopbar::Init(wxFrame* parent)
|
||||
|
||||
wxInitAllImageHandlers();
|
||||
|
||||
this->AddSpacer(5);
|
||||
bool window_btns_on_left = false;
|
||||
|
||||
#ifdef __linux__
|
||||
window_btns_on_left = wxGetApp().app_config->get("window_buttons_on_left") == "true";
|
||||
|
||||
if(window_btns_on_left){
|
||||
wxBitmap close_bitmap = create_scaled_bitmap("topbar_close", nullptr, TOPBAR_ICON_SIZE);
|
||||
wxAuiToolBarItem* close_btn = this->AddTool(wxID_CLOSE_FRAME, "", close_bitmap);
|
||||
|
||||
this->AddSpacer(FromDIP(4));
|
||||
|
||||
maximize_bitmap = create_scaled_bitmap("topbar_max", nullptr, TOPBAR_ICON_SIZE);
|
||||
window_bitmap = create_scaled_bitmap("topbar_win", nullptr, TOPBAR_ICON_SIZE);
|
||||
if (m_frame->IsMaximized()) {
|
||||
maximize_btn = this->AddTool(wxID_MAXIMIZE_FRAME, "", window_bitmap);
|
||||
}
|
||||
else {
|
||||
maximize_btn = this->AddTool(wxID_MAXIMIZE_FRAME, "", maximize_bitmap);
|
||||
}
|
||||
|
||||
this->AddSpacer(FromDIP(4));
|
||||
|
||||
wxBitmap iconize_bitmap = create_scaled_bitmap("topbar_min", nullptr, TOPBAR_ICON_SIZE);
|
||||
wxAuiToolBarItem* iconize_btn = this->AddTool(wxID_ICONIZE_FRAME, "", iconize_bitmap);
|
||||
|
||||
this->AddSpacer(15);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!window_btns_on_left)
|
||||
this->AddSpacer(5);
|
||||
|
||||
/*wxBitmap logo_bitmap = create_scaled_bitmap("topbar_logo", nullptr, TOPBAR_ICON_SIZE);
|
||||
wxAuiToolBarItem* logo_item = this->AddTool(ID_LOGO, "", logo_bitmap);
|
||||
@@ -312,6 +342,7 @@ void BBLTopbar::Init(wxFrame* parent)
|
||||
//this->AddSeparator();
|
||||
//this->AddSpacer(FromDIP(4));
|
||||
|
||||
if(!window_btns_on_left){
|
||||
wxBitmap iconize_bitmap = create_scaled_bitmap("topbar_min", nullptr, TOPBAR_ICON_SIZE);
|
||||
wxAuiToolBarItem* iconize_btn = this->AddTool(wxID_ICONIZE_FRAME, "", iconize_bitmap);
|
||||
|
||||
@@ -330,6 +361,7 @@ void BBLTopbar::Init(wxFrame* parent)
|
||||
|
||||
wxBitmap close_bitmap = create_scaled_bitmap("topbar_close", nullptr, TOPBAR_ICON_SIZE);
|
||||
wxAuiToolBarItem* close_btn = this->AddTool(wxID_CLOSE_FRAME, "", close_bitmap);
|
||||
}
|
||||
|
||||
Realize();
|
||||
// m_toolbar_h = this->GetSize().GetHeight();
|
||||
|
||||
@@ -25,7 +25,7 @@ wxString get_calibration_type_name(CalibMode cali_mode)
|
||||
case CalibMode::Calib_PA_Line:
|
||||
return _L("Flow Dynamics");
|
||||
case CalibMode::Calib_Flow_Rate:
|
||||
return _L("Flow Rate");
|
||||
return _L("Flow ratio");
|
||||
case CalibMode::Calib_Vol_speed_Tower:
|
||||
return _L("Max Volumetric Speed");
|
||||
case CalibMode::Calib_Temp_Tower:
|
||||
|
||||
@@ -46,7 +46,7 @@ CloneDialog::CloneDialog(wxWindow *parent)
|
||||
m_progress->SetProgressForedColour(StateColor::darkModeColorFor(wxColour("#DFDFDF")));
|
||||
m_progress->SetDoubleBuffered(true);
|
||||
m_progress->Hide();
|
||||
bottom_sizer->Add(m_progress, 2, wxEXPAND | wxLEFT, FromDIP(10));
|
||||
bottom_sizer->Add(m_progress, 2, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(10));
|
||||
|
||||
auto dlg_btns = new DialogButtons(this, {"Fill", "OK", "Cancel"}, "", 1 /*left_aligned*/);
|
||||
|
||||
|
||||
@@ -513,6 +513,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
||||
// layer_height shouldn't be equal to zero
|
||||
float skin_depth = config->opt_float("skin_infill_depth");
|
||||
if (config->opt_float("infill_lock_depth") > skin_depth) {
|
||||
// xgettext:no-c-format, no-boost-format
|
||||
const wxString msg_text = _(L("Lock depth should smaller than skin depth.\nReset to 50% of skin depth."));
|
||||
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
|
||||
DynamicPrintConfig new_conf = *config;
|
||||
@@ -667,7 +668,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||
|
||||
bool have_default_acceleration = config->opt_float("default_acceleration") > 0;
|
||||
|
||||
for (auto el : {"outer_wall_acceleration", "inner_wall_acceleration", "initial_layer_acceleration",
|
||||
for (auto el : {"outer_wall_acceleration", "inner_wall_acceleration", "initial_layer_acceleration", "initial_layer_travel_acceleration",
|
||||
"top_surface_acceleration", "travel_acceleration", "bridge_acceleration", "sparse_infill_acceleration", "internal_solid_infill_acceleration"})
|
||||
toggle_field(el, have_default_acceleration);
|
||||
|
||||
@@ -681,13 +682,13 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||
if (machine_supports_junction_deviation) {
|
||||
toggle_field("default_junction_deviation", true);
|
||||
toggle_field("default_jerk", false);
|
||||
for (auto el : { "outer_wall_jerk", "inner_wall_jerk", "initial_layer_jerk", "top_surface_jerk", "travel_jerk", "infill_jerk"})
|
||||
toggle_line(el, false);
|
||||
for (auto el : { "outer_wall_jerk", "inner_wall_jerk", "initial_layer_jerk", "initial_layer_travel_jerk", "top_surface_jerk", "travel_jerk", "infill_jerk"})
|
||||
toggle_line(el, false);
|
||||
} else {
|
||||
toggle_field("default_junction_deviation", false);
|
||||
toggle_field("default_jerk", true);
|
||||
bool have_default_jerk = config->has("default_jerk") && config->opt_float("default_jerk") > 0;
|
||||
for (auto el : { "outer_wall_jerk", "inner_wall_jerk", "initial_layer_jerk", "top_surface_jerk", "travel_jerk", "infill_jerk"}) {
|
||||
for (auto el : { "outer_wall_jerk", "inner_wall_jerk", "initial_layer_jerk", "initial_layer_travel_jerk", "top_surface_jerk", "travel_jerk", "infill_jerk"}) {
|
||||
toggle_line(el, true);
|
||||
toggle_field(el, have_default_jerk);
|
||||
}
|
||||
@@ -706,6 +707,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||
bool have_brim_width = (config->opt_enum<BrimType>("brim_type") != btNoBrim) && config->opt_enum<BrimType>("brim_type") != btAutoBrim &&
|
||||
config->opt_enum<BrimType>("brim_type") != btPainted;
|
||||
toggle_field("brim_width", have_brim_width);
|
||||
toggle_field("brim_flow_ratio", have_brim);
|
||||
// wall_filament uses the same logic as in Print::extruders()
|
||||
toggle_field("wall_filament", have_perimeters || have_brim);
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ bool BitmapTextRenderer::GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value
|
||||
|
||||
// The icon can't be edited so get its old value and reuse it.
|
||||
wxVariant valueOld;
|
||||
GetView()->GetModel()->GetValue(valueOld, m_item, /*colName*/0);
|
||||
GetView()->GetModel()->GetValue(valueOld, m_item, Slic3r::GUI::ColumnNumber::colName);
|
||||
|
||||
DataViewBitmapText bmpText;
|
||||
bmpText << valueOld;
|
||||
@@ -265,13 +265,10 @@ bool BitmapChoiceRenderer::GetValue(wxVariant& value) const
|
||||
|
||||
bool BitmapChoiceRenderer::Render(wxRect rect, wxDC* dc, int state)
|
||||
{
|
||||
// int xoffset = 0;
|
||||
|
||||
const wxBitmap& icon = m_value.GetBitmap();
|
||||
if (icon.IsOk())
|
||||
{
|
||||
dc->DrawBitmap(icon, rect.x, rect.y + (rect.height - icon.GetHeight()) / 2);
|
||||
// xoffset = icon.GetWidth() + 4;
|
||||
|
||||
if (rect.height == 0)
|
||||
rect.height = icon.GetHeight();
|
||||
@@ -299,7 +296,6 @@ wxSize BitmapChoiceRenderer::GetSize() const
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
wxWindow* BitmapChoiceRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelRect, const wxVariant& value)
|
||||
{
|
||||
if (can_create_editor_ctrl && !can_create_editor_ctrl())
|
||||
@@ -316,7 +312,7 @@ wxWindow* BitmapChoiceRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelR
|
||||
labelRect.GetTopLeft(), wxSize(labelRect.GetWidth(), -1),
|
||||
0, nullptr, wxCB_READONLY | CB_NO_DROP_ICON | CB_NO_TEXT);
|
||||
c_editor->GetDropDown().SetUseContentWidth(true);
|
||||
|
||||
|
||||
if (has_default_extruder && has_default_extruder())
|
||||
c_editor->Append(_L("default"), *get_default_extruder_color_icon());
|
||||
|
||||
@@ -328,18 +324,19 @@ wxWindow* BitmapChoiceRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelR
|
||||
else
|
||||
c_editor->SetSelection(atoi(data.GetText().c_str()) - 1);
|
||||
|
||||
#ifdef __linux__
|
||||
// Open the dropdown immediately when the editor is focused.
|
||||
c_editor->Bind(wxEVT_SET_FOCUS, [c_editor](wxFocusEvent& evt) {
|
||||
c_editor->ForceDropdownOpen();
|
||||
evt.Skip();
|
||||
});
|
||||
|
||||
// Close editor after selection is made
|
||||
c_editor->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& evt) {
|
||||
// to avoid event propagation to other sidebar items
|
||||
evt.StopPropagation();
|
||||
evt.StopPropagation();
|
||||
// FinishEditing grabs new selection and triggers config update. We better call
|
||||
// it explicitly, automatic update on KILL_FOCUS didn't work on Linux.
|
||||
this->FinishEditing();
|
||||
});
|
||||
#else
|
||||
// to avoid event propagation to other sidebar items
|
||||
c_editor->Bind(wxEVT_COMBOBOX, [](wxCommandEvent& evt) { evt.StopPropagation(); });
|
||||
#endif
|
||||
|
||||
return c_editor;
|
||||
}
|
||||
|
||||
@@ -132,13 +132,9 @@ private:
|
||||
class BitmapChoiceRenderer : public wxDataViewCustomRenderer
|
||||
{
|
||||
public:
|
||||
BitmapChoiceRenderer(wxDataViewCellMode mode =
|
||||
//#ifdef __WXOSX__
|
||||
// wxDATAVIEW_CELL_INERT
|
||||
//#else
|
||||
wxDATAVIEW_CELL_EDITABLE
|
||||
//#endif
|
||||
, int align = wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL
|
||||
BitmapChoiceRenderer(
|
||||
wxDataViewCellMode mode = wxDATAVIEW_CELL_EDITABLE,
|
||||
int align = wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL
|
||||
) : wxDataViewCustomRenderer(wxT("DataViewBitmapText"), mode, align) {}
|
||||
|
||||
bool SetValue(const wxVariant& value) override;
|
||||
|
||||
@@ -80,6 +80,10 @@ static std::string get_view_type_string(libvgcode::EViewType view_type)
|
||||
return _u8L("Speed");
|
||||
else if (view_type == libvgcode::EViewType::ActualSpeed)
|
||||
return _u8L("Actual Speed");
|
||||
else if (view_type == libvgcode::EViewType::Acceleration)
|
||||
return _u8L("Acceleration");
|
||||
else if (view_type == libvgcode::EViewType::Jerk)
|
||||
return _u8L("Jerk");
|
||||
else if (view_type == libvgcode::EViewType::FanSpeed)
|
||||
return _u8L("Fan Speed");
|
||||
else if (view_type == libvgcode::EViewType::Temperature)
|
||||
@@ -385,6 +389,16 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode
|
||||
sprintf(buff, ("%.1f " + _u8L("mm/s")).c_str(), vertex.feedrate);
|
||||
const std::string text = std::string(buff);
|
||||
ImGuiWrapper::text(text);
|
||||
});
|
||||
append_table_row(_u8L("Acceleration"), [&vertex, &buff]() {
|
||||
sprintf(buff, ("%.0f " + _u8L("mm/s²")).c_str(), vertex.acceleration);
|
||||
const std::string text = std::string(buff);
|
||||
ImGuiWrapper::text(text);
|
||||
});
|
||||
append_table_row(_u8L("Jerk"), [&vertex, &buff]() {
|
||||
sprintf(buff, ("%.1f " + _u8L("mm/s")).c_str(), vertex.jerk);
|
||||
const std::string text = std::string(buff);
|
||||
ImGuiWrapper::text(text);
|
||||
});
|
||||
append_table_row(_u8L("Flow rate"), [&vertex, &buff, NA_TXT]() { // ORCA use "Flow rate" instead "Volumetric flow Rate" to make window more compact
|
||||
std::string text;
|
||||
@@ -620,6 +634,14 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode
|
||||
sprintf(buf, "%s %s%.1f", buf, _u8L("Actual Speed: ").c_str(), vertex.actual_feedrate);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::Acceleration: {
|
||||
sprintf(buf, "%s %s%.0f", buf, _u8L("Acceleration: ").c_str(), vertex.acceleration);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::Jerk: {
|
||||
sprintf(buf, "%s %s%.1f", buf, _u8L("Jerk: ").c_str(), vertex.jerk);
|
||||
break;
|
||||
}
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
case libvgcode::EViewType::PressureAdvance: {
|
||||
sprintf(buf, "%s %s%.4f", buf, _u8L("PA: ").c_str(), vertex.pressure_advance);
|
||||
@@ -1038,6 +1060,8 @@ void GCodeViewer::update_by_mode(ConfigOptionMode mode)
|
||||
view_type_items.push_back(libvgcode::EViewType::ColorPrint);
|
||||
view_type_items.push_back(libvgcode::EViewType::Speed);
|
||||
view_type_items.push_back(libvgcode::EViewType::ActualSpeed);
|
||||
view_type_items.push_back(libvgcode::EViewType::Acceleration);
|
||||
view_type_items.push_back(libvgcode::EViewType::Jerk);
|
||||
view_type_items.push_back(libvgcode::EViewType::Height);
|
||||
view_type_items.push_back(libvgcode::EViewType::Width);
|
||||
view_type_items.push_back(libvgcode::EViewType::VolumetricFlowRate);
|
||||
@@ -2586,6 +2610,8 @@ void GCodeViewer::render_toolpaths()
|
||||
add_range_property_row("height range", m_viewer.get_color_range(libvgcode::EViewType::Height).get_range());
|
||||
add_range_property_row("width range", m_viewer.get_color_range(libvgcode::EViewType::Width).get_range());
|
||||
add_range_property_row("speed range", m_viewer.get_color_range(libvgcode::EViewType::Speed).get_range());
|
||||
add_range_property_row("acceleration range", m_viewer.get_color_range(libvgcode::EViewType::Acceleration).get_range());
|
||||
add_range_property_row("jerk range", m_viewer.get_color_range(libvgcode::EViewType::Jerk).get_range());
|
||||
add_range_property_row("fan speed range", m_viewer.get_color_range(libvgcode::EViewType::FanSpeed).get_range());
|
||||
add_range_property_row("temperature range", m_viewer.get_color_range(libvgcode::EViewType::Temperature).get_range());
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
@@ -3836,6 +3862,16 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
imgui.title(_u8L("Actual Speed (mm/s)"));
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::Acceleration:
|
||||
{
|
||||
imgui.title(_u8L("Acceleration (mm/s²)"));
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::Jerk:
|
||||
{
|
||||
imgui.title(_u8L("Jerk (mm/s)"));
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::FanSpeed: { imgui.title(_u8L("Fan Speed (%)")); break; }
|
||||
case libvgcode::EViewType::Temperature: { imgui.title(_u8L("Temperature (°C)")); break; }
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
@@ -4014,6 +4050,38 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
ImGui::PopStyleVar(1);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::Acceleration: {
|
||||
append_range(m_viewer.get_color_range(libvgcode::EViewType::Acceleration), 0);
|
||||
ImGui::Spacing();
|
||||
ImGui::Dummy({ window_padding, window_padding });
|
||||
ImGui::SameLine();
|
||||
offsets = calculate_offsets({ { _u8L("Options"), { _u8L("Travel")}}, { _u8L("Display"), {""}} }, icon_size);
|
||||
append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} });
|
||||
const bool travel_visible = m_viewer.is_option_visible(libvgcode::EOptionType::Travels);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
|
||||
append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this, travel_visible]() {
|
||||
m_viewer.toggle_option_visibility(libvgcode::EOptionType::Travels);
|
||||
update_moves_slider();
|
||||
});
|
||||
ImGui::PopStyleVar(1);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::Jerk: {
|
||||
append_range(m_viewer.get_color_range(libvgcode::EViewType::Jerk), 1);
|
||||
ImGui::Spacing();
|
||||
ImGui::Dummy({ window_padding, window_padding });
|
||||
ImGui::SameLine();
|
||||
offsets = calculate_offsets({ { _u8L("Options"), { _u8L("Travel")}}, { _u8L("Display"), {""}} }, icon_size);
|
||||
append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} });
|
||||
const bool travel_visible = m_viewer.is_option_visible(libvgcode::EOptionType::Travels);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
|
||||
append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this, travel_visible]() {
|
||||
m_viewer.toggle_option_visibility(libvgcode::EOptionType::Travels);
|
||||
update_moves_slider();
|
||||
});
|
||||
ImGui::PopStyleVar(1);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::FanSpeed: { append_range(m_viewer.get_color_range(libvgcode::EViewType::FanSpeed), 0); break; }
|
||||
case libvgcode::EViewType::Temperature: { append_range(m_viewer.get_color_range(libvgcode::EViewType::Temperature), 0); break; }
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
@@ -4175,6 +4243,14 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
::sprintf(buf, "%d", m_print_statistics.total_filament_changes);
|
||||
imgui.text(buf);
|
||||
|
||||
//display tool change times
|
||||
ImGui::Dummy({window_padding, window_padding});
|
||||
ImGui::SameLine();
|
||||
imgui.text(_u8L("Tool changes") + ":");
|
||||
ImGui::SameLine();
|
||||
::sprintf(buf, "%d", m_print_statistics.total_extruder_changes);
|
||||
imgui.text(buf);
|
||||
|
||||
//BBS display cost
|
||||
ImGui::Dummy({ window_padding, window_padding });
|
||||
ImGui::SameLine();
|
||||
@@ -4370,6 +4446,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
{
|
||||
case libvgcode::EViewType::Speed:
|
||||
case libvgcode::EViewType::ActualSpeed:
|
||||
case libvgcode::EViewType::Acceleration:
|
||||
case libvgcode::EViewType::Jerk:
|
||||
case libvgcode::EViewType::Tool:
|
||||
case libvgcode::EViewType::ColorPrint: {
|
||||
break;
|
||||
|
||||
+50
-104
@@ -33,6 +33,7 @@
|
||||
#include "format.hpp"
|
||||
#include "DailyTips.hpp"
|
||||
#include "FilamentMapDialog.hpp"
|
||||
#include "Gizmos/GLGizmoUtils.hpp"
|
||||
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
@@ -224,43 +225,6 @@ bool GLCanvas3D::LayersEditing::is_allowed() const
|
||||
|
||||
float GLCanvas3D::LayersEditing::s_overlay_window_width;
|
||||
|
||||
void GLCanvas3D::LayersEditing::show_tooltip_information(const GLCanvas3D& canvas, std::map<wxString, wxString> captions_texts, float x, float y)
|
||||
{
|
||||
ImTextureID normal_id = canvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
|
||||
ImTextureID hover_id = canvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
|
||||
|
||||
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||
float caption_max = 0.f;
|
||||
for (auto caption_text : captions_texts) {
|
||||
caption_max = std::max(imgui.calc_text_size(caption_text.first).x, caption_max);
|
||||
}
|
||||
caption_max += GImGui->Style.WindowPadding.x + imgui.scaled(1);
|
||||
|
||||
float scale = canvas.get_scale();
|
||||
#ifdef WIN32
|
||||
int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
|
||||
scale *= (float) dpi / (float) DPI_DEFAULT;
|
||||
#endif // WIN32
|
||||
ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, 0}); // ORCA: Dont add padding
|
||||
ImGui::ImageButton3(normal_id, hover_id, button_size);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip2(ImVec2(x, y));
|
||||
auto draw_text_with_caption = [this, &caption_max, &imgui](const wxString& caption, const wxString& text) {
|
||||
imgui.text_colored(ImGuiWrapper::COL_ACTIVE, caption);
|
||||
ImGui::SameLine(caption_max);
|
||||
imgui.text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
|
||||
};
|
||||
|
||||
for (const auto& caption_text : captions_texts) draw_text_with_caption(caption_text.first, caption_text.second);
|
||||
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
|
||||
void GLCanvas3D::LayersEditing::render_variable_layer_height_dialog(const GLCanvas3D& canvas) {
|
||||
if (!m_enabled)
|
||||
return;
|
||||
@@ -358,15 +322,18 @@ void GLCanvas3D::LayersEditing::render_variable_layer_height_dialog(const GLCanv
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + canvas.m_main_toolbar.get_height();
|
||||
std::map<wxString, wxString> captions_texts = {
|
||||
{_L("Left mouse button") + ":" , _L("Add detail")},
|
||||
{_L("Right mouse button") + ":", _L("Remove detail")},
|
||||
{_L("Shift+") + _L("Left mouse button") + ":", _L("Reset to base")},
|
||||
{_L("Shift+") + _L("Right mouse button") + ":", _L("Smoothing")},
|
||||
{_L("Mouse wheel:"), _L("Increase/decrease edit area")}
|
||||
const wxString shift = GUI::shortkey_shift_prefix();
|
||||
std::vector<std::pair<wxString, wxString>> shortcuts = {
|
||||
{_L("Left mouse button"), _L("Add detail")},
|
||||
{_L("Right mouse button"), _L("Remove detail")},
|
||||
{shift + _L("Left mouse button"), _L("Reset to base")},
|
||||
{shift + _L("Right mouse button"), _L("Smoothing")},
|
||||
{_L("Mouse wheel"), _L("Increase/decrease edit area")}
|
||||
};
|
||||
show_tooltip_information(canvas, captions_texts, x, get_cur_y);
|
||||
|
||||
float y = canvas.m_main_toolbar.get_height();
|
||||
GLGizmoUtils::render_tooltip_button(&imgui, canvas, shortcuts, x, y);
|
||||
|
||||
ImGui::SameLine();
|
||||
if (imgui.button(_L("Reset")))
|
||||
wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), SimpleEvent(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE));
|
||||
@@ -1222,13 +1189,13 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed)
|
||||
|
||||
m_selection.set_volumes(&m_volumes.volumes);
|
||||
|
||||
m_assembly_view_desc["object_selection_caption"] = _L("Left mouse button");
|
||||
m_assembly_view_desc["object_selection"] = _L("Object selection");
|
||||
// FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent?
|
||||
m_assembly_view_desc["part_selection_caption"] = _L("Alt+") + _L("Left mouse button");
|
||||
m_assembly_view_desc["part_selection"] = _L("Part selection");
|
||||
m_assembly_view_desc["number_key_caption"] = "1~16 " + _L("number keys");
|
||||
m_assembly_view_desc["number_key"] = _L("Number keys can quickly change the color of objects");
|
||||
const wxString alt = GUI::shortkey_alt_prefix();
|
||||
|
||||
m_shortcuts_assembly_view = {
|
||||
{_L("Left mouse button"), _L("Object Selection")},
|
||||
{alt + _L("Left mouse button"), _L("Part Selection")},
|
||||
{"1~16 " + _L("number keys"), _L("Number keys can quickly change the color of objects")},
|
||||
};
|
||||
}
|
||||
|
||||
GLCanvas3D::~GLCanvas3D()
|
||||
@@ -4001,14 +3968,14 @@ void GLCanvas3D::on_set_color_timer(wxTimerEvent& evt)
|
||||
}
|
||||
|
||||
|
||||
void GLCanvas3D::schedule_extra_frame(int miliseconds)
|
||||
void GLCanvas3D::schedule_extra_frame(int milliseconds)
|
||||
{
|
||||
// Schedule idle event right now
|
||||
if (miliseconds == 0)
|
||||
if (milliseconds == 0)
|
||||
{
|
||||
// We want to wakeup idle evnt but most likely this is call inside render cycle so we need to wait
|
||||
// We want to wakeup idle event but most likely this is call inside render cycle so we need to wait
|
||||
if (m_in_render)
|
||||
miliseconds = 33;
|
||||
milliseconds = 33;
|
||||
else {
|
||||
m_dirty = true;
|
||||
wxWakeUpIdle();
|
||||
@@ -4018,12 +3985,12 @@ void GLCanvas3D::schedule_extra_frame(int miliseconds)
|
||||
int remaining_time = m_render_timer.GetInterval();
|
||||
// Timer is not running
|
||||
if (!m_render_timer.IsRunning()) {
|
||||
m_render_timer.StartOnce(miliseconds);
|
||||
// Timer is running - restart only if new period is shorter than remaning period
|
||||
m_render_timer.StartOnce(milliseconds);
|
||||
// Timer is running - restart only if new period is shorter than remaining period
|
||||
} else {
|
||||
if (miliseconds + 20 < remaining_time) {
|
||||
if (milliseconds + 20 < remaining_time) {
|
||||
m_render_timer.Stop();
|
||||
m_render_timer.StartOnce(miliseconds);
|
||||
m_render_timer.StartOnce(milliseconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9108,45 +9075,32 @@ void GLCanvas3D::_render_paint_toolbar() const
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
float GLCanvas3D::_show_assembly_tooltip_information(float caption_max, float x, float y) const
|
||||
float GLCanvas3D::_render_assembly_tooltip_button(ImGuiWrapper* imgui_wrapper) const
|
||||
{
|
||||
ImGuiWrapper *imgui = wxGetApp().imgui();
|
||||
ImTextureID normal_id = m_gizmos.get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
|
||||
ImTextureID hover_id = m_gizmos.get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
|
||||
const float text_height = imgui_wrapper->calc_text_size(_L("part selection")).y;
|
||||
ImVec2 windowPos = ImGui::GetWindowPos();
|
||||
float x = windowPos.x;
|
||||
float y = windowPos.y - ImGui::GetFrameHeight() - (5 * text_height);
|
||||
y -= ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight(); // correct default ToolTipButton behaviour
|
||||
|
||||
caption_max += imgui->calc_text_size(": "sv).x + 35.f;
|
||||
GLGizmoUtils::render_tooltip_button(imgui_wrapper, *this, m_shortcuts_assembly_view, x, y);
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(12.f, 0.f));
|
||||
|
||||
float scale = get_scale();
|
||||
#ifdef WIN32
|
||||
int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
|
||||
scale *= (float) dpi / (float) DPI_DEFAULT;
|
||||
#endif // WIN32
|
||||
float scale = get_scale();
|
||||
#ifdef WIN32
|
||||
int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
|
||||
scale *= (float) dpi / (float) DPI_DEFAULT;
|
||||
#endif // WIN32
|
||||
ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, ImGui::GetStyle().FramePadding.y});
|
||||
ImGui::ImageButton3(normal_id, hover_id, button_size);
|
||||
float same_line_width = button_size.x * 1.8; // with an space size
|
||||
ImGui::SameLine(same_line_width);
|
||||
same_line_width = imgui_wrapper->calc_text_size("|"sv).x + same_line_width + imgui_wrapper->calc_text_size(" "sv).x;
|
||||
imgui_wrapper->text_colored(ImGuiWrapper::COL_ACTIVE, "|");
|
||||
ImGui::SameLine(same_line_width);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip2(ImVec2(x, y));
|
||||
auto draw_text_with_caption = [&imgui, & caption_max](const wxString &caption, const wxString &text) {
|
||||
imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption);
|
||||
ImGui::SameLine(caption_max);
|
||||
imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
|
||||
};
|
||||
|
||||
for (const auto &t : std::array<std::string, 3>{"object_selection", "part_selection", "number_key"}) {
|
||||
draw_text_with_caption(m_assembly_view_desc.at(t + "_caption") + ": ", m_assembly_view_desc.at(t));
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
auto same_line_size = button_size.x * 1.8;//with an space size
|
||||
ImGui::SameLine(same_line_size);
|
||||
same_line_size = imgui->calc_text_size("|"sv).x + same_line_size + imgui->calc_text_size(" "sv).x;
|
||||
imgui->text_colored(ImGuiWrapper::COL_ACTIVE, "|");
|
||||
ImGui::SameLine(same_line_size);
|
||||
return same_line_size;
|
||||
return same_line_width; // return the width of the space taken by the tooltip button and the separator
|
||||
}
|
||||
|
||||
//BBS
|
||||
@@ -9180,19 +9134,11 @@ void GLCanvas3D::_render_assemble_control()
|
||||
imgui->begin(_L("Assemble Control"), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
float tip_icon_size;
|
||||
float tooltip_button_width;
|
||||
{
|
||||
float caption_max = 0.f;
|
||||
for (const auto &t : std::array<std::string, 3>{"object_selection", "part_selection", "number_key"}) {
|
||||
caption_max = std::max(caption_max, imgui->calc_text_size(m_assembly_view_desc.at(t + "_caption")).x);
|
||||
}
|
||||
const ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
const float text_y = imgui->calc_text_size(_L("Part selection")).y;
|
||||
float get_cur_x = pos.x;
|
||||
float get_cur_y = pos.y - ImGui::GetFrameHeight() - 4 * text_y;
|
||||
tip_icon_size =_show_assembly_tooltip_information(caption_max, get_cur_x, get_cur_y);
|
||||
tooltip_button_width = _render_assembly_tooltip_button(imgui);
|
||||
}
|
||||
float same_line_width = tip_icon_size;
|
||||
float same_line_width = tooltip_button_width;
|
||||
{
|
||||
float clp_dist = m_gizmos.m_assemble_view_data->model_objects_clipper()->get_position();
|
||||
if (clp_dist == 0.f) {
|
||||
|
||||
@@ -289,7 +289,6 @@ class GLCanvas3D
|
||||
bool is_enabled() const { return m_enabled; }
|
||||
void set_enabled(bool enabled) { m_enabled = is_allowed() && enabled; }
|
||||
|
||||
void show_tooltip_information(const GLCanvas3D& canvas, std::map<wxString, wxString> captions_texts, float x, float y);
|
||||
void render_variable_layer_height_dialog(const GLCanvas3D& canvas);
|
||||
void render_overlay(const GLCanvas3D& canvas);
|
||||
void render_volumes(const GLCanvas3D& canvas, const GLVolumeCollection& volumes);
|
||||
@@ -521,7 +520,8 @@ private:
|
||||
wxGLContext* m_context;
|
||||
SceneRaycaster m_scene_raycaster;
|
||||
Bed3D &m_bed;
|
||||
std::map<std::string, wxString> m_assembly_view_desc;
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts_assembly_view;
|
||||
#if ENABLE_RETINA_GL
|
||||
std::unique_ptr<RetinaHelper> m_retina_helper;
|
||||
#endif
|
||||
@@ -1119,7 +1119,7 @@ public:
|
||||
|
||||
void request_extra_frame() { m_extra_frame_requested = true; }
|
||||
|
||||
void schedule_extra_frame(int miliseconds);
|
||||
void schedule_extra_frame(int milliseconds);
|
||||
|
||||
int get_main_toolbar_item_id(const std::string& name) const { return m_main_toolbar.get_item_id(name); }
|
||||
void force_main_toolbar_left_action(int item_id) { m_main_toolbar.force_left_action(item_id, *this); }
|
||||
@@ -1273,7 +1273,7 @@ private:
|
||||
// BBS
|
||||
//void _render_view_toolbar() const;
|
||||
void _render_paint_toolbar() const;
|
||||
float _show_assembly_tooltip_information(float caption_max, float x, float y) const;
|
||||
float _render_assembly_tooltip_button(ImGuiWrapper* imgui_wrapper) const;
|
||||
void _render_assemble_control();
|
||||
void _render_assemble_info() const;
|
||||
#if ENABLE_SHOW_CAMERA_TARGET
|
||||
|
||||
@@ -78,6 +78,12 @@ void break_to_debugger()
|
||||
#endif /* _WIN32 */
|
||||
}
|
||||
|
||||
const std::string& shortkey_shift_prefix()
|
||||
{
|
||||
static const std::string str = _u8L("Shift+");
|
||||
return str;
|
||||
}
|
||||
|
||||
const std::string& shortkey_ctrl_prefix()
|
||||
{
|
||||
static const std::string str =
|
||||
|
||||
@@ -31,6 +31,7 @@ void break_to_debugger();
|
||||
// Platform specific Ctrl+/Alt+ (Windows, Linux) vs. ⌘/⌥ (OSX) prefixes
|
||||
extern const std::string& shortkey_ctrl_prefix();
|
||||
extern const std::string& shortkey_alt_prefix();
|
||||
extern const std::string& shortkey_shift_prefix(); // Shift is the same on all platforms, but we provide a function for consistency with Ctrl/Alt prefixes
|
||||
|
||||
extern AppConfig* get_app_config();
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include "slic3r/GUI/Tab.hpp"
|
||||
#include "slic3r/Utils/FixModelByWin10.hpp"
|
||||
#include "ParamsPanel.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "wx/utils.h"
|
||||
@@ -85,19 +84,18 @@ std::map<std::string, std::vector<SimpleSettingData>> SettingsFactory::OBJECT_C
|
||||
{"xy_hole_compensation", "",5}, {"xy_contour_compensation", "",6}, {"elefant_foot_compensation", "",7},
|
||||
{"make_overhang_printable_angle","", 8},{"make_overhang_printable_hole_size","",9}, {"wall_sequence","",10},
|
||||
{"precise_z_height", "",10}
|
||||
|
||||
}},
|
||||
{ L("Support"), {{"brim_type", "",1},{"brim_width", "",2},{"brim_object_gap", "",3},{"brim_use_efc_outline", "",4},
|
||||
{"enable_support", "",5},{"support_type", "",6},{"support_threshold_angle", "",7}, {"support_threshold_overlap", "",8}, {"support_on_build_plate_only", "",9},
|
||||
{"support_filament", "",10},{"support_interface_filament", "",11},{"support_expansion", "",12},{"support_style", "",13},
|
||||
{"tree_support_brim_width", "",14}, {"tree_support_branch_angle", "",15},{"tree_support_branch_angle_organic","",16}, {"tree_support_wall_count", "",17},{"tree_support_branch_diameter_angle", "",18},//tree support
|
||||
{"support_bottom_z_distance", "",19},{"support_top_z_distance", "",20},{"support_base_pattern", "",21},{"support_base_pattern_spacing", "",22},
|
||||
{"support_interface_top_layers", "",23},{"support_interface_bottom_layers", "",24},{"support_interface_spacing", "",25},{"support_bottom_interface_spacing", "",26},
|
||||
{"support_object_xy_distance", "",27}, {"bridge_no_support", "",28},{"max_bridge_length", "",29},{"support_critical_regions_only", "",30},{"support_remove_small_overhang","",31},
|
||||
{"support_object_first_layer_gap","",32}
|
||||
}},
|
||||
{ L("Support"), {{"brim_type", "",1},{"brim_width", "",2},{"brim_object_gap", "",3},{"brim_flow_ratio", "",4},{"brim_use_efc_outline", "",5},
|
||||
{"enable_support", "",6},{"support_type", "",7},{"support_threshold_angle", "",8}, {"support_threshold_overlap", "",9}, {"support_on_build_plate_only", "",10},
|
||||
{"support_filament", "",11},{"support_interface_filament", "",12},{"support_expansion", "",13},{"support_style", "",14},
|
||||
{"tree_support_brim_width", "",15}, {"tree_support_branch_angle", "",16},{"tree_support_branch_angle_organic","",17}, {"tree_support_wall_count", "",18},{"tree_support_branch_diameter_angle", "",19},//tree support
|
||||
{"support_bottom_z_distance", "",20},{"support_top_z_distance", "",21},{"support_base_pattern", "",22},{"support_base_pattern_spacing", "",23},
|
||||
{"support_interface_top_layers", "",24},{"support_interface_bottom_layers", "",25},{"support_interface_spacing", "",26},{"support_bottom_interface_spacing", "",27},
|
||||
{"support_object_xy_distance", "",28}, {"bridge_no_support", "",29},{"max_bridge_length", "",30},{"support_critical_regions_only", "",31},{"support_remove_small_overhang","",32},
|
||||
{"support_object_first_layer_gap","",33}
|
||||
}},
|
||||
{ L("Speed"), {{"support_speed", "",12}, {"support_interface_speed", "",13}
|
||||
}}
|
||||
}}
|
||||
};
|
||||
|
||||
std::map<std::string, std::vector<SimpleSettingData>> SettingsFactory::PART_CATEGORY_SETTINGS=
|
||||
@@ -109,7 +107,7 @@ std::map<std::string, std::vector<SimpleSettingData>> SettingsFactory::PART_CAT
|
||||
{"sparse_infill_density", "",1},{"sparse_infill_pattern", "",1},{"lateral_lattice_angle_1", "",1},{"lateral_lattice_angle_2", "",1},{"infill_overhang_angle", "",1},{"infill_anchor", "",1},{"infill_anchor_max", "",1},{"top_surface_pattern", "",1},{"bottom_surface_pattern", "",1}, {"internal_solid_infill_pattern", "",1},
|
||||
{"align_infill_direction_to_model", "", 1},
|
||||
{"extra_solid_infills", "", 1},
|
||||
{"infill_combination", "",1}, {"infill_combination_max_layer_height", "",1}, {"infill_wall_overlap", "",1},{"top_bottom_infill_wall_overlap", "",1}, {"solid_infill_direction", "",1}, {"infill_direction", "",1}, {"bridge_angle", "",1}, {"internal_bridge_angle", "",1}, {"minimum_sparse_infill_area", "",1}
|
||||
{"infill_combination", "",1}, {"infill_combination_max_layer_height", "",1}, {"infill_wall_overlap", "",1},{"top_bottom_infill_wall_overlap", "",1}, {"solid_infill_direction", "",1}, {"infill_direction", "",1}, {"bridge_angle", "",1}, {"internal_bridge_angle", "",1}, {"minimum_sparse_infill_area", "",1}
|
||||
}},
|
||||
{ L("Speed"), {{"outer_wall_speed", "",1},{"inner_wall_speed", "",2},{"sparse_infill_speed", "",3},{"top_surface_speed", "",4}, {"internal_solid_infill_speed", "",5},
|
||||
{"enable_overhang_speed", "",6}, {"overhang_1_4_speed", "",7}, {"overhang_2_4_speed", "",8}, {"overhang_3_4_speed", "",9}, {"overhang_4_4_speed", "",10},
|
||||
@@ -880,14 +878,11 @@ void MenuFactory::append_menu_item_rename(wxMenu* menu)
|
||||
menu->AppendSeparator();
|
||||
}
|
||||
|
||||
wxMenuItem* MenuFactory::append_menu_item_fix_through_netfabb(wxMenu* menu)
|
||||
wxMenuItem* MenuFactory::append_menu_item_fix_through_cgal(wxMenu* menu)
|
||||
{
|
||||
if (!is_windows10())
|
||||
return nullptr;
|
||||
|
||||
wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Fix model"), "",
|
||||
[](wxCommandEvent&) { obj_list()->fix_through_netfabb(); }, "", menu,
|
||||
[]() {return plater()->can_fix_through_netfabb(); }, plater());
|
||||
[](wxCommandEvent&) { obj_list()->fix_through_cgal(); }, "", menu,
|
||||
[]() {return plater()->can_fix_through_cgal(); }, plater());
|
||||
|
||||
return menu_item;
|
||||
}
|
||||
@@ -1357,7 +1352,7 @@ void MenuFactory::create_common_object_menu(wxMenu* menu)
|
||||
// "Scale to print volume" makes a sense just for whole object
|
||||
append_menu_item_scale_selection_to_fit_print_volume(menu);
|
||||
|
||||
append_menu_item_fix_through_netfabb(menu);
|
||||
append_menu_item_fix_through_cgal(menu);
|
||||
append_menu_items_mirror(menu);
|
||||
}
|
||||
|
||||
@@ -1396,7 +1391,7 @@ void MenuFactory::create_extra_object_menu()
|
||||
// Object Clone
|
||||
append_menu_item_clone(&m_object_menu);
|
||||
// Object Repair
|
||||
append_menu_item_fix_through_netfabb(&m_object_menu);
|
||||
append_menu_item_fix_through_cgal(&m_object_menu);
|
||||
// Object Simplify
|
||||
append_menu_item_simplify(&m_object_menu);
|
||||
// Object Mesh Subdivision
|
||||
@@ -1453,7 +1448,7 @@ void MenuFactory::create_bbl_assemble_object_menu()
|
||||
// Delete
|
||||
append_menu_item_delete(&m_assemble_object_menu);
|
||||
// Object Repair
|
||||
append_menu_item_fix_through_netfabb(&m_assemble_object_menu);
|
||||
append_menu_item_fix_through_cgal(&m_assemble_object_menu);
|
||||
// Object Simplify
|
||||
append_menu_item_simplify(&m_assemble_object_menu);
|
||||
// Object Mesh Subdivision
|
||||
@@ -1483,7 +1478,7 @@ void MenuFactory::create_part_menu()
|
||||
append_menu_item_reload_from_disk(menu);
|
||||
append_menu_item_export_stl(menu);
|
||||
append_menu_item_export_drc(menu);
|
||||
append_menu_item_fix_through_netfabb(menu);
|
||||
append_menu_item_fix_through_cgal(menu);
|
||||
append_menu_items_mirror(menu);
|
||||
append_menu_item_merge_parts_to_single_part(menu);
|
||||
|
||||
@@ -1508,7 +1503,7 @@ void MenuFactory::create_text_part_menu()
|
||||
|
||||
append_menu_item_edit_text(menu);
|
||||
append_menu_item_delete(menu);
|
||||
append_menu_item_fix_through_netfabb(menu);
|
||||
append_menu_item_fix_through_cgal(menu);
|
||||
append_menu_item_simplify(menu);
|
||||
append_menu_item_center(menu);
|
||||
append_menu_items_mirror(menu);
|
||||
@@ -1524,7 +1519,7 @@ void MenuFactory::create_svg_part_menu()
|
||||
|
||||
append_menu_item_edit_svg(menu);
|
||||
append_menu_item_delete(menu);
|
||||
append_menu_item_fix_through_netfabb(menu);
|
||||
append_menu_item_fix_through_cgal(menu);
|
||||
append_menu_item_simplify(menu);
|
||||
append_menu_items_mirror(menu);
|
||||
menu->AppendSeparator();
|
||||
@@ -1539,7 +1534,7 @@ void MenuFactory::create_bbl_part_menu()
|
||||
|
||||
append_menu_item_delete(menu);
|
||||
append_menu_item_edit_text(menu);
|
||||
append_menu_item_fix_through_netfabb(menu);
|
||||
append_menu_item_fix_through_cgal(menu);
|
||||
append_menu_item_simplify(menu);
|
||||
append_menu_item_smooth_mesh(menu);
|
||||
append_menu_item_center(menu);
|
||||
@@ -1860,7 +1855,7 @@ wxMenu* MenuFactory::multi_selection_menu()
|
||||
}
|
||||
append_menu_item_center(menu);
|
||||
append_menu_item_drop(menu);
|
||||
append_menu_item_fix_through_netfabb(menu);
|
||||
append_menu_item_fix_through_cgal(menu);
|
||||
//append_menu_item_simplify(menu);
|
||||
append_menu_item_delete(menu);
|
||||
menu->AppendSeparator();
|
||||
@@ -1885,7 +1880,7 @@ wxMenu* MenuFactory::multi_selection_menu()
|
||||
else {
|
||||
append_menu_item_center(menu);
|
||||
append_menu_item_drop(menu);
|
||||
append_menu_item_fix_through_netfabb(menu);
|
||||
append_menu_item_fix_through_cgal(menu);
|
||||
//append_menu_item_simplify(menu);
|
||||
append_menu_item_delete(menu);
|
||||
append_menu_items_convert_unit(menu);
|
||||
@@ -1923,7 +1918,7 @@ wxMenu* MenuFactory::assemble_multi_selection_menu()
|
||||
|
||||
wxMenu* menu = new MenuWithSeparators();
|
||||
append_menu_item_set_visible(menu);
|
||||
//append_menu_item_fix_through_netfabb(menu);
|
||||
//append_menu_item_fix_through_cgal(menu);
|
||||
//append_menu_item_simplify(menu);
|
||||
append_menu_item_delete(menu);
|
||||
menu->AppendSeparator();
|
||||
@@ -1973,7 +1968,7 @@ wxMenu* MenuFactory::assemble_object_menu()
|
||||
// Delete
|
||||
append_menu_item_delete(menu);
|
||||
//// Object Repair
|
||||
//append_menu_item_fix_through_netfabb(menu);
|
||||
//append_menu_item_fix_through_cgal(menu);
|
||||
//// Object Simplify
|
||||
//append_menu_item_simplify(menu);
|
||||
menu->AppendSeparator();
|
||||
|
||||
@@ -139,7 +139,7 @@ private:
|
||||
wxMenuItem* append_menu_item_printable(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_auto_drop(wxMenu* menu);
|
||||
void append_menu_item_rename(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_fix_through_cgal(wxMenu* menu);
|
||||
//wxMenuItem* append_menu_item_simplify(wxMenu* menu);
|
||||
void append_menu_item_export_stl(wxMenu* menu, bool is_mulity_menu = false);
|
||||
void append_menu_item_export_drc(wxMenu* menu, bool is_mulity_menu = false);
|
||||
|
||||
@@ -29,13 +29,14 @@
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <wx/progdlg.h>
|
||||
#include <wx/listbook.h>
|
||||
#include <wx/numformatter.h>
|
||||
#include <wx/utils.h>
|
||||
#include <wx/headerctrl.h>
|
||||
|
||||
#include "slic3r/Utils/FixModelByWin10.hpp"
|
||||
#include "slic3r/Utils/FixModelByCgal.hpp"
|
||||
#include "libslic3r/Format/bbs_3mf.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
@@ -459,6 +460,15 @@ void ObjectList::create_objects_ctrl()
|
||||
AppendBitmapColumn(" ", colEditing, wxOSX ? wxDATAVIEW_CELL_EDITABLE : wxDATAVIEW_CELL_INERT, m_columns_width[colEditing] * em,
|
||||
wxALIGN_CENTER_HORIZONTAL, 0);
|
||||
|
||||
|
||||
// Open filament editor faster
|
||||
this->Bind(wxEVT_DATAVIEW_ITEM_ACTIVATED, [this](wxDataViewEvent& event) {
|
||||
if (event.GetColumn() == colFilament) {
|
||||
// Trigger the editor opening manually
|
||||
this->EditItem(event.GetItem(), GetColumn(colFilament));
|
||||
}
|
||||
});
|
||||
|
||||
//for (int cn = colName; cn < colCount; cn++) {
|
||||
// GetColumn(cn)->SetResizeable(cn == colName);
|
||||
//}
|
||||
@@ -568,7 +578,7 @@ MeshErrorsInfo ObjectList::get_mesh_errors_info(const int obj_idx, const int vol
|
||||
if (non_manifold_edges)
|
||||
*non_manifold_edges = stats.open_edges;
|
||||
|
||||
if (is_windows10() && !sidebar_info)
|
||||
if (!sidebar_info)
|
||||
tooltip += "\n" + _L("Click the icon to repair model object");
|
||||
|
||||
return { tooltip, get_warning_icon_name(stats) };
|
||||
@@ -1540,9 +1550,9 @@ void ObjectList::list_manipulation(const wxPoint& mouse_pos, bool evt_context_me
|
||||
}
|
||||
else if (col_num == colName)
|
||||
{
|
||||
if (is_windows10() && m_objects_model->HasWarningIcon(item) &&
|
||||
if (m_objects_model->HasWarningIcon(item) &&
|
||||
mouse_pos.x > 2 * wxGetApp().em_unit() && mouse_pos.x < 4 * wxGetApp().em_unit())
|
||||
fix_through_netfabb();
|
||||
fix_through_cgal();
|
||||
else if (evt_context_menu)
|
||||
show_context_menu(evt_context_menu); // show context menu for "Name" column too
|
||||
}
|
||||
@@ -5377,6 +5387,11 @@ ModelVolume* ObjectList::get_selected_model_volume()
|
||||
return (*m_objects)[obj_idx]->volumes[vol_idx];
|
||||
}
|
||||
|
||||
// ORCA: kept as dead code (not called by any active path). Preserved in #if 0
|
||||
// form for traceability with upstream Bambu Studio -- removing outright would
|
||||
// produce merge conflicts on every BBL sync. The active "Change Type" UI goes
|
||||
// through the submenu in GUI_Factories.cpp -> ObjectList::set_volume_type().
|
||||
#if 0
|
||||
void ObjectList::change_part_type()
|
||||
{
|
||||
wxDataViewItemArray selections;
|
||||
@@ -5573,6 +5588,7 @@ void ObjectList::change_part_type()
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ModelVolumeType ObjectList::get_selected_volume_type()
|
||||
{
|
||||
@@ -5646,6 +5662,26 @@ void ObjectList::set_volume_type(ModelVolumeType new_type)
|
||||
return;
|
||||
}
|
||||
|
||||
// Defense-in-depth safety net against issue #5070: SVG/text volumes carry emboss metadata
|
||||
// (text_configuration, emboss_shape) that only makes sense for Part / Negative Part / Modifier.
|
||||
// ModelVolume::set_type() does not clear that metadata, so converting such volumes to
|
||||
// Support Blocker / Support Enforcer leaves stale emboss state attached to a support volume
|
||||
// and historically crashed (originally fixed in the now-disabled change_part_type() by hiding
|
||||
// Support entries in the old choice dialog; the UI-side guard for the current submenu lives
|
||||
// in MenuFactory::append_menu_item_change_type, see #13120).
|
||||
// This block must never be reachable under a healthy UI; if it ever logs, the UI guard has
|
||||
// been bypassed (new entry point, refactor, plugin, etc.) and should be investigated.
|
||||
if (new_type == ModelVolumeType::SUPPORT_BLOCKER || new_type == ModelVolumeType::SUPPORT_ENFORCER) {
|
||||
const bool has_text_or_svg = std::any_of(volumes.begin(), volumes.end(),
|
||||
[](const VolumeSelection& sel) { return sel.volume->is_svg() || sel.volume->is_text(); });
|
||||
if (has_text_or_svg) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__
|
||||
<< ": blocked attempt to set SUPPORT_BLOCKER/ENFORCER on SVG/text volume; "
|
||||
<< "UI guard should have prevented this -- possible regression in the Change Type menu";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const bool any_diff = std::any_of(volumes.begin(), volumes.end(),
|
||||
[new_type](const VolumeSelection& sel) { return sel.volume->type() != new_type; });
|
||||
|
||||
@@ -5948,7 +5984,7 @@ void ObjectList::rename_item()
|
||||
update_name_in_model(item);
|
||||
}
|
||||
|
||||
void ObjectList::fix_through_netfabb()
|
||||
void ObjectList::fix_through_cgal()
|
||||
{
|
||||
// Do not fix anything when a gizmo is open. There might be issues with updates
|
||||
// and what is worse, the snapshot time would refer to the internal stack.
|
||||
@@ -5968,11 +6004,11 @@ void ObjectList::fix_through_netfabb()
|
||||
// clear selections from the non-broken models if any exists
|
||||
// and than fill names of models to repairing
|
||||
if (vol_idxs.empty()) {
|
||||
#if !FIX_THROUGH_NETFABB_ALWAYS
|
||||
#if !FIX_THROUGH_CGAL_ALWAYS
|
||||
for (int i = int(obj_idxs.size())-1; i >= 0; --i)
|
||||
if (object(obj_idxs[i])->get_repaired_errors_count() == 0)
|
||||
obj_idxs.erase(obj_idxs.begin()+i);
|
||||
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
||||
#endif // FIX_THROUGH_CGAL_ALWAYS
|
||||
for (int obj_idx : obj_idxs)
|
||||
if (object(obj_idx))
|
||||
model_names.push_back(object(obj_idx)->name);
|
||||
@@ -5980,11 +6016,11 @@ void ObjectList::fix_through_netfabb()
|
||||
else {
|
||||
ModelObject* obj = object(obj_idxs.front());
|
||||
if (obj) {
|
||||
#if !FIX_THROUGH_NETFABB_ALWAYS
|
||||
#if !FIX_THROUGH_CGAL_ALWAYS
|
||||
for (int i = int(vol_idxs.size()) - 1; i >= 0; --i)
|
||||
if (obj->get_repaired_errors_count(vol_idxs[i]) == 0)
|
||||
vol_idxs.erase(vol_idxs.begin() + i);
|
||||
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
||||
#endif // FIX_THROUGH_CGAL_ALWAYS
|
||||
for (int vol_idx : vol_idxs)
|
||||
model_names.push_back(obj->volumes[vol_idx]->name);
|
||||
}
|
||||
@@ -6013,13 +6049,18 @@ void ObjectList::fix_through_netfabb()
|
||||
}
|
||||
|
||||
plater->clear_before_change_mesh(obj_idx);
|
||||
const size_t volumes_before = object(obj_idx)->volumes.size();
|
||||
std::string res;
|
||||
if (!fix_model_by_win10_sdk_gui(*(object(obj_idx)), vol_idx, progress_dlg, msg, res))
|
||||
if (!fix_model_with_cgal_gui(*(object(obj_idx)), vol_idx, progress_dlg, msg, res))
|
||||
return false;
|
||||
//wxGetApp().plater()->changed_mesh(obj_idx);
|
||||
object(obj_idx)->ensure_on_bed();
|
||||
plater->changed_mesh(obj_idx);
|
||||
|
||||
const size_t volumes_after = object(obj_idx)->volumes.size();
|
||||
if (volumes_after != volumes_before)
|
||||
add_volumes_to_object_in_list(obj_idx);
|
||||
|
||||
plater->get_partplate_list().notify_instance_update(obj_idx, 0);
|
||||
plater->sidebar().obj_list()->update_plate_values_for_items();
|
||||
|
||||
@@ -6043,10 +6084,10 @@ void ObjectList::fix_through_netfabb()
|
||||
if (vol_idxs.empty()) {
|
||||
int vol_idx{ -1 };
|
||||
for (int obj_idx : obj_idxs) {
|
||||
#if !FIX_THROUGH_NETFABB_ALWAYS
|
||||
#if !FIX_THROUGH_CGAL_ALWAYS
|
||||
if (object(obj_idx)->get_repaired_errors_count(vol_idx) == 0)
|
||||
continue;
|
||||
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
||||
#endif // FIX_THROUGH_CGAL_ALWAYS
|
||||
if (!fix_and_update_progress(obj_idx, vol_idx, model_idx, progress_dlg, succes_models, failed_models))
|
||||
break;
|
||||
model_idx++;
|
||||
@@ -6079,7 +6120,7 @@ void ObjectList::fix_through_netfabb()
|
||||
}
|
||||
if (msg.IsEmpty())
|
||||
msg = _L("Repairing was canceled");
|
||||
plater->get_notification_manager()->push_notification(NotificationType::NetfabbFinished, NotificationManager::NotificationLevel::PrintInfoShortNotificationLevel, into_u8(msg));
|
||||
plater->get_notification_manager()->push_notification(NotificationType::CgalFinished, NotificationManager::NotificationLevel::PrintInfoShortNotificationLevel, into_u8(msg));
|
||||
}
|
||||
|
||||
void ObjectList::simplify()
|
||||
|
||||
@@ -37,7 +37,7 @@ typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
|
||||
typedef std::map<t_layer_height_range, ModelConfig> t_layer_config_ranges;
|
||||
|
||||
// Manifold mesh may contain self-intersections, so we want to always allow fixing the mesh.
|
||||
#define FIX_THROUGH_NETFABB_ALWAYS 1
|
||||
#define FIX_THROUGH_CGAL_ALWAYS 1
|
||||
|
||||
namespace GUI {
|
||||
struct ObjectVolumeID {
|
||||
@@ -413,7 +413,9 @@ public:
|
||||
bool fix_cut_selection(wxDataViewItemArray &sels);
|
||||
|
||||
ModelVolume* get_selected_model_volume();
|
||||
#if 0 // ORCA: disabled alongside definition in GUI_ObjectList.cpp (see #if 0 block there)
|
||||
void change_part_type();
|
||||
#endif
|
||||
void set_volume_type(ModelVolumeType new_type);
|
||||
ModelVolumeType get_selected_volume_type();
|
||||
|
||||
@@ -428,7 +430,7 @@ public:
|
||||
void instances_to_separated_objects(const int obj_idx);
|
||||
void split_instances();
|
||||
void rename_item();
|
||||
void fix_through_netfabb();
|
||||
void fix_through_cgal();
|
||||
void simplify();
|
||||
void smooth_mesh();
|
||||
void update_item_error_icon(const int obj_idx, int vol_idx) const ;
|
||||
|
||||
@@ -3277,7 +3277,7 @@ void ObjectTablePanel::msw_rescale() {
|
||||
// ObjectTableDialog
|
||||
// ----------------------------------------------------------------------------
|
||||
ObjectTableDialog::ObjectTableDialog(wxWindow* parent, Plater* platerObj, Model *modelObj, wxSize maxSize)
|
||||
: GUI::DPIDialog(parent, wxID_ANY, _L("Object/Part Setting"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX | wxRESIZE_BORDER)
|
||||
: GUI::DPIDialog(parent, wxID_ANY, _L("Object/Part Settings"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX | wxRESIZE_BORDER)
|
||||
,
|
||||
m_model(modelObj), m_plater(platerObj)
|
||||
{
|
||||
@@ -3410,7 +3410,9 @@ void ObjectTableDialog::OnClose(wxCloseEvent &evt)
|
||||
|
||||
void ObjectTableDialog::OnText(wxKeyEvent &evt)
|
||||
{
|
||||
if (evt.GetKeyCode() != WXK_ESCAPE) {
|
||||
if (evt.GetKeyCode() == WXK_ESCAPE) {
|
||||
Close();
|
||||
} else {
|
||||
evt.Skip();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -659,8 +659,7 @@ void GLGizmoAdvancedCut::perform_cut(const Selection& selection)
|
||||
cut_with_groove ? cut.perform_with_groove(m_groove, m_rotate_matrix) :
|
||||
cut.perform_with_plane();
|
||||
// fix_non_manifold_edges
|
||||
#ifdef HAS_WIN10SDK
|
||||
if (is_windows10()) {
|
||||
{
|
||||
bool is_showed_dialog = false;
|
||||
bool user_fix_model = false;
|
||||
for (size_t i = 0; i < new_objects.size(); i++) {
|
||||
@@ -687,7 +686,7 @@ void GLGizmoAdvancedCut::perform_cut(const Selection& selection)
|
||||
wxString msg = _L("Repairing model object");
|
||||
msg += ": " + from_u8(model_name) + "\n";
|
||||
std::string res;
|
||||
if (!fix_model_by_win10_sdk_gui(*model_object, vol_idx, progress_dlg, msg, res)) return false;
|
||||
if (!fix_model_with_cgal_gui(*model_object, vol_idx, progress_dlg, msg, res)) return false;
|
||||
return true;
|
||||
};
|
||||
ProgressDialog progress_dlg(_L("Repairing model object"), "", 100, find_toplevel_parent(plater), wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT, true);
|
||||
@@ -700,7 +699,6 @@ void GLGizmoAdvancedCut::perform_cut(const Selection& selection)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// set offset for new_objects
|
||||
|
||||
// save cut_id to post update synchronization
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
#include "GLGizmoUtils.hpp"
|
||||
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/MeasureUtils.hpp"
|
||||
@@ -43,6 +44,8 @@ std::string GLGizmoAssembly::on_get_name() const
|
||||
|
||||
bool GLGizmoAssembly::on_init()
|
||||
{
|
||||
GLGizmoMeasure::on_init();
|
||||
|
||||
m_shortcut_key = WXK_CONTROL_Y;
|
||||
return true;
|
||||
}
|
||||
@@ -108,14 +111,8 @@ void GLGizmoAssembly::on_render_input_window(float x, float y, float bottom_limi
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
float caption_max = 0.f;
|
||||
float total_text_max = 0.f;
|
||||
for (const auto &t : std::array<std::string, 3>{"point_selection", "reset", "unselect"}) {
|
||||
caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x);
|
||||
total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x);
|
||||
}
|
||||
show_tooltip_information(caption_max, x, get_cur_y);
|
||||
|
||||
GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, m_shortcuts, x, y);
|
||||
|
||||
float f_scale =m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
#include "libslic3r/ExPolygon.hpp"
|
||||
#include "GLGizmoUtils.hpp"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
@@ -44,10 +45,8 @@ bool GLGizmoBrimEars::on_init()
|
||||
|
||||
m_shortcut_key = WXK_CONTROL_E;
|
||||
|
||||
// FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent?
|
||||
const wxString ctrl = _L("Ctrl+");
|
||||
// FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent?
|
||||
const wxString alt = _L("Alt+");
|
||||
const wxString ctrl = GUI::shortkey_ctrl_prefix();
|
||||
const wxString alt = GUI::shortkey_alt_prefix();
|
||||
|
||||
m_desc["head_diameter"] = _L("Head diameter");
|
||||
m_desc["max_angle"] = _L("Max angle");
|
||||
@@ -57,14 +56,12 @@ bool GLGizmoBrimEars::on_init()
|
||||
m_desc["auto_generate"] = _L("Auto-generate points");
|
||||
m_desc["section_view"] = _L("Section view");
|
||||
|
||||
m_desc["left_click_caption"] = _L("Left click");
|
||||
m_desc["left_click"] = _L("Add a brim ear");
|
||||
m_desc["right_click_caption"] = _L("Right click");
|
||||
m_desc["right_click"] = _L("Delete a brim ear");
|
||||
m_desc["ctrl_mouse_wheel_caption"] = ctrl + _L("Mouse wheel");
|
||||
m_desc["ctrl_mouse_wheel"] = _L("Adjust head diameter");
|
||||
m_desc["alt_mouse_wheel_caption"] = alt + _L("Mouse wheel");
|
||||
m_desc["alt_mouse_wheel"] = _L("Adjust section view");
|
||||
m_shortcuts = {
|
||||
{_L("Left mouse button"), _L("Add a brim ear")},
|
||||
{_L("Right mouse button"), _L("Delete a brim ear")},
|
||||
{ctrl + _L("Mouse wheel"), _L("Adjust head diameter")},
|
||||
{alt + _L("Mouse wheel"), _L("Adjust section view")},
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -737,7 +734,8 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi
|
||||
ImGui::PopStyleVar(1);
|
||||
|
||||
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
show_tooltip_information(x, get_cur_y);
|
||||
|
||||
GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, m_shortcuts, x, y);
|
||||
|
||||
if (glb_cfg.opt_enum<BrimType>("brim_type") != btPainted) {
|
||||
ImGui::SameLine();
|
||||
@@ -790,41 +788,6 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi
|
||||
ImGuiWrapper::pop_toolbar_style();
|
||||
}
|
||||
|
||||
void GLGizmoBrimEars::show_tooltip_information(float x, float y)
|
||||
{
|
||||
std::array<std::string, 4> info_array = std::array<std::string, 4>{"left_click", "right_click", "ctrl_mouse_wheel", "alt_mouse_wheel"};
|
||||
float caption_max = 0.f;
|
||||
for (const auto &t : info_array) { caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); }
|
||||
|
||||
ImTextureID normal_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
|
||||
ImTextureID hover_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
|
||||
|
||||
caption_max += m_imgui->calc_text_size(": "sv).x + 35.f;
|
||||
|
||||
float scale = m_parent.get_scale();
|
||||
#ifdef WIN32
|
||||
int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
|
||||
scale *= (float) dpi / (float) DPI_DEFAULT;
|
||||
#endif // WIN32
|
||||
ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, 0}); // ORCA: Dont add padding
|
||||
ImGui::ImageButton3(normal_id, hover_id, button_size);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip2(ImVec2(x, y));
|
||||
auto draw_text_with_caption = [this, &caption_max](const wxString &caption, const wxString &text) {
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption);
|
||||
ImGui::SameLine(caption_max);
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
|
||||
};
|
||||
|
||||
for (const auto &t : info_array) draw_text_with_caption(m_desc.at(t + "_caption") + ": ", m_desc.at(t));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
|
||||
bool GLGizmoBrimEars::on_is_activable() const
|
||||
{
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
|
||||
@@ -117,6 +117,9 @@ private:
|
||||
// This map holds all translated description texts, so they can be easily referenced during layout calculations
|
||||
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.
|
||||
std::map<std::string, wxString> m_desc;
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts;
|
||||
|
||||
|
||||
GLSelectionRectangle m_selection_rectangle;
|
||||
|
||||
@@ -159,7 +162,6 @@ protected:
|
||||
void on_start_dragging() override;
|
||||
void on_stop_dragging() override;
|
||||
void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
void show_tooltip_information(float x, float y);
|
||||
|
||||
std::string on_get_name() const override;
|
||||
bool on_is_activable() const override;
|
||||
|
||||
@@ -12,11 +12,12 @@
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
#include "libslic3r/TriangleMeshSlicer.hpp"
|
||||
#include "GLGizmoUtils.hpp"
|
||||
|
||||
#include "imgui/imgui_internal.h"
|
||||
#include "slic3r/GUI/Field.hpp"
|
||||
#include "slic3r/GUI/MsgDialog.hpp"
|
||||
#include "FixModelByWin10.hpp"
|
||||
#include "FixModelByCgal.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
@@ -1186,16 +1187,21 @@ bool GLGizmoCut3D::on_init()
|
||||
// initiate info shortcuts
|
||||
const wxString ctrl = GUI::shortkey_ctrl_prefix();
|
||||
const wxString alt = GUI::shortkey_alt_prefix();
|
||||
const wxString shift = _L("Shift+");
|
||||
const wxString shift = GUI::shortkey_shift_prefix();
|
||||
|
||||
m_shortcuts_cut.push_back(std::make_pair(shift + _L("Drag"), _L("Draw cut line")));
|
||||
m_shortcuts_cut = {
|
||||
{_L("Drag"), _L("Move cut line")},
|
||||
{shift + _L("Drag"), _L("Draw cut line")}
|
||||
};
|
||||
|
||||
m_shortcuts_connector.push_back(std::make_pair(_L("Left click"), _L("Add connector")));
|
||||
m_shortcuts_connector.push_back(std::make_pair(_L("Right click"), _L("Remove connector")));
|
||||
m_shortcuts_connector.push_back(std::make_pair(_L("Drag"), _L("Move connector")));
|
||||
m_shortcuts_connector.push_back(std::make_pair(shift + _L("Left click"), _L("Add connector to selection")));
|
||||
m_shortcuts_connector.push_back(std::make_pair(alt + _L("Left click"), _L("Remove connector from selection")));
|
||||
m_shortcuts_connector.push_back(std::make_pair(ctrl + "A", _L("Select all connectors")));
|
||||
m_shortcuts_connector = {
|
||||
{_L("Left mouse button"), _L("Add connector")},
|
||||
{_L("Right mouse button"), _L("Remove connector")},
|
||||
{_L("Drag"), _L("Move connector")},
|
||||
{shift + _L("Left mouse button"), _L("Add connector to selection")},
|
||||
{alt + _L("Left mouse button"), _L("Remove connector from selection")},
|
||||
{ctrl + "A", _L("Select all connectors")},
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2313,8 +2319,7 @@ void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors, flo
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
show_tooltip_information(x, get_cur_y);
|
||||
render_tooltip_button(x, y);
|
||||
|
||||
float f_scale = m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
@@ -2757,7 +2762,7 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors, floa
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
show_tooltip_information(x, get_cur_y);
|
||||
render_tooltip_button(x, get_cur_y);
|
||||
|
||||
float f_scale = m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
@@ -2917,43 +2922,11 @@ void GLGizmoCut3D::on_render_input_window(float x, float y, float bottom_limit)
|
||||
render_debug_input_window(x);
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::show_tooltip_information(float x, float y)
|
||||
void GLGizmoCut3D::render_tooltip_button(float x, float y)
|
||||
{
|
||||
auto &shortcuts = m_connectors_editing ? m_shortcuts_connector : m_shortcuts_cut;
|
||||
auto& shortcuts = m_connectors_editing ? m_shortcuts_connector : m_shortcuts_cut;
|
||||
|
||||
float caption_max = 0.f;
|
||||
for (const auto &short_cut : shortcuts) {
|
||||
caption_max = std::max(caption_max, m_imgui->calc_text_size(short_cut.first).x);
|
||||
}
|
||||
|
||||
ImTextureID normal_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
|
||||
ImTextureID hover_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
|
||||
|
||||
caption_max += m_imgui->calc_text_size(std::string_view{": "}).x + 35.f;
|
||||
|
||||
float scale = m_parent.get_scale();
|
||||
#ifdef WIN32
|
||||
int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
|
||||
scale *= (float) dpi / (float) DPI_DEFAULT;
|
||||
#endif // WIN32
|
||||
ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, 0}); // ORCA: Dont add padding
|
||||
ImGui::ImageButton3(normal_id, hover_id, button_size);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip2(ImVec2(x, y));
|
||||
auto draw_text_with_caption = [this, &caption_max](const wxString &caption, const wxString &text) {
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption);
|
||||
ImGui::SameLine(caption_max);
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
|
||||
};
|
||||
|
||||
for (const auto &short_cut : shortcuts)
|
||||
draw_text_with_caption(short_cut.first + ": ", short_cut.second);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, shortcuts, x, y);
|
||||
}
|
||||
|
||||
bool GLGizmoCut3D::is_outside_of_cut_contour(size_t idx, const CutConnectors& connectors, const Vec3d cur_pos)
|
||||
@@ -3367,8 +3340,7 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
|
||||
cut.perform_with_plane();
|
||||
|
||||
// fix_non_manifold_edges
|
||||
#ifdef HAS_WIN10SDK
|
||||
if (is_windows10()) {
|
||||
{
|
||||
bool is_showed_dialog = false;
|
||||
bool user_fix_model = false;
|
||||
for (size_t i = 0; i < new_objects.size(); i++) {
|
||||
@@ -3395,7 +3367,7 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
|
||||
wxString msg = _L("Repairing model object");
|
||||
msg += ": " + from_u8(model_name) + "\n";
|
||||
std::string res;
|
||||
if (!fix_model_by_win10_sdk_gui(*model_object, vol_idx, progress_dlg, msg, res)) return false;
|
||||
if (!fix_model_with_cgal_gui(*model_object, vol_idx, progress_dlg, msg, res)) return false;
|
||||
return true;
|
||||
};
|
||||
ProgressDialog progress_dlg(_L("Repairing model object"), "", 100, find_toplevel_parent(plater), wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT, true);
|
||||
@@ -3408,7 +3380,6 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
check_objects_after_cut(new_objects);
|
||||
|
||||
// save cut_id to post update synchronization
|
||||
|
||||
@@ -200,7 +200,9 @@ class GLGizmoCut3D : public GLGizmoBase
|
||||
|
||||
PartSelection m_part_selection;
|
||||
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts_cut;
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts_connector;
|
||||
|
||||
enum class CutMode {
|
||||
@@ -321,7 +323,7 @@ protected:
|
||||
void update_plane_model();
|
||||
|
||||
void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
void show_tooltip_information(float x, float y);
|
||||
void render_tooltip_button(float x, float y);
|
||||
|
||||
bool wants_enter_leave_snapshots() const override { return true; }
|
||||
std::string get_gizmo_entering_text() const override { return _u8L("Entering Cut gizmo"); }
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "slic3r/GUI/Jobs/NotificationProgressIndicator.hpp"
|
||||
#include "slic3r/Utils/WxFontUtils.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
#include "GLGizmoUtils.hpp"
|
||||
|
||||
#include "libslic3r/Geometry.hpp" // to range pi pi
|
||||
#include "libslic3r/Timer.hpp"
|
||||
@@ -725,6 +726,10 @@ bool GLGizmoEmboss::on_init()
|
||||
// NOTE: It has special handling in GLGizmosManager::handle_shortcut
|
||||
m_shortcut_key = WXK_CONTROL_T;
|
||||
|
||||
m_shortcuts = {
|
||||
{_L("Drag"), _L("Position on surface")}
|
||||
};
|
||||
|
||||
// initialize text styles
|
||||
m_style_manager.init(wxGetApp().app_config);
|
||||
|
||||
@@ -918,7 +923,7 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
|
||||
|
||||
GizmoImguiBegin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
|
||||
|
||||
draw_window();
|
||||
draw_window(x, y);
|
||||
|
||||
GizmoImguiEnd();
|
||||
|
||||
@@ -1341,7 +1346,7 @@ void GLGizmoEmboss::close()
|
||||
mng.open_gizmo(GLGizmosManager::Emboss);
|
||||
}
|
||||
|
||||
void GLGizmoEmboss::draw_window()
|
||||
void GLGizmoEmboss::draw_window(float x, float y)
|
||||
{
|
||||
#ifdef ALLOW_DEBUG_MODE
|
||||
if (ImGui::Button("re-process")) process();
|
||||
@@ -1357,21 +1362,30 @@ void GLGizmoEmboss::draw_window()
|
||||
|
||||
draw_text_input();
|
||||
|
||||
ImGui::Indent();
|
||||
// When unknown font is inside .3mf only font selection is allowed
|
||||
m_imgui->disabled_end(/*m_is_unknown_font*/);
|
||||
draw_font_list_line();
|
||||
m_imgui->disabled_begin(m_is_unknown_font);
|
||||
bool use_inch = wxGetApp().app_config->get_bool("use_inches");
|
||||
draw_height(use_inch);
|
||||
draw_depth(use_inch);
|
||||
ImGui::Unindent();
|
||||
// subtract 4.0f to counteract weird additional spacing/padding of the revert buttons
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10.0f, 10.0f - 4.0f));
|
||||
ScopeGuard spacing_sc([](){ ImGui::PopStyleVar(/*ImGuiStyleVar_ItemSpacing*/); });
|
||||
|
||||
draw_style_list();
|
||||
|
||||
// When unknown font is inside .3mf only font selection is allowed
|
||||
m_imgui->disabled_end(/*m_is_unknown_font*/);
|
||||
draw_font_list_line();
|
||||
m_imgui->disabled_begin(m_is_unknown_font);
|
||||
|
||||
bool use_inch = wxGetApp().app_config->get_bool("use_inches");
|
||||
draw_height(use_inch);
|
||||
draw_depth(use_inch);
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
// close advanced style property when unknown font is selected
|
||||
if (m_is_unknown_font && m_is_advanced_edit_style)
|
||||
ImGui::SetNextTreeNodeOpen(false);
|
||||
|
||||
if (ImGui::TreeNode(_u8L("Advanced").c_str())) {
|
||||
// ImGui Bug: After switching to another window and switching back, clicking the text doesnt open/close the TreeNode anymore
|
||||
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_FramePadding;
|
||||
if (ImGui::TreeNodeEx(_u8L("Advanced").c_str(), flags)) {
|
||||
if (!m_is_advanced_edit_style) {
|
||||
m_is_advanced_edit_style = true;
|
||||
m_imgui->set_requires_extra_frame();
|
||||
@@ -1384,15 +1398,17 @@ void GLGizmoEmboss::draw_window()
|
||||
m_imgui->set_requires_extra_frame();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
draw_style_list();
|
||||
ImGui::Spacing();
|
||||
|
||||
// Do not select volume type, when it is text object
|
||||
if (!m_volume->is_the_only_one_part()) {
|
||||
ImGui::Separator();
|
||||
draw_model_type();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, m_shortcuts, x, y);
|
||||
|
||||
#ifdef SHOW_WX_FONT_DESCRIPTOR
|
||||
if (is_selected_style)
|
||||
@@ -1671,21 +1687,29 @@ void GLGizmoEmboss::draw_font_list_line()
|
||||
}
|
||||
|
||||
EmbossStyle &style = m_style_manager.get_style();
|
||||
if (exist_change_in_font) {
|
||||
ImGui::SameLine(ImGui::GetStyle().WindowPadding.x);
|
||||
auto r_icon = get_icon(m_icons, IconType::undo, IconState::hovered);
|
||||
if (Slic3r::GUI::button(r_icon, r_icon, r_icon)) { // ORCA draw bottom with same orange color
|
||||
const EmbossStyle *stored_style = m_style_manager.get_stored_style();
|
||||
auto r_icon = get_icon(m_icons, IconType::undo, IconState::hovered);
|
||||
if (exist_change_in_font == false) {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.0f);
|
||||
m_imgui->disabled_begin(true);
|
||||
}
|
||||
|
||||
style.path = stored_style->path;
|
||||
style.prop.boldness = stored_style->prop.boldness;
|
||||
style.prop.skew = stored_style->prop.skew;
|
||||
ImGui::SameLine();
|
||||
if (Slic3r::GUI::button(r_icon, r_icon, r_icon)) { // ORCA draw bottom with same orange color
|
||||
const EmbossStyle *stored_style = m_style_manager.get_stored_style();
|
||||
|
||||
wxFont new_wx_font = WxFontUtils::load_wxFont(style.path);
|
||||
if (new_wx_font.IsOk() && m_style_manager.set_wx_font(new_wx_font))
|
||||
exist_change = true;
|
||||
style.path = stored_style->path;
|
||||
style.prop.boldness = stored_style->prop.boldness;
|
||||
style.prop.skew = stored_style->prop.skew;
|
||||
|
||||
wxFont new_wx_font = WxFontUtils::load_wxFont(style.path);
|
||||
if (new_wx_font.IsOk() && m_style_manager.set_wx_font(new_wx_font))
|
||||
exist_change = true;
|
||||
} else if (ImGui::IsItemHovered())
|
||||
m_imgui->tooltip(_u8L("Revert font changes."), m_gui_cfg->max_tooltip_width);
|
||||
m_imgui->tooltip(_u8L("Revert font changes."), m_gui_cfg->max_tooltip_width);
|
||||
|
||||
if (exist_change_in_font == false) {
|
||||
ImGui::PopStyleVar();
|
||||
m_imgui->disabled_end();
|
||||
}
|
||||
|
||||
if (exist_change) {
|
||||
@@ -1741,6 +1765,7 @@ void GLGizmoEmboss::draw_font_list()
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2(0, 0));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.0f, 0.5f)); // vertically align label
|
||||
|
||||
for (int i = 0; i < show_items_count; i++) {
|
||||
int idx = is_filtered ? filtered_items_idx[i] : i;
|
||||
@@ -1774,7 +1799,7 @@ void GLGizmoEmboss::draw_font_list()
|
||||
::draw_font_preview(face, m_text, *m_face_names, *m_gui_cfg, ImGui::IsItemVisible());
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(3);
|
||||
ImGui::PopStyleVar(4); // ImGuiStyleVar_ItemSpacing, ImGuiStyleVar_ItemInnerSpacing, ImGuiStyleVar_FrameRounding, ImGuiStyleVar_SelectableTextAlign
|
||||
ImGui::EndListBox();
|
||||
ImGui::EndPopup();
|
||||
} else if (m_face_names->is_init) {
|
||||
@@ -1832,7 +1857,8 @@ void GLGizmoEmboss::draw_font_list()
|
||||
|
||||
void GLGizmoEmboss::draw_model_type()
|
||||
{
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Spacing();
|
||||
|
||||
bool is_last_solid_part = m_volume->is_the_only_one_part();
|
||||
std::string title = _u8L("Operation");
|
||||
if (is_last_solid_part) {
|
||||
@@ -1849,13 +1875,18 @@ void GLGizmoEmboss::draw_model_type()
|
||||
ModelVolumeType type = m_volume->type();
|
||||
|
||||
//TRN EmbossOperation
|
||||
float minimum_spacing_x = 8.0f;
|
||||
float minimum_offset_x = ImGui::GetCursorPosX() + minimum_spacing_x;
|
||||
float offset_x = std::max(m_gui_cfg->input_offset, minimum_offset_x);
|
||||
ImGui::SameLine(offset_x);
|
||||
|
||||
ImGuiWrapper::push_radio_style(m_parent.get_scale()); // ORCA
|
||||
if (ImGui::RadioButton(_u8L("Join").c_str(), type == part))
|
||||
new_type = part;
|
||||
else if (ImGui::IsItemHovered())
|
||||
m_imgui->tooltip(_u8L("Click to change text into object part."), m_gui_cfg->max_tooltip_width);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::SameLine();
|
||||
std::string last_solid_part_hint = _u8L("You can't change a type of the last solid part of the object.");
|
||||
if (ImGui::RadioButton(_CTX_utf8(L_CONTEXT("Cut", "EmbossOperation"), "EmbossOperation").c_str(), type == negative))
|
||||
new_type = negative;
|
||||
@@ -2172,13 +2203,17 @@ void GLGizmoEmboss::draw_style_list() {
|
||||
trunc_name = ImGuiWrapper::trunc(current_name, max_style_name_width);
|
||||
}
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
|
||||
std::string title = _u8L("Style");
|
||||
if (m_style_manager.exist_stored_style())
|
||||
ImGui::Text("%s", title.c_str());
|
||||
else
|
||||
ImGui::TextColored(ImGuiWrapper::COL_ORCA, "%s", title.c_str());
|
||||
|
||||
ImGui::SetNextItemWidth(m_gui_cfg->input_width);
|
||||
ImGui::SameLine(m_gui_cfg->input_offset);
|
||||
|
||||
ImGui::SetNextItemWidth(2 * m_gui_cfg->input_width);
|
||||
auto add_text_modify = [&is_modified](const std::string& name) {
|
||||
if (!is_modified) return name;
|
||||
return name + Preset::suffix_modified();
|
||||
@@ -2190,6 +2225,14 @@ void GLGizmoEmboss::draw_style_list() {
|
||||
m_style_manager.init_style_images(m_gui_cfg->max_style_image_size, m_text);
|
||||
m_style_manager.init_trunc_names(max_style_name_width);
|
||||
std::optional<std::pair<size_t,size_t>> swap_indexes;
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2(0, 0));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.0f, 0.5f)); // vertically align label
|
||||
|
||||
const StyleManager::Styles &styles = m_style_manager.get_styles();
|
||||
for (const StyleManager::Style &style : styles) {
|
||||
size_t index = &style - &styles.front();
|
||||
@@ -2197,12 +2240,10 @@ void GLGizmoEmboss::draw_style_list() {
|
||||
ImGui::PushID(actual_style_name.c_str());
|
||||
bool is_selected = (index == m_style_manager.get_style_index());
|
||||
|
||||
float select_height = static_cast<float>(m_gui_cfg->max_style_image_size.y());
|
||||
ImVec2 select_size(0.f, select_height); // 0,0 --> calculate in draw
|
||||
const std::optional<StyleManager::StyleImage> &img = style.image;
|
||||
ImVec2 selectable_size(0, m_imgui->scaled(32.f / 15.f)); // 0.0f -> calculated during draw
|
||||
// allow click delete button
|
||||
ImGuiSelectableFlags_ flags = ImGuiSelectableFlags_AllowItemOverlap;
|
||||
if (ImGui::BBLSelectable(style.truncated_name.c_str(), is_selected, flags, select_size)) {
|
||||
if (ImGui::BBLSelectable(style.truncated_name.c_str(), is_selected, flags, selectable_size)) {
|
||||
selected_style_index = index;
|
||||
} else if (ImGui::IsItemHovered())
|
||||
tooltip = actual_style_name;
|
||||
@@ -2218,6 +2259,7 @@ void GLGizmoEmboss::draw_style_list() {
|
||||
ImGui::ResetMouseDragDelta();
|
||||
}
|
||||
|
||||
const std::optional<StyleManager::StyleImage> &img = style.image;
|
||||
// draw style name
|
||||
if (img.has_value()) {
|
||||
ImGui::SameLine(max_style_name_width);
|
||||
@@ -2230,6 +2272,10 @@ void GLGizmoEmboss::draw_style_list() {
|
||||
if (swap_indexes.has_value())
|
||||
m_style_manager.swap(swap_indexes->first,
|
||||
swap_indexes->second);
|
||||
|
||||
// ImGuiStyleVar_ItemSpacing, ImGuiStyleVar_ItemInnerSpacing, ImGuiStyleVar_FrameRounding,
|
||||
// ImGuiStyleVar_WindowPadding, ImGuiStyleVar_FramePadding, ImGuiStyleVar_SelectableTextAlign
|
||||
ImGui::PopStyleVar(6);
|
||||
ImGui::EndCombo();
|
||||
} else {
|
||||
// do not keep in memory style images when no combo box open
|
||||
@@ -2404,30 +2450,43 @@ bool GLGizmoEmboss::revertible(const std::string &name,
|
||||
Draw draw) const
|
||||
{
|
||||
ImGui::AlignTextToFramePadding();
|
||||
bool changed = exist_change(value, default_value);
|
||||
if (changed || default_value == nullptr)
|
||||
bool changed_from_default = exist_change(value, default_value);
|
||||
if (changed_from_default || default_value == nullptr)
|
||||
ImGuiWrapper::text_colored(ImGuiWrapper::COL_MODIFIED, name); // ORCA Match color
|
||||
else
|
||||
ImGuiWrapper::text(name);
|
||||
|
||||
// render revert changes button
|
||||
if (changed) {
|
||||
ImGuiWindow *window = ImGui::GetCurrentWindow();
|
||||
float prev_x = window->DC.CursorPosPrevLine.x;
|
||||
ImGui::SameLine(undo_offset); // change cursor postion
|
||||
auto r_icon = get_icon(m_icons, IconType::undo, IconState::hovered);
|
||||
if (Slic3r::GUI::button(r_icon, r_icon, r_icon)) { // ORCA draw bottom with same orange color
|
||||
value = *default_value;
|
||||
bool changed = draw();
|
||||
|
||||
// !! Fix to detect change of value after revert of float-slider
|
||||
m_imgui->get_last_slider_status().deactivated_after_edit = true;
|
||||
|
||||
return true;
|
||||
} else if (ImGui::IsItemHovered())
|
||||
m_imgui->tooltip(undo_tooltip, m_gui_cfg->max_tooltip_width);
|
||||
window->DC.CursorPosPrevLine.x = prev_x; // set back previous position
|
||||
if (changed_from_default == false) {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.0f);
|
||||
m_imgui->disabled_begin(true);
|
||||
}
|
||||
return draw();
|
||||
|
||||
// render revert changes button
|
||||
auto r_icon = get_icon(m_icons, IconType::undo, IconState::hovered);
|
||||
ImGuiWindow *window = ImGui::GetCurrentWindow();
|
||||
float prev_x = window->DC.CursorPosPrevLine.x;
|
||||
ImGui::SameLine(undo_offset); // change cursor postion
|
||||
if (Slic3r::GUI::button(r_icon, r_icon, r_icon)) { // ORCA draw bottom with same orange color
|
||||
value = *default_value;
|
||||
|
||||
// !! Fix to detect change of value after revert of float-slider
|
||||
m_imgui->get_last_slider_status().deactivated_after_edit = true;
|
||||
|
||||
return true;
|
||||
} else if (ImGui::IsItemHovered())
|
||||
m_imgui->tooltip(undo_tooltip, m_gui_cfg->max_tooltip_width);
|
||||
|
||||
if (undo_offset != 0.0f)
|
||||
window->DC.CursorPosPrevLine.x = prev_x; // set back previous position
|
||||
|
||||
if (changed_from_default == false) {
|
||||
ImGui::PopStyleVar();
|
||||
m_imgui->disabled_end();
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
// May be move to ImGuiWrapper
|
||||
template<typename T> bool imgui_input(const char *label, T *v, T step, T step_fast, const char *format, ImGuiInputTextFlags flags);
|
||||
@@ -2448,8 +2507,8 @@ bool GLGizmoEmboss::rev_input(const std::string &name, T &value, const T *defaul
|
||||
return imgui_input(("##" + name).c_str(),
|
||||
&value, step, step_fast, format, flags);
|
||||
};
|
||||
float undo_offset = ImGui::GetStyle().WindowPadding.x;
|
||||
return revertible(name, value, default_value, undo_tooltip, undo_offset, draw_offseted_input);
|
||||
return revertible(name, value, default_value, undo_tooltip,
|
||||
0.0f, draw_offseted_input);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -2500,9 +2559,8 @@ bool GLGizmoEmboss::rev_checkbox(const std::string &name,
|
||||
ImGui::SameLine(offset);
|
||||
return m_imgui->bbl_checkbox(wxString::FromUTF8("##" + name), value);
|
||||
};
|
||||
float undo_offset = ImGui::GetStyle().WindowPadding.x;
|
||||
return revertible(name, value, default_value, undo_tooltip,
|
||||
undo_offset, draw_offseted_input);
|
||||
0.0f, draw_offseted_input);
|
||||
}
|
||||
|
||||
bool GLGizmoEmboss::set_height() {
|
||||
@@ -2583,9 +2641,8 @@ bool GLGizmoEmboss::rev_slider(const std::string &name,
|
||||
return m_imgui->slider_optional_int( ("##" + name).c_str(), value,
|
||||
v_min, v_max, format.c_str(), 1.f, false, tooltip);
|
||||
};
|
||||
float undo_offset = ImGui::GetStyle().WindowPadding.x;
|
||||
return revertible(name, value, default_value,
|
||||
undo_tooltip, undo_offset, draw_slider_optional_int);
|
||||
undo_tooltip, 0.0f, draw_slider_optional_int);
|
||||
}
|
||||
|
||||
bool GLGizmoEmboss::rev_slider(const std::string &name,
|
||||
@@ -2605,9 +2662,8 @@ bool GLGizmoEmboss::rev_slider(const std::string &name,
|
||||
return m_imgui->slider_optional_float(("##" + name).c_str(), value,
|
||||
v_min, v_max, format.c_str(), 1.f, false, tooltip);
|
||||
};
|
||||
float undo_offset = ImGui::GetStyle().WindowPadding.x;
|
||||
return revertible(name, value, default_value,
|
||||
undo_tooltip, undo_offset, draw_slider_optional_float);
|
||||
undo_tooltip, 0.0f, draw_slider_optional_float);
|
||||
}
|
||||
|
||||
bool GLGizmoEmboss::rev_slider(const std::string &name,
|
||||
@@ -2627,9 +2683,8 @@ bool GLGizmoEmboss::rev_slider(const std::string &name,
|
||||
return m_imgui->slider_float("##" + name, &value, v_min, v_max,
|
||||
format.c_str(), 1.f, false, tooltip);
|
||||
};
|
||||
float undo_offset = ImGui::GetStyle().WindowPadding.x;
|
||||
return revertible(name, value, default_value,
|
||||
undo_tooltip, undo_offset, draw_slider_float);
|
||||
undo_tooltip, 0.0f, draw_slider_float);
|
||||
}
|
||||
|
||||
void GLGizmoEmboss::draw_advanced()
|
||||
@@ -2659,6 +2714,8 @@ void GLGizmoEmboss::draw_advanced()
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_GREY_DARK, ff_property);
|
||||
#endif // SHOW_FONT_FILE_PROPERTY
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
auto &tr = m_gui_cfg->translations;
|
||||
|
||||
const StyleManager::Style *stored_style = nullptr;
|
||||
@@ -2735,8 +2792,7 @@ void GLGizmoEmboss::draw_advanced()
|
||||
return is_change;
|
||||
};
|
||||
const FontProp::Align * def_align = stored_style ? &stored_style->prop.align : nullptr;
|
||||
float undo_offset = ImGui::GetStyle().WindowPadding.x;
|
||||
if (revertible(tr.alignment, font_prop.align, def_align, _u8L("Revert alignment."), undo_offset, draw_align)) {
|
||||
if (revertible(tr.alignment, font_prop.align, def_align, _u8L("Revert alignment."), 0.0f, draw_align)) {
|
||||
if (font_prop.per_glyph)
|
||||
reinit_text_lines(m_text_lines.get_lines().size());
|
||||
// TODO: move with text in finalize to not change position
|
||||
@@ -3632,7 +3688,7 @@ GuiCfg create_gui_configuration()
|
||||
ImGui::CalcTextSize(tr.font.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.height.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.depth.c_str()).x});
|
||||
cfg.indent = static_cast<float>(cfg.icon_width);
|
||||
cfg.indent = 20.0f;
|
||||
cfg.input_offset = style.WindowPadding.x + cfg.indent + max_text_width + space;
|
||||
|
||||
// TRN - Input label. Be short as possible
|
||||
@@ -3699,8 +3755,7 @@ GuiCfg create_gui_configuration()
|
||||
cfg.height_of_volume_type_selector = separator_height + line_height_with_spacing + input_height;
|
||||
|
||||
int max_style_image_width = static_cast<int>(std::round(cfg.max_style_name_width - 2 * style.FramePadding.x));
|
||||
int max_style_image_height = static_cast<int>(std::round(input_height));
|
||||
cfg.max_style_image_size = Vec2i32(max_style_image_width, line_height);
|
||||
cfg.max_style_image_size = Vec2i32(max_style_image_width, line_height_with_spacing);
|
||||
cfg.face_name_size = Vec2i32(cfg.input_width, line_height_with_spacing);
|
||||
cfg.face_name_texture_offset_x = cfg.face_name_size.x() + style.WindowPadding.x + space;
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ private:
|
||||
// create volume from text - main functionality
|
||||
bool process(bool make_snapshot = true);
|
||||
void close();
|
||||
void draw_window();
|
||||
void draw_window(float x, float y);
|
||||
void draw_text_input();
|
||||
void draw_model_type();
|
||||
void draw_style_list();
|
||||
@@ -229,6 +229,9 @@ private:
|
||||
|
||||
// only temporary solution
|
||||
static const std::string M_ICON_FILENAME;
|
||||
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts;
|
||||
};
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "slic3r/GUI/format.hpp"
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
#include "GLGizmoUtils.hpp"
|
||||
|
||||
#include <glad/gl.h>
|
||||
|
||||
@@ -79,33 +80,47 @@ bool GLGizmoFdmSupports::on_init()
|
||||
// BBS
|
||||
m_shortcut_key = WXK_CONTROL_L;
|
||||
|
||||
// FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent?
|
||||
const wxString ctrl = _L("Ctrl+");
|
||||
// FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent?
|
||||
const wxString alt = _L("Alt+");
|
||||
const wxString shift = _L("Shift+");
|
||||
m_desc["perform"] = _L("Perform");
|
||||
m_desc["on_overhangs_only"] = _L("On overhangs only");
|
||||
m_desc["remove_all"] = _L("Erase all painting");
|
||||
m_desc["highlight_by_angle"] = _L("Highlight overhang areas");
|
||||
m_desc["tool_type"] = _L("Tool type");
|
||||
m_desc["gap_fill"] = _L("Gap fill");
|
||||
m_desc["reset_direction"] = _L("Reset direction");
|
||||
m_desc["clipping_of_view"] = _L("Section view");
|
||||
m_desc["cursor_size"] = _L("Pen size");
|
||||
m_desc["smart_fill_angle"] = _L("Smart fill angle");
|
||||
m_desc["gap_area"] = _L("Gap area");
|
||||
|
||||
m_desc["clipping_of_view_caption"] = alt + _L("Mouse wheel");
|
||||
m_desc["clipping_of_view"] = _L("Section view");
|
||||
m_desc["reset_direction"] = _L("Reset direction");
|
||||
m_desc["cursor_size_caption"] = ctrl + _L("Mouse wheel");
|
||||
m_desc["cursor_size"] = _L("Pen size");
|
||||
m_desc["enforce_caption"] = _L("Left mouse button");
|
||||
m_desc["enforce"] = _L("Enforce supports");
|
||||
m_desc["block_caption"] = _L("Right mouse button");
|
||||
m_desc["block"] = _L("Block supports");
|
||||
m_desc["remove_caption"] = shift + _L("Left mouse button");
|
||||
m_desc["remove"] = _L("Erase");
|
||||
m_desc["remove_all"] = _L("Erase all painting");
|
||||
m_desc["highlight_by_angle"] = _L("Highlight overhang areas");
|
||||
m_desc["gap_fill"] = _L("Gap fill");
|
||||
m_desc["perform"] = _L("Perform");
|
||||
m_desc["gap_area_caption"] = ctrl + _L("Mouse wheel");
|
||||
m_desc["gap_area"] = _L("Gap area");
|
||||
m_desc["tool_type"] = _L("Tool type");
|
||||
m_desc["smart_fill_angle_caption"] = ctrl + _L("Mouse wheel");
|
||||
m_desc["smart_fill_angle"] = _L("Smart fill angle");
|
||||
m_desc["on_overhangs_only"] = _L("On overhangs only");
|
||||
|
||||
const wxString ctrl = GUI::shortkey_ctrl_prefix();
|
||||
const wxString alt = GUI::shortkey_alt_prefix();
|
||||
const wxString shift = GUI::shortkey_shift_prefix();
|
||||
|
||||
std::pair<wxString, wxString> enforce_shortcut = {_L("Left mouse button"), _L("Enforce supports")};
|
||||
std::pair<wxString, wxString> block_shortcut = {_L("Right mouse button"), _L("Block supports")};
|
||||
std::pair<wxString, wxString> remove_shortcut = {shift + _L("Left mouse button"), _L("Erase")};
|
||||
std::pair<wxString, wxString> clipping_shortcut = {alt + _L("Mouse wheel"), m_desc["clipping_of_view"]};
|
||||
|
||||
m_shortcuts_brush = {
|
||||
enforce_shortcut,
|
||||
block_shortcut,
|
||||
remove_shortcut,
|
||||
{ctrl + _L("Mouse wheel"), m_desc["cursor_size"]},
|
||||
clipping_shortcut
|
||||
};
|
||||
|
||||
m_shortcuts_bucket_fill = {
|
||||
enforce_shortcut,
|
||||
block_shortcut,
|
||||
remove_shortcut,
|
||||
{ctrl + _L("Mouse wheel"), m_desc["smart_fill_angle"]},
|
||||
clipping_shortcut
|
||||
};
|
||||
|
||||
m_shortcuts_gap_fill = {
|
||||
{ctrl + _L("Mouse wheel"), _L("Gap area")}
|
||||
};
|
||||
|
||||
memset(&m_print_instance, 0, sizeof(m_print_instance));
|
||||
return true;
|
||||
@@ -228,7 +243,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
||||
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
|
||||
|
||||
const float sliders_width = m_imgui->scaled(7.0f);
|
||||
const float drag_left_width = ImGui::GetStyle().WindowPadding.x + sliders_left_width + sliders_width - space_size;
|
||||
const float drag_left_width = ImGui::GetStyle().WindowPadding.x + sliders_width - space_size;
|
||||
|
||||
float drag_pos_times = 0.7;
|
||||
|
||||
@@ -281,11 +296,6 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
||||
}
|
||||
}
|
||||
|
||||
m_imgui->bbl_checkbox(m_desc["on_overhangs_only"], m_paint_on_overhangs_only);
|
||||
if (ImGui::IsItemHovered())
|
||||
m_imgui->tooltip(format_wxstr(_L("Allows painting only on facets selected by: \"%1%\""), m_desc["highlight_by_angle"]), max_tooltip_width);
|
||||
ImGui::Separator();
|
||||
|
||||
if (m_current_tool != old_tool)
|
||||
this->tool_changed(old_tool, m_current_tool);
|
||||
|
||||
@@ -300,7 +310,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
||||
ImGui::SameLine(sliders_left_width);
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
m_imgui->bbl_slider_float_style("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true);
|
||||
ImGui::SameLine(drag_left_width);
|
||||
ImGui::SameLine(drag_left_width + sliders_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
ImGui::BBLDragFloat("##cursor_radius_input", &m_cursor_radius, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
} else if (m_current_tool == ImGui::SphereButtonIcon) {
|
||||
@@ -312,7 +322,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
||||
ImGui::SameLine(sliders_left_width);
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
m_imgui->bbl_slider_float_style("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true);
|
||||
ImGui::SameLine(drag_left_width);
|
||||
ImGui::SameLine(drag_left_width + sliders_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
ImGui::BBLDragFloat("##cursor_radius_input", &m_cursor_radius, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
} else if (m_current_tool == ImGui::FillButtonIcon) {
|
||||
@@ -320,16 +330,19 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
||||
m_tool_type = ToolType::SMART_FILL;
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc.at("smart_fill_angle"));
|
||||
std::string format_str = std::string("%.f") + I18N::translate_utf8("", "Face angle threshold, placed after the number with no whitespace in between.");
|
||||
m_imgui->text(m_desc["smart_fill_angle"]);
|
||||
std::string format_str = std::string("%.f") + I18N::translate_utf8("°",
|
||||
"Face angle threshold,"
|
||||
"placed after the number with no whitespace in between.");
|
||||
ImGui::SameLine(sliders_left_width);
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
if (m_imgui->bbl_slider_float_style("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data(), 1.0f, true))
|
||||
if (m_imgui->bbl_slider_float_style("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax,
|
||||
format_str.data(), 1.0f, true))
|
||||
for (auto& triangle_selector : m_triangle_selectors) {
|
||||
triangle_selector->seed_fill_unselect_all_triangles();
|
||||
triangle_selector->request_update_render_data();
|
||||
}
|
||||
ImGui::SameLine(drag_left_width);
|
||||
ImGui::SameLine(drag_left_width + sliders_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
ImGui::BBLDragFloat("##smart_fill_angle_input", &m_smart_fill_angle, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
} else if (m_current_tool == ImGui::GapFillIcon) {
|
||||
@@ -342,11 +355,12 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
std::string format_str = std::string("%.2f") + I18N::translate_utf8("", "Triangle patch area threshold,""triangle patch will be merged to neighbor if its area is less than threshold");
|
||||
m_imgui->bbl_slider_float_style("##gap_area", &TriangleSelectorPatch::gap_area, TriangleSelectorPatch::GapAreaMin, TriangleSelectorPatch::GapAreaMax, format_str.data(), 1.0f, true);
|
||||
ImGui::SameLine(drag_left_width);
|
||||
ImGui::SameLine(drag_left_width + sliders_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
ImGui::BBLDragFloat("##gap_area_input", &TriangleSelectorPatch::gap_area, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
float position_before_text_y = ImGui::GetCursorPos().y;
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc["highlight_by_angle"]);
|
||||
@@ -380,40 +394,42 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::SameLine(drag_left_width);
|
||||
ImGui::SameLine(drag_left_width + sliders_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
ImGui::BBLDragFloat("##angle_threshold_deg_input", &m_highlight_by_angle_threshold_deg, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
if (m_current_tool != ImGui::GapFillIcon) {
|
||||
ImGui::Separator();
|
||||
if (m_c->object_clipper()->get_position() == 0.f) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc.at("clipping_of_view"));
|
||||
}
|
||||
else {
|
||||
if (m_imgui->button(m_desc.at("reset_direction"))) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
m_c->object_clipper()->set_position_by_ratio(-1., false);
|
||||
});
|
||||
}
|
||||
}
|
||||
m_imgui->bbl_checkbox(m_desc["on_overhangs_only"], m_paint_on_overhangs_only);
|
||||
if (ImGui::IsItemHovered())
|
||||
m_imgui->tooltip(format_wxstr(_L("Allows painting only on facets selected by: \"%1%\""), m_desc["highlight_by_angle"]),
|
||||
max_tooltip_width);
|
||||
|
||||
auto clp_dist = float(m_c->object_clipper()->get_position());
|
||||
ImGui::SameLine(sliders_left_width);
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
bool b_bbl_slider_float = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true);
|
||||
|
||||
ImGui::SameLine(drag_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
bool b_drag_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
if (b_bbl_slider_float || b_drag_input) m_c->object_clipper()->set_position_by_ratio(clp_dist, true);
|
||||
ImGui::Separator();
|
||||
if (m_c->object_clipper()->get_position() == 0.f) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc.at("clipping_of_view"));
|
||||
}
|
||||
else {
|
||||
if (m_imgui->button(m_desc.at("reset_direction"))) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
m_c->object_clipper()->set_position_by_ratio(-1., false);
|
||||
});
|
||||
}
|
||||
}
|
||||
auto clp_dist = float(m_c->object_clipper()->get_position());
|
||||
ImGui::SameLine(sliders_left_width);
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
bool b_bbl_slider_float = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true);
|
||||
|
||||
ImGui::SameLine(drag_left_width + sliders_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
bool b_drag_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
if (b_bbl_slider_float || b_drag_input) m_c->object_clipper()->set_position_by_ratio(clp_dist, true);
|
||||
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
show_tooltip_information(caption_max, x, get_cur_y);
|
||||
render_tooltip_button(x, y);
|
||||
|
||||
float f_scale =m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
@@ -471,53 +487,22 @@ void GLGizmoFdmSupports::tool_changed(wchar_t old_tool, wchar_t new_tool)
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoFdmSupports::show_tooltip_information(float caption_max, float x, float y)
|
||||
{
|
||||
ImTextureID normal_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
|
||||
ImTextureID hover_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
|
||||
|
||||
caption_max += m_imgui->calc_text_size(std::string_view{": "}).x + 15.f;
|
||||
|
||||
float scale = m_parent.get_scale();
|
||||
#ifdef WIN32
|
||||
int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
|
||||
scale *= (float) dpi / (float) DPI_DEFAULT;
|
||||
#endif // WIN32
|
||||
ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, 0}); // ORCA: Dont add padding
|
||||
ImGui::ImageButton3(normal_id, hover_id, button_size);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip2(ImVec2(x, y));
|
||||
auto draw_text_with_caption = [this, &caption_max](const wxString &caption, const wxString &text) {
|
||||
// BBS
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption);
|
||||
ImGui::SameLine(caption_max);
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
|
||||
};
|
||||
|
||||
std::vector<std::string> tip_items;
|
||||
switch (m_tool_type) {
|
||||
case ToolType::BRUSH:
|
||||
tip_items = {"enforce", "block", "remove", "cursor_size", "clipping_of_view"};
|
||||
break;
|
||||
case ToolType::BUCKET_FILL:
|
||||
break;
|
||||
case ToolType::SMART_FILL:
|
||||
tip_items = {"enforce", "block", "remove", "smart_fill_angle", "clipping_of_view"};
|
||||
break;
|
||||
case ToolType::GAP_FILL:
|
||||
tip_items = {"gap_area"};
|
||||
break;
|
||||
void GLGizmoFdmSupports::render_tooltip_button(float x, float y) {
|
||||
auto get_shortcuts = [this]() -> std::vector<std::pair<wxString, wxString>> {
|
||||
switch (m_current_tool) {
|
||||
case ImGui::CircleButtonIcon:
|
||||
case ImGui::SphereButtonIcon:
|
||||
return m_shortcuts_brush;
|
||||
case ImGui::FillButtonIcon:
|
||||
return m_shortcuts_bucket_fill;
|
||||
case ImGui::GapFillIcon:
|
||||
return m_shortcuts_gap_fill;
|
||||
default:
|
||||
break;
|
||||
return {};
|
||||
}
|
||||
for (const auto &t : tip_items) draw_text_with_caption(m_desc.at(t + "_caption") + ": ", m_desc.at(t));
|
||||
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
};
|
||||
|
||||
GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, get_shortcuts(), x, y);
|
||||
}
|
||||
|
||||
// BBS
|
||||
|
||||
@@ -33,7 +33,7 @@ protected:
|
||||
std::string on_get_name() const override;
|
||||
|
||||
void on_set_state() override;
|
||||
void show_tooltip_information(float caption_max, float x, float y);
|
||||
void render_tooltip_button(float x, float y);
|
||||
wxString handle_snapshot_action_name(bool shift_down, Button button_down) const override;
|
||||
|
||||
std::string get_gizmo_entering_text() const override { return "Entering Paint-on supports"; }
|
||||
@@ -90,6 +90,13 @@ private:
|
||||
// This map holds all translated description texts, so they can be easily referenced during layout calculations
|
||||
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.
|
||||
std::map<std::string, wxString> m_desc;
|
||||
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts_brush;
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts_bucket_fill;
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts_gap_fill;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "slic3r/GUI/MsgDialog.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
#include "GLGizmoUtils.hpp"
|
||||
|
||||
#include <glad/gl.h>
|
||||
#include <algorithm>
|
||||
@@ -31,31 +32,47 @@ bool GLGizmoFuzzySkin::on_init()
|
||||
{
|
||||
m_shortcut_key = WXK_CONTROL_H;
|
||||
|
||||
// FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent?
|
||||
const wxString ctrl = _L("Ctrl+");
|
||||
// FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent?
|
||||
const wxString alt = _L("Alt+");
|
||||
const wxString shift = _L("Shift+");
|
||||
const wxString ctrl = GUI::shortkey_ctrl_prefix();
|
||||
const wxString alt = GUI::shortkey_alt_prefix();
|
||||
const wxString shift = GUI::shortkey_shift_prefix();
|
||||
|
||||
m_desc["clipping_of_view_caption"] = alt + _L("Mouse wheel");
|
||||
m_desc["clipping_of_view"] = _L("Section view");
|
||||
m_desc["reset_direction"] = _L("Reset direction");
|
||||
m_desc["cursor_size_caption"] = ctrl + _L("Mouse wheel");
|
||||
m_desc["cursor_size"] = _L("Brush size");
|
||||
m_desc["cursor_type"] = _L("Brush shape") ;
|
||||
m_desc["add_fuzzy_skin_caption"] = _L("Left mouse button");
|
||||
m_desc["add_fuzzy_skin"] = _L("Add fuzzy skin");
|
||||
m_desc["remove_fuzzy_skin_caption"] = shift + _L("Left mouse button");
|
||||
m_desc["remove_fuzzy_skin"] = _L("Remove fuzzy skin");
|
||||
m_desc["remove_all"] = _L("Erase all painting");
|
||||
m_desc["circle"] = _L("Circle");
|
||||
m_desc["sphere"] = _L("Sphere");
|
||||
m_desc["pointer"] = _L("Triangles");
|
||||
m_desc["tool_type"] = _L("Tool type");
|
||||
m_desc["tool_brush"] = _L("Brush");
|
||||
m_desc["tool_smart_fill"] = _L("Smart fill");
|
||||
m_desc["smart_fill_angle_caption"] = ctrl + _L("Mouse wheel");
|
||||
m_desc["smart_fill_angle"] = _L("Smart fill angle");
|
||||
m_desc["reset_direction"] = _L("Reset direction");
|
||||
m_desc["remove_all"] = _L("Erase all painting");
|
||||
m_desc["circle"] = _L("Circle");
|
||||
m_desc["sphere"] = _L("Sphere");
|
||||
m_desc["pointer"] = _L("Triangles");
|
||||
m_desc["tool_type"] = _L("Tool type");
|
||||
m_desc["tool_brush"] = _L("Brush");
|
||||
m_desc["tool_smart_fill"] = _L("Smart fill");
|
||||
m_desc["clipping_of_view"] = _L("Section view");
|
||||
m_desc["cursor_size"] = _L("Pen size");
|
||||
m_desc["add_fuzzy_skin"] = _L("Add fuzzy skin");
|
||||
m_desc["remove_fuzzy_skin"] = _L("Remove fuzzy skin");
|
||||
m_desc["smart_fill_angle"] = _L("Smart fill angle");
|
||||
|
||||
std::pair<wxString, wxString> add_fuzzy_skin_shortcut = {_L("Left mouse button"), m_desc["add_fuzzy_skin"]};
|
||||
std::pair<wxString, wxString> remove_fuzzy_skin_shortcut = {shift + _L("Left mouse button"), m_desc["remove_fuzzy_skin"]};
|
||||
std::pair<wxString, wxString> clipping_shortcut = {alt + _L("Mouse wheel"), m_desc["clipping_of_view"]};
|
||||
|
||||
m_shortcuts_brush = {
|
||||
add_fuzzy_skin_shortcut,
|
||||
remove_fuzzy_skin_shortcut,
|
||||
{ctrl + _L("Mouse wheel"), m_desc["cursor_size"]},
|
||||
clipping_shortcut
|
||||
};
|
||||
|
||||
m_shortcuts_triangle = {
|
||||
add_fuzzy_skin_shortcut,
|
||||
remove_fuzzy_skin_shortcut,
|
||||
clipping_shortcut
|
||||
};
|
||||
|
||||
m_shortcuts_smart_fill = {
|
||||
add_fuzzy_skin_shortcut,
|
||||
remove_fuzzy_skin_shortcut,
|
||||
{ctrl + _L("Mouse wheel"), m_desc["smart_fill_angle"]},
|
||||
clipping_shortcut
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -80,50 +97,18 @@ void GLGizmoFuzzySkin::render_painter_gizmo()
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
|
||||
void GLGizmoFuzzySkin::show_tooltip_information(float caption_max, float x, float y)
|
||||
void GLGizmoFuzzySkin::render_tooltip_button(float x, float y)
|
||||
{
|
||||
ImTextureID normal_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
|
||||
ImTextureID hover_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
|
||||
|
||||
caption_max += m_imgui->calc_text_size(std::string_view{": "}).x + 15.f;
|
||||
|
||||
float scale = m_parent.get_scale();
|
||||
#ifdef WIN32
|
||||
int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
|
||||
scale *= (float) dpi / (float) DPI_DEFAULT;
|
||||
#endif // WIN32
|
||||
ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, 0}); // ORCA: Dont add padding
|
||||
ImGui::ImageButton3(normal_id, hover_id, button_size);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip2(ImVec2(x, y));
|
||||
auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) {
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption);
|
||||
ImGui::SameLine(caption_max);
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
|
||||
};
|
||||
|
||||
std::vector<std::string> tip_items;
|
||||
auto get_shortcuts = [this]() -> std::vector<std::pair<wxString, wxString>> {
|
||||
switch (m_tool_type) {
|
||||
case ToolType::BRUSH:
|
||||
if (m_cursor_type == TriangleSelector::POINTER) {
|
||||
tip_items = {"add_fuzzy_skin", "remove_fuzzy_skin", "clipping_of_view"};
|
||||
} else {
|
||||
tip_items = {"add_fuzzy_skin", "remove_fuzzy_skin", "cursor_size", "clipping_of_view"};
|
||||
}
|
||||
break;
|
||||
case ToolType::SMART_FILL:
|
||||
tip_items = {"add_fuzzy_skin", "remove_fuzzy_skin", "smart_fill_angle", "clipping_of_view"};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case ToolType::BRUSH: return m_cursor_type == TriangleSelector::POINTER ? m_shortcuts_triangle : m_shortcuts_brush;
|
||||
|
||||
case ToolType::SMART_FILL: return m_shortcuts_smart_fill;
|
||||
default: return {};
|
||||
}
|
||||
for (const auto &t : tip_items) draw_text_with_caption(m_desc.at(t + "_caption") + ": ", m_desc.at(t));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
};
|
||||
|
||||
GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, get_shortcuts(), x, y);
|
||||
}
|
||||
|
||||
void GLGizmoFuzzySkin::on_render_input_window(float x, float y, float bottom_limit)
|
||||
@@ -271,13 +256,14 @@ void GLGizmoFuzzySkin::on_render_input_window(float x, float y, float bottom_lim
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc["smart_fill_angle"]);
|
||||
std::string format_str = std::string("%.f") +
|
||||
I18N::translate_utf8("°", "Degree sign to use in the respective slider in fuzzy skin gizmo, "
|
||||
"placed after the number with no whitespace in between.");
|
||||
std::string format_str = std::string("%.f") + I18N::translate_utf8("°",
|
||||
"Face angle threshold,"
|
||||
"placed after the number with no whitespace in between.");
|
||||
ImGui::SameLine(sliders_left_width);
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
if (m_imgui->bbl_slider_float_style("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data(), 1.0f, true))
|
||||
for (auto &triangle_selector : m_triangle_selectors) {
|
||||
if (m_imgui->bbl_slider_float_style("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax,
|
||||
format_str.data(), 1.0f, true))
|
||||
for (auto& triangle_selector : m_triangle_selectors) {
|
||||
triangle_selector->seed_fill_unselect_all_triangles();
|
||||
triangle_selector->request_update_render_data();
|
||||
}
|
||||
@@ -313,8 +299,7 @@ void GLGizmoFuzzySkin::on_render_input_window(float x, float y, float bottom_lim
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
show_tooltip_information(caption_max, x, get_cur_y);
|
||||
render_tooltip_button(x, y);
|
||||
|
||||
float f_scale = m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
@@ -18,7 +18,7 @@ protected:
|
||||
void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
std::string on_get_name() const override;
|
||||
|
||||
void show_tooltip_information(float caption_max, float x, float y);
|
||||
void render_tooltip_button(float x, float y);
|
||||
|
||||
wxString handle_snapshot_action_name(bool shift_down, Button button_down) const override;
|
||||
|
||||
@@ -45,6 +45,13 @@ private:
|
||||
// This map holds all translated description texts, so they can be easily referenced during layout calculations
|
||||
// etc. When language changes, GUI is recreated, and this class constructed again, so the change takes effect.
|
||||
std::map<std::string, wxString> m_desc;
|
||||
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts_brush;
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts_triangle;
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts_smart_fill;
|
||||
};
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
#include "GLGizmoUtils.hpp"
|
||||
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/MeasureUtils.hpp"
|
||||
@@ -444,15 +445,14 @@ bool GLGizmoMeasure::on_init()
|
||||
{
|
||||
m_shortcut_key = WXK_CONTROL_U;
|
||||
|
||||
const wxString shift = _L("Shift+");
|
||||
const wxString shift = GUI::shortkey_shift_prefix();
|
||||
|
||||
m_desc["feature_selection"] = _L("Select feature");
|
||||
m_desc["point_selection_caption"] = shift + _L("Left mouse button");
|
||||
m_desc["point_selection"] = _L("Select point");
|
||||
m_desc["reset_caption"] = _L("Delete");
|
||||
m_desc["reset"] = _L("Restart selection");
|
||||
m_desc["unselect_caption"] = _L("Esc");
|
||||
m_desc["unselect"] = _L("Cancel a feature until exit");
|
||||
m_shortcuts = {
|
||||
{_L("Left mouse button"), _L("Select")},
|
||||
{shift + _L("Left mouse button"), _L("Select point")},
|
||||
{_L("Delete"), _L("Restart selection")},
|
||||
{_L("Esc"), _L("Cancel a feature until exit")},
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2177,16 +2177,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit
|
||||
show_distance_xyz_ui();
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
float caption_max = 0.f;
|
||||
float total_text_max = 0.f;
|
||||
for (const auto &t : std::array<std::string, 3>{"point_selection", "reset", "unselect"}) {
|
||||
caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x);
|
||||
total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x);
|
||||
}
|
||||
show_tooltip_information(caption_max, x, get_cur_y);
|
||||
ImGui::PopStyleVar(1);
|
||||
GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, m_shortcuts, x, y);
|
||||
|
||||
if (last_feature != m_curr_feature || last_mode != m_mode || last_selected_features != m_selected_features) {
|
||||
// the dialog may have changed its size, ask for an extra frame to render it properly
|
||||
last_feature = m_curr_feature;
|
||||
@@ -2239,38 +2231,6 @@ void GLGizmoMeasure::update_measurement_result()
|
||||
m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, Measure::SurfaceFeature(std::get<0>(m_selected_features.first.feature->get_circle())));
|
||||
}
|
||||
|
||||
void GLGizmoMeasure::show_tooltip_information(float caption_max, float x, float y)
|
||||
{
|
||||
ImTextureID normal_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
|
||||
ImTextureID hover_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
|
||||
|
||||
caption_max += m_imgui->calc_text_size(": "sv).x + 35.f;
|
||||
|
||||
float scale = m_parent.get_scale();
|
||||
#ifdef WIN32
|
||||
int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
|
||||
scale *= (float) dpi / (float) DPI_DEFAULT;
|
||||
#endif // WIN32
|
||||
ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 0, 0 }); // ORCA: Dont add padding
|
||||
ImGui::ImageButton3(normal_id, hover_id, button_size);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip2(ImVec2(x, y));
|
||||
auto draw_text_with_caption = [this, &caption_max](const wxString &caption, const wxString &text) {
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption);
|
||||
ImGui::SameLine(caption_max);
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
|
||||
};
|
||||
|
||||
for (const auto &t : std::array<std::string, 3>{"point_selection", "reset", "unselect"})
|
||||
draw_text_with_caption(m_desc.at(t + "_caption") + ": ", m_desc.at(t));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
|
||||
void GLGizmoMeasure::reset_all_pick()
|
||||
{
|
||||
std::map<GLVolume*, std::shared_ptr<PickRaycaster>>().swap(m_mesh_raycaster_map);
|
||||
|
||||
@@ -271,7 +271,6 @@ protected:
|
||||
void remove_selected_sphere_raycaster(int id);
|
||||
void update_measurement_result();
|
||||
|
||||
void show_tooltip_information(float caption_max, float x, float y);
|
||||
void reset_all_pick();
|
||||
void reset_gripper_pick(GripperType id,bool is_all = false);
|
||||
void register_single_mesh_pick();
|
||||
@@ -303,9 +302,9 @@ protected:
|
||||
|
||||
bool is_pick_meet_assembly_mode(const SelectedFeatures::Item& item);
|
||||
protected:
|
||||
// This map holds all translated description texts, so they can be easily referenced during layout calculations
|
||||
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.
|
||||
std::map<std::string, wxString> m_desc;
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts;
|
||||
|
||||
bool m_show_reset_first_tip{false};
|
||||
bool m_selected_wrong_feature_waring_tip{false};
|
||||
EMeasureMode m_measure_mode{EMeasureMode::ONLY_MEASURE};
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
#include "GLGizmoUtils.hpp"
|
||||
|
||||
|
||||
#include <glad/gl.h>
|
||||
@@ -88,55 +89,61 @@ bool GLGizmoMmuSegmentation::on_init()
|
||||
// BBS
|
||||
m_shortcut_key = WXK_CONTROL_N;
|
||||
|
||||
// FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent?
|
||||
const wxString ctrl = _L("Ctrl+");
|
||||
// FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent?
|
||||
const wxString alt = _L("Alt+");
|
||||
const wxString shift = _L("Shift+");
|
||||
const wxString ctrl = GUI::shortkey_ctrl_prefix();
|
||||
const wxString alt = GUI::shortkey_alt_prefix();
|
||||
const wxString shift = GUI::shortkey_shift_prefix();
|
||||
|
||||
m_desc["clipping_of_view_caption"] = alt + _L("Mouse wheel");
|
||||
m_desc["clipping_of_view"] = _L("Section view");
|
||||
m_desc["reset_direction"] = _L("Reset direction");
|
||||
m_desc["cursor_size_caption"] = ctrl + _L("Mouse wheel");
|
||||
m_desc["cursor_size"] = _L("Pen size");
|
||||
m_desc["cursor_type"] = _L("Pen shape");
|
||||
m_desc["clipping_of_view"] = _L("Section view");
|
||||
m_desc["reset_direction"] = _L("Reset direction");
|
||||
m_desc["cursor_size"] = _L("Pen size");
|
||||
m_desc["cursor_type"] = _L("Pen shape");
|
||||
m_desc["paint"] = _L("Paint");
|
||||
m_desc["erase"] = _L("Erase");
|
||||
m_desc["shortcut_key"] = _L("Choose filament");
|
||||
m_desc["edge_detection"] = _L("Edge detection");
|
||||
m_desc["gap_area"] = _L("Gap area");
|
||||
m_desc["perform"] = _L("Perform");
|
||||
m_desc["remove_all"] = _L("Erase all painting");
|
||||
m_desc["circle"] = _L("Circle");
|
||||
m_desc["sphere"] = _L("Sphere");
|
||||
m_desc["pointer"] = _L("Triangles");
|
||||
m_desc["filaments"] = _L("Filaments");
|
||||
m_desc["tool_type"] = _L("Tool type");
|
||||
m_desc["tool_brush"] = _L("Brush");
|
||||
m_desc["tool_smart_fill"] = _L("Smart fill");
|
||||
m_desc["tool_bucket_fill"] = _L("Bucket fill");
|
||||
m_desc["smart_fill_angle"] = _L("Smart fill angle");
|
||||
m_desc["height_range"] = _L("Height range");
|
||||
m_desc["toggle_wireframe"] = _L("Toggle Wireframe");
|
||||
m_desc["perform_remap"] = _L("Remap filaments");
|
||||
m_desc["remap"] = _L("Remap");
|
||||
m_desc["cancel_remap"] = _L("Cancel");
|
||||
|
||||
m_desc["paint_caption"] = _L("Left mouse button");
|
||||
m_desc["paint"] = _L("Paint");
|
||||
m_desc["erase_caption"] = shift + _L("Left mouse button");
|
||||
m_desc["erase"] = _L("Erase");
|
||||
m_desc["shortcut_key_caption"] = _L("Key 1~9");
|
||||
m_desc["shortcut_key"] = _L("Choose filament");
|
||||
m_desc["edge_detection"] = _L("Edge detection");
|
||||
m_desc["gap_area_caption"] = ctrl + _L("Mouse wheel");
|
||||
m_desc["gap_area"] = _L("Gap area");
|
||||
m_desc["perform"] = _L("Perform");
|
||||
std::pair<wxString, wxString> paint_shortcut = {_L("Left mouse button"), m_desc["paint"]};
|
||||
std::pair<wxString, wxString> erase_shortcut = {shift + _L("Left mouse button"), m_desc["erase"]};
|
||||
std::pair<wxString, wxString> clipping_shortcut = {alt + _L("Mouse wheel"), m_desc["clipping_of_view"]};
|
||||
std::pair<wxString, wxString> toggle_wireframe_shortcut = {alt + shift + _L("Enter"), m_desc["toggle_wireframe"]};
|
||||
|
||||
m_desc["remove_all"] = _L("Erase all painting");
|
||||
m_desc["circle"] = _L("Circle");
|
||||
m_desc["sphere"] = _L("Sphere");
|
||||
m_desc["pointer"] = _L("Triangles");
|
||||
m_shortcuts_brush = {
|
||||
paint_shortcut,
|
||||
erase_shortcut,
|
||||
{ctrl + _L("Mouse wheel"), m_desc["cursor_size"]},
|
||||
clipping_shortcut,
|
||||
toggle_wireframe_shortcut
|
||||
};
|
||||
|
||||
m_desc["filaments"] = _L("Filaments");
|
||||
m_desc["tool_type"] = _L("Tool type");
|
||||
m_desc["tool_brush"] = _L("Brush");
|
||||
m_desc["tool_smart_fill"] = _L("Smart fill");
|
||||
m_desc["tool_bucket_fill"] = _L("Bucket fill");
|
||||
m_shortcuts_bucket_fill = {
|
||||
paint_shortcut,
|
||||
erase_shortcut,
|
||||
{ctrl + _L("Mouse wheel"), m_desc["smart_fill_angle"]},
|
||||
clipping_shortcut,
|
||||
toggle_wireframe_shortcut
|
||||
};
|
||||
|
||||
m_desc["smart_fill_angle_caption"] = ctrl + _L("Mouse wheel");
|
||||
m_desc["smart_fill_angle"] = _L("Smart fill angle");
|
||||
|
||||
m_desc["height_range_caption"] = ctrl + _L("Mouse wheel");
|
||||
m_desc["height_range"] = _L("Height range");
|
||||
|
||||
//add toggle wire frame hint
|
||||
m_desc["toggle_wireframe_caption"] = alt + shift + _L("Enter");
|
||||
m_desc["toggle_wireframe"] = _L("Toggle Wireframe");
|
||||
|
||||
// Filament remapping descriptions
|
||||
m_desc["perform_remap"] = _L("Remap filaments");
|
||||
m_desc["remap"] = _L("Remap");
|
||||
m_desc["cancel_remap"] = _L("Cancel");
|
||||
m_shortcuts_gap_fill = {
|
||||
{ctrl + _L("Mouse wheel"), m_desc["gap_area"]},
|
||||
toggle_wireframe_shortcut
|
||||
};
|
||||
|
||||
init_extruders_data();
|
||||
|
||||
@@ -279,52 +286,22 @@ static void render_extruders_combo(const std::string& label,
|
||||
selection_idx = selection_out;
|
||||
}
|
||||
|
||||
void GLGizmoMmuSegmentation::show_tooltip_information(float caption_max, float x, float y)
|
||||
void GLGizmoMmuSegmentation::render_tooltip_button(float x, float y)
|
||||
{
|
||||
ImTextureID normal_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
|
||||
ImTextureID hover_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
|
||||
|
||||
caption_max += m_imgui->calc_text_size(std::string_view{": "}).x + 15.f;
|
||||
|
||||
float scale = m_parent.get_scale();
|
||||
#ifdef WIN32
|
||||
int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
|
||||
scale *= (float) dpi / (float) DPI_DEFAULT;
|
||||
#endif // WIN32
|
||||
ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, 0}); // ORCA: Dont add padding
|
||||
ImGui::ImageButton3(normal_id, hover_id, button_size);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip2(ImVec2(x, y));
|
||||
auto draw_text_with_caption = [this, &caption_max](const wxString &caption, const wxString &text) {
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption);
|
||||
ImGui::SameLine(caption_max);
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
|
||||
};
|
||||
|
||||
std::vector<std::string> tip_items;
|
||||
auto get_shortcuts = [this]() -> std::vector<std::pair<wxString, wxString>> {
|
||||
switch (m_tool_type) {
|
||||
case ToolType::BRUSH:
|
||||
tip_items = {"paint", "erase", "cursor_size", "clipping_of_view", "toggle_wireframe"};
|
||||
break;
|
||||
case ToolType::BUCKET_FILL:
|
||||
tip_items = {"paint", "erase", "smart_fill_angle", "clipping_of_view", "toggle_wireframe"};
|
||||
break;
|
||||
case ToolType::SMART_FILL:
|
||||
// TODO:
|
||||
break;
|
||||
case ToolType::GAP_FILL:
|
||||
tip_items = {"gap_area", "toggle_wireframe"};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case ToolType::BRUSH: return m_shortcuts_brush;
|
||||
|
||||
case ToolType::BUCKET_FILL:
|
||||
case ToolType::SMART_FILL: return m_shortcuts_bucket_fill;
|
||||
|
||||
case ToolType::GAP_FILL: return m_shortcuts_gap_fill;
|
||||
|
||||
default: return {};
|
||||
}
|
||||
for (const auto &t : tip_items) draw_text_with_caption(m_desc.at(t + "_caption") + ": ", m_desc.at(t));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
};
|
||||
|
||||
GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, get_shortcuts(), x, y);
|
||||
}
|
||||
|
||||
void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bottom_limit)
|
||||
@@ -513,67 +490,45 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc.at("cursor_size"));
|
||||
ImGui::SameLine(circle_max_width);
|
||||
ImGui::SameLine(sliders_left_width);
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
m_imgui->bbl_slider_float_style("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true);
|
||||
ImGui::SameLine(drag_left_width + circle_max_width);
|
||||
ImGui::SameLine(drag_left_width + sliders_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
ImGui::BBLDragFloat("##cursor_radius_input", &m_cursor_radius, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
ImGui::Separator();
|
||||
if (m_c->object_clipper()->get_position() == 0.f) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc.at("clipping_of_view"));
|
||||
}
|
||||
else {
|
||||
if (m_imgui->button(m_desc.at("reset_direction"))) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
m_c->object_clipper()->set_position_by_ratio(-1., false);
|
||||
});
|
||||
if (m_imgui->bbl_checkbox(_L("Vertical"), m_vertical_only)) {
|
||||
if (m_vertical_only) {
|
||||
m_horizontal_only = false;
|
||||
}
|
||||
}
|
||||
|
||||
auto clp_dist = float(m_c->object_clipper()->get_position());
|
||||
ImGui::SameLine(circle_max_width);
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
bool slider_clp_dist = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true);
|
||||
ImGui::SameLine(drag_left_width + circle_max_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); }
|
||||
|
||||
} else if (m_current_tool == ImGui::TriangleButtonIcon) {
|
||||
if (m_imgui->bbl_checkbox(_L("Horizontal"), m_horizontal_only)) {
|
||||
if (m_horizontal_only) {
|
||||
m_vertical_only = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_current_tool == ImGui::TriangleButtonIcon) {
|
||||
m_cursor_type = TriangleSelector::CursorType::POINTER;
|
||||
m_tool_type = ToolType::BRUSH;
|
||||
|
||||
if (m_c->object_clipper()->get_position() == 0.f) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc.at("clipping_of_view"));
|
||||
}
|
||||
else {
|
||||
if (m_imgui->button(m_desc.at("reset_direction"))) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
m_c->object_clipper()->set_position_by_ratio(-1., false);
|
||||
});
|
||||
if (m_imgui->bbl_checkbox(_L("Vertical"), m_vertical_only)) {
|
||||
if (m_vertical_only) {
|
||||
m_horizontal_only = false;
|
||||
}
|
||||
}
|
||||
|
||||
auto clp_dist = float(m_c->object_clipper()->get_position());
|
||||
ImGui::SameLine(clipping_slider_left);
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
bool slider_clp_dist = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true);
|
||||
ImGui::SameLine(drag_left_width + clipping_slider_left);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); }
|
||||
|
||||
} else if (m_current_tool == ImGui::FillButtonIcon) {
|
||||
if (m_imgui->bbl_checkbox(_L("Horizontal"), m_horizontal_only)) {
|
||||
if (m_horizontal_only) {
|
||||
m_vertical_only = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_current_tool == ImGui::FillButtonIcon) {
|
||||
m_cursor_type = TriangleSelector::CursorType::POINTER;
|
||||
m_imgui->bbl_checkbox(m_desc["edge_detection"], m_detect_geometry_edge);
|
||||
m_tool_type = ToolType::BUCKET_FILL;
|
||||
|
||||
m_imgui->bbl_checkbox(m_desc["edge_detection"], m_detect_geometry_edge);
|
||||
|
||||
if (m_detect_geometry_edge) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc["smart_fill_angle"]);
|
||||
@@ -593,94 +548,57 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
// set to negative value to disable edge detection
|
||||
m_smart_fill_angle = -1.f;
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (m_c->object_clipper()->get_position() == 0.f) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc.at("clipping_of_view"));
|
||||
}
|
||||
else {
|
||||
if (m_imgui->button(m_desc.at("reset_direction"))) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
m_c->object_clipper()->set_position_by_ratio(-1., false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
auto clp_dist = float(m_c->object_clipper()->get_position());
|
||||
ImGui::SameLine(sliders_left_width);
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
bool slider_clp_dist = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true);
|
||||
ImGui::SameLine(drag_left_width + sliders_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true);}
|
||||
|
||||
} else if (m_current_tool == ImGui::HeightRangeIcon) {
|
||||
}
|
||||
else if (m_current_tool == ImGui::HeightRangeIcon) {
|
||||
m_tool_type = ToolType::BRUSH;
|
||||
m_cursor_type = TriangleSelector::CursorType::HEIGHT_RANGE;
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc["height_range"] + ":");
|
||||
ImGui::SameLine(height_max_width);
|
||||
ImGui::SameLine(sliders_left_width);
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
std::string format_str = std::string("%.2f") + I18N::translate_utf8("mm", "Height range," "Facet in [cursor z, cursor z + height] will be selected.");
|
||||
m_imgui->bbl_slider_float_style("##cursor_height", &m_cursor_height, CursorHeightMin, CursorHeightMax, format_str.data(), 1.0f, true);
|
||||
ImGui::SameLine(drag_left_width + height_max_width);
|
||||
ImGui::SameLine(drag_left_width + sliders_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
ImGui::BBLDragFloat("##cursor_height_input", &m_cursor_height, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
ImGui::Separator();
|
||||
if (m_c->object_clipper()->get_position() == 0.f) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc.at("clipping_of_view"));
|
||||
}
|
||||
else {
|
||||
if (m_imgui->button(m_desc.at("reset_direction"))) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
m_c->object_clipper()->set_position_by_ratio(-1., false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
auto clp_dist = float(m_c->object_clipper()->get_position());
|
||||
ImGui::SameLine(height_max_width);
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
bool slider_clp_dist = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true);
|
||||
ImGui::SameLine(drag_left_width + height_max_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); }
|
||||
}
|
||||
else if (m_current_tool == ImGui::GapFillIcon) {
|
||||
m_tool_type = ToolType::GAP_FILL;
|
||||
m_cursor_type = TriangleSelector::CursorType::POINTER;
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc["gap_area"] + ":");
|
||||
ImGui::SameLine(gap_area_slider_left);
|
||||
ImGui::SameLine(sliders_left_width);
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
std::string format_str = std::string("%.2f") + I18N::translate_utf8("", "Triangle patch area threshold,""triangle patch will be merged to neighbor if its area is less than threshold");
|
||||
m_imgui->bbl_slider_float_style("##gap_area", &TriangleSelectorPatch::gap_area, TriangleSelectorPatch::GapAreaMin, TriangleSelectorPatch::GapAreaMax, format_str.data(), 1.0f, true);
|
||||
ImGui::SameLine(drag_left_width + gap_area_slider_left);
|
||||
ImGui::SameLine(drag_left_width + sliders_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
ImGui::BBLDragFloat("##gap_area_input", &TriangleSelectorPatch::gap_area, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
if(m_imgui->bbl_checkbox(_L("Vertical"), m_vertical_only)){
|
||||
if(m_vertical_only){
|
||||
m_horizontal_only = false;
|
||||
if (m_c->object_clipper()->get_position() == 0.f) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc.at("clipping_of_view"));
|
||||
} else {
|
||||
if (m_imgui->button(m_desc.at("reset_direction"))) {
|
||||
wxGetApp().CallAfter([this]() { m_c->object_clipper()->set_position_by_ratio(-1., false); });
|
||||
}
|
||||
}
|
||||
if(m_imgui->bbl_checkbox(_L("Horizontal"), m_horizontal_only)){
|
||||
if(m_horizontal_only){
|
||||
m_vertical_only = false;
|
||||
}
|
||||
|
||||
auto clp_dist = float(m_c->object_clipper()->get_position());
|
||||
ImGui::SameLine(sliders_left_width);
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
bool slider_clp_dist = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true);
|
||||
ImGui::SameLine(drag_left_width + sliders_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
if (slider_clp_dist || b_clp_dist_input) {
|
||||
m_c->object_clipper()->set_position_by_ratio(clp_dist, true);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.5f));
|
||||
|
||||
// ORCA: Remap filaments section (Border only, Title in border).
|
||||
// Styled as a panel for visual grouping.
|
||||
if (m_imgui->button(m_desc.at("perform_remap"))) {
|
||||
@@ -689,6 +607,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
|
||||
if (m_show_remap_panel)
|
||||
{
|
||||
ImGui::Spacing();
|
||||
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
std::string title = into_u8(m_desc.at("perform_remap"));
|
||||
float available_width = ImGui::GetContentRegionAvail().x;
|
||||
@@ -719,7 +639,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
remap_panel_high = ImGui::GetCursorPos().y - start_y;
|
||||
|
||||
// ORCA: Add Remap and Cancel buttons (outside the panel)
|
||||
ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.2f));
|
||||
ImGui::Spacing();
|
||||
if (m_imgui->button(m_desc.at("remap"))) {
|
||||
this->remap_filament_assignments();
|
||||
// Reset mapping to identity after apply
|
||||
@@ -732,12 +652,10 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.5f));
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
show_tooltip_information(caption_max, x, get_cur_y);
|
||||
render_tooltip_button(x, y);
|
||||
|
||||
float f_scale =m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
@@ -94,7 +94,7 @@ protected:
|
||||
|
||||
void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
std::string on_get_name() const override;
|
||||
void show_tooltip_information(float caption_max, float x, float y);
|
||||
void render_tooltip_button(float x, float y);
|
||||
bool on_is_selectable() const override;
|
||||
bool on_is_activable() const override;
|
||||
|
||||
@@ -149,6 +149,13 @@ private:
|
||||
// This map holds all translated description texts, so they can be easily referenced during layout calculations
|
||||
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.
|
||||
std::map<std::string, wxString> m_desc;
|
||||
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts_brush;
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts_bucket_fill;
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts_gap_fill;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
#include "GLGizmoUtils.hpp"
|
||||
|
||||
#include <glad/gl.h>
|
||||
|
||||
@@ -29,28 +30,29 @@ bool GLGizmoSeam::on_init()
|
||||
{
|
||||
m_shortcut_key = WXK_CONTROL_P;
|
||||
|
||||
// FIXME: maybe should be using GUI::shortkey_ctrl_prefix() or equivalent?
|
||||
const wxString ctrl = _L("Ctrl+");
|
||||
// FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent?
|
||||
const wxString alt = _L("Alt+");
|
||||
const wxString shift = _L("Shift+");
|
||||
const wxString ctrl = GUI::shortkey_ctrl_prefix();
|
||||
const wxString alt = GUI::shortkey_alt_prefix();
|
||||
const wxString shift = GUI::shortkey_shift_prefix();
|
||||
|
||||
m_desc["clipping_of_view_caption"] = alt + _L("Mouse wheel");
|
||||
m_desc["clipping_of_view"] = _L("Section view");
|
||||
m_desc["reset_direction"] = _L("Reset direction");
|
||||
m_desc["cursor_size_caption"] = ctrl + _L("Mouse wheel");
|
||||
m_desc["cursor_size"] = _L("Brush size");
|
||||
m_desc["cursor_type"] = _L("Brush shape");
|
||||
m_desc["enforce_caption"] = _L("Left mouse button");
|
||||
m_desc["cursor_size"] = _L("Pen size");
|
||||
m_desc["tool_type"] = _L("Tool type");
|
||||
m_desc["enforce"] = _L("Enforce seam");
|
||||
m_desc["block_caption"] = _L("Right mouse button");
|
||||
m_desc["block"] = _L("Block seam");
|
||||
m_desc["remove_caption"] = shift + _L("Left mouse button");
|
||||
m_desc["remove"] = _L("Erase");
|
||||
m_desc["remove_all"] = _L("Erase all painting");
|
||||
m_desc["circle"] = _L("Circle");
|
||||
m_desc["sphere"] = _L("Sphere");
|
||||
|
||||
m_shortcuts = {
|
||||
{_L("Left mouse button"), m_desc["enforce"]},
|
||||
{_L("Right mouse button"), m_desc["block"]},
|
||||
{shift + _L("Left mouse button"), m_desc["remove"]},
|
||||
{ctrl + _L("Mouse wheel"), m_desc["cursor_size"]},
|
||||
{alt + _L("Mouse wheel"), m_desc["clipping_of_view"]}
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -101,36 +103,6 @@ bool GLGizmoSeam::on_key_down_select_tool_type(int keyCode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLGizmoSeam::show_tooltip_information(float caption_max, float x, float y)
|
||||
{
|
||||
ImTextureID normal_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
|
||||
ImTextureID hover_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
|
||||
|
||||
caption_max += m_imgui->calc_text_size(std::string_view{": "}).x + 35.f;
|
||||
|
||||
float scale = m_parent.get_scale();
|
||||
#ifdef WIN32
|
||||
int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
|
||||
scale *= (float) dpi / (float) DPI_DEFAULT;
|
||||
#endif // WIN32
|
||||
ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, 0}); // ORCA: Dont add padding
|
||||
ImGui::ImageButton3(normal_id, hover_id, button_size);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip2(ImVec2(x, y));
|
||||
auto draw_text_with_caption = [this, &caption_max](const wxString &caption, const wxString &text) {
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption);
|
||||
ImGui::SameLine(caption_max);
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
|
||||
};
|
||||
|
||||
for (const auto &t : std::array<std::string, 5>{"enforce", "block", "remove", "cursor_size", "clipping_of_view"}) draw_text_with_caption(m_desc.at(t + "_caption") + ": ", m_desc.at(t));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
|
||||
void GLGizmoSeam::tool_changed(wchar_t old_tool, wchar_t new_tool)
|
||||
{
|
||||
@@ -184,12 +156,12 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
|
||||
const float slider_icon_width = m_imgui->get_slider_icon_size().x;
|
||||
|
||||
const float sliders_width = m_imgui->scaled(7.0f);
|
||||
const float drag_left_width = ImGui::GetStyle().WindowPadding.x + sliders_left_width + sliders_width - space_size;
|
||||
const float drag_left_width = ImGui::GetStyle().WindowPadding.x + sliders_width - space_size;
|
||||
|
||||
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc.at("cursor_type"));
|
||||
m_imgui->text(m_desc.at("tool_type"));
|
||||
std::array<wchar_t, 2> tool_ids = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon };
|
||||
std::array<wchar_t, 2> icons;
|
||||
if (m_is_dark_mode)
|
||||
@@ -250,13 +222,14 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc.at("cursor_size"));
|
||||
ImGui::SameLine(sliders_left_width);
|
||||
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
m_imgui->bbl_slider_float_style("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true);
|
||||
ImGui::SameLine(drag_left_width);
|
||||
ImGui::SameLine(drag_left_width + sliders_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
ImGui::BBLDragFloat("##cursor_radius_input", &m_cursor_radius, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
m_imgui->bbl_checkbox(_L("Vertical"), m_vertical_only);
|
||||
|
||||
ImGui::Separator();
|
||||
if (m_c->object_clipper()->get_position() == 0.f) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
@@ -272,23 +245,17 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
|
||||
|
||||
auto clp_dist = float(m_c->object_clipper()->get_position());
|
||||
ImGui::SameLine(sliders_left_width);
|
||||
|
||||
ImGui::PushItemWidth(sliders_width);
|
||||
bool slider_clp_dist = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true);
|
||||
|
||||
ImGui::SameLine(drag_left_width);
|
||||
ImGui::SameLine(drag_left_width + sliders_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); }
|
||||
|
||||
ImGui::Separator();
|
||||
m_imgui->bbl_checkbox(_L("Vertical"), m_vertical_only);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
show_tooltip_information(caption_max, x, get_cur_y);
|
||||
GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, m_shortcuts, x, y);
|
||||
|
||||
float f_scale =m_parent.get_gizmos_manager().get_layout_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale));
|
||||
|
||||
@@ -24,8 +24,6 @@ protected:
|
||||
std::string on_get_name() const override;
|
||||
PainterGizmoType get_painter_type() const override;
|
||||
|
||||
void show_tooltip_information(float caption_max, float x, float y);
|
||||
|
||||
void tool_changed(wchar_t old_tool, wchar_t new_tool);
|
||||
|
||||
wxString handle_snapshot_action_name(bool shift_down, Button button_down) const override;
|
||||
@@ -51,6 +49,9 @@ private:
|
||||
// This map holds all translated description texts, so they can be easily referenced during layout calculations
|
||||
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.
|
||||
std::map<std::string, wxString> m_desc;
|
||||
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#include "GLGizmoUtils.hpp"
|
||||
#include "slic3r/GUI/ImGuiWrapper.hpp"
|
||||
#include "GLGizmosManager.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include <wx/app.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <wx/msw/winundef.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
GizmoUI Footer Structure:
|
||||
|
||||
~ Content ~
|
||||
----------------------------------------
|
||||
[Button1] [Button2]
|
||||
----------------------------------------
|
||||
[?] [Reset] [Confirm] [Cancel]
|
||||
----------------------------------------
|
||||
~ Warnings ~
|
||||
|
||||
|
||||
Additional details:
|
||||
- [Confirm], [Cancel], [Done], ... are buttons that close the Tool Dialog
|
||||
- [Reset], [Button1], ... are buttons that do not!
|
||||
- Non-consequential buttons like [Cancel] and [Done] are always the right-most buttons
|
||||
- Multiple warnings can show, but should only have one ImGui::Separator above
|
||||
- If no warnings is shown, dont render the ImGui::Separator
|
||||
|
||||
*/
|
||||
|
||||
namespace Slic3r::GUI::GLGizmoUtils {
|
||||
|
||||
void render_tooltip_button(
|
||||
ImGuiWrapper* imgui_wrapper, const GLCanvas3D& canvas, const std::vector<std::pair<wxString, wxString>>& shortcuts, float x, float y)
|
||||
{
|
||||
float caption_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
float caption_x_max = 0.f;
|
||||
for (const auto& item : shortcuts) {
|
||||
caption_x_max = std::max(caption_x_max, imgui_wrapper->calc_text_size(item.first).x);
|
||||
}
|
||||
caption_x_max += imgui_wrapper->calc_text_size(": "sv).x + 35.f;
|
||||
|
||||
auto& gizmos_manager = canvas.get_gizmos_manager();
|
||||
ImTextureID normal_id = gizmos_manager.get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
|
||||
ImTextureID hover_id = gizmos_manager.get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
|
||||
|
||||
float scale = canvas.get_scale();
|
||||
#ifdef WIN32
|
||||
int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
|
||||
scale *= (float) dpi / (float) DPI_DEFAULT;
|
||||
#endif
|
||||
|
||||
ImVec2 button_size = ImVec2(25 * scale, 25 * scale);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, 0});
|
||||
|
||||
ImGui::ImageButton3(normal_id, hover_id, button_size);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip2(ImVec2(x, caption_y));
|
||||
for (const auto& item : shortcuts) {
|
||||
imgui_wrapper->text_colored(ImGuiWrapper::COL_ACTIVE, item.first + ": ");
|
||||
ImGui::SameLine(caption_x_max);
|
||||
imgui_wrapper->text_colored(ImGuiWrapper::COL_WINDOW_BG, item.second);
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
|
||||
} // namespace Slic3r::GUI::GLGizmoUtils
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef GL_GIZMO_UTIL_HPP
|
||||
#define GL_GIZMO_UTIL_HPP
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <wx/string.h>
|
||||
#include "imgui.h"
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
// Forward declaration
|
||||
class ImGuiWrapper;
|
||||
class GLCanvas3D;
|
||||
|
||||
namespace GLGizmoUtils {
|
||||
|
||||
// Renders a tooltip button using the provided shortcuts
|
||||
void render_tooltip_button(
|
||||
ImGuiWrapper* imgui_wrapper, const GLCanvas3D& canvas, const std::vector<std::pair<wxString, wxString>>& shortcuts, float x, float y);
|
||||
|
||||
} // namespace GLGizmoUtils
|
||||
} // namespace Slic3r::GUI
|
||||
|
||||
#endif // GL_GIZMO_UTIL_HPP
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "slic3r/GUI/Selection.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/MainFrame.hpp"
|
||||
#include "GLGizmoUtils.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
@@ -55,24 +56,22 @@ GizmoObjectManipulation::GizmoObjectManipulation(GLCanvas3D& glcanvas)
|
||||
m_imperial_units = wxGetApp().app_config->get("use_inches") == "1";
|
||||
m_new_unit_string = m_imperial_units ? L("in") : L("mm");
|
||||
|
||||
const wxString shift = _L("Shift+");
|
||||
const wxString shift = GUI::shortkey_shift_prefix();
|
||||
const wxString alt = GUI::shortkey_alt_prefix();
|
||||
const wxString ctrl = GUI::shortkey_ctrl_prefix();
|
||||
|
||||
m_desc_move["part_selection_caption"] = alt + _L("Left mouse button");
|
||||
m_desc_move["part_selection"] = _L("Part selection");
|
||||
m_desc_move["snap_step_caption"] = shift + _L("Left mouse button");
|
||||
m_desc_move["snap_step"] = _L("Fixed step drag");
|
||||
m_shortcuts_move = {
|
||||
{alt + _L("Left mouse button"), _L("Part selection")},
|
||||
{shift + _L("Left mouse button"), _L("Fixed step drag")}
|
||||
};
|
||||
|
||||
m_desc_rotate["part_selection_caption"] = alt + _L("Left mouse button");
|
||||
m_desc_rotate["part_selection"] = _L("Part selection");
|
||||
m_shortcuts_rotate = {
|
||||
{alt + _L("Left mouse button"), _L("Part selection")}};
|
||||
|
||||
m_desc_scale["part_selection_caption"] = alt + _L("Left mouse button");
|
||||
m_desc_scale["part_selection"] = _L("Part selection");
|
||||
m_desc_scale["snap_step_caption"] = shift + _L("Left mouse button");
|
||||
m_desc_scale["snap_step"] = _L("Fixed step drag");
|
||||
m_desc_scale["single_sided_caption"] = ctrl + _L("Left mouse button");
|
||||
m_desc_scale["single_sided"] = _L("Single sided scaling");
|
||||
m_shortcuts_scale = {
|
||||
{alt + _L("Left mouse button"), _L("Part selection")},
|
||||
{shift + _L("Left mouse button"), _L("Fixed step drag")},
|
||||
{ctrl + _L("Left mouse button"), _L("Single sided scaling")}};
|
||||
}
|
||||
|
||||
void GizmoObjectManipulation::UpdateAndShow(const bool show)
|
||||
@@ -719,102 +718,6 @@ bool GizmoObjectManipulation::reset_zero_button(ImGuiWrapper *imgui_wrapper, flo
|
||||
return result;
|
||||
}
|
||||
|
||||
void GizmoObjectManipulation::show_move_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y)
|
||||
{
|
||||
ImTextureID normal_id = m_glcanvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
|
||||
ImTextureID hover_id = m_glcanvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
|
||||
|
||||
caption_max += imgui_wrapper->calc_text_size(": "sv).x + 35.f;
|
||||
|
||||
float scale = m_glcanvas.get_scale();
|
||||
#ifdef WIN32
|
||||
int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
|
||||
scale *= (float) dpi / (float) DPI_DEFAULT;
|
||||
#endif // WIN32
|
||||
ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, ImGui::GetStyle().FramePadding.y});
|
||||
ImGui::ImageButton3(normal_id, hover_id, button_size);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip2(ImVec2(x, y));
|
||||
auto draw_text_with_caption = [this, &imgui_wrapper,& caption_max](const wxString &caption, const wxString &text) {
|
||||
imgui_wrapper->text_colored(ImGuiWrapper::COL_ACTIVE, caption);
|
||||
ImGui::SameLine(caption_max);
|
||||
imgui_wrapper->text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
|
||||
};
|
||||
|
||||
for (const auto &t : std::array<std::string, 2>{"part_selection", "snap_step"})
|
||||
draw_text_with_caption(m_desc_move.at(t + "_caption") + ": ", m_desc_move.at(t));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
|
||||
void GizmoObjectManipulation::show_rotate_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y)
|
||||
{
|
||||
ImTextureID normal_id = m_glcanvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
|
||||
ImTextureID hover_id = m_glcanvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
|
||||
|
||||
caption_max += imgui_wrapper->calc_text_size(": "sv).x + 35.f;
|
||||
|
||||
float scale = m_glcanvas.get_scale();
|
||||
#ifdef WIN32
|
||||
int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
|
||||
scale *= (float) dpi / (float) DPI_DEFAULT;
|
||||
#endif // WIN32
|
||||
ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, ImGui::GetStyle().FramePadding.y});
|
||||
ImGui::ImageButton3(normal_id, hover_id, button_size);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip2(ImVec2(x, y));
|
||||
auto draw_text_with_caption = [this, &imgui_wrapper, &caption_max](const wxString &caption, const wxString &text) {
|
||||
imgui_wrapper->text_colored(ImGuiWrapper::COL_ACTIVE, caption);
|
||||
ImGui::SameLine(caption_max);
|
||||
imgui_wrapper->text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
|
||||
};
|
||||
|
||||
for (const auto &t : std::array<std::string, 1>{"part_selection"})
|
||||
draw_text_with_caption(m_desc_rotate.at(t + "_caption") + ": ", m_desc_rotate.at(t));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
|
||||
void GizmoObjectManipulation::show_scale_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y)
|
||||
{
|
||||
ImTextureID normal_id = m_glcanvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
|
||||
ImTextureID hover_id = m_glcanvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
|
||||
|
||||
caption_max += imgui_wrapper->calc_text_size(": "sv).x + 35.f;
|
||||
|
||||
float scale = m_glcanvas.get_scale();
|
||||
#ifdef WIN32
|
||||
int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
|
||||
scale *= (float) dpi / (float) DPI_DEFAULT;
|
||||
#endif // WIN32
|
||||
ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, ImGui::GetStyle().FramePadding.y});
|
||||
ImGui::ImageButton3(normal_id, hover_id, button_size);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip2(ImVec2(x, y));
|
||||
auto draw_text_with_caption = [this, &imgui_wrapper, &caption_max](const wxString &caption, const wxString &text) {
|
||||
imgui_wrapper->text_colored(ImGuiWrapper::COL_ACTIVE, caption);
|
||||
ImGui::SameLine(caption_max);
|
||||
imgui_wrapper->text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
|
||||
};
|
||||
|
||||
for (const auto &t : std::array<std::string, 3>{"part_selection", "snap_step", "single_sided"})
|
||||
draw_text_with_caption(m_desc_scale.at(t + "_caption") + ": ", m_desc_scale.at(t));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
|
||||
void GizmoObjectManipulation::set_init_rotation(const Geometry::Transformation &value) {
|
||||
m_init_rotation_scale_tran = value.get_matrix_no_offset();
|
||||
m_init_rotation = value.get_rotation();
|
||||
@@ -957,14 +860,9 @@ void GizmoObjectManipulation::do_render_move_window(ImGuiWrapper *imgui_wrapper,
|
||||
}
|
||||
}
|
||||
if (!focued_on_text) m_glcanvas.handle_sidebar_focus_event("", false);
|
||||
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
float tip_caption_max = 0.f;
|
||||
float total_text_max = 0.f;
|
||||
for (const auto &t : std::array<std::string, 2>{"part_selection", "snap_step"}) {
|
||||
tip_caption_max = std::max(tip_caption_max, imgui_wrapper->calc_text_size(m_desc_move[t + "_caption"]).x);
|
||||
total_text_max = std::max(total_text_max, imgui_wrapper->calc_text_size(m_desc_move[t]).x);
|
||||
}
|
||||
show_move_tooltip_information(imgui_wrapper, tip_caption_max, x, get_cur_y);
|
||||
|
||||
GLGizmoUtils::render_tooltip_button(imgui_wrapper, m_glcanvas, m_shortcuts_move, x, y);
|
||||
|
||||
m_last_active_item = current_active_id;
|
||||
last_move_input_window_width = ImGui::GetWindowWidth();
|
||||
imgui_wrapper->end();
|
||||
@@ -1154,14 +1052,8 @@ void GizmoObjectManipulation::do_render_rotate_window(ImGuiWrapper *imgui_wrappe
|
||||
if (!focued_on_text && !absolute_focued_on_text)
|
||||
m_glcanvas.handle_sidebar_focus_event("", false);
|
||||
|
||||
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
float tip_caption_max = 0.f;
|
||||
float total_text_max = 0.f;
|
||||
for (const auto &t : std::array<std::string, 1>{"part_selection"}) {
|
||||
tip_caption_max = std::max(tip_caption_max, imgui_wrapper->calc_text_size(m_desc_move[t + "_caption"]).x);
|
||||
total_text_max = std::max(total_text_max, imgui_wrapper->calc_text_size(m_desc_move[t]).x);
|
||||
}
|
||||
show_rotate_tooltip_information(imgui_wrapper, tip_caption_max, x, get_cur_y);
|
||||
GLGizmoUtils::render_tooltip_button(imgui_wrapper, m_glcanvas, m_shortcuts_rotate, x, y);
|
||||
|
||||
m_last_active_item = current_active_id;
|
||||
last_rotate_input_window_width = ImGui::GetWindowWidth();
|
||||
imgui_wrapper->end();
|
||||
@@ -1394,14 +1286,9 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
|
||||
}
|
||||
if (!focued_on_text)
|
||||
m_glcanvas.handle_sidebar_focus_event("", false);
|
||||
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
float tip_caption_max = 0.f;
|
||||
float total_text_max = 0.f;
|
||||
for (const auto &t : std::array<std::string, 3>{"part_selection", "snap_step", "single_sided"}) {
|
||||
tip_caption_max = std::max(tip_caption_max, imgui_wrapper->calc_text_size(m_desc_scale[t + "_caption"]).x);
|
||||
total_text_max = std::max(total_text_max, imgui_wrapper->calc_text_size(m_desc_scale[t]).x);
|
||||
}
|
||||
show_scale_tooltip_information(imgui_wrapper, tip_caption_max, x, get_cur_y);
|
||||
|
||||
GLGizmoUtils::render_tooltip_button(imgui_wrapper, m_glcanvas, m_shortcuts_scale, x, y);
|
||||
|
||||
m_last_active_item = current_active_id;
|
||||
|
||||
last_scale_input_window_width = ImGui::GetWindowWidth();
|
||||
|
||||
@@ -143,9 +143,6 @@ public:
|
||||
bool reset_zero_button(ImGuiWrapper *imgui_wrapper, float caption_max, float unit_size, float space_size, float end_text_size);
|
||||
bool bbl_checkbox(const wxString &label, bool &value);
|
||||
|
||||
void show_move_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y);
|
||||
void show_rotate_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y);
|
||||
void show_scale_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y);
|
||||
void set_init_rotation(const Geometry::Transformation &value);
|
||||
|
||||
private:
|
||||
@@ -171,9 +168,14 @@ private:
|
||||
|
||||
GLCanvas3D& m_glcanvas;
|
||||
unsigned int m_last_active_item { 0 };
|
||||
std::map<std::string, wxString> m_desc_move;
|
||||
std::map<std::string, wxString> m_desc_rotate;
|
||||
std::map<std::string, wxString> m_desc_scale;
|
||||
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts_move;
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts_rotate;
|
||||
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
||||
std::vector<std::pair<wxString, wxString>> m_shortcuts_scale;
|
||||
|
||||
Vec3d m_init_rotation;
|
||||
Transform3d m_init_rotation_scale_tran;
|
||||
};
|
||||
|
||||
@@ -225,13 +225,17 @@ GCodeInputData convert(const Slic3r::GCodeProcessorResult& result, const std::ve
|
||||
curr.mm3_per_mm, curr.fan_speed, curr.temperature, 0.0f, convert(curr.extrusion_role), curr_type,
|
||||
static_cast<uint32_t>(curr.gcode_id), static_cast<uint32_t>(curr.layer_id),
|
||||
static_cast<uint8_t>(curr.extruder_id), static_cast<uint8_t>(curr.cp_color_id), { 0.0f, 0.0f },
|
||||
/* ORCA: Add Pressure Advance visualization support */ 0.0f, curr.pressure_advance };
|
||||
/* ORCA: Add Pressure Advance visualization support */ 0.0f, curr.pressure_advance,
|
||||
/* ORCA: Add Acceleration visualization support */ curr.acceleration,
|
||||
/* ORCA: Add Jerk visualization support */ curr.jerk };
|
||||
#else
|
||||
const libvgcode::PathVertex vertex = { convert(prev.position), curr.height, curr.width, curr.feedrate, prev.actual_feedrate,
|
||||
curr.mm3_per_mm, curr.fan_speed, curr.temperature, convert(curr.extrusion_role), curr_type,
|
||||
static_cast<uint32_t>(curr.gcode_id), static_cast<uint32_t>(curr.layer_id),
|
||||
static_cast<uint8_t>(curr.extruder_id), static_cast<uint8_t>(curr.cp_color_id), { 0.0f, 0.0f },
|
||||
/* ORCA: Add Pressure Advance visualization support */ 0.0f, curr.pressure_advance };
|
||||
/* ORCA: Add Pressure Advance visualization support */ 0.0f, curr.pressure_advance,
|
||||
/* ORCA: Add Acceleration visualization support */ curr.acceleration,
|
||||
/* ORCA: Add Jerk visualization support */ curr.jerk };
|
||||
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
|
||||
ret.vertices.emplace_back(vertex);
|
||||
}
|
||||
@@ -243,13 +247,17 @@ GCodeInputData convert(const Slic3r::GCodeProcessorResult& result, const std::ve
|
||||
result.filament_densities[curr.extruder_id] * curr.mm3_per_mm * (curr.position - prev.position).norm(),
|
||||
convert(curr.extrusion_role), curr_type, static_cast<uint32_t>(curr.gcode_id), static_cast<uint32_t>(curr.layer_id),
|
||||
static_cast<uint8_t>(curr.extruder_id), static_cast<uint8_t>(curr.cp_color_id), curr.time,
|
||||
/* ORCA: Add Pressure Advance visualization support */ 0.0f, curr.pressure_advance };
|
||||
/* ORCA: Add Pressure Advance visualization support */ 0.0f, curr.pressure_advance,
|
||||
/* ORCA: Add Acceleration visualization support */ curr.acceleration,
|
||||
/* ORCA: Add Jerk visualization support */ curr.jerk };
|
||||
#else
|
||||
const libvgcode::PathVertex vertex = { convert(curr.position), curr.height, curr.width, curr.feedrate, curr.actual_feedrate,
|
||||
curr.mm3_per_mm, curr.fan_speed, curr.temperature, convert(curr.extrusion_role), curr_type,
|
||||
static_cast<uint32_t>(curr.gcode_id), static_cast<uint32_t>(curr.layer_id),
|
||||
static_cast<uint8_t>(curr.extruder_id), static_cast<uint8_t>(curr.cp_color_id), curr.time,
|
||||
/* ORCA: Add Pressure Advance visualization support */ 0.0f, curr.pressure_advance };
|
||||
/* ORCA: Add Pressure Advance visualization support */ 0.0f, curr.pressure_advance,
|
||||
/* ORCA: Add Acceleration visualization support */ curr.acceleration,
|
||||
/* ORCA: Add Jerk visualization support */ curr.jerk };
|
||||
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
|
||||
ret.vertices.emplace_back(vertex);
|
||||
}
|
||||
|
||||
@@ -3278,23 +3278,15 @@ void MainFrame::init_menubar_as_editor()
|
||||
}, "", nullptr,
|
||||
[this]() {return m_plater->is_view3D_shown();; }, this);
|
||||
|
||||
// Flow rate (with submenu)
|
||||
auto flowrate_menu = new wxMenu();
|
||||
append_menu_item(
|
||||
flowrate_menu, wxID_ANY, _L("Pass 1"), _L("Flow ratio test - Pass 1"),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(false, 1); }, "", nullptr,
|
||||
// Flow rate (Wizard Dialog)
|
||||
append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("Flow ratio"), _L("Flow Rate Calibration"),
|
||||
[this](wxCommandEvent&) {
|
||||
if (!m_plater) return;
|
||||
if (!m_flow_rate_calib_dlg)
|
||||
m_flow_rate_calib_dlg = new FlowRateCalibrationDialog((wxWindow*)this, wxID_ANY, m_plater);
|
||||
m_flow_rate_calib_dlg->ShowModal();
|
||||
}, "", nullptr,
|
||||
[this]() {return m_plater->is_view3D_shown();; }, this);
|
||||
append_menu_item(flowrate_menu, wxID_ANY, _L("Pass 2"), _L("Flow ratio test - Pass 2"),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(false, 2); }, "", nullptr,
|
||||
[this]() {return m_plater->is_view3D_shown();; }, this);
|
||||
flowrate_menu->AppendSeparator();
|
||||
append_menu_item(flowrate_menu, wxID_ANY, _L("YOLO (Recommended)"), _L("Orca YOLO flowratio calibration, 0.01 step"),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(true, 1); }, "", nullptr,
|
||||
[this]() {return m_plater->is_view3D_shown();; }, this);
|
||||
append_menu_item(flowrate_menu, wxID_ANY, _L("YOLO (perfectionist version)"), _L("Orca YOLO flowratio calibration, 0.005 step"),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(true, 2); }, "", nullptr,
|
||||
[this]() {return m_plater->is_view3D_shown();; }, this);
|
||||
m_topbar->GetCalibMenu()->AppendSubMenu(flowrate_menu, _L("Flow ratio"));
|
||||
|
||||
// Retraction
|
||||
append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("Retraction"), _L("Retraction"),
|
||||
@@ -3390,21 +3382,14 @@ void MainFrame::init_menubar_as_editor()
|
||||
[this]() {return m_plater->is_view3D_shown();; }, this);
|
||||
|
||||
// Flowrate (with submenu)
|
||||
auto flowrate_menu = new wxMenu();
|
||||
append_menu_item(flowrate_menu, wxID_ANY, _L("Pass 1"), _L("Flow ratio test - Pass 1"),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(false, 1); }, "", nullptr,
|
||||
[this]() {return m_plater->is_view3D_shown();; }, this);
|
||||
append_menu_item(flowrate_menu, wxID_ANY, _L("Pass 2"), _L("Flow ratio test - Pass 2"),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(false, 2); }, "", nullptr,
|
||||
[this]() {return m_plater->is_view3D_shown();; }, this);
|
||||
append_submenu(calib_menu,flowrate_menu,wxID_ANY,_L("Flow ratio"),_L("Flow ratio"),"",
|
||||
[this]() {return m_plater->is_view3D_shown();; });
|
||||
flowrate_menu->AppendSeparator();
|
||||
append_menu_item(flowrate_menu, wxID_ANY, _L("YOLO (Recommended)"), _L("Orca YOLO flowratio calibration, 0.01 step"),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(true, 1); }, "", nullptr,
|
||||
[this]() {return m_plater->is_view3D_shown();; }, this);
|
||||
append_menu_item(flowrate_menu, wxID_ANY, _L("YOLO (perfectionist version)"), _L("Orca YOLO flowratio calibration, 0.005 step"),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(true, 2); }, "", nullptr,
|
||||
// ORCA: Flow rate (Wizard Dialog)
|
||||
append_menu_item(calib_menu, wxID_ANY, _L("Flow ratio"), _L("Flow Rate Calibration"),
|
||||
[this](wxCommandEvent&) {
|
||||
if (!m_plater) return;
|
||||
if (!m_flow_rate_calib_dlg)
|
||||
m_flow_rate_calib_dlg = new FlowRateCalibrationDialog((wxWindow*)this, wxID_ANY, m_plater);
|
||||
m_flow_rate_calib_dlg->ShowModal();
|
||||
}, "", nullptr,
|
||||
[this]() {return m_plater->is_view3D_shown();; }, this);
|
||||
|
||||
// Retraction
|
||||
@@ -4361,3 +4346,4 @@ void SettingsDialog::on_dpi_changed(const wxRect& suggested_rect)
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
|
||||
@@ -362,6 +362,7 @@ public:
|
||||
void fit_tab_labels(); // ORCA
|
||||
|
||||
PA_Calibration_Dlg* m_pa_calib_dlg{ nullptr };
|
||||
FlowRateCalibrationDialog* m_flow_rate_calib_dlg{ nullptr };
|
||||
Temp_Calibration_Dlg* m_temp_calib_dlg{ nullptr };
|
||||
MaxVolumetricSpeed_Test_Dlg* m_vol_test_dlg { nullptr };
|
||||
VFA_Test_Dlg* m_vfa_test_dlg { nullptr };
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
static constexpr float GAP_WIDTH = 10.0f;
|
||||
static constexpr float SPACE_RIGHT_PANEL = 10.0f;
|
||||
static constexpr float FADING_OUT_DURATION = 2.0f;
|
||||
// Time in Miliseconds after next render when fading out is requested
|
||||
// Time in Milliseconds after next render when fading out is requested
|
||||
static constexpr int FADING_OUT_TIMEOUT = 100;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -126,8 +126,8 @@ enum class NotificationType
|
||||
SimplifySuggestion,
|
||||
// Change of text will change font to similar one on.
|
||||
UnknownFont,
|
||||
// information about netfabb is finished repairing model (blocking proccess)
|
||||
NetfabbFinished,
|
||||
// information about cgal is finished repairing model (blocking process)
|
||||
CgalFinished,
|
||||
// Short meesage to fill space between start and finish of export
|
||||
ExportOngoing,
|
||||
// Progressbar of download from prusaslicer://url
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include "PrintHostDialogs.hpp"
|
||||
#include "../Utils/ASCIIFolding.hpp"
|
||||
#include "../Utils/PrintHost.hpp"
|
||||
#include "../Utils/FixModelByWin10.hpp"
|
||||
#include "../Utils/UndoRedo.hpp"
|
||||
#include "RemovableDriveManager.hpp"
|
||||
#include "BitmapCache.hpp"
|
||||
|
||||
+142
-103
@@ -115,7 +115,6 @@
|
||||
#include "ConfigWizard.hpp"
|
||||
#include "SyncAmsInfoDialog.hpp"
|
||||
#include "../Utils/ASCIIFolding.hpp"
|
||||
#include "../Utils/FixModelByWin10.hpp"
|
||||
#include "../Utils/UndoRedo.hpp"
|
||||
#include "../Utils/PresetUpdater.hpp"
|
||||
#include "../Utils/Process.hpp"
|
||||
@@ -586,7 +585,7 @@ void Sidebar::priv::layout_printer(bool isBBL, bool isDual)
|
||||
//if (isBBL) {
|
||||
wxBoxSizer *hsizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
hsizer->Add(image_printer, 0, wxLEFT | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, FromDIP(10));
|
||||
hsizer->Add(combo_printer, 1, wxEXPAND | wxALL, FromDIP(2));
|
||||
hsizer->Add(combo_printer, 1, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(2)); // 1 already triggers wxEXPAND
|
||||
hsizer->AddSpacer(FromDIP(2));
|
||||
hsizer->Add(btn_edit_printer, 0, wxRIGHT | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(SidebarProps::IconSpacing()));
|
||||
//hsizer->Add(btn_connect_printer, 0, wxRIGHT | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(SidebarProps::IconSpacing()));
|
||||
@@ -4033,6 +4032,8 @@ void Sidebar::update_printer_thumbnail()
|
||||
if (printer_thumbnails.find(printer_type) != printer_thumbnails.end()) // Use known cache first
|
||||
p->image_printer->SetBitmap(create_scaled_bitmap(printer_thumbnails[printer_type], this, PRINTER_THUMBNAIL_SIZE.GetHeight()));
|
||||
else {
|
||||
/* ORCA this part check images folder for BBL covers but not checks file existence and causes crash on Linux
|
||||
* BBL covers already exist on profile folder so no need to use this section
|
||||
try {
|
||||
// No cache, try dedicated printer preview
|
||||
p->image_printer->SetBitmap(create_scaled_bitmap("printer_preview_" + printer_type, this, 48));
|
||||
@@ -4040,6 +4041,7 @@ void Sidebar::update_printer_thumbnail()
|
||||
printer_thumbnails[printer_type] = "printer_preview_" + printer_type;
|
||||
return;
|
||||
} catch (...) {}
|
||||
*/
|
||||
|
||||
// Orca: try to use the printer model cover as the thumbnail
|
||||
const auto model_name = selected_preset.config.opt_string("printer_model");
|
||||
@@ -4731,7 +4733,7 @@ struct Plater::priv
|
||||
bool can_split_to_volumes() const;
|
||||
bool can_arrange() const;
|
||||
bool can_layers_editing() const;
|
||||
bool can_fix_through_netfabb() const;
|
||||
bool can_fix_through_cgal() const;
|
||||
bool can_simplify() const;
|
||||
bool can_smooth_mesh() const;
|
||||
bool can_set_instance_to_object() const;
|
||||
@@ -4879,13 +4881,13 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
"extruder_clearance_radius",
|
||||
"extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod",
|
||||
"nozzle_height", "skirt_type", "skirt_loops", "skirt_speed","min_skirt_length", "skirt_distance", "skirt_start_angle",
|
||||
"brim_width", "brim_object_gap", "brim_use_efc_outline", "combine_brims", "brim_type", "nozzle_diameter", "single_extruder_multi_material", "preferred_orientation",
|
||||
"brim_width", "brim_object_gap", "brim_flow_ratio", "brim_use_efc_outline", "combine_brims", "brim_type", "nozzle_diameter", "single_extruder_multi_material", "preferred_orientation",
|
||||
"enable_prime_tower", "wipe_tower_x", "wipe_tower_y", "prime_tower_width", "prime_tower_brim_width", "prime_tower_skip_points", "prime_tower_enable_framework",
|
||||
"prime_tower_infill_gap", "prime_volume",
|
||||
"extruder_colour", "filament_colour", "filament_type", "material_colour", "printable_height", "extruder_printable_height", "printer_model", "printer_technology",
|
||||
// These values are necessary to construct SlicingParameters by the Canvas3D variable layer height editor.
|
||||
"layer_height", "initial_layer_print_height", "min_layer_height", "max_layer_height",
|
||||
"brim_width", "wall_loops", "wall_filament", "sparse_infill_density", "sparse_infill_filament", "top_shell_layers",
|
||||
"wall_loops", "wall_filament", "sparse_infill_density", "sparse_infill_filament", "top_shell_layers",
|
||||
"enable_support", "support_filament", "support_interface_filament",
|
||||
"support_top_z_distance", "support_bottom_z_distance", "raft_layers",
|
||||
"wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_extra_flow", "wipe_tower_max_purge_speed",
|
||||
@@ -5955,9 +5957,9 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
if (cancel)
|
||||
is_user_cancel = cancel;
|
||||
});
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__
|
||||
<< boost::format(", plate_data.size %1%, project_preset.size %2%, is_bbs_3mf %3%, file_version %4% \n") % plate_data.size() %
|
||||
project_presets.size() % (en_3mf_file_type == En3mfType::From_BBS) % file_version.to_string();
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__
|
||||
<< boost::format(", plate_data.size %1%, project_preset.size %2%, is_bbs_or_orca_3mf %3%, file_version %4% \n") % plate_data.size() %
|
||||
project_presets.size() % (en_3mf_file_type == En3mfType::From_BBS || en_3mf_file_type == En3mfType::From_Orca) % file_version.to_string();
|
||||
|
||||
// 1. add extruder for prusa model if the number of existing extruders is not enough
|
||||
// 2. add extruder for BBS or Other model if only import geometry
|
||||
@@ -5999,88 +6001,123 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
if(load_type != LoadType::LoadGeometry)
|
||||
show_info(q, _L("The 3MF is not supported by OrcaSlicer, loading geometry data only."), _L("Load 3MF"));
|
||||
}
|
||||
// else if (load_config && (file_version.maj() != app_version.maj())) {
|
||||
// // version mismatch, only load geometries
|
||||
// load_config = false;
|
||||
// if (!load_model) {
|
||||
// // only load config case, return directly
|
||||
// show_info(q, _L("The Config cannot be loaded."), _L("Load 3MF"));
|
||||
// q->skip_thumbnail_invalid = false;
|
||||
// return empty_result;
|
||||
// }
|
||||
// load_old_project = true;
|
||||
// // select view to 3D
|
||||
// q->select_view_3D("3D");
|
||||
// // select plate 0 as default
|
||||
// q->select_plate(0);
|
||||
// if (load_type != LoadType::LoadGeometry) {
|
||||
// if (en_3mf_file_type == En3mfType::From_BBS)
|
||||
// show_info(q, _L("The 3MF was generated by an old OrcaSlicer, loading geometry data only."), _L("Load 3MF"));
|
||||
// else
|
||||
// show_info(q, _L("The 3MF is not supported by OrcaSlicer, loading geometry data only."), _L("Load 3MF"));
|
||||
// }
|
||||
// for (ModelObject *model_object : model.objects) {
|
||||
// model_object->config.reset();
|
||||
// // Is there any modifier or advanced config data?
|
||||
// for (ModelVolume *model_volume : model_object->volumes) model_volume->config.reset();
|
||||
// }
|
||||
// }
|
||||
// Orca: check if the project is created with OrcaSlicer 2.3.1-alpha and use the sparse infill rotation template for non-safe infill patterns
|
||||
else if (load_config && (file_version < app_version) && file_version == Semver("2.3.1-alpha")) {
|
||||
if (!config_loaded.opt_string("sparse_infill_rotate_template").empty()) {
|
||||
const auto _sparse_infill_pattern =
|
||||
config_loaded.option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value;
|
||||
bool is_safe_to_rotate = _sparse_infill_pattern == ipRectilinear || _sparse_infill_pattern == ipLine ||
|
||||
_sparse_infill_pattern == ipZigZag || _sparse_infill_pattern == ipCrossZag ||
|
||||
_sparse_infill_pattern == ipLockedZag;
|
||||
if (!is_safe_to_rotate) {
|
||||
wxString msg_text = _(
|
||||
L("This project was created with an OrcaSlicer 2.3.1-alpha and uses "
|
||||
"infill rotation template settings that may not work properly with your current infill pattern. "
|
||||
"This could result in weak support or print quality issues."));
|
||||
msg_text += "\n\n" +
|
||||
_(L("Would you like OrcaSlicer to automatically fix this by clearing the rotation template settings?"));
|
||||
MessageDialog dialog(wxGetApp().plater(), msg_text, "", wxICON_WARNING | wxYES | wxNO);
|
||||
dialog.SetButtonLabel(wxID_YES, _L("Yes"));
|
||||
dialog.SetButtonLabel(wxID_NO, _L("No"));
|
||||
if (dialog.ShowModal() == wxID_YES) {
|
||||
config_loaded.opt_string("sparse_infill_rotate_template") = "";
|
||||
else if (en_3mf_file_type == En3mfType::From_Orca) {
|
||||
// OrcaSlicer file (has OrcaSlicer tag) - compare file_version with SoftFever_VERSION
|
||||
// Migration fix for OrcaSlicer 2.3.1-alpha sparse infill rotation template
|
||||
if (load_config && (file_version < app_version) && file_version == Semver("2.3.1-alpha")) {
|
||||
if (!config_loaded.opt_string("sparse_infill_rotate_template").empty()) {
|
||||
const auto _sparse_infill_pattern =
|
||||
config_loaded.option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value;
|
||||
bool is_safe_to_rotate = _sparse_infill_pattern == ipRectilinear || _sparse_infill_pattern == ipLine ||
|
||||
_sparse_infill_pattern == ipZigZag || _sparse_infill_pattern == ipCrossZag ||
|
||||
_sparse_infill_pattern == ipLockedZag;
|
||||
if (!is_safe_to_rotate) {
|
||||
wxString msg_text = _(
|
||||
L("This project was created with an OrcaSlicer 2.3.1-alpha and uses "
|
||||
"infill rotation template settings that may not work properly with your current infill pattern. "
|
||||
"This could result in weak support or print quality issues."));
|
||||
msg_text += "\n\n" +
|
||||
_(L("Would you like OrcaSlicer to automatically fix this by clearing the rotation template settings?"));
|
||||
MessageDialog dialog(wxGetApp().plater(), msg_text, "", wxICON_WARNING | wxYES | wxNO);
|
||||
dialog.SetButtonLabel(wxID_YES, _L("Yes"));
|
||||
dialog.SetButtonLabel(wxID_NO, _L("No"));
|
||||
if (dialog.ShowModal() == wxID_YES) {
|
||||
config_loaded.opt_string("sparse_infill_rotate_template") = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (load_config && (file_version > app_version)) {
|
||||
if (config_substitutions.unrecogized_keys.size() > 0) {
|
||||
wxString text = wxString::Format(_L("The 3MF file version %s is newer than %s's version %s, found the following unrecognized keys:"),
|
||||
file_version.to_string_sf(), std::string(SLIC3R_APP_FULL_NAME), app_version.to_string_sf());
|
||||
text += "\n";
|
||||
wxString context = text;
|
||||
wxString append = _L("You'd better upgrade your software.\n");
|
||||
context += "\n\n";
|
||||
context += append;
|
||||
show_info(q, context, _L("Newer 3MF version"));
|
||||
}
|
||||
else {
|
||||
//if the minor version is not matched
|
||||
if (file_version.min() != app_version.min()) {
|
||||
wxString text = wxString::Format(_L("The 3MF file version %s is newer than %s's version %s, we suggest to upgrade your software."),
|
||||
file_version.to_string_sf(), std::string(SLIC3R_APP_FULL_NAME), app_version.to_string_sf());
|
||||
text += "\n";
|
||||
show_info(q, text, _L("Newer 3MF version"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (load_config && (file_version > app_version)) {
|
||||
if (config_substitutions.unrecogized_keys.size() > 0) {
|
||||
wxString text = wxString::Format(_L("The 3MF file version %s is newer than %s's version %s, found the following unrecognized keys:"),
|
||||
file_version.to_string(), std::string(SLIC3R_APP_FULL_NAME), app_version.to_string());
|
||||
text += "\n";
|
||||
bool first = true;
|
||||
// std::string context = into_u8(text);
|
||||
wxString context = text;
|
||||
// if (wxGetApp().app_config->get("user_mode") == "develop") {
|
||||
// for (auto &key : config_substitutions.unrecogized_keys) {
|
||||
// context += " -";
|
||||
// context += key;
|
||||
// context += ";\n";
|
||||
// first = false;
|
||||
// }
|
||||
// }
|
||||
wxString append = _L("You'd better upgrade your software.\n");
|
||||
context += "\n\n";
|
||||
// context += into_u8(append);
|
||||
context += append;
|
||||
show_info(q, context, _L("Newer 3MF version"));
|
||||
else if (load_config && config_loaded.empty()) {
|
||||
load_config = false;
|
||||
show_info(q, _L("The 3MF file was generated by an old OrcaSlicer version, loading geometry data only."), _L("Load 3MF"));
|
||||
}
|
||||
else {
|
||||
//if the minor version is not matched
|
||||
if (file_version.min() != app_version.min()) {
|
||||
wxString text = wxString::Format(_L("The 3MF file version %s is newer than %s's version %s, we suggest to upgrade your software."),
|
||||
file_version.to_string(), std::string(SLIC3R_APP_FULL_NAME), app_version.to_string());
|
||||
text += "\n";
|
||||
show_info(q, text, _L("Newer 3MF version"));
|
||||
}
|
||||
else if (en_3mf_file_type == En3mfType::From_BBS) {
|
||||
// No OrcaSlicer tag - check Bambu/Application version
|
||||
Semver orca_tag_start_version(2, 3, 2);
|
||||
if (file_version <= orca_tag_start_version) {
|
||||
// Compatible old version (before OrcaSlicer tagging was introduced after 2.3.2).
|
||||
// Any version prior or equal to 2.3.2 is older than the current one, no version warnings needed.
|
||||
// Still apply migration fixes for known old versions.
|
||||
if (load_config && (file_version == Semver("2.3.1-alpha"))) {
|
||||
if (!config_loaded.opt_string("sparse_infill_rotate_template").empty()) {
|
||||
const auto _sparse_infill_pattern =
|
||||
config_loaded.option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value;
|
||||
bool is_safe_to_rotate = _sparse_infill_pattern == ipRectilinear || _sparse_infill_pattern == ipLine ||
|
||||
_sparse_infill_pattern == ipZigZag || _sparse_infill_pattern == ipCrossZag ||
|
||||
_sparse_infill_pattern == ipLockedZag;
|
||||
if (!is_safe_to_rotate) {
|
||||
wxString msg_text = _(
|
||||
L("This project was created with an OrcaSlicer 2.3.1-alpha and uses "
|
||||
"infill rotation template settings that may not work properly with your current infill pattern. "
|
||||
"This could result in weak support or print quality issues."));
|
||||
msg_text += "\n\n" +
|
||||
_(L("Would you like OrcaSlicer to automatically fix this by clearing the rotation template settings?"));
|
||||
MessageDialog dialog(wxGetApp().plater(), msg_text, "", wxICON_WARNING | wxYES | wxNO);
|
||||
dialog.SetButtonLabel(wxID_YES, _L("Yes"));
|
||||
dialog.SetButtonLabel(wxID_NO, _L("No"));
|
||||
if (dialog.ShowModal() == wxID_YES) {
|
||||
config_loaded.opt_string("sparse_infill_rotate_template") = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (load_config && config_loaded.empty()) {
|
||||
load_config = false;
|
||||
show_info(q, _L("The 3MF file was generated by an older version, loading geometry data only."), _L("Load 3MF"));
|
||||
}
|
||||
} else {
|
||||
// BambuStudio project (version > 2.3.2 without OrcaSlicer tag)
|
||||
// Report that a BambuStudio project is being imported and compare with SLIC3R_VERSION
|
||||
Semver slic3r_version = *(Semver::parse(SLIC3R_VERSION));
|
||||
if (load_config && config_loaded.empty()) {
|
||||
load_config = false;
|
||||
show_info(q, _L("The 3MF file was generated by BambuStudio, loading geometry data only."), _L("Load 3MF"));
|
||||
}
|
||||
else if (load_config && (file_version > slic3r_version)) {
|
||||
// BambuStudio file version is newer than our compatible SLIC3R_VERSION
|
||||
if (config_substitutions.unrecogized_keys.size() > 0) {
|
||||
wxString text = wxString::Format(_L("The 3MF was created by BambuStudio (version %s), which is newer than the compatible version %s. Found unrecognized settings:"),
|
||||
file_version.to_string(), slic3r_version.to_string());
|
||||
text += "\n";
|
||||
wxString context = text;
|
||||
wxString append = _L("You'd better upgrade your software.\n");
|
||||
context += "\n\n";
|
||||
context += append;
|
||||
show_info(q, context, _L("BambuStudio Project"));
|
||||
} else {
|
||||
wxString text = wxString::Format(_L("The 3MF was created by BambuStudio (version %s), which is newer than the compatible version %s. Some settings may not be fully compatible."),
|
||||
file_version.to_string(), slic3r_version.to_string());
|
||||
text += "\n";
|
||||
show_info(q, text, _L("BambuStudio Project"));
|
||||
}
|
||||
} else if (load_config) {
|
||||
// BambuStudio version is older or same as our SLIC3R_VERSION
|
||||
wxString text = _L("The 3MF was created by BambuStudio. Some settings may differ from OrcaSlicer.");
|
||||
show_info(q, text, _L("BambuStudio Project"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (load_config && config_loaded.empty()) {
|
||||
load_config = false;
|
||||
show_info(q, _L("The 3MF file was generated by an old OrcaSlicer version, loading geometry data only."), _L("Load 3MF"));
|
||||
@@ -6121,7 +6158,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
}
|
||||
|
||||
Semver old_version(1, 5, 9);
|
||||
if ((en_3mf_file_type == En3mfType::From_BBS) && (file_version < old_version) && load_model && load_config && !config_loaded.empty()) {
|
||||
if ((en_3mf_file_type == En3mfType::From_BBS || en_3mf_file_type == En3mfType::From_Orca) && (file_version < old_version) && load_model && load_config && !config_loaded.empty()) {
|
||||
translate_old = true;
|
||||
partplate_list.get_plate_size(current_width, current_depth, current_height);
|
||||
}
|
||||
@@ -6208,7 +6245,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
{
|
||||
// BBS: modify the prime tower params for old version file
|
||||
Semver old_version3(2, 0, 0);
|
||||
if (en_3mf_file_type == En3mfType::From_BBS && file_version < old_version3) {
|
||||
if ((en_3mf_file_type == En3mfType::From_BBS || en_3mf_file_type == En3mfType::From_Orca) && file_version < old_version3) {
|
||||
double old_filament_prime_volume = 0.;
|
||||
int filament_count = 0;
|
||||
{
|
||||
@@ -10371,10 +10408,10 @@ void Plater::priv::on_object_select(SimpleEvent& evt)
|
||||
selection_changed();
|
||||
}
|
||||
|
||||
//BBS: repair model through netfabb
|
||||
//BBS: repair model through cgal
|
||||
void Plater::priv::on_repair_model(wxCommandEvent &event)
|
||||
{
|
||||
wxGetApp().obj_list()->fix_through_netfabb();
|
||||
wxGetApp().obj_list()->fix_through_cgal();
|
||||
}
|
||||
|
||||
void Plater::priv::on_filament_color_changed(wxCommandEvent &event)
|
||||
@@ -11348,15 +11385,15 @@ bool Plater::priv::can_delete_plate() const
|
||||
return q->get_partplate_list().get_plate_count() > 1;
|
||||
}
|
||||
|
||||
bool Plater::priv::can_fix_through_netfabb() const
|
||||
bool Plater::priv::can_fix_through_cgal() const
|
||||
{
|
||||
std::vector<int> obj_idxs, vol_idxs;
|
||||
sidebar->obj_list()->get_selection_indexes(obj_idxs, vol_idxs);
|
||||
|
||||
#if FIX_THROUGH_NETFABB_ALWAYS
|
||||
#if FIX_THROUGH_CGAL_ALWAYS
|
||||
// Fixing always.
|
||||
return ! obj_idxs.empty() || ! vol_idxs.empty();
|
||||
#else // FIX_THROUGH_NETFABB_ALWAYS
|
||||
#else // FIX_THROUGH_CGAL_ALWAYS
|
||||
// Fixing only if the model is not manifold.
|
||||
if (vol_idxs.empty()) {
|
||||
for (auto obj_idx : obj_idxs)
|
||||
@@ -11370,7 +11407,7 @@ bool Plater::priv::can_fix_through_netfabb() const
|
||||
if (model.objects[obj_idx]->get_repaired_errors_count(vol_idx) > 0)
|
||||
return true;
|
||||
return false;
|
||||
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
||||
#endif // FIX_THROUGH_CGAL_ALWAYS
|
||||
}
|
||||
|
||||
bool Plater::priv::can_simplify() const
|
||||
@@ -12901,7 +12938,8 @@ void Plater::_calib_pa_select_added_objects() {
|
||||
|
||||
// Adjust settings for flowrate calibration
|
||||
// For linear mode, pass 1 means normal version while pass 2 mean "for perfectionists" version
|
||||
void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, int pass)
|
||||
// ORCA: Add pattern parameter
|
||||
void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, int pass, InfillPattern pattern)
|
||||
{
|
||||
auto print_config = &wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
auto printerConfig = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||
@@ -12964,7 +13002,8 @@ void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, i
|
||||
_obj->config.set_key_value("sparse_infill_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinear));
|
||||
_obj->config.set_key_value("top_surface_line_width", new ConfigOptionFloatOrPercent(nozzle_diameter * 1.2f, false));
|
||||
_obj->config.set_key_value("internal_solid_infill_line_width", new ConfigOptionFloatOrPercent(nozzle_diameter * 1.2f, false));
|
||||
_obj->config.set_key_value("top_surface_pattern", new ConfigOptionEnum<InfillPattern>(ipArchimedeanChords));
|
||||
// ORCA: use the pattern parameter
|
||||
_obj->config.set_key_value("top_surface_pattern", new ConfigOptionEnum<InfillPattern>(pattern));
|
||||
_obj->config.set_key_value("top_solid_infill_flow_ratio", new ConfigOptionFloat(1.0f));
|
||||
_obj->config.set_key_value("infill_direction", new ConfigOptionFloat(45));
|
||||
_obj->config.set_key_value("solid_infill_direction", new ConfigOptionFloat(135));
|
||||
@@ -13015,7 +13054,8 @@ void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, i
|
||||
wxGetApp().get_tab(Preset::TYPE_PRINTER)->reload_config();
|
||||
}
|
||||
|
||||
void Plater::calib_flowrate(bool is_linear, int pass) {
|
||||
// ORCA: Add pattern parameter
|
||||
void Plater::calib_flowrate(bool is_linear, int pass, InfillPattern pattern) {
|
||||
if (pass != 1 && pass != 2)
|
||||
return;
|
||||
wxString calib_name;
|
||||
@@ -13047,7 +13087,8 @@ void Plater::calib_flowrate(bool is_linear, int pass) {
|
||||
(boost::filesystem::path(Slic3r::resources_dir()) / "calib" / "filament_flow" / "flowrate-test-pass2.3mf").string());
|
||||
}
|
||||
|
||||
adjust_settings_for_flowrate_calib(model().objects, is_linear, pass);
|
||||
// ORCA: pass the pattern
|
||||
adjust_settings_for_flowrate_calib(model().objects, is_linear, pass, pattern);
|
||||
wxGetApp().get_tab(Preset::TYPE_PRINTER)->reload_config();
|
||||
auto printer_config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
|
||||
@@ -18183,15 +18224,13 @@ void Plater::show_object_info()
|
||||
int non_manifold_edges = 0;
|
||||
auto mesh_errors = p->sidebar->obj_list()->get_mesh_errors_info(&info_manifold, &non_manifold_edges);
|
||||
|
||||
#ifndef __WINDOWS__
|
||||
if (non_manifold_edges > 0) {
|
||||
info_manifold += into_u8("\n" + _L("Tips:") + "\n" +_L("\"Fix Model\" feature is currently only on Windows. Please repair the model on Orca Slicer(windows) or CAD softwares."));
|
||||
}
|
||||
#endif //APPLE & LINUX
|
||||
if (non_manifold_edges > 0) {
|
||||
info_manifold += into_u8("\n" + _L("Tips:") + "\n" + _L("Use \"Fix Model\" to repair the mesh."));
|
||||
}
|
||||
|
||||
info_manifold = "<Error>" + info_manifold + "</Error>";
|
||||
info_text += into_u8(info_manifold);
|
||||
notify_manager->bbl_show_objectsinfo_notification(info_text, is_windows10()&&(non_manifold_edges > 0), !(p->current_panel == p->view3D));
|
||||
notify_manager->bbl_show_objectsinfo_notification(info_text, non_manifold_edges > 0, !(p->current_panel == p->view3D));
|
||||
}
|
||||
|
||||
bool Plater::show_publish_dialog(bool show)
|
||||
@@ -18368,7 +18407,7 @@ bool Plater::can_delete_plate() const { return p->can_delete_plate(); }
|
||||
bool Plater::can_increase_instances() const { return p->can_increase_instances(); }
|
||||
bool Plater::can_decrease_instances() const { return p->can_decrease_instances(); }
|
||||
bool Plater::can_set_instance_to_object() const { return p->can_set_instance_to_object(); }
|
||||
bool Plater::can_fix_through_netfabb() const { return p->can_fix_through_netfabb(); }
|
||||
bool Plater::can_fix_through_cgal() const { return p->can_fix_through_cgal(); }
|
||||
bool Plater::can_simplify() const { return p->can_simplify(); }
|
||||
bool Plater::can_smooth_mesh() const { return p->can_smooth_mesh(); }
|
||||
bool Plater::can_split_to_objects() const { return p->can_split_to_objects(); }
|
||||
|
||||
@@ -331,7 +331,8 @@ public:
|
||||
|
||||
// SoftFever
|
||||
void calib_pa(const Calib_Params& params);
|
||||
void calib_flowrate(bool is_linear, int pass);
|
||||
//ORCA: Add pattern parameter to calib_flowrate
|
||||
void calib_flowrate(bool is_linear, int pass, InfillPattern pattern = ipArchimedeanChords);
|
||||
void calib_temp(const Calib_Params& params);
|
||||
void calib_max_vol_speed(const Calib_Params& params);
|
||||
void calib_retraction(const Calib_Params& params);
|
||||
@@ -674,7 +675,7 @@ public:
|
||||
bool can_increase_instances() const;
|
||||
bool can_decrease_instances() const;
|
||||
bool can_set_instance_to_object() const;
|
||||
bool can_fix_through_netfabb() const;
|
||||
bool can_fix_through_cgal() const;
|
||||
bool can_simplify() const;
|
||||
bool can_smooth_mesh() const;
|
||||
bool can_split_to_objects() const;
|
||||
|
||||
@@ -1360,6 +1360,11 @@ void PreferencesDialog::create_items()
|
||||
auto item_show_splash_scr = create_item_checkbox(_L("Show splash screen"), _L("Show the splash screen during startup."), "show_splash_screen");
|
||||
g_sizer->Add(item_show_splash_scr);
|
||||
|
||||
#ifdef __linux__
|
||||
auto item_window_button_pos = create_item_checkbox(_L("Use window buttons on left side"), "", "window_buttons_on_left", _L("(Requires restart)"));
|
||||
g_sizer->Add(item_window_button_pos);
|
||||
#endif
|
||||
|
||||
//auto item_hints = create_item_checkbox(_L("Show \"Daily Tips\" after start"), page, _L("If enabled, useful hints are displayed at startup."), "show_daily_tips");
|
||||
//g_sizer->Add(item_hints);
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include "Tab.hpp"
|
||||
#include "ConfigWizard.hpp"
|
||||
#include "../Utils/ASCIIFolding.hpp"
|
||||
#include "../Utils/FixModelByWin10.hpp"
|
||||
#include "../Utils/UndoRedo.hpp"
|
||||
#include "../Utils/ColorSpaceConvert.hpp"
|
||||
#include "BitmapCache.hpp"
|
||||
@@ -1210,14 +1209,24 @@ void PlaterPresetComboBox::update()
|
||||
//BBS: move system to the end
|
||||
if (m_type == Preset::TYPE_PRINTER) {
|
||||
auto printer_model = preset.config.opt_string("printer_model");
|
||||
name = from_u8(printer_model);
|
||||
|
||||
// ORCA: Make system printer presets display the dirty "*" prefix when edited.
|
||||
name = from_u8(is_selected && preset.is_dirty ? Preset::suffix_modified() + printer_model : printer_model);
|
||||
|
||||
if (system_printer_models.count(printer_model) == 0) {
|
||||
system_presets.emplace(name, bmp);
|
||||
system_printer_models.insert(printer_model);
|
||||
}
|
||||
else if (is_selected) {
|
||||
const wxString alternate_name = from_u8(preset.is_dirty ? printer_model : Preset::suffix_modified() + printer_model);
|
||||
// Remove the old preset name if exists, and add the new one with the same name but with modified suffix if needed.
|
||||
if (system_presets.erase(alternate_name))
|
||||
system_presets.emplace(name, bmp);
|
||||
}
|
||||
} else {
|
||||
system_presets.emplace(name, bmp);
|
||||
}
|
||||
|
||||
if (is_selected) {
|
||||
tooltip = get_tooltip(preset);
|
||||
selected_system_preset = name;
|
||||
|
||||
+65
-17
@@ -69,6 +69,9 @@ namespace GUI {
|
||||
|
||||
#define DISABLE_UNDO_SYS
|
||||
|
||||
// Forward declaration for early use; definitions live later in this translation unit.
|
||||
static void validate_custom_gcode_cb(Tab* tab, const wxString& title, const t_config_option_key& opt_key, const boost::any& value);
|
||||
|
||||
static const std::vector<std::string> plate_keys = { "curr_bed_type", "skirt_start_angle", "first_layer_print_sequence", "first_layer_sequence_choice", "other_layers_print_sequence", "other_layers_sequence_choice", "print_sequence", "spiral_mode"};
|
||||
|
||||
void Tab::Highlighter::set_timer_owner(wxEvtHandler* owner, int timerid/* = wxID_ANY*/)
|
||||
@@ -2505,6 +2508,7 @@ void TabPrint::build()
|
||||
optgroup->append_single_option_line("sparse_infill_acceleration", "speed_settings_acceleration#sparse-infill");
|
||||
optgroup->append_single_option_line("internal_solid_infill_acceleration", "speed_settings_acceleration#internal-solid-infill");
|
||||
optgroup->append_single_option_line("initial_layer_acceleration", "speed_settings_acceleration#initial-layer");
|
||||
optgroup->append_single_option_line("initial_layer_travel_acceleration", "speed_settings_acceleration#initial-layer-travel");
|
||||
optgroup->append_single_option_line("top_surface_acceleration", "speed_settings_acceleration#top-surface");
|
||||
optgroup->append_single_option_line("travel_acceleration", "speed_settings_acceleration#travel");
|
||||
optgroup->append_single_option_line("accel_to_decel_enable", "speed_settings_acceleration");
|
||||
@@ -2518,6 +2522,7 @@ void TabPrint::build()
|
||||
optgroup->append_single_option_line("infill_jerk", "speed_settings_jerk_xy#infill");
|
||||
optgroup->append_single_option_line("top_surface_jerk", "speed_settings_jerk_xy#top-surface");
|
||||
optgroup->append_single_option_line("initial_layer_jerk", "speed_settings_jerk_xy#initial-layer");
|
||||
optgroup->append_single_option_line("initial_layer_travel_jerk", "speed_settings_jerk_xy#initial-layer-travel");
|
||||
optgroup->append_single_option_line("travel_jerk", "speed_settings_jerk_xy#travel");
|
||||
|
||||
optgroup = page->new_optgroup(L("Advanced"), L"param_advanced", 15);
|
||||
@@ -2659,6 +2664,7 @@ void TabPrint::build()
|
||||
optgroup->append_single_option_line("brim_type", "others_settings_brim#type");
|
||||
optgroup->append_single_option_line("brim_width", "others_settings_brim#width");
|
||||
optgroup->append_single_option_line("brim_object_gap", "others_settings_brim#brim-object-gap");
|
||||
optgroup->append_single_option_line("brim_flow_ratio", "others_settings_brim#brim-flow-ratio");
|
||||
optgroup->append_single_option_line("brim_use_efc_outline", "others_settings_brim#brim-use-efc-outline");
|
||||
optgroup->append_single_option_line("combine_brims", "others_settings_brim#combine-brims");
|
||||
optgroup->append_single_option_line("brim_ears_max_angle", "others_settings_brim#ear-max-angle");
|
||||
@@ -2701,6 +2707,17 @@ void TabPrint::build()
|
||||
// option.opt.height = 5;
|
||||
optgroup->append_single_option_line(option, "others_settings_g_code_output#filename-format");
|
||||
|
||||
optgroup = page->new_optgroup(L("Change extrusion role G-code"), L"param_gcode", 0);
|
||||
optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(this, optgroup_title, opt_key, value);
|
||||
};
|
||||
optgroup->edit_custom_gcode = [this](const t_config_option_key& opt_key) { edit_custom_gcode(opt_key); };
|
||||
option = optgroup->get_option("process_change_extrusion_role_gcode");
|
||||
option.opt.full_width = true;
|
||||
option.opt.is_code = true;
|
||||
option.opt.height = 15;
|
||||
optgroup->append_single_option_line(option);
|
||||
|
||||
optgroup = page->new_optgroup(L("Post-processing Scripts"), L"param_gcode", 0);
|
||||
option = optgroup->get_option("post_process");
|
||||
option.opt.full_width = true;
|
||||
@@ -3883,8 +3900,8 @@ void TabFilament::build()
|
||||
//
|
||||
|
||||
optgroup = page->new_optgroup(L("Print chamber temperature"), L"param_chamber_temp");
|
||||
optgroup->append_single_option_line("chamber_temperature", "material_temperatures#print-chamber-temperature");
|
||||
optgroup->append_single_option_line("activate_chamber_temp_control", "material_temperatures#print-chamber-temperature");
|
||||
optgroup->append_single_option_line("chamber_temperature", "material_temperatures#print-chamber-temperature");
|
||||
|
||||
optgroup = page->new_optgroup(L("Print temperature"), L"param_extruder_temp");
|
||||
line = { L("Nozzle"), L("Nozzle temperature when printing") };
|
||||
@@ -4021,12 +4038,14 @@ void TabFilament::build()
|
||||
optgroup->append_single_option_line("activate_air_filtration", "material_cooling#activate-air-filtration");
|
||||
|
||||
line = {L("During print"), ""};
|
||||
line.append_option(optgroup->get_option("activate_air_filtration_during_print"));
|
||||
line.append_option(optgroup->get_option("during_print_exhaust_fan_speed"));
|
||||
line.label_path = "material_cooling#during-print";
|
||||
optgroup->append_line(line);
|
||||
|
||||
|
||||
line = {L("Complete print"), ""};
|
||||
line.append_option(optgroup->get_option("activate_air_filtration_on_completion"));
|
||||
line.append_option(optgroup->get_option("complete_print_exhaust_fan_speed"));
|
||||
line.label_path = "material_cooling#complete-print";
|
||||
optgroup->append_line(line);
|
||||
@@ -4049,6 +4068,17 @@ void TabFilament::build()
|
||||
option.opt.height = gcode_field_height;// 150;
|
||||
optgroup->append_single_option_line(option);
|
||||
|
||||
optgroup = page->new_optgroup(L("Change extrusion role G-code"), L"param_gcode", 0);
|
||||
optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(this, optgroup_title, opt_key, value);
|
||||
};
|
||||
optgroup->edit_custom_gcode = edit_custom_gcode_fn;
|
||||
option = optgroup->get_option("filament_change_extrusion_role_gcode");
|
||||
option.opt.full_width = true;
|
||||
option.opt.is_code = true;
|
||||
option.opt.height = gcode_field_height;// 150;
|
||||
optgroup->append_single_option_line(option);
|
||||
|
||||
optgroup = page->new_optgroup(L("Filament end G-code"), L"param_gcode", 0);
|
||||
optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(this, optgroup_title, opt_key, value);
|
||||
@@ -4182,22 +4212,33 @@ void TabFilament::toggle_options()
|
||||
return;
|
||||
bool is_BBL_printer = false;
|
||||
if (m_preset_bundle) {
|
||||
is_BBL_printer =
|
||||
wxGetApp().preset_bundle->is_bbl_vendor();
|
||||
is_BBL_printer = wxGetApp().preset_bundle->is_bbl_vendor();
|
||||
}
|
||||
bool is_multi_extruder = m_preset_bundle->printers.get_edited_preset().config.option<ConfigOptionFloats>("nozzle_diameter")->size() > 1;
|
||||
|
||||
auto cfg = m_preset_bundle->printers.get_edited_preset().config;
|
||||
auto printer_cfg = m_preset_bundle->printers.get_edited_preset().config;
|
||||
|
||||
if (m_active_page->title() == L("Cooling")) {
|
||||
bool has_enable_overhang_bridge_fan = m_config->opt_bool("enable_overhang_bridge_fan", 0);
|
||||
for (auto el : {"overhang_fan_speed", "overhang_fan_threshold", "internal_bridge_fan_speed"}) // ORCA: Add support for separate internal bridge fan speed control
|
||||
bool has_enable_overhang_bridge_fan = m_config->opt_bool("enable_overhang_bridge_fan", 0);
|
||||
for (auto el : {"overhang_fan_speed", "overhang_fan_threshold", "internal_bridge_fan_speed"}) // ORCA: Add support for separate internal bridge fan speed control
|
||||
toggle_option(el, has_enable_overhang_bridge_fan);
|
||||
|
||||
toggle_option("additional_cooling_fan_speed", cfg.opt_bool("auxiliary_fan"));
|
||||
// Orca: toggle dont slow down for external perimeters if
|
||||
bool has_slow_down_for_layer_cooling = m_config->opt_bool("slow_down_for_layer_cooling", 0);
|
||||
toggle_option("dont_slow_down_outer_wall", has_slow_down_for_layer_cooling);
|
||||
|
||||
// Orca: toggle dont slow down for external perimeters if
|
||||
bool has_slow_down_for_layer_cooling = m_config->opt_bool("slow_down_for_layer_cooling", 0);
|
||||
toggle_option("dont_slow_down_outer_wall", has_slow_down_for_layer_cooling);
|
||||
toggle_line("additional_cooling_fan_speed", printer_cfg.opt_bool("auxiliary_fan"));
|
||||
|
||||
bool support_air_filtration = printer_cfg.opt_bool("support_air_filtration");
|
||||
for (auto el : {"activate_air_filtration", "during_print_exhaust_fan_speed", "complete_print_exhaust_fan_speed"})
|
||||
toggle_line(el, support_air_filtration);
|
||||
|
||||
if (support_air_filtration) {
|
||||
bool activate_air_filtration = m_config->opt_bool("activate_air_filtration", 0);
|
||||
toggle_option("activate_air_filtration_during_print", activate_air_filtration);
|
||||
toggle_option("during_print_exhaust_fan_speed", activate_air_filtration && m_config->opt_bool("activate_air_filtration_during_print", 0));
|
||||
toggle_option("activate_air_filtration_on_completion", activate_air_filtration);
|
||||
toggle_option("complete_print_exhaust_fan_speed", activate_air_filtration && m_config->opt_bool("activate_air_filtration_on_completion", 0));
|
||||
}
|
||||
}
|
||||
if (m_active_page->title() == L("Filament"))
|
||||
{
|
||||
@@ -4218,7 +4259,7 @@ void TabFilament::toggle_options()
|
||||
|
||||
bool support_multi_bed_types = std::find(bed_temp_keys.begin(), bed_temp_keys.end(), bed_temp_1st_layer_key) ==
|
||||
bed_temp_keys.end() ||
|
||||
is_BBL_printer || cfg.opt_bool("support_multi_bed_types");
|
||||
is_BBL_printer || printer_cfg.opt_bool("support_multi_bed_types");
|
||||
|
||||
for (const auto& key : bed_temp_keys)
|
||||
{
|
||||
@@ -4237,20 +4278,26 @@ void TabFilament::toggle_options()
|
||||
toggle_line("adaptive_pressure_advance_model", has_adaptive_pa && pa);
|
||||
toggle_line("adaptive_pressure_advance_bridges", has_adaptive_pa && pa);
|
||||
|
||||
bool is_pellet_printer = cfg.opt_bool("pellet_modded_printer");
|
||||
bool is_pellet_printer = printer_cfg.opt_bool("pellet_modded_printer");
|
||||
toggle_line("pellet_flow_coefficient", is_pellet_printer);
|
||||
toggle_line("filament_diameter", !is_pellet_printer);
|
||||
|
||||
bool support_chamber_temp_control = this->m_preset_bundle->printers.get_edited_preset().config.opt_bool("support_chamber_temp_control");
|
||||
bool support_chamber_temp_control = printer_cfg.opt_bool("support_chamber_temp_control");
|
||||
toggle_line("activate_chamber_temp_control", support_chamber_temp_control);
|
||||
toggle_line("chamber_temperature", support_chamber_temp_control);
|
||||
|
||||
if (support_chamber_temp_control) {
|
||||
bool activate_chamber_temp_control = m_config->opt_bool("activate_chamber_temp_control", 0);
|
||||
toggle_option("chamber_temperature", activate_chamber_temp_control);
|
||||
}
|
||||
|
||||
std::string volumetric_speed_cos = m_config->opt_string("volumetric_speed_coefficients", 0u);
|
||||
bool enable_fit = volumetric_speed_cos != "0 0 0 0 0 0";
|
||||
toggle_option("filament_adaptive_volumetric_speed", enable_fit, 256 + 0u);
|
||||
}
|
||||
|
||||
if (m_active_page->title() == L("Setting Overrides"))
|
||||
update_filament_overrides_page(&cfg);
|
||||
update_filament_overrides_page(&printer_cfg);
|
||||
|
||||
if (m_active_page->title() == L("Multimaterial")) {
|
||||
// Orca: hide specific settings for BBL printers
|
||||
@@ -4263,9 +4310,10 @@ void TabFilament::toggle_options()
|
||||
toggle_option("filament_multitool_ramming_volume", multitool_ramming);
|
||||
toggle_option("filament_multitool_ramming_flow", multitool_ramming);
|
||||
|
||||
bool is_BBL_multi_extruder = is_BBL_printer && printer_cfg.option<ConfigOptionFloats>("nozzle_diameter")->size() > 1;
|
||||
const int extruder_idx = 0; // m_variant_combo->GetSelection(); // TODO: Orca hack
|
||||
toggle_line("long_retractions_when_ec", is_multi_extruder && is_BBL_printer, 256 + extruder_idx);
|
||||
toggle_line("retraction_distances_when_ec", is_multi_extruder && is_BBL_printer && m_config->opt_bool("long_retractions_when_ec", extruder_idx), 256 + extruder_idx);
|
||||
toggle_line("long_retractions_when_ec", is_BBL_multi_extruder, 256 + extruder_idx);
|
||||
toggle_line("retraction_distances_when_ec", is_BBL_multi_extruder && m_config->opt_bool("long_retractions_when_ec", extruder_idx), 256 + extruder_idx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <boost/cast.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "MainFrame.hpp"
|
||||
#include <boost/dll.hpp>
|
||||
@@ -985,6 +986,17 @@ int GuideFrame::GetFilamentInfo( std::string VendorDirectory, json & pFilaList,
|
||||
//GetStardardFilePath(filepath);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " GetFilamentInfo:VendorDirectory - " << VendorDirectory << ", Filepath - "<<filepath;
|
||||
|
||||
const auto cache_it = filament_info_cache.find(filepath);
|
||||
if (cache_it != filament_info_cache.end()) {
|
||||
if (sVendor.empty()) {
|
||||
sVendor = cache_it->second.vendor;
|
||||
}
|
||||
if (sType.empty()) {
|
||||
sType = cache_it->second.type;
|
||||
}
|
||||
return cache_it->second.status;
|
||||
}
|
||||
|
||||
try {
|
||||
std::string contents;
|
||||
LoadFile(filepath, contents);
|
||||
@@ -1014,6 +1026,7 @@ int GuideFrame::GetFilamentInfo( std::string VendorDirectory, json & pFilaList,
|
||||
|
||||
if (!pFilaList.contains(FName)) {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "pFilaList - Not Contains inherits filaments: " << FName;
|
||||
filament_info_cache[filepath] = CachedFilamentInfo{-1, sVendor, sType};
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1025,28 +1038,36 @@ int GuideFrame::GetFilamentInfo( std::string VendorDirectory, json & pFilaList,
|
||||
inherits_path = (boost::filesystem::path(m_OrcaFilaLibPath) / boost::filesystem::path(FPath)).make_preferred();
|
||||
|
||||
//boost::filesystem::path nf(strNewFile.c_str());
|
||||
if (boost::filesystem::exists(inherits_path))
|
||||
return GetFilamentInfo(VendorDirectory,pFilaList, inherits_path.string(), sVendor, sType);
|
||||
else {
|
||||
if (boost::filesystem::exists(inherits_path)) {
|
||||
const int ret = GetFilamentInfo(VendorDirectory,pFilaList, inherits_path.string(), sVendor, sType);
|
||||
filament_info_cache[filepath] = CachedFilamentInfo{ret, sVendor, sType};
|
||||
return ret;
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " inherits File Not Exist: " << inherits_path;
|
||||
filament_info_cache[filepath] = CachedFilamentInfo{-1, sVendor, sType};
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << filepath << " - Not Contains inherits";
|
||||
if (sType == "") {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "sType is Empty";
|
||||
filament_info_cache[filepath] = CachedFilamentInfo{-1, sVendor, sType};
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
sVendor = "Generic";
|
||||
filament_info_cache[filepath] = CachedFilamentInfo{0, sVendor, sType};
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
filament_info_cache[filepath] = CachedFilamentInfo{0, sVendor, sType};
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch(nlohmann::detail::parse_error &err) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "<<filepath <<" got a nlohmann::detail::parse_error, reason = " << err.what();
|
||||
filament_info_cache[filepath] = CachedFilamentInfo{-1, sVendor, sType};
|
||||
return -1;
|
||||
}
|
||||
catch (std::exception &e)
|
||||
@@ -1054,6 +1075,7 @@ int GuideFrame::GetFilamentInfo( std::string VendorDirectory, json & pFilaList,
|
||||
// wxLogMessage("GUIDE: load_profile_error %s ", e.what());
|
||||
// wxMessageBox(e.what(), "", MB_OK);
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse " << filepath <<" got exception: "<<e.what();
|
||||
filament_info_cache[filepath] = CachedFilamentInfo{-1, sVendor, sType};
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1155,6 +1177,7 @@ int GuideFrame::LoadProfileData()
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ", error: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
filament_info_cache.clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1454,6 +1477,7 @@ int GuideFrame::LoadProfileFamily(std::string strVendor, std::string strFilePath
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GuideFrame::StrReplace(std::string &strBase, std::string strSrc, std::string strDes)
|
||||
{
|
||||
int pos = 0;
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "slic3r/Utils/PresetUpdater.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
@@ -135,6 +137,14 @@ private:
|
||||
|
||||
wxString m_bbl_user_agent;
|
||||
std::string m_editing_filament_id;
|
||||
|
||||
struct CachedFilamentInfo
|
||||
{
|
||||
int status{-1};
|
||||
std::string vendor;
|
||||
std::string type;
|
||||
};
|
||||
std::unordered_map<std::string, CachedFilamentInfo> filament_info_cache;
|
||||
};
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
||||
@@ -241,6 +241,23 @@ void ComboBox::DoDeleteOneItem(unsigned int pos)
|
||||
drop.Invalidate(true);
|
||||
}
|
||||
|
||||
void ComboBox::ForceDropdownOpen()
|
||||
{
|
||||
if (!IsEnabled())
|
||||
return;
|
||||
|
||||
if (!drop_down) {
|
||||
drop.need_sync = true;
|
||||
drop.messureSize();
|
||||
drop.autoPosition();
|
||||
drop_down = true;
|
||||
drop.Popup(&drop);
|
||||
|
||||
wxCommandEvent e(wxEVT_COMBOBOX_DROPDOWN);
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int ComboBox::GetCount() const { return items.size(); }
|
||||
|
||||
void ComboBox::set_replace_text(wxString text, wxString image_name)
|
||||
|
||||
@@ -76,6 +76,9 @@ public:
|
||||
void SetItemBitmap(unsigned int n, wxBitmap const &bitmap);
|
||||
bool is_drop_down(){return drop_down;}
|
||||
void DeleteOneItem(unsigned int pos) { DoDeleteOneItem(pos); }
|
||||
|
||||
void ForceDropdownOpen();
|
||||
|
||||
protected:
|
||||
virtual int DoInsertItems(const wxArrayStringsAdapter &items,
|
||||
unsigned int pos,
|
||||
|
||||
@@ -525,7 +525,7 @@ void DropDown::messureSize()
|
||||
}
|
||||
if (!align_icon) iconSize.x = 0;
|
||||
wxSize szContent = textSize;
|
||||
if (szContent.x < FromDIP(120))
|
||||
if (szContent.x < FromDIP(120) && !use_content_width)
|
||||
szContent.x = FromDIP(120);
|
||||
szContent.x += 10;
|
||||
if (check_bitmap.bmp().IsOk()) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
@@ -1436,4 +1437,97 @@ void Cornering_Test_Dlg::on_dpi_changed(const wxRect& suggested_rect) {
|
||||
Fit();
|
||||
}
|
||||
|
||||
// FlowRateCalibrationDialog
|
||||
//
|
||||
FlowRateCalibrationDialog::FlowRateCalibrationDialog(wxWindow* parent, wxWindowID id, Plater* plater)
|
||||
: DPIDialog(parent, id, _L("Flow Ratio Calibration"), wxDefaultPosition, parent->FromDIP(wxSize(-1, 280)), wxDEFAULT_DIALOG_STYLE), m_plater(plater)
|
||||
{
|
||||
SetBackgroundColour(*wxWHITE); // make sure background color set for dialog
|
||||
SetForegroundColour(wxColour("#363636"));
|
||||
SetFont(Label::Body_14);
|
||||
|
||||
wxBoxSizer* v_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
SetSizer(v_sizer);
|
||||
|
||||
// Type selection
|
||||
auto labeled_box_type = new LabeledStaticBox(this, _L("Calibration Test Type"));
|
||||
auto type_box = new wxStaticBoxSizer(labeled_box_type, wxVERTICAL);
|
||||
|
||||
m_rbType = new RadioGroup(this, { _L("Pass 1 (Coarse)"), _L("Pass 2 (Fine)"), _L("YOLO (Recommended)"), _L("YOLO (Perfectionist)") }, wxVERTICAL, 1);
|
||||
m_rbType->SetSelection(2); // Default to YOLO Recommended
|
||||
type_box->Add(m_rbType, 0, wxALL | wxEXPAND, FromDIP(4));
|
||||
v_sizer->Add(type_box, 0, wxTOP | wxRIGHT | wxLEFT | wxEXPAND, FromDIP(10));
|
||||
|
||||
// Pattern selection
|
||||
auto labeled_box_pattern = new LabeledStaticBox(this, _L("Top Surface Pattern"));
|
||||
auto pattern_box = new wxStaticBoxSizer(labeled_box_pattern, wxVERTICAL);
|
||||
|
||||
// ORCA: Use ComboBox with icons instead of RadioGroup
|
||||
m_rbPattern = new ComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxCB_READONLY);
|
||||
|
||||
boost::filesystem::path image_path(Slic3r::resources_dir());
|
||||
image_path /= "images";
|
||||
|
||||
auto add_pattern_item = [&](const std::string& name, const wxString& label) {
|
||||
auto icon_name = "param_" + name;
|
||||
if (boost::filesystem::exists(image_path / (icon_name + ".svg"))) {
|
||||
// Using 24px icon size to match other settings (Field.cpp uses 24)
|
||||
ScalableBitmap bm(this, icon_name, 24);
|
||||
m_rbPattern->Append(label, bm.bmp());
|
||||
} else {
|
||||
m_rbPattern->Append(label);
|
||||
}
|
||||
};
|
||||
|
||||
add_pattern_item("archimedeanchords", _L("Archimedean Chords"));
|
||||
add_pattern_item("monotonic", _L("Monotonic"));
|
||||
m_rbPattern->SetSelection(0); // Default to Archimedean Chords
|
||||
// ORCA: explicit set value to ensure display on Windows
|
||||
m_rbPattern->SetValue(m_rbPattern->GetString(0));
|
||||
|
||||
pattern_box->Add(m_rbPattern, 0, wxALL | wxEXPAND, FromDIP(4));
|
||||
v_sizer->Add(pattern_box, 0, wxTOP | wxRIGHT | wxLEFT | wxEXPAND, FromDIP(10));
|
||||
|
||||
v_sizer->AddSpacer(FromDIP(5));
|
||||
|
||||
auto dlg_btns = new DialogButtons(this, {"OK"});
|
||||
|
||||
auto bottom_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto wiki = new HyperLink(this, _L("Wiki Guide"), "https://www.orcaslicer.com/wiki/calibration/flow-ratio-calib");
|
||||
bottom_sizer->Add(wiki, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(20));
|
||||
bottom_sizer->AddStretchSpacer();
|
||||
bottom_sizer->Add(dlg_btns, 0, wxEXPAND);
|
||||
v_sizer->Add(bottom_sizer, 0, wxEXPAND);
|
||||
|
||||
dlg_btns->GetOK()->Bind(wxEVT_BUTTON, &FlowRateCalibrationDialog::on_start, this);
|
||||
|
||||
wxGetApp().UpdateDlgDarkUI(this);
|
||||
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
|
||||
FlowRateCalibrationDialog::~FlowRateCalibrationDialog() {
|
||||
// Disconnect Events
|
||||
}
|
||||
|
||||
void FlowRateCalibrationDialog::on_start(wxCommandEvent& event) {
|
||||
int type = m_rbType->GetSelection();
|
||||
int patternIdx = m_rbPattern->GetSelection();
|
||||
|
||||
InfillPattern pattern = ipArchimedeanChords;
|
||||
if (patternIdx == 1) pattern = ipMonotonic;
|
||||
|
||||
bool is_linear = (type >= 2);
|
||||
int pass = (type % 2) + 1;
|
||||
|
||||
m_plater->calib_flowrate(is_linear, pass, pattern);
|
||||
EndModal(wxID_OK);
|
||||
}
|
||||
|
||||
void FlowRateCalibrationDialog::on_dpi_changed(const wxRect& suggested_rect) {
|
||||
this->Refresh();
|
||||
Fit();
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
@@ -180,5 +180,21 @@ protected:
|
||||
TextInput* m_tiJDEnd;
|
||||
Plater* m_plater;
|
||||
};
|
||||
|
||||
class FlowRateCalibrationDialog : public DPIDialog
|
||||
{
|
||||
public:
|
||||
FlowRateCalibrationDialog(wxWindow* parent, wxWindowID id, Plater* plater);
|
||||
~FlowRateCalibrationDialog();
|
||||
void on_dpi_changed(const wxRect& suggested_rect) override;
|
||||
|
||||
protected:
|
||||
virtual void on_start(wxCommandEvent& event);
|
||||
|
||||
RadioGroup* m_rbType;
|
||||
// ORCA: use standard OrcaSlicer ComboBox instead of BitmapComboBox
|
||||
ComboBox* m_rbPattern;
|
||||
Plater* m_plater;
|
||||
};
|
||||
}} // namespace Slic3r::GUI
|
||||
#endif
|
||||
@@ -401,7 +401,7 @@ void StyleManager::init_style_images(const Vec2i32 &max_size,
|
||||
auto mf = wxGetApp().mainframe;
|
||||
// dot per inch for monitor
|
||||
int dpi = get_dpi_for_window(mf);
|
||||
// pixel per milimeter
|
||||
// pixel per millimeter
|
||||
double ppm = dpi / GizmoObjectManipulation::in_to_mm;
|
||||
|
||||
auto &worker = wxGetApp().plater()->get_ui_job_worker();
|
||||
|
||||
@@ -309,7 +309,7 @@ private:
|
||||
// place to store result in main thread in Finalize
|
||||
std::shared_ptr<StyleImages> result;
|
||||
|
||||
// pixel per milimeter (scaled DPI)
|
||||
// pixel per millimeter (scaled DPI)
|
||||
double ppm;
|
||||
};
|
||||
std::shared_ptr<StyleImagesData::StyleImages> m_temp_style_images = nullptr;
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
#include "FixModelByCgal.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <condition_variable>
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "libslic3r/MeshBoolean.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/format.hpp"
|
||||
#include "../GUI/I18N.hpp"
|
||||
|
||||
// Orca: This file provides utilities for repairing 3D model meshes using the CGAL library, handling mesh splitting, merging, and boolean operations.
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace {
|
||||
|
||||
// Orca: Helper functions for analyzing mesh properties and transformations.
|
||||
|
||||
bool is_not_3dimensional_part(const TriangleMesh &mesh)
|
||||
{
|
||||
// Orca: Determines if a mesh is degenerate or represents a non-3dimensional part by checking volume and bounding box dimensions.
|
||||
if (mesh.its.indices.empty())
|
||||
return true;
|
||||
|
||||
indexed_triangle_set tmp = mesh.its;
|
||||
its_remove_degenerate_faces(tmp, true);
|
||||
if (tmp.indices.empty())
|
||||
return true;
|
||||
|
||||
const BoundingBoxf3 bbox = mesh.bounding_box();
|
||||
const Vec3d size = bbox.size();
|
||||
const double min_dim = std::min(size.x(), std::min(size.y(), size.z()));
|
||||
const double max_dim = std::max(size.x(), std::max(size.y(), size.z()));
|
||||
if (min_dim <= EPSILON)
|
||||
return true;
|
||||
|
||||
const double volume = std::abs(its_volume(mesh.its));
|
||||
const double bbox_volume = size.x() * size.y() * size.z();
|
||||
if (volume <= EPSILON)
|
||||
return true;
|
||||
|
||||
const double min_relative_thickness = 1e-6;
|
||||
const double min_volume_ratio = 1e-6;
|
||||
if (min_dim / max_dim <= min_relative_thickness)
|
||||
return true;
|
||||
if (bbox_volume > 0.0 && volume / bbox_volume <= min_volume_ratio)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Orca: Exception class for handling user-initiated cancellation of model repair operations.
|
||||
class RepairCanceledException : public std::exception {
|
||||
public:
|
||||
const char* what() const noexcept override { return "Model repair has been canceled"; }
|
||||
};
|
||||
|
||||
// Orca: Main function to repair model objects using CGAL, with progress dialog and cancellation support.
|
||||
// Returns false if fixing was canceled. fix_result contains error message if failed.
|
||||
bool fix_model_with_cgal_gui(ModelObject &model_object, int volume_idx, GUI::ProgressDialog &progress_dialog, const wxString &msg_header, std::string &fix_result)
|
||||
{
|
||||
// Orca: Synchronization primitives for progress updates between worker thread and GUI.
|
||||
std::mutex mtx;
|
||||
std::condition_variable condition;
|
||||
struct Progress {
|
||||
std::string message;
|
||||
int percent = 0;
|
||||
bool updated = false;
|
||||
} progress;
|
||||
|
||||
std::atomic<bool> canceled = false;
|
||||
std::atomic<bool> finished = false;
|
||||
|
||||
bool success = false;
|
||||
size_t ivolume = 0;
|
||||
|
||||
// Orca: Lambda for updating progress from worker thread.
|
||||
auto on_progress = [&mtx, &condition, &ivolume, &model_object, &progress](const char *msg, unsigned prcnt) {
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
progress.message = msg;
|
||||
const size_t total = std::max<size_t>(1, model_object.volumes.size());
|
||||
progress.percent = int(std::floor((float(prcnt) + float(ivolume) * 100.f) / float(total)));
|
||||
progress.updated = true;
|
||||
condition.notify_all();
|
||||
};
|
||||
|
||||
// Orca: Worker thread that performs the actual model repair operations.
|
||||
auto worker_thread = std::thread([&model_object, volume_idx, &ivolume, on_progress, &success, &canceled, &finished, &fix_result]() {
|
||||
try {
|
||||
size_t start_volume = volume_idx == -1 ? 0 : size_t(volume_idx);
|
||||
size_t end_volume = volume_idx == -1 ? std::numeric_limits<size_t>::max() : size_t(volume_idx);
|
||||
|
||||
for (ivolume = start_volume; ivolume < model_object.volumes.size(); ++ivolume) {
|
||||
if (volume_idx != -1 && ivolume > end_volume)
|
||||
break;
|
||||
if (canceled)
|
||||
throw RepairCanceledException();
|
||||
|
||||
on_progress(L("Repairing model object"), 10);
|
||||
|
||||
ModelVolume *volume = model_object.volumes[ivolume];
|
||||
|
||||
// Orca: Split splittable volumes into parts for individual processing.
|
||||
size_t parts_count = 1;
|
||||
if (volume->is_splittable()) {
|
||||
parts_count = volume->split(1);
|
||||
if (parts_count > 1) {
|
||||
const std::string msg = Slic3r::format(L("Split into %1% parts"), parts_count);
|
||||
on_progress(msg.c_str(), 10);
|
||||
}
|
||||
}
|
||||
|
||||
size_t part_end = std::min(ivolume + parts_count - 1, model_object.volumes.size() - 1);
|
||||
if (volume_idx != -1)
|
||||
end_volume = part_end;
|
||||
|
||||
size_t removed_parts = 0;
|
||||
for (size_t idx = part_end + 1; idx > ivolume; --idx) {
|
||||
const size_t part_idx = idx - 1;
|
||||
const ModelVolume *part_volume = model_object.volumes[part_idx];
|
||||
if (!is_not_3dimensional_part(part_volume->mesh()))
|
||||
continue;
|
||||
|
||||
model_object.delete_volume(part_idx);
|
||||
++removed_parts;
|
||||
if (part_end > 0)
|
||||
--part_end;
|
||||
else
|
||||
part_end = 0;
|
||||
if (volume_idx != -1)
|
||||
end_volume = part_end;
|
||||
}
|
||||
|
||||
if (removed_parts >= parts_count) {
|
||||
ivolume = part_end;
|
||||
on_progress(L("Repair finished"), 100);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t part_idx = ivolume; part_idx <= part_end && part_idx < model_object.volumes.size(); ++part_idx) {
|
||||
ModelVolume *part_volume = model_object.volumes[part_idx];
|
||||
TriangleMesh mesh = part_volume->mesh();
|
||||
if (its_num_open_edges(mesh.its) != 0) {
|
||||
std::string error;
|
||||
if (!MeshBoolean::cgal::repair(mesh, nullptr, &error))
|
||||
throw Slic3r::RuntimeError(error.empty() ? L("Repair failed") : error.c_str());
|
||||
|
||||
part_volume->set_mesh(std::move(mesh));
|
||||
part_volume->calculate_convex_hull();
|
||||
part_volume->invalidate_convex_hull_2d();
|
||||
part_volume->set_new_unique_id();
|
||||
}
|
||||
}
|
||||
|
||||
ivolume = part_end;
|
||||
|
||||
on_progress(L("Repair finished"), 100);
|
||||
}
|
||||
|
||||
model_object.invalidate_bounding_box();
|
||||
|
||||
if (ivolume > 0)
|
||||
--ivolume;
|
||||
on_progress(L("Repair finished"), 100);
|
||||
success = true;
|
||||
finished = true;
|
||||
} catch (RepairCanceledException &) {
|
||||
canceled = true;
|
||||
finished = true;
|
||||
on_progress(L("Repair canceled"), 100);
|
||||
} catch (std::exception &ex) {
|
||||
success = false;
|
||||
finished = true;
|
||||
fix_result = ex.what();
|
||||
on_progress(ex.what(), 100);
|
||||
}
|
||||
});
|
||||
|
||||
// Orca: Main GUI loop to update progress dialog and handle cancellation.
|
||||
while (!finished) {
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
condition.wait_for(lock, std::chrono::milliseconds(250), [&progress]{ return progress.updated; });
|
||||
|
||||
// Decrease progress percent slightly to avoid auto-closing.
|
||||
if (!progress_dialog.Update(progress.percent - 1, msg_header + _(progress.message)))
|
||||
canceled = true;
|
||||
else
|
||||
progress_dialog.Fit();
|
||||
|
||||
progress.updated = false;
|
||||
}
|
||||
|
||||
if (canceled) {
|
||||
// Nothing to show.
|
||||
} else if (success) {
|
||||
fix_result.clear();
|
||||
}
|
||||
|
||||
if (worker_thread.joinable())
|
||||
worker_thread.join();
|
||||
|
||||
return !canceled;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef slic3r_GUI_Utils_FixModelByCgal_hpp_
|
||||
#define slic3r_GUI_Utils_FixModelByCgal_hpp_
|
||||
|
||||
#include <string>
|
||||
#include "../GUI/Widgets/ProgressDialog.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Model;
|
||||
class ModelObject;
|
||||
class Print;
|
||||
|
||||
// Return false if fixing was canceled. fix_result is empty on success.
|
||||
extern bool fix_model_with_cgal_gui(ModelObject &model_object, int volume_idx, GUI::ProgressDialog &progress_dlg, const wxString &msg_header, std::string &fix_result);
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_GUI_Utils_FixModelByCgal_hpp_ */
|
||||
@@ -1,447 +0,0 @@
|
||||
#ifdef HAS_WIN10SDK
|
||||
|
||||
#ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
#endif
|
||||
|
||||
// Windows Runtime
|
||||
#include <roapi.h>
|
||||
// for ComPtr
|
||||
#include <wrl/client.h>
|
||||
|
||||
// from C:/Program Files (x86)/Windows Kits/10/Include/10.0.17134.0/
|
||||
#include <winrt/robuffer.h>
|
||||
#include <winrt/windows.storage.provider.h>
|
||||
#include <winrt/windows.graphics.printing3d.h>
|
||||
|
||||
#include "FixModelByWin10.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <condition_variable>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/Format/3mf.hpp"
|
||||
#include "../GUI/GUI.hpp"
|
||||
#include "../GUI/I18N.hpp"
|
||||
#include "../GUI/MsgDialog.hpp"
|
||||
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/progdlg.h>
|
||||
|
||||
extern "C"{
|
||||
// from rapi.h
|
||||
typedef HRESULT (__stdcall* FunctionRoInitialize)(int);
|
||||
typedef HRESULT (__stdcall* FunctionRoUninitialize)();
|
||||
typedef HRESULT (__stdcall* FunctionRoActivateInstance)(HSTRING activatableClassId, IInspectable **instance);
|
||||
typedef HRESULT (__stdcall* FunctionRoGetActivationFactory)(HSTRING activatableClassId, REFIID iid, void **factory);
|
||||
// from winstring.h
|
||||
typedef HRESULT (__stdcall* FunctionWindowsCreateString)(LPCWSTR sourceString, UINT32 length, HSTRING *string);
|
||||
typedef HRESULT (__stdcall* FunctionWindowsDelteString)(HSTRING string);
|
||||
}
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
static std::string saving_failed_str = L("Saving objects into the 3MF failed.");
|
||||
|
||||
HMODULE s_hRuntimeObjectLibrary = nullptr;
|
||||
FunctionRoInitialize s_RoInitialize = nullptr;
|
||||
FunctionRoUninitialize s_RoUninitialize = nullptr;
|
||||
FunctionRoActivateInstance s_RoActivateInstance = nullptr;
|
||||
FunctionRoGetActivationFactory s_RoGetActivationFactory = nullptr;
|
||||
FunctionWindowsCreateString s_WindowsCreateString = nullptr;
|
||||
FunctionWindowsDelteString s_WindowsDeleteString = nullptr;
|
||||
|
||||
bool winrt_load_runtime_object_library()
|
||||
{
|
||||
if (s_hRuntimeObjectLibrary == nullptr)
|
||||
s_hRuntimeObjectLibrary = LoadLibrary(L"ComBase.dll");
|
||||
if (s_hRuntimeObjectLibrary != nullptr) {
|
||||
s_RoInitialize = (FunctionRoInitialize) GetProcAddress(s_hRuntimeObjectLibrary, "RoInitialize");
|
||||
s_RoUninitialize = (FunctionRoUninitialize) GetProcAddress(s_hRuntimeObjectLibrary, "RoUninitialize");
|
||||
s_RoActivateInstance = (FunctionRoActivateInstance) GetProcAddress(s_hRuntimeObjectLibrary, "RoActivateInstance");
|
||||
s_RoGetActivationFactory = (FunctionRoGetActivationFactory) GetProcAddress(s_hRuntimeObjectLibrary, "RoGetActivationFactory");
|
||||
s_WindowsCreateString = (FunctionWindowsCreateString) GetProcAddress(s_hRuntimeObjectLibrary, "WindowsCreateString");
|
||||
s_WindowsDeleteString = (FunctionWindowsDelteString) GetProcAddress(s_hRuntimeObjectLibrary, "WindowsDeleteString");
|
||||
}
|
||||
return s_RoInitialize && s_RoUninitialize && s_RoActivateInstance && s_WindowsCreateString && s_WindowsDeleteString;
|
||||
}
|
||||
|
||||
static HRESULT winrt_activate_instance(const std::wstring &class_name, IInspectable **pinst)
|
||||
{
|
||||
HSTRING hClassName;
|
||||
HRESULT hr = (*s_WindowsCreateString)(class_name.c_str(), class_name.size(), &hClassName);
|
||||
if (S_OK != hr)
|
||||
return hr;
|
||||
hr = (*s_RoActivateInstance)(hClassName, pinst);
|
||||
(*s_WindowsDeleteString)(hClassName);
|
||||
return hr;
|
||||
}
|
||||
|
||||
template<typename TYPE>
|
||||
static HRESULT winrt_activate_instance(const std::wstring &class_name, TYPE **pinst)
|
||||
{
|
||||
IInspectable *pinspectable = nullptr;
|
||||
HRESULT hr = winrt_activate_instance(class_name, &pinspectable);
|
||||
if (S_OK != hr)
|
||||
return hr;
|
||||
hr = pinspectable->QueryInterface(__uuidof(TYPE), (void**)pinst);
|
||||
pinspectable->Release();
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT winrt_get_activation_factory(const std::wstring &class_name, REFIID iid, void **pinst)
|
||||
{
|
||||
HSTRING hClassName;
|
||||
HRESULT hr = (*s_WindowsCreateString)(class_name.c_str(), class_name.size(), &hClassName);
|
||||
if (S_OK != hr)
|
||||
return hr;
|
||||
hr = (*s_RoGetActivationFactory)(hClassName, iid, pinst);
|
||||
(*s_WindowsDeleteString)(hClassName);
|
||||
return hr;
|
||||
}
|
||||
|
||||
template<typename TYPE>
|
||||
static HRESULT winrt_get_activation_factory(const std::wstring &class_name, TYPE **pinst)
|
||||
{
|
||||
return winrt_get_activation_factory(class_name, __uuidof(TYPE), reinterpret_cast<void**>(pinst));
|
||||
}
|
||||
|
||||
// To be called often to test whether to cancel the operation.
|
||||
typedef std::function<void ()> ThrowOnCancelFn;
|
||||
|
||||
template<typename T>
|
||||
static AsyncStatus winrt_async_await(const Microsoft::WRL::ComPtr<T> &asyncAction, ThrowOnCancelFn throw_on_cancel, int blocking_tick_ms = 100)
|
||||
{
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
|
||||
asyncAction.As(&asyncInfo);
|
||||
AsyncStatus status;
|
||||
// Ugly blocking loop until the RepairAsync call finishes.
|
||||
//FIXME replace with a callback.
|
||||
// https://social.msdn.microsoft.com/Forums/en-US/a5038fb4-b7b7-4504-969d-c102faa389fb/trying-to-block-an-async-operation-and-wait-for-a-particular-time?forum=vclanguage
|
||||
for (;;) {
|
||||
asyncInfo->get_Status(&status);
|
||||
if (status != AsyncStatus::Started)
|
||||
return status;
|
||||
throw_on_cancel();
|
||||
::Sleep(blocking_tick_ms);
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT winrt_open_file_stream(
|
||||
const std::wstring &path,
|
||||
ABI::Windows::Storage::FileAccessMode mode,
|
||||
ABI::Windows::Storage::Streams::IRandomAccessStream **fileStream,
|
||||
ThrowOnCancelFn throw_on_cancel)
|
||||
{
|
||||
// Get the file factory.
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFileStatics> fileFactory;
|
||||
HRESULT hr = winrt_get_activation_factory(L"Windows.Storage.StorageFile", fileFactory.GetAddressOf());
|
||||
if (FAILED(hr)) return hr;
|
||||
|
||||
// Open the file asynchronously.
|
||||
HSTRING hstr_path;
|
||||
hr = (*s_WindowsCreateString)(path.c_str(), path.size(), &hstr_path);
|
||||
if (FAILED(hr)) return hr;
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFile*>> fileOpenAsync;
|
||||
hr = fileFactory->GetFileFromPathAsync(hstr_path, fileOpenAsync.GetAddressOf());
|
||||
if (FAILED(hr)) return hr;
|
||||
(*s_WindowsDeleteString)(hstr_path);
|
||||
|
||||
// Wait until the file gets open, get the actual file.
|
||||
AsyncStatus status = winrt_async_await(fileOpenAsync, throw_on_cancel);
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFile> storageFile;
|
||||
if (status == AsyncStatus::Completed) {
|
||||
hr = fileOpenAsync->GetResults(storageFile.GetAddressOf());
|
||||
} else {
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
|
||||
hr = fileOpenAsync.As(&asyncInfo);
|
||||
if (FAILED(hr)) return hr;
|
||||
HRESULT err;
|
||||
hr = asyncInfo->get_ErrorCode(&err);
|
||||
return FAILED(hr) ? hr : err;
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IRandomAccessStream*>> fileStreamAsync;
|
||||
hr = storageFile->OpenAsync(mode, fileStreamAsync.GetAddressOf());
|
||||
if (FAILED(hr)) return hr;
|
||||
|
||||
status = winrt_async_await(fileStreamAsync, throw_on_cancel);
|
||||
if (status == AsyncStatus::Completed) {
|
||||
hr = fileStreamAsync->GetResults(fileStream);
|
||||
} else {
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
|
||||
hr = fileStreamAsync.As(&asyncInfo);
|
||||
if (FAILED(hr)) return hr;
|
||||
HRESULT err;
|
||||
hr = asyncInfo->get_ErrorCode(&err);
|
||||
if (!FAILED(hr))
|
||||
hr = err;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
bool is_windows10()
|
||||
{
|
||||
HKEY hKey;
|
||||
LONG lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &hKey);
|
||||
if (lRes == ERROR_SUCCESS) {
|
||||
WCHAR szBuffer[512];
|
||||
DWORD dwBufferSize = sizeof(szBuffer);
|
||||
lRes = RegQueryValueExW(hKey, L"ProductName", 0, nullptr, (LPBYTE)szBuffer, &dwBufferSize);
|
||||
if (lRes == ERROR_SUCCESS)
|
||||
return wcsncmp(szBuffer, L"Windows 10", 10) == 0;
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Progress function, to be called regularly to update the progress.
|
||||
typedef std::function<void (const char * /* message */, unsigned /* progress */)> ProgressFn;
|
||||
|
||||
void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path_dst, ProgressFn on_progress, ThrowOnCancelFn throw_on_cancel)
|
||||
{
|
||||
if (! is_windows10())
|
||||
throw Slic3r::RuntimeError(L("Only Windows 10 is supported."));
|
||||
|
||||
if (! winrt_load_runtime_object_library())
|
||||
throw Slic3r::RuntimeError(L("Failed to initialize the WinRT library."));
|
||||
|
||||
HRESULT hr = (*s_RoInitialize)(RO_INIT_MULTITHREADED);
|
||||
{
|
||||
on_progress(L("Exporting objects"), 20);
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream> fileStream;
|
||||
hr = winrt_open_file_stream(boost::nowide::widen(path_src), ABI::Windows::Storage::FileAccessMode::FileAccessMode_Read, fileStream.GetAddressOf(), throw_on_cancel);
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Printing3D::IPrinting3D3MFPackage> printing3d3mfpackage;
|
||||
hr = winrt_activate_instance(L"Windows.Graphics.Printing3D.Printing3D3MFPackage", printing3d3mfpackage.GetAddressOf());
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Graphics::Printing3D::Printing3DModel*>> modelAsync;
|
||||
hr = printing3d3mfpackage->LoadModelFromPackageAsync(fileStream.Get(), modelAsync.GetAddressOf());
|
||||
|
||||
AsyncStatus status = winrt_async_await(modelAsync, throw_on_cancel);
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Printing3D::IPrinting3DModel> model;
|
||||
if (status == AsyncStatus::Completed)
|
||||
hr = modelAsync->GetResults(model.GetAddressOf());
|
||||
else
|
||||
throw Slic3r::RuntimeError(L("Failed loading objects."));
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVector<ABI::Windows::Graphics::Printing3D::Printing3DMesh*>> meshes;
|
||||
hr = model->get_Meshes(meshes.GetAddressOf());
|
||||
unsigned num_meshes = 0;
|
||||
hr = meshes->get_Size(&num_meshes);
|
||||
on_progress(L("Repairing object by Windows service"), 40);
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> repairAsync;
|
||||
hr = model->RepairAsync(repairAsync.GetAddressOf());
|
||||
status = winrt_async_await(repairAsync, throw_on_cancel);
|
||||
if (status != AsyncStatus::Completed)
|
||||
throw Slic3r::RuntimeError(L("Repair failed."));
|
||||
repairAsync->GetResults();
|
||||
|
||||
on_progress(L("Loading repaired objects"), 60);
|
||||
|
||||
// Verify the number of meshes returned after the repair action.
|
||||
meshes.Reset();
|
||||
hr = model->get_Meshes(meshes.GetAddressOf());
|
||||
hr = meshes->get_Size(&num_meshes);
|
||||
|
||||
// Save model to this class' Printing3D3MFPackage.
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> saveToPackageAsync;
|
||||
hr = printing3d3mfpackage->SaveModelToPackageAsync(model.Get(), saveToPackageAsync.GetAddressOf());
|
||||
status = winrt_async_await(saveToPackageAsync, throw_on_cancel);
|
||||
if (status != AsyncStatus::Completed)
|
||||
throw Slic3r::RuntimeError(saving_failed_str);
|
||||
hr = saveToPackageAsync->GetResults();
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IRandomAccessStream*>> generatorStreamAsync;
|
||||
hr = printing3d3mfpackage->SaveAsync(generatorStreamAsync.GetAddressOf());
|
||||
status = winrt_async_await(generatorStreamAsync, throw_on_cancel);
|
||||
if (status != AsyncStatus::Completed)
|
||||
throw Slic3r::RuntimeError(saving_failed_str);
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream> generatorStream;
|
||||
hr = generatorStreamAsync->GetResults(generatorStream.GetAddressOf());
|
||||
|
||||
// Go to the beginning of the stream.
|
||||
generatorStream->Seek(0);
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IInputStream> inputStream;
|
||||
hr = generatorStream.As(&inputStream);
|
||||
|
||||
// Get the buffer factory.
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBufferFactory> bufferFactory;
|
||||
hr = winrt_get_activation_factory(L"Windows.Storage.Streams.Buffer", bufferFactory.GetAddressOf());
|
||||
|
||||
// Open the destination file.
|
||||
FILE *fout = boost::nowide::fopen(path_dst.c_str(), "wb");
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
|
||||
byte *buffer_ptr;
|
||||
bufferFactory->Create(65536 * 2048, buffer.GetAddressOf());
|
||||
{
|
||||
Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
|
||||
buffer.As(&bufferByteAccess);
|
||||
hr = bufferByteAccess->Buffer(&buffer_ptr);
|
||||
}
|
||||
uint32_t length;
|
||||
hr = buffer->get_Length(&length);
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer*, UINT32>> asyncRead;
|
||||
for (;;) {
|
||||
hr = inputStream->ReadAsync(buffer.Get(), 65536 * 2048, ABI::Windows::Storage::Streams::InputStreamOptions_ReadAhead, asyncRead.GetAddressOf());
|
||||
status = winrt_async_await(asyncRead, throw_on_cancel);
|
||||
if (status != AsyncStatus::Completed)
|
||||
throw Slic3r::RuntimeError(saving_failed_str);
|
||||
hr = buffer->get_Length(&length);
|
||||
if (length == 0)
|
||||
break;
|
||||
fwrite(buffer_ptr, length, 1, fout);
|
||||
}
|
||||
fclose(fout);
|
||||
// Here all the COM objects will be released through the ComPtr destructors.
|
||||
}
|
||||
(*s_RoUninitialize)();
|
||||
}
|
||||
|
||||
class RepairCanceledException : public std::exception {
|
||||
public:
|
||||
const char* what() const throw() { return "Model repair has been canceled"; }
|
||||
};
|
||||
|
||||
// returt FALSE, if fixing was canceled
|
||||
// fix_result is empty, if fixing finished successfully
|
||||
// fix_result containes a message if fixing failed
|
||||
bool fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx, GUI::ProgressDialog& progress_dialog, const wxString& msg_header, std::string& fix_result)
|
||||
{
|
||||
std::mutex mtx;
|
||||
std::condition_variable condition;
|
||||
struct Progress {
|
||||
std::string message;
|
||||
int percent = 0;
|
||||
bool updated = false;
|
||||
} progress;
|
||||
std::atomic<bool> canceled = false;
|
||||
std::atomic<bool> finished = false;
|
||||
|
||||
std::vector<ModelVolume*> volumes;
|
||||
if (volume_idx == -1)
|
||||
volumes = model_object.volumes;
|
||||
else
|
||||
volumes.emplace_back(model_object.volumes[volume_idx]);
|
||||
|
||||
// Executing the calculation in a background thread, so that the COM context could be created with its own threading model.
|
||||
// (It seems like wxWidgets initialize the COM contex as single threaded and we need a multi-threaded context).
|
||||
bool success = false;
|
||||
size_t ivolume = 0;
|
||||
auto on_progress = [&mtx, &condition, &ivolume, &volumes, &progress](const char *msg, unsigned prcnt) {
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
progress.message = msg;
|
||||
progress.percent = (int)floor((float(prcnt) + float(ivolume) * 100.f) / float(volumes.size()));
|
||||
progress.updated = true;
|
||||
condition.notify_all();
|
||||
};
|
||||
auto worker_thread = boost::thread([&model_object, &volumes, &ivolume, on_progress, &success, &canceled, &finished]() {
|
||||
try {
|
||||
std::vector<TriangleMesh> meshes_repaired;
|
||||
meshes_repaired.reserve(volumes.size());
|
||||
for (; ivolume < volumes.size(); ++ ivolume) {
|
||||
on_progress(L("Exporting objects"), 0);
|
||||
boost::filesystem::path path_src = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
path_src += ".3mf";
|
||||
Model model;
|
||||
ModelObject *mo = model.add_object();
|
||||
mo->add_volume(*volumes[ivolume]);
|
||||
|
||||
// We are about to save a 3mf, fix it by netfabb and load the fixed 3mf back.
|
||||
// store_3mf currently bakes the volume transformation into the mesh itself.
|
||||
// If we then loaded the repaired 3mf and pushed the mesh into the original ModelVolume
|
||||
// (which remembers the matrix the whole time), the transformation would be used twice.
|
||||
// We will therefore set the volume transform on the dummy ModelVolume to identity.
|
||||
mo->volumes.back()->set_transformation(Geometry::Transformation());
|
||||
|
||||
mo->add_instance();
|
||||
if (!Slic3r::store_3mf(path_src.string().c_str(), &model, nullptr, false, nullptr, false)) {
|
||||
boost::filesystem::remove(path_src);
|
||||
throw Slic3r::RuntimeError(L("Exporting 3MF file failed"));
|
||||
}
|
||||
model.clear_objects();
|
||||
model.clear_materials();
|
||||
boost::filesystem::path path_dst = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
path_dst += ".3mf";
|
||||
fix_model_by_win10_sdk(path_src.string().c_str(), path_dst.string(), on_progress,
|
||||
[&canceled]() { if (canceled) throw RepairCanceledException(); });
|
||||
boost::filesystem::remove(path_src);
|
||||
// PresetBundle bundle;
|
||||
on_progress(L("Loading repaired objects"), 80);
|
||||
DynamicPrintConfig config;
|
||||
ConfigSubstitutionContext config_substitutions{ ForwardCompatibilitySubstitutionRule::EnableSilent };
|
||||
bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), config, config_substitutions, &model, false);
|
||||
boost::filesystem::remove(path_dst);
|
||||
if (! loaded)
|
||||
throw Slic3r::RuntimeError(L("Import 3MF file failed"));
|
||||
if (model.objects.size() == 0)
|
||||
throw Slic3r::RuntimeError(L("Repaired 3MF file does not contain any object"));
|
||||
if (model.objects.size() > 1)
|
||||
throw Slic3r::RuntimeError(L("Repaired 3MF file contains more than one object"));
|
||||
if (model.objects.front()->volumes.size() == 0)
|
||||
throw Slic3r::RuntimeError(L("Repaired 3MF file does not contain any volume"));
|
||||
if (model.objects.front()->volumes.size() > 1)
|
||||
throw Slic3r::RuntimeError(L("Repaired 3MF file contains more than one volume"));
|
||||
meshes_repaired.emplace_back(std::move(model.objects.front()->volumes.front()->mesh()));
|
||||
}
|
||||
for (size_t i = 0; i < volumes.size(); ++ i) {
|
||||
volumes[i]->set_mesh(std::move(meshes_repaired[i]));
|
||||
volumes[i]->calculate_convex_hull();
|
||||
volumes[i]->invalidate_convex_hull_2d();
|
||||
volumes[i]->set_new_unique_id();
|
||||
}
|
||||
model_object.invalidate_bounding_box();
|
||||
-- ivolume;
|
||||
on_progress(L("Repair finished"), 100);
|
||||
success = true;
|
||||
finished = true;
|
||||
} catch (RepairCanceledException & /* ex */) {
|
||||
canceled = true;
|
||||
finished = true;
|
||||
on_progress(L("Repair canceled"), 100);
|
||||
} catch (std::exception &ex) {
|
||||
success = false;
|
||||
finished = true;
|
||||
on_progress(ex.what(), 100);
|
||||
}
|
||||
});
|
||||
while (! finished) {
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
condition.wait_for(lock, std::chrono::milliseconds(250), [&progress]{ return progress.updated; });
|
||||
// decrease progress.percent value to avoid closing of the progress dialog
|
||||
if (!progress_dialog.Update(progress.percent-1, msg_header + _(progress.message)))
|
||||
canceled = true;
|
||||
else
|
||||
progress_dialog.Fit();
|
||||
progress.updated = false;
|
||||
}
|
||||
|
||||
if (canceled) {
|
||||
// Nothing to show.
|
||||
} else if (success) {
|
||||
fix_result = "";
|
||||
} else {
|
||||
fix_result = progress.message;
|
||||
}
|
||||
worker_thread.join();
|
||||
return !canceled;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* HAS_WIN10SDK */
|
||||
@@ -1,31 +0,0 @@
|
||||
#ifndef slic3r_GUI_Utils_FixModelByWin10_hpp_
|
||||
#define slic3r_GUI_Utils_FixModelByWin10_hpp_
|
||||
|
||||
#include <string>
|
||||
#include "../GUI/Widgets/ProgressDialog.hpp"
|
||||
|
||||
class ProgressDialog;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Model;
|
||||
class ModelObject;
|
||||
class Print;
|
||||
|
||||
#ifdef HAS_WIN10SDK
|
||||
|
||||
extern bool is_windows10();
|
||||
// returt false, if fixing was canceled
|
||||
extern bool fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx,GUI::ProgressDialog &progress_dlg, const wxString &msg_header, std::string &fix_result);
|
||||
|
||||
#else /* HAS_WIN10SDK */
|
||||
|
||||
inline bool is_windows10() { return false; }
|
||||
// returt false, if fixing was canceled
|
||||
inline bool fix_model_by_win10_sdk_gui(ModelObject &, int, GUI::ProgressDialog &, const wxString &, std::string &) { return false; }
|
||||
|
||||
#endif /* HAS_WIN10SDK */
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_GUI_Utils_FixModelByWin10_hpp_ */
|
||||
Reference in new issue
Block a user