Merge remote-tracking branch 'upstream/main' into feedback

This commit is contained in:
Clifford Garwood committed 2026-04-25 00:46:48 -04:00
commit 357fcb374d
140 files changed
+2283 -1850

No files matched your search

+5
View File
@@ -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");
+15
View File
@@ -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;
+4 -2
View File
@@ -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
+36 -10
View File
@@ -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);
+1 -1
View File
@@ -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
View File
@@ -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 {
+48 -3
View File
@@ -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);
+5
View File
@@ -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;
+87 -1
View File
@@ -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}};
+3
View File
@@ -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 {
+8 -4
View File
@@ -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)
+1
View File
@@ -719,6 +719,7 @@ enum class ConversionType : int {
};
enum class En3mfType : int {
From_Orca,
From_BBS,
From_Prusa,
From_Other
+17 -3
View File
@@ -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);
+6 -6
View File
@@ -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",
+16
View File
@@ -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)
+4
View File
@@ -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"
+68 -1
View File
@@ -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", {}},
+7
View File
@@ -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))
+18 -2
View File
@@ -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"
+6 -3
View File
@@ -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.
+11 -6
View File
@@ -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;
}
+3 -2
View File
@@ -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
+2 -2
View File
@@ -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);
+10
View File
@@ -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
+4
View File
@@ -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
};
+8
View File
@@ -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
+31 -1
View File
@@ -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);
}
}
+4
View File
@@ -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{
+4 -2
View File
@@ -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
+33 -1
View File
@@ -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();
+1 -1
View File
@@ -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:
+1 -1
View File
@@ -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*/);
+6 -4
View File
@@ -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);
+10 -13
View File
@@ -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;
}
+3 -7
View File
@@ -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;
+78
View File
@@ -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
View File
@@ -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) {
+4 -4
View File
@@ -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
+6
View File
@@ -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 =
+1
View File
@@ -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();
+25 -30
View File
@@ -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();
+1 -1
View File
@@ -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);
+54 -13
View File
@@ -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()
+4 -2
View File
@@ -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 ;
+4 -2
View File
@@ -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();
}
}
+2 -4
View File
@@ -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
+5 -8
View File
@@ -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));
+11 -48
View File
@@ -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();
+3 -1
View File
@@ -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;
+22 -51
View File
@@ -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
+3 -1
View File
@@ -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"); }
+123 -68
View File
@@ -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;
+4 -1
View File
@@ -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
+95 -110
View File
@@ -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
+8 -1
View File
@@ -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;
};
+57 -72
View File
@@ -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));
+8 -1
View File
@@ -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
+10 -50
View File
@@ -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);
+3 -4
View File
@@ -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};
+115 -197
View File
@@ -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
+21 -54
View File
@@ -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));
+3 -2
View File
@@ -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;
};
+75
View File
@@ -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
+25
View File
@@ -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
+20 -133
View File
@@ -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;
};
+12 -4
View File
@@ -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);
}
+17 -31
View File
@@ -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
+1
View File
@@ -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 };
+1 -1
View File
@@ -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 {
+2 -2
View File
@@ -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
-1
View File
@@ -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
View File
@@ -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(); }
+3 -2
View File
@@ -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;
+5
View File
@@ -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);
+11 -2
View File
@@ -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
View File
@@ -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);
}
}
+28 -4
View File
@@ -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;
+10
View File
@@ -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
+17
View File
@@ -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)
+3
View File
@@ -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,
+1 -1
View File
@@ -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()) {
+94
View File
@@ -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
+16
View File
@@ -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
+1 -1
View File
@@ -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();
+1 -1
View File
@@ -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;
+214
View File
@@ -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
+18
View File
@@ -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_ */
-447
View File
@@ -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 */
-31
View File
@@ -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_ */