mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-24 09:11:23 -06:00
Fixed conflicts after merge with master
This commit is contained in:
commit
3369e1b599
85 changed files with 2018 additions and 969 deletions
|
|
@ -141,11 +141,13 @@ void Bed3D::Axes::render() const
|
|||
bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom)
|
||||
{
|
||||
auto check_texture = [](const std::string& texture) {
|
||||
return !texture.empty() && (boost::algorithm::iends_with(texture, ".png") || boost::algorithm::iends_with(texture, ".svg")) && boost::filesystem::exists(texture);
|
||||
boost::system::error_code ec; // so the exists call does not throw (e.g. after a permission problem)
|
||||
return !texture.empty() && (boost::algorithm::iends_with(texture, ".png") || boost::algorithm::iends_with(texture, ".svg")) && boost::filesystem::exists(texture, ec);
|
||||
};
|
||||
|
||||
auto check_model = [](const std::string& model) {
|
||||
return !model.empty() && boost::algorithm::iends_with(model, ".stl") && boost::filesystem::exists(model);
|
||||
boost::system::error_code ec;
|
||||
return !model.empty() && boost::algorithm::iends_with(model, ".stl") && boost::filesystem::exists(model, ec);
|
||||
};
|
||||
|
||||
EType type;
|
||||
|
|
@ -161,12 +163,16 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c
|
|||
}
|
||||
|
||||
std::string texture_filename = custom_texture.empty() ? texture : custom_texture;
|
||||
if (!check_texture(texture_filename))
|
||||
if (! texture_filename.empty() && ! check_texture(texture_filename)) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Unable to load bed texture: " << texture_filename;
|
||||
texture_filename.clear();
|
||||
}
|
||||
|
||||
std::string model_filename = custom_model.empty() ? model : custom_model;
|
||||
if (!check_model(model_filename))
|
||||
if (! model_filename.empty() && ! check_model(model_filename)) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Unable to load bed model: " << model_filename;
|
||||
model_filename.clear();
|
||||
}
|
||||
|
||||
if (m_shape == shape && m_type == type && m_texture_filename == texture_filename && m_model_filename == model_filename)
|
||||
// No change, no need to update the UI.
|
||||
|
|
|
|||
|
|
@ -574,11 +574,8 @@ Print::ApplyStatus BackgroundSlicingProcess::apply(const Model &model, const Dyn
|
|||
// Some FFF status was invalidated, and the G-code was not exported yet.
|
||||
// Let the G-code preview UI know that the final G-code preview is not valid.
|
||||
// In addition, this early memory deallocation reduces memory footprint.
|
||||
if (m_gcode_result != nullptr) {
|
||||
//FIXME calling platter from here is not a staple of a good architecture.
|
||||
GUI::wxGetApp().plater()->stop_mapping_gcode_window();
|
||||
if (m_gcode_result != nullptr)
|
||||
m_gcode_result->reset();
|
||||
}
|
||||
}
|
||||
return invalidated;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
|||
toggle_field(el, have_skirt);
|
||||
|
||||
bool have_brim = config->opt_enum<BrimType>("brim_type") != btNoBrim;
|
||||
for (auto el : { "brim_width", "brim_offset" })
|
||||
for (auto el : { "brim_width", "brim_separation" })
|
||||
toggle_field(el, have_brim);
|
||||
// perimeter_extruder uses the same logic as in Print::extruders()
|
||||
toggle_field("perimeter_extruder", have_perimeters || have_brim);
|
||||
|
|
@ -312,7 +312,8 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
|||
toggle_field("support_material_speed", have_support_material || have_brim || have_skirt);
|
||||
|
||||
toggle_field("raft_contact_distance", have_raft && !have_support_soluble);
|
||||
toggle_field("raft_expansion", have_raft);
|
||||
for (auto el : { "raft_expansion", "first_layer_acceleration_over_raft", "first_layer_speed_over_raft" })
|
||||
toggle_field(el, have_raft);
|
||||
|
||||
bool has_ironing = config->opt_bool("ironing");
|
||||
for (auto el : { "ironing_type", "ironing_flowrate", "ironing_spacing", "ironing_speed" })
|
||||
|
|
|
|||
|
|
@ -382,40 +382,44 @@ void DesktopIntegrationDialog::perform_desktop_integration()
|
|||
app_config->set("desktop_integration_app_path", GUI::format("%1%/applications/PrusaSlicer%2%.desktop", target_dir_desktop, version_suffix));
|
||||
|
||||
// Repeat for Gcode viewer - use same paths as for slicer files
|
||||
// Icon
|
||||
if (!target_dir_icons.empty())
|
||||
{
|
||||
std::string icon_path = GUI::format("%1%/icons/PrusaSlicer-gcodeviewer_192px.png",resources_dir());
|
||||
std::string dest_path = GUI::format("%1%/icons/%2%PrusaSlicer-gcodeviewer%3%.png", target_dir_icons, icon_theme_path, version_suffix);
|
||||
if (copy_icon(icon_path, dest_path))
|
||||
// save path to icon
|
||||
app_config->set("desktop_integration_icon_viewer_path", dest_path);
|
||||
else
|
||||
BOOST_LOG_TRIVIAL(error) << "Copying Gcode Viewer icon to icons directory failed.";
|
||||
}
|
||||
// Do NOT add gcode viewer desktop file on ChromeOS
|
||||
if (platform_flavor() != PlatformFlavor::LinuxOnChromium) {
|
||||
// Icon
|
||||
if (!target_dir_icons.empty())
|
||||
{
|
||||
std::string icon_path = GUI::format("%1%/icons/PrusaSlicer-gcodeviewer_192px.png",resources_dir());
|
||||
std::string dest_path = GUI::format("%1%/icons/%2%PrusaSlicer-gcodeviewer%3%.png", target_dir_icons, icon_theme_path, version_suffix);
|
||||
if (copy_icon(icon_path, dest_path))
|
||||
// save path to icon
|
||||
app_config->set("desktop_integration_icon_viewer_path", dest_path);
|
||||
else
|
||||
BOOST_LOG_TRIVIAL(error) << "Copying Gcode Viewer icon to icons directory failed.";
|
||||
}
|
||||
|
||||
// Desktop file
|
||||
std::string desktop_file = GUI::format(
|
||||
"[Desktop Entry]\n"
|
||||
"Name=Prusa Gcode Viewer%1%\n"
|
||||
"GenericName=3D Printing Software\n"
|
||||
"Icon=PrusaSlicer-gcodeviewer%2%\n"
|
||||
"Exec=\"%3%\" --gcodeviewer %%F\n"
|
||||
"Terminal=false\n"
|
||||
"Type=Application\n"
|
||||
"MimeType=text/x.gcode;\n"
|
||||
"Categories=Graphics;3DGraphics;\n"
|
||||
"Keywords=3D;Printing;Slicer;\n"
|
||||
"StartupNotify=false\n", name_suffix, version_suffix, excutable_path);
|
||||
// Desktop file
|
||||
std::string desktop_file = GUI::format(
|
||||
"[Desktop Entry]\n"
|
||||
"Name=Prusa Gcode Viewer%1%\n"
|
||||
"GenericName=3D Printing Software\n"
|
||||
"Icon=PrusaSlicer-gcodeviewer%2%\n"
|
||||
"Exec=\"%3%\" --gcodeviewer %%F\n"
|
||||
"Terminal=false\n"
|
||||
"Type=Application\n"
|
||||
"MimeType=text/x.gcode;\n"
|
||||
"Categories=Graphics;3DGraphics;\n"
|
||||
"Keywords=3D;Printing;Slicer;\n"
|
||||
"StartupNotify=false\n", name_suffix, version_suffix, excutable_path);
|
||||
|
||||
std::string desktop_path = GUI::format("%1%/applications/PrusaSlicerGcodeViewer%2%.desktop", target_dir_desktop, version_suffix);
|
||||
if (create_desktop_file(desktop_path, desktop_file))
|
||||
// save path to desktop file
|
||||
app_config->set("desktop_integration_app_viewer_path", desktop_path);
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - could not create Gcodeviewer desktop file";
|
||||
show_error(nullptr, _L("Performing desktop integration failed - could not create Gcodeviewer desktop file. PrusaSlicer desktop file was probably created successfully."));
|
||||
std::string desktop_path = GUI::format("%1%/applications/PrusaSlicerGcodeViewer%2%.desktop", target_dir_desktop, version_suffix);
|
||||
if (create_desktop_file(desktop_path, desktop_file))
|
||||
// save path to desktop file
|
||||
app_config->set("desktop_integration_app_viewer_path", desktop_path);
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - could not create Gcodeviewer desktop file";
|
||||
show_error(nullptr, _L("Performing desktop integration failed - could not create Gcodeviewer desktop file. PrusaSlicer desktop file was probably created successfully."));
|
||||
}
|
||||
}
|
||||
|
||||
wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::DesktopIntegrationSuccess);
|
||||
}
|
||||
void DesktopIntegrationDialog::undo_desktop_intgration()
|
||||
|
|
@ -433,17 +437,20 @@ void DesktopIntegrationDialog::undo_desktop_intgration()
|
|||
BOOST_LOG_TRIVIAL(debug) << "removing " << path;
|
||||
std::remove(path.c_str());
|
||||
}
|
||||
// gcode viwer .desktop
|
||||
path = std::string(app_config->get("desktop_integration_app_viewer_path"));
|
||||
if (!path.empty()) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "removing " << path;
|
||||
std::remove(path.c_str());
|
||||
}
|
||||
// gcode viewer icon
|
||||
path = std::string(app_config->get("desktop_integration_icon_viewer_path"));
|
||||
if (!path.empty()) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "removing " << path;
|
||||
std::remove(path.c_str());
|
||||
// No gcode viewer at ChromeOS
|
||||
if (platform_flavor() != PlatformFlavor::LinuxOnChromium) {
|
||||
// gcode viewer .desktop
|
||||
path = std::string(app_config->get("desktop_integration_app_viewer_path"));
|
||||
if (!path.empty()) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "removing " << path;
|
||||
std::remove(path.c_str());
|
||||
}
|
||||
// gcode viewer icon
|
||||
path = std::string(app_config->get("desktop_integration_icon_viewer_path"));
|
||||
if (!path.empty()) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "removing " << path;
|
||||
std::remove(path.c_str());
|
||||
}
|
||||
}
|
||||
wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::UndoDesktopIntegrationSuccess);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -230,18 +230,21 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
|
|||
}
|
||||
double val;
|
||||
|
||||
bool is_na_value = m_opt.nullable && str == na_value();
|
||||
|
||||
const char dec_sep = is_decimal_separator_point() ? '.' : ',';
|
||||
const char dec_sep_alt = dec_sep == '.' ? ',' : '.';
|
||||
// Replace the first incorrect separator in decimal number.
|
||||
if (str.Replace(dec_sep_alt, dec_sep, false) != 0)
|
||||
// Replace the first incorrect separator in decimal number,
|
||||
// if this value doesn't "N/A" value in some language
|
||||
// see https://github.com/prusa3d/PrusaSlicer/issues/6921
|
||||
if (!is_na_value && str.Replace(dec_sep_alt, dec_sep, false) != 0)
|
||||
set_value(str, false);
|
||||
|
||||
|
||||
if (str == dec_sep)
|
||||
val = 0.0;
|
||||
else
|
||||
{
|
||||
if (m_opt.nullable && str == na_value())
|
||||
if (is_na_value)
|
||||
val = ConfigOptionFloatsNullable::nil_value();
|
||||
else if (!str.ToDouble(&val))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -70,18 +70,9 @@ static std::vector<std::array<float, 4>> decode_colors(const std::vector<std::st
|
|||
return output;
|
||||
}
|
||||
|
||||
static float round_to_nearest(float value, unsigned int decimals)
|
||||
static float round_to_nearest_percent(float value)
|
||||
{
|
||||
float res = 0.0f;
|
||||
if (decimals == 0)
|
||||
res = std::round(value);
|
||||
else {
|
||||
char buf[64];
|
||||
// locales should not matter, both sprintf and stof are sensitive, so...
|
||||
sprintf(buf, "%.*g", decimals, value);
|
||||
res = std::stof(buf);
|
||||
}
|
||||
return res;
|
||||
return std::round(value * 100.f) * 0.01f;
|
||||
}
|
||||
|
||||
void GCodeViewer::VBuffer::reset()
|
||||
|
|
@ -146,7 +137,7 @@ bool GCodeViewer::Path::matches(const GCodeProcessor::MoveVertex& move) const
|
|||
// use rounding to reduce the number of generated paths
|
||||
return type == move.type && extruder_id == move.extruder_id && cp_color_id == move.cp_color_id && role == move.extrusion_role &&
|
||||
move.position.z() <= sub_paths.front().first.position.z() && feedrate == move.feedrate && fan_speed == move.fan_speed &&
|
||||
height == round_to_nearest(move.height, 2) && width == round_to_nearest(move.width, 2) &&
|
||||
height == round_to_nearest_percent(move.height) && width == round_to_nearest_percent(move.width) &&
|
||||
matches_percent(volumetric_rate, move.volumetric_rate(), 0.05f);
|
||||
}
|
||||
case EMoveType::Travel: {
|
||||
|
|
@ -183,7 +174,7 @@ void GCodeViewer::TBuffer::add_path(const GCodeProcessor::MoveVertex& move, unsi
|
|||
Path::Endpoint endpoint = { b_id, i_id, s_id, move.position };
|
||||
// use rounding to reduce the number of generated paths
|
||||
paths.push_back({ move.type, move.extrusion_role, move.delta_extruder,
|
||||
round_to_nearest(move.height, 2), round_to_nearest(move.width, 2),
|
||||
round_to_nearest_percent(move.height), round_to_nearest_percent(move.width),
|
||||
move.feedrate, move.fan_speed, move.temperature,
|
||||
move.volumetric_rate(), move.extruder_id, move.cp_color_id, { { endpoint, endpoint } } });
|
||||
}
|
||||
|
|
@ -293,45 +284,14 @@ void GCodeViewer::SequentialView::Marker::render() const
|
|||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
void GCodeViewer::SequentialView::GCodeWindow::load_gcode()
|
||||
void GCodeViewer::SequentialView::GCodeWindow::load_gcode(const std::string& filename, const std::vector<size_t> &lines_ends)
|
||||
{
|
||||
if (m_filename.empty())
|
||||
return;
|
||||
|
||||
assert(! m_file.is_open());
|
||||
if (m_file.is_open())
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// generate mapping for accessing data in file by line number
|
||||
boost::nowide::ifstream f(m_filename);
|
||||
|
||||
f.seekg(0, f.end);
|
||||
uint64_t file_length = static_cast<uint64_t>(f.tellg());
|
||||
f.seekg(0, f.beg);
|
||||
|
||||
std::string line;
|
||||
uint64_t offset = 0;
|
||||
while (std::getline(f, line)) {
|
||||
uint64_t line_length = static_cast<uint64_t>(line.length());
|
||||
m_lines_map.push_back({ offset, line_length });
|
||||
offset += static_cast<uint64_t>(line_length) + 1;
|
||||
}
|
||||
|
||||
if (offset != file_length) {
|
||||
// if the final offset does not match with file length, lines are terminated with CR+LF
|
||||
// so update all offsets accordingly
|
||||
for (size_t i = 0; i < m_lines_map.size(); ++i) {
|
||||
m_lines_map[i].first += static_cast<uint64_t>(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "Unable to load data from " << m_filename << ". Cannot show G-code window.";
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
m_filename = filename;
|
||||
m_lines_ends = std::move(lines_ends);
|
||||
|
||||
m_selected_line_id = 0;
|
||||
m_last_lines_size = 0;
|
||||
|
|
@ -354,7 +314,9 @@ void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, u
|
|||
ret.reserve(end_id - start_id + 1);
|
||||
for (uint64_t id = start_id; id <= end_id; ++id) {
|
||||
// read line from file
|
||||
std::string gline(m_file.data() + m_lines_map[id - 1].first, m_lines_map[id - 1].second);
|
||||
const size_t start = id == 1 ? 0 : m_lines_ends[id - 2];
|
||||
const size_t len = m_lines_ends[id - 1] - start;
|
||||
std::string gline(m_file.data() + start, len);
|
||||
|
||||
std::string command;
|
||||
std::string parameters;
|
||||
|
|
@ -388,7 +350,7 @@ void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, u
|
|||
static const ImVec4 PARAMETERS_COLOR = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
static const ImVec4 COMMENT_COLOR = { 0.7f, 0.7f, 0.7f, 1.0f };
|
||||
|
||||
if (!m_visible || m_filename.empty() || m_lines_map.empty() || curr_line_id == 0)
|
||||
if (!m_visible || m_filename.empty() || m_lines_ends.empty() || curr_line_id == 0)
|
||||
return;
|
||||
|
||||
// window height
|
||||
|
|
@ -406,8 +368,8 @@ void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, u
|
|||
const uint64_t half_lines_count = lines_count / 2;
|
||||
uint64_t start_id = (curr_line_id >= half_lines_count) ? curr_line_id - half_lines_count : 0;
|
||||
uint64_t end_id = start_id + lines_count - 1;
|
||||
if (end_id >= static_cast<uint64_t>(m_lines_map.size())) {
|
||||
end_id = static_cast<uint64_t>(m_lines_map.size()) - 1;
|
||||
if (end_id >= static_cast<uint64_t>(m_lines_ends.size())) {
|
||||
end_id = static_cast<uint64_t>(m_lines_ends.size()) - 1;
|
||||
start_id = end_id - lines_count + 1;
|
||||
}
|
||||
|
||||
|
|
@ -512,7 +474,7 @@ void GCodeViewer::SequentialView::render(float legend_height) const
|
|||
}
|
||||
|
||||
const std::vector<GCodeViewer::Color> GCodeViewer::Extrusion_Role_Colors {{
|
||||
{ 0.75f, 0.75f, 0.75f, 1.0f }, // erNone
|
||||
{ 0.90f, 0.70f, 0.70f, 1.0f }, // erNone
|
||||
{ 1.00f, 0.90f, 0.30f, 1.0f }, // erPerimeter
|
||||
{ 1.00f, 0.49f, 0.22f, 1.0f }, // erExternalPerimeter
|
||||
{ 0.12f, 0.12f, 1.00f, 1.0f }, // erOverhangPerimeter
|
||||
|
|
@ -615,8 +577,7 @@ void GCodeViewer::load(const GCodeProcessor::Result& gcode_result, const Print&
|
|||
// release gpu memory, if used
|
||||
reset();
|
||||
|
||||
m_sequential_view.gcode_window.set_filename(gcode_result.filename);
|
||||
m_sequential_view.gcode_window.load_gcode();
|
||||
m_sequential_view.gcode_window.load_gcode(gcode_result.filename, gcode_result.lines_ends);
|
||||
|
||||
#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
|
||||
if (wxGetApp().is_gcode_viewer())
|
||||
|
|
@ -704,8 +665,8 @@ void GCodeViewer::refresh(const GCodeProcessor::Result& gcode_result, const std:
|
|||
// update tool colors
|
||||
m_tool_colors = decode_colors(str_tool_colors);
|
||||
|
||||
// ensure at least one (default) color is defined
|
||||
if (m_tool_colors.empty())
|
||||
// ensure there are enough colors defined
|
||||
while (m_tool_colors.size() < std::max(size_t(1), gcode_result.extruders_count))
|
||||
m_tool_colors.push_back(decode_color("#FF8000"));
|
||||
|
||||
// update ranges for coloring / legend
|
||||
|
|
@ -721,11 +682,11 @@ void GCodeViewer::refresh(const GCodeProcessor::Result& gcode_result, const std:
|
|||
{
|
||||
case EMoveType::Extrude:
|
||||
{
|
||||
m_extrusions.ranges.height.update_from(round_to_nearest(curr.height, 2));
|
||||
m_extrusions.ranges.width.update_from(round_to_nearest(curr.width, 2));
|
||||
m_extrusions.ranges.height.update_from(round_to_nearest_percent(curr.height));
|
||||
m_extrusions.ranges.width.update_from(round_to_nearest_percent(curr.width));
|
||||
m_extrusions.ranges.fan_speed.update_from(curr.fan_speed);
|
||||
m_extrusions.ranges.temperature.update_from(curr.temperature);
|
||||
m_extrusions.ranges.volumetric_rate.update_from(round_to_nearest(curr.volumetric_rate(), 2));
|
||||
m_extrusions.ranges.volumetric_rate.update_from(round_to_nearest_percent(curr.volumetric_rate()));
|
||||
[[fallthrough]];
|
||||
}
|
||||
case EMoveType::Travel:
|
||||
|
|
@ -807,7 +768,26 @@ void GCodeViewer::render()
|
|||
case EMoveType::Unretract:
|
||||
case EMoveType::Seam: {
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
if (wxGetApp().is_gl_version_greater_or_equal_to(3, 1)) {
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
|
||||
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::InstancedModel;
|
||||
buffer.shader = "gouraud_light_instanced";
|
||||
buffer.model.model.init_from(diamond(16));
|
||||
buffer.model.color = option_color(type);
|
||||
buffer.model.instances.format = InstanceVBuffer::EFormat::InstancedModel;
|
||||
}
|
||||
else {
|
||||
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::BatchedModel;
|
||||
buffer.vertices.format = VBuffer::EFormat::PositionNormal3;
|
||||
buffer.shader = "gouraud_light";
|
||||
|
||||
buffer.model.data = diamond(16);
|
||||
buffer.model.color = option_color(type);
|
||||
buffer.model.instances.format = InstanceVBuffer::EFormat::BatchedModel;
|
||||
}
|
||||
break;
|
||||
#else
|
||||
if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
|
||||
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Model;
|
||||
buffer.shader = "gouraud_light_instanced";
|
||||
buffer.model.model.init_from(diamond(16));
|
||||
|
|
@ -819,6 +799,7 @@ void GCodeViewer::render()
|
|||
buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
|
||||
}
|
||||
break;
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
#else
|
||||
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point;
|
||||
buffer.vertices.format = VBuffer::EFormat::Position;
|
||||
|
|
@ -1100,7 +1081,7 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const
|
|||
// save vertices to file
|
||||
fprintf(fp, "\n# vertices\n");
|
||||
for (const Vec3f& v : out_vertices) {
|
||||
fprintf(fp, "v %g %g %g\n", v.x(), v.y(), v.x());
|
||||
fprintf(fp, "v %g %g %g\n", v.x(), v.y(), v.z());
|
||||
}
|
||||
|
||||
// save normals to file
|
||||
|
|
@ -1155,16 +1136,6 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const
|
|||
fclose(fp);
|
||||
}
|
||||
|
||||
void GCodeViewer::start_mapping_gcode_window()
|
||||
{
|
||||
m_sequential_view.gcode_window.load_gcode();
|
||||
}
|
||||
|
||||
void GCodeViewer::stop_mapping_gcode_window()
|
||||
{
|
||||
m_sequential_view.gcode_window.stop_mapping_file();
|
||||
}
|
||||
|
||||
void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
||||
{
|
||||
// max index buffer size, in bytes
|
||||
|
|
@ -1219,9 +1190,9 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||
};
|
||||
auto add_indices_as_line = [](const GCodeProcessor::MoveVertex& prev, const GCodeProcessor::MoveVertex& curr, TBuffer& buffer,
|
||||
unsigned int ibuffer_id, IndexBuffer& indices, size_t move_id) {
|
||||
if (prev.type != curr.type || !buffer.paths.back().matches(curr)) {
|
||||
if (buffer.paths.empty() || prev.type != curr.type || !buffer.paths.back().matches(curr)) {
|
||||
// add starting index
|
||||
indices.push_back(static_cast<unsigned int>(indices.size()));
|
||||
indices.push_back(static_cast<IBufferType>(indices.size()));
|
||||
buffer.add_path(curr, ibuffer_id, indices.size() - 1, move_id - 1);
|
||||
buffer.paths.back().sub_paths.front().first.position = prev.position;
|
||||
}
|
||||
|
|
@ -1229,11 +1200,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||
Path& last_path = buffer.paths.back();
|
||||
if (last_path.sub_paths.front().first.i_id != last_path.sub_paths.back().last.i_id) {
|
||||
// add previous index
|
||||
indices.push_back(static_cast<unsigned int>(indices.size()));
|
||||
indices.push_back(static_cast<IBufferType>(indices.size()));
|
||||
}
|
||||
|
||||
// add current index
|
||||
indices.push_back(static_cast<unsigned int>(indices.size()));
|
||||
indices.push_back(static_cast<IBufferType>(indices.size()));
|
||||
last_path.sub_paths.back().last = { ibuffer_id, indices.size() - 1, move_id, curr.position };
|
||||
};
|
||||
|
||||
|
|
@ -1436,20 +1407,63 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||
};
|
||||
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
// format data into the buffers to be rendered as model
|
||||
// format data into the buffers to be rendered as instanced model
|
||||
auto add_model_instance = [](const GCodeProcessor::MoveVertex& curr, InstanceBuffer& instances, InstanceIdBuffer& instances_ids, size_t move_id) {
|
||||
// append position
|
||||
instances.push_back(curr.position.x());
|
||||
instances.push_back(curr.position.y());
|
||||
instances.push_back(curr.position.z());
|
||||
// append width
|
||||
instances.push_back(1.5f * curr.width);
|
||||
instances.push_back(curr.width);
|
||||
// append height
|
||||
instances.push_back(1.5f * curr.height);
|
||||
instances.push_back(curr.height);
|
||||
|
||||
// append id
|
||||
instances_ids.push_back(move_id);
|
||||
};
|
||||
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
// format data into the buffers to be rendered as batched model
|
||||
auto add_vertices_as_model_batch = [](const GCodeProcessor::MoveVertex& curr, const GLModel::InitializationData& data, VertexBuffer& vertices, InstanceBuffer& instances, InstanceIdBuffer& instances_ids, size_t move_id) {
|
||||
const double width = static_cast<double>(1.5f * curr.width);
|
||||
const double height = static_cast<double>(1.5f * curr.height);
|
||||
|
||||
const Transform3d trafo = Geometry::assemble_transform((curr.position - 0.5f * curr.height * Vec3f::UnitZ()).cast<double>(), Vec3d::Zero(), { width, width, height });
|
||||
const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> normal_matrix = trafo.matrix().template block<3, 3>(0, 0).inverse().transpose();
|
||||
|
||||
for (const auto& entity : data.entities) {
|
||||
// append vertices
|
||||
for (size_t i = 0; i < entity.positions.size(); ++i) {
|
||||
// append position
|
||||
const Vec3d position = trafo * entity.positions[i].cast<double>();
|
||||
vertices.push_back(static_cast<float>(position.x()));
|
||||
vertices.push_back(static_cast<float>(position.y()));
|
||||
vertices.push_back(static_cast<float>(position.z()));
|
||||
|
||||
// append normal
|
||||
const Vec3d normal = normal_matrix * entity.normals[i].cast<double>();
|
||||
vertices.push_back(static_cast<float>(normal.x()));
|
||||
vertices.push_back(static_cast<float>(normal.y()));
|
||||
vertices.push_back(static_cast<float>(normal.z()));
|
||||
}
|
||||
}
|
||||
|
||||
// append instance position
|
||||
instances.push_back(curr.position.x());
|
||||
instances.push_back(curr.position.y());
|
||||
instances.push_back(curr.position.z());
|
||||
// append instance id
|
||||
instances_ids.push_back(move_id);
|
||||
};
|
||||
|
||||
auto add_indices_as_model_batch = [](const GLModel::InitializationData& data, IndexBuffer& indices, IBufferType base_index) {
|
||||
for (const auto& entity : data.entities) {
|
||||
for (size_t i = 0; i < entity.indices.size(); ++i) {
|
||||
indices.push_back(static_cast<IBufferType>(entity.indices[i] + base_index));
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
#endif // ENABLE_SEAMS_USING_MODELS
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
|
@ -1533,7 +1547,12 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||
|
||||
// if adding the vertices for the current segment exceeds the threshold size of the current vertex buffer
|
||||
// add another vertex buffer
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
size_t vertices_size_to_add = (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) ? t_buffer.model.data.vertices_size_bytes() : t_buffer.max_vertices_per_segment_size_bytes();
|
||||
if (v_multibuffer.back().size() * sizeof(float) > t_buffer.vertices.max_size_bytes() - vertices_size_to_add) {
|
||||
#else
|
||||
if (v_multibuffer.back().size() * sizeof(float) > t_buffer.vertices.max_size_bytes() - t_buffer.max_vertices_per_segment_size_bytes()) {
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
v_multibuffer.push_back(VertexBuffer());
|
||||
if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Triangle) {
|
||||
Path& last_path = t_buffer.paths.back();
|
||||
|
|
@ -1550,6 +1569,24 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||
case TBuffer::ERenderPrimitiveType::Line: { add_vertices_as_line(prev, curr, v_buffer); break; }
|
||||
case TBuffer::ERenderPrimitiveType::Triangle: { add_vertices_as_solid(prev, curr, t_buffer, static_cast<unsigned int>(v_multibuffer.size()) - 1, v_buffer, i); break; }
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
case TBuffer::ERenderPrimitiveType::InstancedModel:
|
||||
{
|
||||
add_model_instance(curr, inst_buffer, inst_id_buffer, i);
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
++m_statistics.instances_count;
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
break;
|
||||
}
|
||||
case TBuffer::ERenderPrimitiveType::BatchedModel:
|
||||
{
|
||||
add_vertices_as_model_batch(curr, t_buffer.model.data, v_buffer, inst_buffer, inst_id_buffer, i);
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
++m_statistics.batched_count;
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
break;
|
||||
}
|
||||
#else
|
||||
case TBuffer::ERenderPrimitiveType::Model:
|
||||
{
|
||||
add_model_instance(curr, inst_buffer, inst_id_buffer, i);
|
||||
|
|
@ -1559,6 +1596,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||
break;
|
||||
}
|
||||
#endif // ENABLE_SEAMS_USING_MODELS
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
}
|
||||
|
||||
// collect options zs for later use
|
||||
|
|
@ -1741,6 +1779,23 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||
for (size_t i = 0; i < m_buffers.size(); ++i) {
|
||||
TBuffer& t_buffer = m_buffers[i];
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel) {
|
||||
const InstanceBuffer& inst_buffer = instances[i];
|
||||
if (!inst_buffer.empty()) {
|
||||
t_buffer.model.instances.buffer = inst_buffer;
|
||||
t_buffer.model.instances.s_ids = instances_ids[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) {
|
||||
const InstanceBuffer& inst_buffer = instances[i];
|
||||
if (!inst_buffer.empty()) {
|
||||
t_buffer.model.instances.buffer = inst_buffer;
|
||||
t_buffer.model.instances.s_ids = instances_ids[i];
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Model) {
|
||||
const InstanceBuffer& inst_buffer = instances[i];
|
||||
if (!inst_buffer.empty()) {
|
||||
|
|
@ -1749,6 +1804,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||
}
|
||||
}
|
||||
else {
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
#endif // ENABLE_SEAMS_USING_MODELS
|
||||
const MultiVertexBuffer& v_multibuffer = vertices[i];
|
||||
for (const VertexBuffer& v_buffer : v_multibuffer) {
|
||||
|
|
@ -1842,10 +1898,20 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||
|
||||
// if adding the indices for the current segment exceeds the threshold size of the current index buffer
|
||||
// create another index buffer
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
size_t indiced_size_to_add = (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) ? t_buffer.model.data.indices_size_bytes() : t_buffer.max_indices_per_segment_size_bytes();
|
||||
if (i_multibuffer.back().size() * sizeof(IBufferType) >= IBUFFER_THRESHOLD_BYTES - indiced_size_to_add) {
|
||||
#else
|
||||
if (i_multibuffer.back().size() * sizeof(IBufferType) >= IBUFFER_THRESHOLD_BYTES - t_buffer.max_indices_per_segment_size_bytes()) {
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
i_multibuffer.push_back(IndexBuffer());
|
||||
vbo_index_list.push_back(t_buffer.vertices.vbos[curr_vertex_buffer.first]);
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point &&
|
||||
t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel) {
|
||||
#else
|
||||
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point) {
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
Path& last_path = t_buffer.paths.back();
|
||||
last_path.add_sub_path(prev, static_cast<unsigned int>(i_multibuffer.size()) - 1, 0, i - 1);
|
||||
}
|
||||
|
|
@ -1853,14 +1919,24 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||
|
||||
// if adding the vertices for the current segment exceeds the threshold size of the current vertex buffer
|
||||
// create another index buffer
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
size_t vertices_size_to_add = (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) ? t_buffer.model.data.vertices_size_bytes() : t_buffer.max_vertices_per_segment_size_bytes();
|
||||
if (curr_vertex_buffer.second * t_buffer.vertices.vertex_size_bytes() > t_buffer.vertices.max_size_bytes() - vertices_size_to_add) {
|
||||
#else
|
||||
if (curr_vertex_buffer.second * t_buffer.vertices.vertex_size_bytes() > t_buffer.vertices.max_size_bytes() - t_buffer.max_vertices_per_segment_size_bytes()) {
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
i_multibuffer.push_back(IndexBuffer());
|
||||
|
||||
++curr_vertex_buffer.first;
|
||||
curr_vertex_buffer.second = 0;
|
||||
vbo_index_list.push_back(t_buffer.vertices.vbos[curr_vertex_buffer.first]);
|
||||
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point &&
|
||||
t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel) {
|
||||
#else
|
||||
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point) {
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
Path& last_path = t_buffer.paths.back();
|
||||
last_path.add_sub_path(prev, static_cast<unsigned int>(i_multibuffer.size()) - 1, 0, i - 1);
|
||||
}
|
||||
|
|
@ -1884,6 +1960,13 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||
add_indices_as_solid(prev, curr, next, t_buffer, curr_vertex_buffer.second, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, i);
|
||||
break;
|
||||
}
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
case TBuffer::ERenderPrimitiveType::BatchedModel: {
|
||||
add_indices_as_model_batch(t_buffer.model.data, i_buffer, curr_vertex_buffer.second);
|
||||
curr_vertex_buffer.second += t_buffer.model.data.vertices_count();
|
||||
break;
|
||||
}
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
default: { break; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1898,7 +1981,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||
for (size_t i = 0; i < m_buffers.size(); ++i) {
|
||||
TBuffer& t_buffer = m_buffers[i];
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::InstancedModel) {
|
||||
#else
|
||||
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Model) {
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
#endif // ENABLE_SEAMS_USING_MODELS
|
||||
const MultiIndexBuffer& i_multibuffer = indices[i];
|
||||
for (const IndexBuffer& i_buffer : i_multibuffer) {
|
||||
|
|
@ -2174,7 +2261,12 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
|
|||
continue;
|
||||
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel ||
|
||||
buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) {
|
||||
#else
|
||||
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Model) {
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
for (size_t id : buffer.model.instances.s_ids) {
|
||||
if (id < m_layers.get_endpoints_at(m_layers_z_range[0]).first || m_layers.get_endpoints_at(m_layers_z_range[1]).last < id)
|
||||
continue;
|
||||
|
|
@ -2239,7 +2331,12 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
|
|||
bool found = false;
|
||||
for (const TBuffer& buffer : m_buffers) {
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel ||
|
||||
buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) {
|
||||
#else
|
||||
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Model) {
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
for (size_t i = 0; i < buffer.model.instances.s_ids.size(); ++i) {
|
||||
if (buffer.model.instances.s_ids[i] == m_sequential_view.current.last) {
|
||||
size_t offset = i * buffer.model.instances.instance_size_floats();
|
||||
|
|
@ -2400,15 +2497,24 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
|
|||
}
|
||||
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
// second pass: for buffers using instanced and batched models, update the instances render ranges
|
||||
#else
|
||||
// second pass: for buffers using instanced models, update the instances render ranges
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
for (size_t b = 0; b < m_buffers.size(); ++b) {
|
||||
TBuffer& buffer = const_cast<TBuffer&>(m_buffers[b]);
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
if (buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::InstancedModel &&
|
||||
buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel)
|
||||
#else
|
||||
if (buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Model)
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
continue;
|
||||
|
||||
buffer.model.instances.render_ranges.reset();
|
||||
|
||||
if (!buffer.visible)
|
||||
if (!buffer.visible || buffer.model.instances.s_ids.empty())
|
||||
continue;
|
||||
|
||||
buffer.model.instances.render_ranges.ranges.push_back({ 0, 0, 0, buffer.model.color });
|
||||
|
|
@ -2419,7 +2525,11 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
|
|||
if (m_sequential_view.current.first <= buffer.model.instances.s_ids.back() && buffer.model.instances.s_ids.front() <= m_sequential_view.current.last) {
|
||||
for (size_t id : buffer.model.instances.s_ids) {
|
||||
if (has_second_range) {
|
||||
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
|
||||
if (id < m_sequential_view.endpoints.first) {
|
||||
#else
|
||||
if (id <= m_sequential_view.endpoints.first) {
|
||||
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
|
||||
++buffer.model.instances.render_ranges.ranges.front().offset;
|
||||
if (id <= m_sequential_view.current.first)
|
||||
++buffer.model.instances.render_ranges.ranges.back().offset;
|
||||
|
|
@ -2665,7 +2775,11 @@ void GCodeViewer::render_toolpaths()
|
|||
};
|
||||
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
auto render_as_instanced_model = [this]
|
||||
#else
|
||||
auto render_as_instanced_model = []
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
(TBuffer& buffer, GLShaderProgram & shader) {
|
||||
for (auto& range : buffer.model.instances.render_ranges.ranges) {
|
||||
if (range.vbo == 0 && range.count > 0) {
|
||||
|
|
@ -2685,6 +2799,66 @@ void GCodeViewer::render_toolpaths()
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
auto render_as_batched_model = [this](TBuffer& buffer, GLShaderProgram& shader) {
|
||||
#else
|
||||
auto render_as_batched_model = [](TBuffer& buffer, GLShaderProgram& shader) {
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
||||
struct Range
|
||||
{
|
||||
unsigned int first;
|
||||
unsigned int last;
|
||||
bool intersects(const Range& other) const { return (other.last < first || other.first > last) ? false : true; }
|
||||
};
|
||||
Range buffer_range = { 0, 0 };
|
||||
size_t indices_per_instance = buffer.model.data.indices_count();
|
||||
|
||||
for (size_t j = 0; j < buffer.indices.size(); ++j) {
|
||||
const IBuffer& i_buffer = buffer.indices[j];
|
||||
buffer_range.last = buffer_range.first + i_buffer.count / indices_per_instance;
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, i_buffer.vbo));
|
||||
glsafe(::glVertexPointer(buffer.vertices.position_size_floats(), GL_FLOAT, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.position_offset_bytes()));
|
||||
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
||||
bool has_normals = buffer.vertices.normal_size_floats() > 0;
|
||||
if (has_normals) {
|
||||
glsafe(::glNormalPointer(GL_FLOAT, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.normal_offset_bytes()));
|
||||
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
|
||||
}
|
||||
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_buffer.ibo));
|
||||
|
||||
for (auto& range : buffer.model.instances.render_ranges.ranges) {
|
||||
Range range_range = { range.offset, range.offset + range.count };
|
||||
if (range_range.intersects(buffer_range)) {
|
||||
shader.set_uniform("uniform_color", range.color);
|
||||
unsigned int offset = (range_range.first > buffer_range.first) ? range_range.first - buffer_range.first : 0;
|
||||
size_t offset_bytes = static_cast<size_t>(offset) * indices_per_instance * sizeof(IBufferType);
|
||||
Range render_range = { std::max(range_range.first, buffer_range.first), std::min(range_range.last, buffer_range.last) };
|
||||
size_t count = static_cast<size_t>(render_range.last - render_range.first) * indices_per_instance;
|
||||
if (count > 0) {
|
||||
glsafe(::glDrawElements(GL_TRIANGLES, (GLsizei)count, GL_UNSIGNED_SHORT, (const void*)offset_bytes));
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
++m_statistics.gl_batched_models_calls_count;
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
|
||||
if (has_normals)
|
||||
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
|
||||
|
||||
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
|
||||
buffer_range.first = buffer_range.last;
|
||||
}
|
||||
};
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
#endif // ENABLE_SEAMS_USING_MODELS
|
||||
|
||||
auto line_width = [](double zoom) {
|
||||
|
|
@ -2708,11 +2882,22 @@ void GCodeViewer::render_toolpaths()
|
|||
shader->start_using();
|
||||
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel) {
|
||||
#else
|
||||
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Model) {
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
shader->set_uniform("emission_factor", 0.25f);
|
||||
render_as_instanced_model(buffer, *shader);
|
||||
shader->set_uniform("emission_factor", 0.0f);
|
||||
}
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
else if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) {
|
||||
shader->set_uniform("emission_factor", 0.25f);
|
||||
render_as_batched_model(buffer, *shader);
|
||||
shader->set_uniform("emission_factor", 0.0f);
|
||||
}
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
else {
|
||||
#endif // ENABLE_SEAMS_USING_MODELS
|
||||
for (size_t j = 0; j < buffer.indices.size(); ++j) {
|
||||
|
|
@ -2860,7 +3045,7 @@ void GCodeViewer::render_legend(float& legend_height)
|
|||
|
||||
bool imperial_units = wxGetApp().app_config->get("use_inches") == "1";
|
||||
|
||||
auto append_item = [this, icon_size, percent_bar_size, &imgui, imperial_units](EItemType type, const Color& color, const std::string& label,
|
||||
auto append_item = [icon_size, percent_bar_size, &imgui, imperial_units](EItemType type, const Color& color, const std::string& label,
|
||||
bool visible = true, const std::string& time = "", float percent = 0.0f, float max_percent = 0.0f, const std::array<float, 4>& offsets = { 0.0f, 0.0f, 0.0f, 0.0f },
|
||||
double used_filament_m = 0.0, double used_filament_g = 0.0,
|
||||
std::function<void()> callback = nullptr) {
|
||||
|
|
@ -2878,6 +3063,7 @@ void GCodeViewer::render_legend(float& legend_height)
|
|||
}
|
||||
case EItemType::Circle: {
|
||||
ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size));
|
||||
#if !ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
if (m_buffers[buffer_id(EMoveType::Retract)].shader == "options_120") {
|
||||
draw_list->AddCircleFilled(center, 0.5f * icon_size,
|
||||
ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
|
||||
|
|
@ -2887,6 +3073,7 @@ void GCodeViewer::render_legend(float& legend_height)
|
|||
draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
|
||||
}
|
||||
else
|
||||
#endif // !ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
draw_list->AddCircleFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
|
||||
|
||||
break;
|
||||
|
|
@ -3532,7 +3719,11 @@ void GCodeViewer::render_legend(float& legend_height)
|
|||
auto add_option = [this, append_item](EMoveType move_type, EOptionsColors color, const std::string& text) {
|
||||
const TBuffer& buffer = m_buffers[buffer_id(move_type)];
|
||||
if (buffer.visible && buffer.has_data())
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
append_item(EItemType::Circle, Options_Colors[static_cast<unsigned int>(color)], text);
|
||||
#else
|
||||
append_item((buffer.shader == "options_110") ? EItemType::Rect : EItemType::Circle, Options_Colors[static_cast<unsigned int>(color)], text);
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
};
|
||||
|
||||
// options section
|
||||
|
|
@ -3752,7 +3943,11 @@ void GCodeViewer::render_statistics()
|
|||
add_counter(std::string("Multi GL_TRIANGLES:"), m_statistics.gl_multi_triangles_calls_count);
|
||||
add_counter(std::string("GL_TRIANGLES:"), m_statistics.gl_triangles_calls_count);
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
ImGui::Separator();
|
||||
add_counter(std::string("Instanced models:"), m_statistics.gl_instanced_models_calls_count);
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
add_counter(std::string("Batched models:"), m_statistics.gl_batched_models_calls_count);
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
#endif // ENABLE_SEAMS_USING_MODELS
|
||||
}
|
||||
|
||||
|
|
@ -3784,6 +3979,9 @@ void GCodeViewer::render_statistics()
|
|||
add_counter(std::string("Extrude segments count:"), m_statistics.extrude_segments_count);
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
add_counter(std::string("Instances count:"), m_statistics.instances_count);
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
add_counter(std::string("Batched count:"), m_statistics.batched_count);
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
#endif // ENABLE_SEAMS_USING_MODELS
|
||||
ImGui::Separator();
|
||||
add_counter(std::string("VBuffers count:"), m_statistics.vbuffers_count);
|
||||
|
|
|
|||
|
|
@ -105,9 +105,16 @@ class GCodeViewer
|
|||
};
|
||||
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
// buffer containing instances data used to render a toolpaths using instanced or batched models
|
||||
// instance record format:
|
||||
// instanced models: 5 floats -> position.x|position.y|position.z|width|height (which are sent to the shader as -> vec3 (offset) + vec2 (scales) in GLModel::render_instanced())
|
||||
// batched models: 3 floats -> position.x|position.y|position.z
|
||||
#else
|
||||
// buffer containing instances data used to render a toolpaths using instanced models
|
||||
// instance record format: 5 floats -> position.x|position.y|position.z|width|height
|
||||
// which is sent to the shader as -> vec3 (offset) + vec2 (scales) in GLModel::render_instanced()
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
struct InstanceVBuffer
|
||||
{
|
||||
// ranges used to render only subparts of the intances
|
||||
|
|
@ -130,6 +137,16 @@ class GCodeViewer
|
|||
void reset();
|
||||
};
|
||||
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
enum class EFormat : unsigned char
|
||||
{
|
||||
InstancedModel,
|
||||
BatchedModel
|
||||
};
|
||||
|
||||
EFormat format;
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
|
||||
// cpu-side buffer containing all instances data
|
||||
InstanceBuffer buffer;
|
||||
// indices of the moves for all instances
|
||||
|
|
@ -138,7 +155,18 @@ class GCodeViewer
|
|||
|
||||
size_t data_size_bytes() const { return s_ids.size() * instance_size_bytes(); }
|
||||
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
size_t instance_size_floats() const {
|
||||
switch (format)
|
||||
{
|
||||
case EFormat::InstancedModel: { return 5; }
|
||||
case EFormat::BatchedModel: { return 3; }
|
||||
default: { return 0; }
|
||||
}
|
||||
}
|
||||
#else
|
||||
size_t instance_size_floats() const { return 5; }
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
size_t instance_size_bytes() const { return instance_size_floats() * sizeof(float); }
|
||||
|
||||
void reset();
|
||||
|
|
@ -280,7 +308,12 @@ class GCodeViewer
|
|||
Line,
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
Triangle,
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
InstancedModel,
|
||||
BatchedModel
|
||||
#else
|
||||
Model
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
#else
|
||||
Triangle
|
||||
#endif // ENABLE_SEAMS_USING_MODELS
|
||||
|
|
@ -298,6 +331,9 @@ class GCodeViewer
|
|||
GLModel model;
|
||||
Color color;
|
||||
InstanceVBuffer instances;
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
GLModel::InitializationData data;
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
|
@ -362,7 +398,15 @@ class GCodeViewer
|
|||
case ERenderPrimitiveType::Triangle: {
|
||||
return !vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0;
|
||||
}
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
case ERenderPrimitiveType::InstancedModel: { return model.model.is_initialized() && !model.instances.buffer.empty(); }
|
||||
case ERenderPrimitiveType::BatchedModel: {
|
||||
return model.data.vertices_count() > 0 && model.data.indices_count() &&
|
||||
!vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0;
|
||||
}
|
||||
#else
|
||||
case ERenderPrimitiveType::Model: { return model.model.is_initialized() && !model.instances.buffer.empty(); }
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
default: { return false; }
|
||||
}
|
||||
}
|
||||
|
|
@ -520,6 +564,9 @@ class GCodeViewer
|
|||
int64_t gl_triangles_calls_count{ 0 };
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
int64_t gl_instanced_models_calls_count{ 0 };
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
int64_t gl_batched_models_calls_count{ 0 };
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
#endif // ENABLE_SEAMS_USING_MODELS
|
||||
// memory
|
||||
int64_t results_size{ 0 };
|
||||
|
|
@ -541,6 +588,9 @@ class GCodeViewer
|
|||
int64_t extrude_segments_count{ 0 };
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
int64_t instances_count{ 0 };
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
int64_t batched_count{ 0 };
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
#endif // ENABLE_SEAMS_USING_MODELS
|
||||
int64_t vbuffers_count{ 0 };
|
||||
int64_t ibuffers_count{ 0 };
|
||||
|
|
@ -569,6 +619,9 @@ class GCodeViewer
|
|||
gl_triangles_calls_count = 0;
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
gl_instanced_models_calls_count = 0;
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
gl_batched_models_calls_count = 0;
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
#endif // ENABLE_SEAMS_USING_MODELS
|
||||
}
|
||||
|
||||
|
|
@ -594,6 +647,9 @@ class GCodeViewer
|
|||
extrude_segments_count = 0;
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
instances_count = 0;
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
batched_count = 0;
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
#endif // ENABLE_SEAMS_USING_MODELS
|
||||
vbuffers_count = 0;
|
||||
ibuffers_count = 0;
|
||||
|
|
@ -639,18 +695,17 @@ public:
|
|||
std::string m_filename;
|
||||
boost::iostreams::mapped_file_source m_file;
|
||||
// map for accessing data in file by line number
|
||||
std::vector<std::pair<uint64_t, uint64_t>> m_lines_map;
|
||||
std::vector<size_t> m_lines_ends;
|
||||
// current visible lines
|
||||
std::vector<Line> m_lines;
|
||||
|
||||
public:
|
||||
GCodeWindow() = default;
|
||||
~GCodeWindow() { stop_mapping_file(); }
|
||||
void set_filename(const std::string& filename) { m_filename = filename; }
|
||||
void load_gcode();
|
||||
void load_gcode(const std::string& filename, const std::vector<size_t> &lines_ends);
|
||||
void reset() {
|
||||
stop_mapping_file();
|
||||
m_lines_map.clear();
|
||||
m_lines_ends.clear();
|
||||
m_lines.clear();
|
||||
m_filename.clear();
|
||||
}
|
||||
|
|
@ -777,8 +832,6 @@ public:
|
|||
|
||||
void export_toolpaths_to_obj(const char* filename) const;
|
||||
|
||||
void start_mapping_gcode_window();
|
||||
void stop_mapping_gcode_window();
|
||||
void toggle_gcode_window_visibility() { m_sequential_view.gcode_window.toggle_visibility(); }
|
||||
|
||||
#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
|
||||
|
|
|
|||
|
|
@ -1114,16 +1114,6 @@ int GLCanvas3D::check_volumes_outside_state() const
|
|||
return (int)state;
|
||||
}
|
||||
|
||||
void GLCanvas3D::start_mapping_gcode_window()
|
||||
{
|
||||
m_gcode_viewer.start_mapping_gcode_window();
|
||||
}
|
||||
|
||||
void GLCanvas3D::stop_mapping_gcode_window()
|
||||
{
|
||||
m_gcode_viewer.stop_mapping_gcode_window();
|
||||
}
|
||||
|
||||
void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo, int instance_idx)
|
||||
{
|
||||
m_render_sla_auxiliaries = visible;
|
||||
|
|
@ -4108,13 +4098,24 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const
|
|||
}
|
||||
}
|
||||
|
||||
#if !ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
|
||||
if (visible_volumes.empty())
|
||||
return;
|
||||
#endif // !ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
|
||||
|
||||
BoundingBoxf3 volumes_box;
|
||||
for (const GLVolume* vol : visible_volumes) {
|
||||
volumes_box.merge(vol->transformed_bounding_box());
|
||||
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
|
||||
if (!visible_volumes.empty()) {
|
||||
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
|
||||
for (const GLVolume* vol : visible_volumes) {
|
||||
volumes_box.merge(vol->transformed_bounding_box());
|
||||
}
|
||||
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
|
||||
}
|
||||
else
|
||||
// This happens for empty projects
|
||||
volumes_box = wxGetApp().plater()->get_bed().get_bounding_box(true);
|
||||
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
|
||||
|
||||
Camera camera;
|
||||
camera.set_type(camera_type);
|
||||
|
|
|
|||
|
|
@ -621,9 +621,6 @@ public:
|
|||
const GCodeViewer::SequentialView& get_gcode_sequential_view() const { return m_gcode_viewer.get_sequential_view(); }
|
||||
void update_gcode_sequential_view_current(unsigned int first, unsigned int last) { m_gcode_viewer.update_sequential_view_current(first, last); }
|
||||
|
||||
void start_mapping_gcode_window();
|
||||
void stop_mapping_gcode_window();
|
||||
|
||||
void toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
|
||||
void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
|
||||
void update_instance_printable_state_for_object(size_t obj_idx);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,26 @@
|
|||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
size_t GLModel::InitializationData::vertices_count() const
|
||||
{
|
||||
size_t ret = 0;
|
||||
for (const Entity& entity : entities) {
|
||||
ret += entity.positions.size();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t GLModel::InitializationData::indices_count() const
|
||||
{
|
||||
size_t ret = 0;
|
||||
for (const Entity& entity : entities) {
|
||||
ret += entity.indices.size();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
|
||||
void GLModel::init_from(const InitializationData& data)
|
||||
{
|
||||
if (!m_render_data.empty()) // call reset() if you want to reuse this model
|
||||
|
|
|
|||
|
|
@ -48,6 +48,15 @@ namespace GUI {
|
|||
};
|
||||
|
||||
std::vector<Entity> entities;
|
||||
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
size_t vertices_count() const;
|
||||
size_t vertices_size_floats() const { return vertices_count() * 6; }
|
||||
size_t vertices_size_bytes() const { return vertices_size_floats() * sizeof(float); }
|
||||
|
||||
size_t indices_count() const;
|
||||
size_t indices_size_bytes() const { return indices_count() * sizeof(unsigned int); }
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -33,13 +33,21 @@ std::pair<bool, std::string> GLShadersManager::init()
|
|||
|
||||
bool valid = true;
|
||||
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
// used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells, options in gcode preview
|
||||
#else
|
||||
// used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
valid &= append_shader("gouraud_light", { "gouraud_light.vs", "gouraud_light.fs" });
|
||||
// used to render printbed
|
||||
valid &= append_shader("printbed", { "printbed.vs", "printbed.fs" });
|
||||
// used to render options in gcode preview
|
||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
if (GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 3))
|
||||
valid &= append_shader("gouraud_light_instanced", { "gouraud_light_instanced.vs", "gouraud_light_instanced.fs" });
|
||||
#else
|
||||
#if ENABLE_SEAMS_USING_MODELS
|
||||
if (GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 1))
|
||||
if (GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 3))
|
||||
valid &= append_shader("gouraud_light_instanced", { "gouraud_light_instanced.vs", "gouraud_light_instanced.fs" });
|
||||
else {
|
||||
#endif // ENABLE_SEAMS_USING_MODELS
|
||||
|
|
@ -49,6 +57,7 @@ std::pair<bool, std::string> GLShadersManager::init()
|
|||
#if ENABLE_SEAMS_USING_MODELS
|
||||
}
|
||||
#endif // ENABLE_SEAMS_USING_MODELS
|
||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||
// used to render extrusion and travel paths as lines in gcode preview
|
||||
valid &= append_shader("toolpaths_lines", { "toolpaths_lines.vs", "toolpaths_lines.fs" });
|
||||
// used to render objects in 3d editor
|
||||
|
|
|
|||
|
|
@ -2082,10 +2082,10 @@ std::vector<std::pair<unsigned int, std::string>> GUI_App::get_selected_presets(
|
|||
|
||||
// This is called when closing the application, when loading a config file or when starting the config wizard
|
||||
// to notify the user whether he is aware that some preset changes will be lost.
|
||||
bool GUI_App::check_and_save_current_preset_changes(const wxString& header)
|
||||
bool GUI_App::check_and_save_current_preset_changes(const wxString& header, const wxString& caption)
|
||||
{
|
||||
if (/*this->plater()->model().objects.empty() && */has_current_preset_changes()) {
|
||||
UnsavedChangesDialog dlg(header);
|
||||
UnsavedChangesDialog dlg(header, caption);
|
||||
if (wxGetApp().app_config->get("default_action_on_close_application") == "none" && dlg.ShowModal() == wxID_CANCEL)
|
||||
return false;
|
||||
|
||||
|
|
@ -2334,10 +2334,13 @@ bool GUI_App::run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage
|
|||
{
|
||||
wxCHECK_MSG(mainframe != nullptr, false, "Internal error: Main frame not created / null");
|
||||
|
||||
if (reason == ConfigWizard::RR_USER)
|
||||
if (PresetUpdater::UpdateResult result = preset_updater->config_update(app_config->orig_version(), PresetUpdater::UpdateParams::FORCED_BEFORE_WIZARD);
|
||||
result == PresetUpdater::R_ALL_CANCELED)
|
||||
if (reason == ConfigWizard::RR_USER) {
|
||||
wxString header = _L("Updates to Configuration Wizard may cause an another preset selection and lost of preset modification as a result.\n"
|
||||
"So, check unsaved changes and save them if necessary.") + "\n";
|
||||
if (!check_and_save_current_preset_changes(header, _L("ConfigWizard is opening")) ||
|
||||
preset_updater->config_update(app_config->orig_version(), PresetUpdater::UpdateParams::FORCED_BEFORE_WIZARD) == PresetUpdater::R_ALL_CANCELED)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! m_wizard) {
|
||||
wxBusyCursor wait;
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ public:
|
|||
bool has_current_preset_changes() const;
|
||||
void update_saved_preset_from_current_preset();
|
||||
std::vector<std::pair<unsigned int, std::string>> get_selected_presets() const;
|
||||
bool check_and_save_current_preset_changes(const wxString& header = wxString());
|
||||
bool check_and_save_current_preset_changes(const wxString& header = wxString(), const wxString& caption = wxString());
|
||||
bool check_print_host_queue();
|
||||
bool checked_tab(Tab* tab);
|
||||
void load_current_presets(bool check_printer_presets = true);
|
||||
|
|
|
|||
|
|
@ -1044,13 +1044,8 @@ void ObjectList::key_event(wxKeyEvent& event)
|
|||
{
|
||||
if (event.GetKeyCode() == WXK_TAB)
|
||||
Navigate(event.ShiftDown() ? wxNavigationKeyEvent::IsBackward : wxNavigationKeyEvent::IsForward);
|
||||
else if (event.GetKeyCode() == WXK_DELETE
|
||||
#ifdef __WXOSX__
|
||||
|| event.GetKeyCode() == WXK_BACK
|
||||
#endif //__WXOSX__
|
||||
) {
|
||||
else if (event.GetKeyCode() == WXK_DELETE || event.GetKeyCode() == WXK_BACK )
|
||||
remove();
|
||||
}
|
||||
else if (event.GetKeyCode() == WXK_F5)
|
||||
wxGetApp().plater()->reload_all_from_disk();
|
||||
else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/))
|
||||
|
|
@ -1702,8 +1697,7 @@ void ObjectList::load_shape_object_from_gallery(const wxArrayString& input_files
|
|||
snapshot_label += ", " + wxString::FromUTF8(paths[i].filename().string().c_str());
|
||||
|
||||
take_snapshot(snapshot_label);
|
||||
std::vector<size_t> res = wxGetApp().plater()->load_files(paths, true, false);
|
||||
if (!res.empty())
|
||||
if (! wxGetApp().plater()->load_files(paths, true, false).empty())
|
||||
wxGetApp().mainframe->update_title();
|
||||
}
|
||||
|
||||
|
|
@ -2562,6 +2556,9 @@ wxDataViewItem ObjectList::add_settings_item(wxDataViewItem parent_item, const D
|
|||
|
||||
void ObjectList::update_info_items(size_t obj_idx, wxDataViewItemArray* selections/* = nullptr*/, bool added_object/* = false*/)
|
||||
{
|
||||
if (obj_idx >= m_objects->size())
|
||||
return;
|
||||
|
||||
const ModelObject* model_object = (*m_objects)[obj_idx];
|
||||
wxDataViewItem item_obj = m_objects_model->GetItemById(obj_idx);
|
||||
assert(item_obj.IsOk());
|
||||
|
|
@ -4028,17 +4025,12 @@ void ObjectList::simplify()
|
|||
|
||||
// Do not simplify when a gizmo is open. There might be issues with updates
|
||||
// and what is worse, the snapshot time would refer to the internal stack.
|
||||
auto current_type = gizmos_mgr.get_current_type();
|
||||
if (current_type == GLGizmosManager::Simplify) {
|
||||
if (! gizmos_mgr.check_gizmos_closed_except(GLGizmosManager::EType::Simplify))
|
||||
return;
|
||||
|
||||
if (gizmos_mgr.get_current_type() == GLGizmosManager::Simplify) {
|
||||
// close first
|
||||
gizmos_mgr.open_gizmo(GLGizmosManager::EType::Simplify);
|
||||
}else if (current_type != GLGizmosManager::Undefined) {
|
||||
plater->get_notification_manager()->push_notification(
|
||||
NotificationType::CustomSupportsAndSeamRemovedAfterRepair,
|
||||
NotificationManager::NotificationLevel::RegularNotification,
|
||||
_u8L("ERROR: Please close all manipulators available from "
|
||||
"the left toolbar before start simplify the mesh."));
|
||||
return;
|
||||
}
|
||||
gizmos_mgr.open_gizmo(GLGizmosManager::EType::Simplify);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -232,6 +232,20 @@ void GLGizmoBase::render_input_window(float x, float y, float bottom_limit)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string GLGizmoBase::get_name(bool include_shortcut) const
|
||||
{
|
||||
int key = get_shortcut_key();
|
||||
assert( key >= WXK_CONTROL_A && key <= WXK_CONTROL_Z);
|
||||
std::string out = on_get_name();
|
||||
if (include_shortcut)
|
||||
out += std::string(" [") + char(int('A') + key - int(WXK_CONTROL_A)) + "]";
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Produce an alpha channel checksum for the red green blue components. The alpha channel may then be used to verify, whether the rgb components
|
||||
// were not interpolated by alpha blending or multi sampling.
|
||||
unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char green, unsigned char blue)
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ public:
|
|||
void load(cereal::BinaryInputArchive& ar) { m_state = On; on_load(ar); }
|
||||
void save(cereal::BinaryOutputArchive& ar) const { on_save(ar); }
|
||||
|
||||
std::string get_name() const { return on_get_name(); }
|
||||
std::string get_name(bool include_shortcut = true) const;
|
||||
|
||||
int get_group_id() const { return m_group_id; }
|
||||
void set_group_id(int id) { m_group_id = id; }
|
||||
|
|
@ -135,6 +135,7 @@ public:
|
|||
bool is_activable() const { return on_is_activable(); }
|
||||
bool is_selectable() const { return on_is_selectable(); }
|
||||
CommonGizmosDataID get_requirements() const { return on_get_requirements(); }
|
||||
virtual bool wants_enter_leave_snapshots() const { return false; }
|
||||
void set_common_data_pool(CommonGizmosDataPool* ptr) { m_c = ptr; }
|
||||
|
||||
unsigned int get_sprite_id() const { return m_sprite_id; }
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ bool GLGizmoCut::on_init()
|
|||
|
||||
std::string GLGizmoCut::on_get_name() const
|
||||
{
|
||||
return (_L("Cut") + " [C]").ToUTF8().data();
|
||||
return _u8L("Cut");
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_set_state()
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ void GLGizmoFdmSupports::on_shutdown()
|
|||
|
||||
std::string GLGizmoFdmSupports::on_get_name() const
|
||||
{
|
||||
return (_L("Paint-on supports") + " [L]").ToUTF8().data();
|
||||
return _u8L("Paint-on supports");
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
|||
y = std::min(y, bottom_limit - approx_height);
|
||||
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
|
||||
|
||||
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
|
||||
m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
|
||||
const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x,
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ CommonGizmosDataID GLGizmoFlatten::on_get_requirements() const
|
|||
|
||||
std::string GLGizmoFlatten::on_get_name() const
|
||||
{
|
||||
return (_L("Place on face") + " [F]").ToUTF8().data();
|
||||
return _u8L("Place on face");
|
||||
}
|
||||
|
||||
bool GLGizmoFlatten::on_is_activable() const
|
||||
|
|
|
|||
|
|
@ -505,7 +505,7 @@ RENDER_AGAIN:
|
|||
y = std::min(y, bottom_limit - approx_height);
|
||||
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
|
||||
|
||||
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
|
||||
m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
|
||||
const float settings_sliders_left =
|
||||
|
|
@ -773,7 +773,7 @@ bool GLGizmoHollow::on_is_selectable() const
|
|||
|
||||
std::string GLGizmoHollow::on_get_name() const
|
||||
{
|
||||
return (_(L("Hollow and drill")) + " [H]").ToUTF8().data();
|
||||
return _u8L("Hollow and drill");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ void GLGizmoMmuSegmentation::on_shutdown()
|
|||
std::string GLGizmoMmuSegmentation::on_get_name() const
|
||||
{
|
||||
// FIXME Lukas H.: Discuss and change shortcut
|
||||
return (_L("Multimaterial painting") + " [N]").ToUTF8().data();
|
||||
return _u8L("Multimaterial painting");
|
||||
}
|
||||
|
||||
bool GLGizmoMmuSegmentation::on_is_selectable() const
|
||||
|
|
@ -124,13 +124,12 @@ bool GLGizmoMmuSegmentation::on_init()
|
|||
m_desc["sphere"] = _L("Sphere");
|
||||
m_desc["pointer"] = _L("Pointer");
|
||||
|
||||
m_desc["tool_type"] = _L("Tool type");
|
||||
m_desc["tool_type"] = _L("Tool type");
|
||||
m_desc["tool_brush"] = _L("Brush");
|
||||
m_desc["tool_seed_fill"] = _L("Seed fill");
|
||||
m_desc["tool_smart_fill"] = _L("Smart fill");
|
||||
m_desc["tool_bucket_fill"] = _L("Bucket fill");
|
||||
|
||||
m_desc["seed_fill"] = _L("Seed fill");
|
||||
m_desc["seed_fill_angle"] = _L("Seed fill angle");
|
||||
m_desc["smart_fill_angle"] = _L("Smart fill angle");
|
||||
|
||||
init_extruders_data();
|
||||
|
||||
|
|
@ -240,16 +239,16 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
y = std::min(y, bottom_limit - approx_height);
|
||||
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
|
||||
|
||||
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
|
||||
m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
|
||||
const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x,
|
||||
m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f);
|
||||
const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f);
|
||||
const float seed_fill_slider_left = m_imgui->calc_text_size(m_desc.at("seed_fill_angle")).x + m_imgui->scaled(1.f);
|
||||
const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.f);
|
||||
|
||||
const float cursor_type_radio_circle = m_imgui->calc_text_size(m_desc["circle"]).x + m_imgui->scaled(2.5f);
|
||||
const float cursor_type_radio_sphere = m_imgui->calc_text_size(m_desc["sphere"]).x + m_imgui->scaled(2.5f);
|
||||
const float cursor_type_radio_circle = m_imgui->calc_text_size(m_desc["circle"]).x + m_imgui->scaled(2.5f);
|
||||
const float cursor_type_radio_sphere = m_imgui->calc_text_size(m_desc["sphere"]).x + m_imgui->scaled(2.5f);
|
||||
const float cursor_type_radio_pointer = m_imgui->calc_text_size(m_desc["pointer"]).x + m_imgui->scaled(2.5f);
|
||||
|
||||
const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f);
|
||||
|
|
@ -259,9 +258,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
const float combo_label_width = std::max(m_imgui->calc_text_size(m_desc.at("first_color")).x,
|
||||
m_imgui->calc_text_size(m_desc.at("second_color")).x) + m_imgui->scaled(1.f);
|
||||
|
||||
const float tool_type_radio_brush = m_imgui->calc_text_size(m_desc["tool_brush"]).x + m_imgui->scaled(2.5f);
|
||||
const float tool_type_radio_brush = m_imgui->calc_text_size(m_desc["tool_brush"]).x + m_imgui->scaled(2.5f);
|
||||
const float tool_type_radio_bucket_fill = m_imgui->calc_text_size(m_desc["tool_bucket_fill"]).x + m_imgui->scaled(2.5f);
|
||||
const float tool_type_radio_seed_fill = m_imgui->calc_text_size(m_desc["tool_seed_fill"]).x + m_imgui->scaled(2.5f);
|
||||
const float tool_type_radio_smart_fill = m_imgui->calc_text_size(m_desc["tool_smart_fill"]).x + m_imgui->scaled(2.5f);
|
||||
|
||||
float caption_max = 0.f;
|
||||
float total_text_max = 0.;
|
||||
|
|
@ -272,12 +271,12 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
caption_max += m_imgui->scaled(1.f);
|
||||
total_text_max += m_imgui->scaled(1.f);
|
||||
|
||||
float sliders_width = std::max(seed_fill_slider_left, std::max(cursor_slider_left, clipping_slider_left));
|
||||
float sliders_width = std::max(smart_fill_slider_left, std::max(cursor_slider_left, clipping_slider_left));
|
||||
float window_width = minimal_slider_width + sliders_width;
|
||||
window_width = std::max(window_width, total_text_max);
|
||||
window_width = std::max(window_width, button_width);
|
||||
window_width = std::max(window_width, cursor_type_radio_circle + cursor_type_radio_sphere + cursor_type_radio_pointer);
|
||||
window_width = std::max(window_width, tool_type_radio_brush + tool_type_radio_bucket_fill + tool_type_radio_seed_fill);
|
||||
window_width = std::max(window_width, tool_type_radio_brush + tool_type_radio_bucket_fill + tool_type_radio_smart_fill);
|
||||
window_width = std::max(window_width, 2.f * buttons_width + m_imgui->scaled(1.f));
|
||||
|
||||
auto draw_text_with_caption = [this, &caption_max](const wxString &caption, const wxString &text) {
|
||||
|
|
@ -321,7 +320,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc.at("tool_type"));
|
||||
|
||||
float tool_type_offset = (window_width - tool_type_radio_brush - tool_type_radio_bucket_fill - tool_type_radio_seed_fill + m_imgui->scaled(2.f)) / 2.f;
|
||||
float tool_type_offset = (window_width - tool_type_radio_brush - tool_type_radio_bucket_fill - tool_type_radio_smart_fill + m_imgui->scaled(2.f)) / 2.f;
|
||||
|
||||
ImGui::NewLine();
|
||||
|
||||
|
|
@ -345,9 +344,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
}
|
||||
|
||||
ImGui::SameLine(tool_type_offset + tool_type_radio_brush + m_imgui->scaled(0.f));
|
||||
ImGui::PushItemWidth(tool_type_radio_seed_fill);
|
||||
if (m_imgui->radio_button(m_desc["tool_seed_fill"], m_tool_type == GLGizmoMmuSegmentation::ToolType::SEED_FILL)) {
|
||||
m_tool_type = GLGizmoMmuSegmentation::ToolType::SEED_FILL;
|
||||
ImGui::PushItemWidth(tool_type_radio_smart_fill);
|
||||
if (m_imgui->radio_button(m_desc["tool_smart_fill"], m_tool_type == GLGizmoMmuSegmentation::ToolType::SMART_FILL)) {
|
||||
m_tool_type = GLGizmoMmuSegmentation::ToolType::SMART_FILL;
|
||||
for (auto &triangle_selector : m_triangle_selectors) {
|
||||
triangle_selector->seed_fill_unselect_all_triangles();
|
||||
triangle_selector->request_update_render_data();
|
||||
|
|
@ -362,7 +361,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
ImGui::SameLine(tool_type_offset + tool_type_radio_brush + tool_type_radio_seed_fill + m_imgui->scaled(0.f));
|
||||
ImGui::SameLine(tool_type_offset + tool_type_radio_brush + tool_type_radio_smart_fill + m_imgui->scaled(0.f));
|
||||
ImGui::PushItemWidth(tool_type_radio_bucket_fill);
|
||||
if (m_imgui->radio_button(m_desc["tool_bucket_fill"], m_tool_type == GLGizmoMmuSegmentation::ToolType::BUCKET_FILL)) {
|
||||
m_tool_type = GLGizmoMmuSegmentation::ToolType::BUCKET_FILL;
|
||||
|
|
@ -458,14 +457,14 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
m_imgui->disabled_end();
|
||||
|
||||
ImGui::Separator();
|
||||
} else if(m_tool_type == ToolType::SEED_FILL) {
|
||||
m_imgui->text(m_desc["seed_fill_angle"] + ":");
|
||||
} else if(m_tool_type == ToolType::SMART_FILL) {
|
||||
m_imgui->text(m_desc["smart_fill_angle"] + ":");
|
||||
ImGui::AlignTextToFramePadding();
|
||||
std::string format_str = std::string("%.f") + I18N::translate_utf8("°", "Degree sign to use in the respective slider in MMU gizmo,"
|
||||
"placed after the number with no whitespace in between.");
|
||||
ImGui::SameLine(sliders_width);
|
||||
ImGui::PushItemWidth(window_width - sliders_width);
|
||||
if(m_imgui->slider_float("##seed_fill_angle", &m_seed_fill_angle, SeedFillAngleMin, SeedFillAngleMax, format_str.data()))
|
||||
if(m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data()))
|
||||
for (auto &triangle_selector : m_triangle_selectors) {
|
||||
triangle_selector->seed_fill_unselect_all_triangles();
|
||||
triangle_selector->request_update_render_data();
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ bool GLGizmoMove3D::on_init()
|
|||
|
||||
std::string GLGizmoMove3D::on_get_name() const
|
||||
{
|
||||
return (_L("Move") + " [M]").ToUTF8().data();
|
||||
return _u8L("Move");
|
||||
}
|
||||
|
||||
bool GLGizmoMove3D::on_is_activable() const
|
||||
|
|
|
|||
|
|
@ -282,12 +282,12 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
: std::min(m_cursor_radius + CursorRadiusStep, CursorRadiusMax);
|
||||
m_parent.set_as_dirty();
|
||||
return true;
|
||||
} else if (m_tool_type == ToolType::SEED_FILL) {
|
||||
m_seed_fill_angle = action == SLAGizmoEventType::MouseWheelDown ? std::max(m_seed_fill_angle - SeedFillAngleStep, SeedFillAngleMin)
|
||||
: std::min(m_seed_fill_angle + SeedFillAngleStep, SeedFillAngleMax);
|
||||
} else if (m_tool_type == ToolType::SMART_FILL) {
|
||||
m_smart_fill_angle = action == SLAGizmoEventType::MouseWheelDown ? std::max(m_smart_fill_angle - SmartFillAngleStep, SmartFillAngleMin)
|
||||
: std::min(m_smart_fill_angle + SmartFillAngleStep, SmartFillAngleMax);
|
||||
m_parent.set_as_dirty();
|
||||
if (m_rr.mesh_id != -1) {
|
||||
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), m_seed_fill_angle, true);
|
||||
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), m_smart_fill_angle, true);
|
||||
m_triangle_selectors[m_rr.mesh_id]->request_update_render_data();
|
||||
m_seed_fill_last_mesh_id = m_rr.mesh_id;
|
||||
}
|
||||
|
|
@ -379,10 +379,10 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
Vec3f camera_pos = (trafo_matrix.inverse() * camera.get_position()).cast<float>();
|
||||
|
||||
assert(m_rr.mesh_id < int(m_triangle_selectors.size()));
|
||||
if (m_tool_type == ToolType::SEED_FILL || m_tool_type == ToolType::BUCKET_FILL || (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER)) {
|
||||
if (m_tool_type == ToolType::SMART_FILL || m_tool_type == ToolType::BUCKET_FILL || (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER)) {
|
||||
m_triangle_selectors[m_rr.mesh_id]->seed_fill_apply_on_triangles(new_state);
|
||||
if (m_tool_type == ToolType::SEED_FILL)
|
||||
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), m_seed_fill_angle, true);
|
||||
if (m_tool_type == ToolType::SMART_FILL)
|
||||
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), m_smart_fill_angle, true);
|
||||
else if (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER)
|
||||
m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), false, true);
|
||||
else if (m_tool_type == ToolType::BUCKET_FILL)
|
||||
|
|
@ -400,7 +400,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
return true;
|
||||
}
|
||||
|
||||
if (action == SLAGizmoEventType::Moving && (m_tool_type == ToolType::SEED_FILL || m_tool_type == ToolType::BUCKET_FILL || (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER))) {
|
||||
if (action == SLAGizmoEventType::Moving && (m_tool_type == ToolType::SMART_FILL || m_tool_type == ToolType::BUCKET_FILL || (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER))) {
|
||||
if (m_triangle_selectors.empty())
|
||||
return false;
|
||||
|
||||
|
|
@ -440,8 +440,8 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
seed_fill_unselect_all();
|
||||
|
||||
assert(m_rr.mesh_id < int(m_triangle_selectors.size()));
|
||||
if (m_tool_type == ToolType::SEED_FILL)
|
||||
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), m_seed_fill_angle);
|
||||
if (m_tool_type == ToolType::SMART_FILL)
|
||||
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), m_smart_fill_angle);
|
||||
else if (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER)
|
||||
m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), false);
|
||||
else if (m_tool_type == ToolType::BUCKET_FILL)
|
||||
|
|
|
|||
|
|
@ -109,16 +109,16 @@ protected:
|
|||
enum class ToolType {
|
||||
BRUSH,
|
||||
BUCKET_FILL,
|
||||
SEED_FILL
|
||||
SMART_FILL
|
||||
};
|
||||
|
||||
bool m_triangle_splitting_enabled = true;
|
||||
ToolType m_tool_type = ToolType::BRUSH;
|
||||
float m_seed_fill_angle = 30.f;
|
||||
float m_smart_fill_angle = 30.f;
|
||||
|
||||
static constexpr float SeedFillAngleMin = 0.0f;
|
||||
static constexpr float SeedFillAngleMax = 90.f;
|
||||
static constexpr float SeedFillAngleStep = 1.f;
|
||||
static constexpr float SmartFillAngleMin = 0.0f;
|
||||
static constexpr float SmartFillAngleMax = 90.f;
|
||||
static constexpr float SmartFillAngleStep = 1.f;
|
||||
|
||||
// It stores the value of the previous mesh_id to which the seed fill was applied.
|
||||
// It is used to detect when the mouse has moved from one volume to another one.
|
||||
|
|
|
|||
|
|
@ -463,7 +463,7 @@ bool GLGizmoRotate3D::on_init()
|
|||
|
||||
std::string GLGizmoRotate3D::on_get_name() const
|
||||
{
|
||||
return (_L("Rotate") + " [R]").ToUTF8().data();
|
||||
return _u8L("Rotate");
|
||||
}
|
||||
|
||||
bool GLGizmoRotate3D::on_is_activable() const
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ bool GLGizmoScale3D::on_init()
|
|||
|
||||
std::string GLGizmoScale3D::on_get_name() const
|
||||
{
|
||||
return (_L("Scale") + " [S]").ToUTF8().data();
|
||||
return _u8L("Scale");
|
||||
}
|
||||
|
||||
bool GLGizmoScale3D::on_is_activable() const
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ bool GLGizmoSeam::on_init()
|
|||
|
||||
std::string GLGizmoSeam::on_get_name() const
|
||||
{
|
||||
return (_L("Seam painting") + " [P]").ToUTF8().data();
|
||||
return _u8L("Seam painting");
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
|
|||
const float approx_height = m_imgui->scaled(14.0f);
|
||||
y = std::min(y, bottom_limit - approx_height);
|
||||
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
|
||||
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
|
||||
m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
|
||||
const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x,
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ bool GLGizmoSimplify::on_init()
|
|||
|
||||
std::string GLGizmoSimplify::on_get_name() const
|
||||
{
|
||||
return (_L("Simplify")).ToUTF8().data();
|
||||
return _u8L("Simplify");
|
||||
}
|
||||
|
||||
void GLGizmoSimplify::on_render() {}
|
||||
|
|
@ -55,6 +55,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi
|
|||
create_gui_cfg();
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
int object_idx = selection.get_object_idx();
|
||||
if (!is_selected_object(&object_idx)) return;
|
||||
ModelObject *obj = wxGetApp().plater()->model().objects[object_idx];
|
||||
ModelVolume *act_volume = obj->volumes.front();
|
||||
|
||||
|
|
@ -96,7 +97,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi
|
|||
|
||||
int flag = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoCollapse;
|
||||
m_imgui->begin(on_get_name(), flag);
|
||||
m_imgui->begin(get_name(), flag);
|
||||
|
||||
size_t triangle_count = m_volume->mesh().its.indices.size();
|
||||
// already reduced mesh
|
||||
|
|
@ -329,9 +330,9 @@ void GLGizmoSimplify::on_set_state()
|
|||
{
|
||||
// Closing gizmo. e.g. selecting another one
|
||||
if (GLGizmoBase::m_state == GLGizmoBase::Off) {
|
||||
|
||||
// refuse outgoing during simlification
|
||||
if (m_state != State::settings) {
|
||||
// object is not selected when it is deleted(cancel and close gizmo)
|
||||
if (m_state != State::settings && is_selected_object()) {
|
||||
GLGizmoBase::m_state = GLGizmoBase::On;
|
||||
auto notification_manager = wxGetApp().plater()->get_notification_manager();
|
||||
notification_manager->push_notification(
|
||||
|
|
@ -383,4 +384,20 @@ void GLGizmoSimplify::request_rerender() {
|
|||
});
|
||||
}
|
||||
|
||||
bool GLGizmoSimplify::is_selected_object(int *object_idx)
|
||||
{
|
||||
int index = (object_idx != nullptr) ? *object_idx :
|
||||
m_parent.get_selection().get_object_idx();
|
||||
// no selected object --> can appear after delete model
|
||||
if (index < 0) {
|
||||
switch (m_state) {
|
||||
case State::settings: close(); break;
|
||||
case State::canceling: break;
|
||||
default: m_state = State::canceling;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ private:
|
|||
void set_its(indexed_triangle_set &its);
|
||||
void create_gui_cfg();
|
||||
void request_rerender();
|
||||
bool is_selected_object(int *object_idx = nullptr);
|
||||
|
||||
std::atomic_bool m_is_valid_result; // differ what to do in apply
|
||||
std::atomic_bool m_exist_preview; // set when process end
|
||||
|
|
|
|||
|
|
@ -625,7 +625,7 @@ RENDER_AGAIN:
|
|||
//ImGui::SetNextWindowPos(ImVec2(x, y - std::max(0.f, y+window_size.y-bottom_limit) ));
|
||||
//ImGui::SetNextWindowSize(ImVec2(window_size));
|
||||
|
||||
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
|
||||
m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
// adjust window position to avoid overlap the view toolbar
|
||||
float win_h = ImGui::GetWindowHeight();
|
||||
|
|
@ -863,7 +863,7 @@ bool GLGizmoSlaSupports::on_is_selectable() const
|
|||
|
||||
std::string GLGizmoSlaSupports::on_get_name() const
|
||||
{
|
||||
return (_L("SLA Support Points") + " [L]").ToUTF8().data();
|
||||
return _u8L("SLA Support Points");
|
||||
}
|
||||
|
||||
CommonGizmosDataID GLGizmoSlaSupports::on_get_requirements() const
|
||||
|
|
@ -901,15 +901,6 @@ void GLGizmoSlaSupports::on_set_state()
|
|||
return;
|
||||
|
||||
if (m_state == On && m_old_state != On) { // the gizmo was just turned on
|
||||
if (! m_parent.get_gizmos_manager().is_serializing()) {
|
||||
// Only take the snapshot when the USER opens the gizmo. Common gizmos
|
||||
// data are not yet available, the CallAfter will postpone taking the
|
||||
// snapshot until they are. No, it does not feel right.
|
||||
wxGetApp().CallAfter([]() {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Entering SLA gizmo"));
|
||||
});
|
||||
}
|
||||
|
||||
// Set default head diameter from config.
|
||||
const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
|
||||
m_new_point_head_diameter = static_cast<const ConfigOptionFloat*>(cfg.option("support_head_front_diameter"))->value;
|
||||
|
|
@ -925,8 +916,6 @@ void GLGizmoSlaSupports::on_set_state()
|
|||
else {
|
||||
// we are actually shutting down
|
||||
disable_editing_mode(); // so it is not active next time the gizmo opens
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Leaving SLA gizmo"));
|
||||
m_normal_cache.clear();
|
||||
m_old_mo_id = -1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ public:
|
|||
bool has_backend_supports() const;
|
||||
void reslice_SLA_supports(bool postpone_error_messages = false) const;
|
||||
|
||||
bool wants_enter_leave_snapshots() const override { return true; }
|
||||
|
||||
private:
|
||||
bool on_init() override;
|
||||
void on_update(const UpdateData& data) override;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoSimplify.hpp"
|
||||
|
||||
#include "libslic3r/format.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
|
||||
|
|
@ -163,10 +164,8 @@ void GLGizmosManager::refresh_on_off_state()
|
|||
return;
|
||||
|
||||
if (m_current != Undefined
|
||||
&& ! m_gizmos[m_current]->is_activable()) {
|
||||
activate_gizmo(Undefined);
|
||||
&& ! m_gizmos[m_current]->is_activable() && activate_gizmo(Undefined))
|
||||
update_data();
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmosManager::reset_all_states()
|
||||
|
|
@ -181,14 +180,28 @@ void GLGizmosManager::reset_all_states()
|
|||
bool GLGizmosManager::open_gizmo(EType type)
|
||||
{
|
||||
int idx = int(type);
|
||||
if (m_gizmos[idx]->is_activable()) {
|
||||
activate_gizmo(m_current == idx ? Undefined : (EType)idx);
|
||||
if (m_gizmos[idx]->is_activable()
|
||||
&& activate_gizmo(m_current == idx ? Undefined : (EType)idx)) {
|
||||
update_data();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool GLGizmosManager::check_gizmos_closed_except(EType type) const
|
||||
{
|
||||
if (get_current_type() != type && get_current_type() != Undefined) {
|
||||
wxGetApp().plater()->get_notification_manager()->push_notification(
|
||||
NotificationType::CustomSupportsAndSeamRemovedAfterRepair,
|
||||
NotificationManager::NotificationLevel::RegularNotification,
|
||||
_u8L("ERROR: Please close all manipulators available from "
|
||||
"the left toolbar first"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLGizmosManager::set_hover_id(int id)
|
||||
{
|
||||
if (!m_enabled || m_current == Undefined)
|
||||
|
|
@ -1193,31 +1206,35 @@ std::string GLGizmosManager::update_hover_state(const Vec2d& mouse_pos)
|
|||
return name;
|
||||
}
|
||||
|
||||
void GLGizmosManager::activate_gizmo(EType type)
|
||||
bool GLGizmosManager::activate_gizmo(EType type)
|
||||
{
|
||||
if (m_gizmos.empty() || m_current == type)
|
||||
return;
|
||||
return true;
|
||||
|
||||
if (m_current != Undefined) {
|
||||
m_gizmos[m_current]->set_state(GLGizmoBase::Off);
|
||||
if (m_gizmos[m_current]->get_state() != GLGizmoBase::Off)
|
||||
return; // gizmo refused to be turned off, do nothing.
|
||||
GLGizmoBase* old_gizmo = m_current == Undefined ? nullptr : m_gizmos[m_current].get();
|
||||
GLGizmoBase* new_gizmo = type == Undefined ? nullptr : m_gizmos[type].get();
|
||||
|
||||
if (old_gizmo) {
|
||||
old_gizmo->set_state(GLGizmoBase::Off);
|
||||
if (old_gizmo->get_state() != GLGizmoBase::Off)
|
||||
return false; // gizmo refused to be turned off, do nothing.
|
||||
|
||||
if (! m_parent.get_gizmos_manager().is_serializing()
|
||||
&& old_gizmo->wants_enter_leave_snapshots())
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(),
|
||||
Slic3r::format(_utf8("Leaving %1%"), old_gizmo->get_name(false)));
|
||||
}
|
||||
|
||||
if (new_gizmo && ! m_parent.get_gizmos_manager().is_serializing()
|
||||
&& new_gizmo->wants_enter_leave_snapshots())
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(),
|
||||
Slic3r::format(_utf8("Entering %1%"), new_gizmo->get_name(false)));
|
||||
|
||||
m_current = type;
|
||||
|
||||
// Updating common data should be left to the update_data function, which
|
||||
// is always called after this one. activate_gizmo can be called by undo/redo,
|
||||
// when selection is not yet deserialized, so the common data would update
|
||||
// incorrectly (or crash if relying on unempty selection). Undo/redo stack
|
||||
// will also call update_data, after selection is restored.
|
||||
|
||||
//m_common_gizmos_data->update(get_current()
|
||||
// ? get_current()->get_requirements()
|
||||
// : CommonGizmosDataID(0));
|
||||
|
||||
if (type != Undefined)
|
||||
m_gizmos[type]->set_state(GLGizmoBase::On);
|
||||
if (new_gizmo)
|
||||
new_gizmo->set_state(GLGizmoBase::On);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ private:
|
|||
std::vector<size_t> get_selectable_idxs() const;
|
||||
size_t get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const;
|
||||
|
||||
void activate_gizmo(EType type);
|
||||
bool activate_gizmo(EType type);
|
||||
|
||||
struct MouseCapture
|
||||
{
|
||||
|
|
@ -176,6 +176,7 @@ public:
|
|||
void reset_all_states();
|
||||
bool is_serializing() const { return m_serializing; }
|
||||
bool open_gizmo(EType type);
|
||||
bool check_gizmos_closed_except(EType) const;
|
||||
|
||||
void set_hover_id(int id);
|
||||
void enable_grabber(EType type, unsigned int id, bool enable);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "I18N.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#include "GLCanvas3D.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
|
|
@ -57,10 +58,6 @@ inline void push_style_color(ImGuiCol idx, const ImVec4& col, bool fading_out, f
|
|||
ImGui::PushStyleColor(idx, col);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void write_used_binary(const std::vector<std::string>& ids)
|
||||
{
|
||||
boost::filesystem::ofstream file((boost::filesystem::path(data_dir()) / "cache" / "hints.cereal"), std::ios::binary);
|
||||
|
|
@ -77,7 +74,12 @@ void write_used_binary(const std::vector<std::string>& ids)
|
|||
}
|
||||
void read_used_binary(std::vector<std::string>& ids)
|
||||
{
|
||||
boost::filesystem::ifstream file((boost::filesystem::path(data_dir()) / "cache" / "hints.cereal"));
|
||||
boost::filesystem::path path(boost::filesystem::path(data_dir()) / "cache" / "hints.cereal");
|
||||
if (!boost::filesystem::exists(path)) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Failed to load to hints.cereal. File does not exists. " << path.string();
|
||||
return;
|
||||
}
|
||||
boost::filesystem::ifstream file(path);
|
||||
cereal::BinaryInputArchive archive(file);
|
||||
HintsCerealData cd;
|
||||
try
|
||||
|
|
@ -245,6 +247,13 @@ HintDatabase::~HintDatabase()
|
|||
write_used_binary(m_used_ids);
|
||||
}
|
||||
}
|
||||
void HintDatabase::uninit()
|
||||
{
|
||||
if (m_initialized) {
|
||||
write_used_binary(m_used_ids);
|
||||
}
|
||||
m_initialized = false;
|
||||
}
|
||||
void HintDatabase::init()
|
||||
{
|
||||
load_hints_from_file(std::move(boost::filesystem::path(resources_dir()) / "data" / "hints.ini"));
|
||||
|
|
@ -379,7 +388,13 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path)
|
|||
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, []() {
|
||||
// Deselect all objects, otherwise gallery wont show.
|
||||
wxGetApp().plater()->canvas3D()->deselect_all();
|
||||
wxGetApp().obj_list()->load_shape_object_from_gallery(); } };
|
||||
wxGetApp().obj_list()->load_shape_object_from_gallery(); }
|
||||
};
|
||||
m_loaded_hints.emplace_back(hint_data);
|
||||
} else if (dict["hypertext_type"] == "menubar") {
|
||||
wxString menu(_L("&" + dict["hypertext_menubar_menu_name"]));
|
||||
wxString item(_L(dict["hypertext_menubar_item_name"]));
|
||||
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [menu, item]() { wxGetApp().mainframe->open_menubar_item(menu, item); } };
|
||||
m_loaded_hints.emplace_back(hint_data);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ public:
|
|||
return 0;
|
||||
return m_loaded_hints.size();
|
||||
}
|
||||
// resets m_initiailized to false and writes used if was initialized
|
||||
// used when reloading in runtime - like change language
|
||||
void uninit();
|
||||
private:
|
||||
void init();
|
||||
void load_hints_from_file(const boost::filesystem::path& path);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <wx/debug.h>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
|
|
@ -141,11 +142,11 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
|
|||
default:
|
||||
case GUI_App::EAppMode::Editor:
|
||||
m_taskbar_icon = std::make_unique<PrusaSlicerTaskBarIcon>(wxTBI_DOCK);
|
||||
m_taskbar_icon->SetIcon(wxIcon(Slic3r::var("PrusaSlicer_128px.png"), wxBITMAP_TYPE_PNG), "PrusaSlicer");
|
||||
m_taskbar_icon->SetIcon(wxIcon(Slic3r::var("PrusaSlicer-mac_128px.png"), wxBITMAP_TYPE_PNG), "PrusaSlicer");
|
||||
break;
|
||||
case GUI_App::EAppMode::GCodeViewer:
|
||||
m_taskbar_icon = std::make_unique<GCodeViewerTaskBarIcon>(wxTBI_DOCK);
|
||||
m_taskbar_icon->SetIcon(wxIcon(Slic3r::var("PrusaSlicer-gcodeviewer_128px.png"), wxBITMAP_TYPE_PNG), "G-code Viewer");
|
||||
m_taskbar_icon->SetIcon(wxIcon(Slic3r::var("PrusaSlicer-gcodeviewer-mac_128px.png"), wxBITMAP_TYPE_PNG), "G-code Viewer");
|
||||
break;
|
||||
}
|
||||
#endif // __APPLE__
|
||||
|
|
@ -824,15 +825,26 @@ bool MainFrame::can_start_new_project() const
|
|||
|
||||
bool MainFrame::can_save() const
|
||||
{
|
||||
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
|
||||
return (m_plater != nullptr) &&
|
||||
!m_plater->canvas3D()->get_gizmos_manager().is_in_editing_mode(false) &&
|
||||
!m_plater->get_project_filename().empty() && m_plater->is_project_dirty();
|
||||
#else
|
||||
return (m_plater != nullptr) && !m_plater->model().objects.empty() &&
|
||||
!m_plater->canvas3D()->get_gizmos_manager().is_in_editing_mode(false) &&
|
||||
!m_plater->get_project_filename().empty() && m_plater->is_project_dirty();
|
||||
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
|
||||
}
|
||||
|
||||
bool MainFrame::can_save_as() const
|
||||
{
|
||||
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
|
||||
return (m_plater != nullptr) &&
|
||||
!m_plater->canvas3D()->get_gizmos_manager().is_in_editing_mode(false);
|
||||
#else
|
||||
return (m_plater != nullptr) && !m_plater->model().objects.empty() &&
|
||||
!m_plater->canvas3D()->get_gizmos_manager().is_in_editing_mode(false);
|
||||
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
|
||||
}
|
||||
|
||||
void MainFrame::save_project()
|
||||
|
|
@ -1227,9 +1239,10 @@ void MainFrame::init_menubar_as_editor()
|
|||
append_menu_item(export_menu, wxID_ANY, _L("Export plate as STL &including supports") + dots, _L("Export current plate as STL including supports"),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(true); }, "export_plater", nullptr,
|
||||
[this](){return can_export_supports(); }, this);
|
||||
append_menu_item(export_menu, wxID_ANY, _L("Export plate as &AMF") + dots, _L("Export current plate as AMF"),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->export_amf(); }, "export_plater", nullptr,
|
||||
[this](){return can_export_model(); }, this);
|
||||
// Deprecating AMF export. Let's wait for user feedback.
|
||||
// append_menu_item(export_menu, wxID_ANY, _L("Export plate as &AMF") + dots, _L("Export current plate as AMF"),
|
||||
// [this](wxCommandEvent&) { if (m_plater) m_plater->export_amf(); }, "export_plater", nullptr,
|
||||
// [this](){return can_export_model(); }, this);
|
||||
export_menu->AppendSeparator();
|
||||
append_menu_item(export_menu, wxID_ANY, _L("Export &toolpaths as OBJ") + dots, _L("Export toolpaths as OBJ"),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->export_toolpaths_to_obj(); }, "export_plater", nullptr,
|
||||
|
|
@ -1468,6 +1481,33 @@ void MainFrame::init_menubar_as_editor()
|
|||
update_menubar();
|
||||
}
|
||||
|
||||
void MainFrame::open_menubar_item(const wxString& menu_name,const wxString& item_name)
|
||||
{
|
||||
if (m_menubar == nullptr)
|
||||
return;
|
||||
// Get menu object from menubar
|
||||
int menu_index = m_menubar->FindMenu(menu_name);
|
||||
wxMenu* menu = m_menubar->GetMenu(menu_index);
|
||||
if (menu == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Mainframe open_menubar_item function couldn't find menu: " << menu_name;
|
||||
return;
|
||||
}
|
||||
// Get item id from menu
|
||||
int item_id = menu->FindItem(item_name);
|
||||
if (item_id == wxNOT_FOUND)
|
||||
{
|
||||
// try adding three dots char
|
||||
item_id = menu->FindItem(item_name + dots);
|
||||
}
|
||||
if (item_id == wxNOT_FOUND)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "Mainframe open_menubar_item function couldn't find item: " << item_name;
|
||||
return;
|
||||
}
|
||||
// wxEVT_MENU will trigger item
|
||||
wxPostEvent((wxEvtHandler*)menu, wxCommandEvent(wxEVT_MENU, item_id));
|
||||
}
|
||||
|
||||
void MainFrame::init_menubar_as_gcodeviewer()
|
||||
{
|
||||
wxMenu* fileMenu = new wxMenu;
|
||||
|
|
|
|||
|
|
@ -158,6 +158,8 @@ public:
|
|||
void init_menubar_as_editor();
|
||||
void init_menubar_as_gcodeviewer();
|
||||
void update_menubar();
|
||||
// Open item in menu by menu and item name (in actual language)
|
||||
void open_menubar_item(const wxString& menu_name,const wxString& item_name);
|
||||
#ifdef _WIN32
|
||||
void show_tabs_menu(bool show);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1107,6 +1107,10 @@ NotificationManager::NotificationManager(wxEvtHandler* evt_handler) :
|
|||
m_evt_handler(evt_handler)
|
||||
{
|
||||
}
|
||||
NotificationManager::~NotificationManager()
|
||||
{
|
||||
HintDatabase::get_instance().uninit();
|
||||
}
|
||||
void NotificationManager::push_notification(const NotificationType type, int timestamp)
|
||||
{
|
||||
auto it = std::find_if(std::begin(basic_notifications), std::end(basic_notifications),
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ public:
|
|||
};
|
||||
|
||||
NotificationManager(wxEvtHandler* evt_handler);
|
||||
~NotificationManager();
|
||||
|
||||
// Push a prefabricated notification from basic_notifications (see the table at the end of this file).
|
||||
void push_notification(const NotificationType type, int timestamp = 0);
|
||||
|
|
|
|||
|
|
@ -1361,7 +1361,8 @@ wxDataViewItem ObjectDataViewModel::ReorganizeChildren( const int current_volume
|
|||
if (!node_parent) // happens if item.IsOk()==false
|
||||
return ret_item;
|
||||
|
||||
const size_t shift = node_parent->GetChildren().Item(0)->m_type == itSettings ? 1 : 0;
|
||||
size_t shift;
|
||||
for (shift = 0; shift < node_parent->GetChildCount() && node_parent->GetNthChild(shift)->GetType() != itVolume; shift ++);
|
||||
|
||||
ObjectDataViewModelNode *deleted_node = node_parent->GetNthChild(current_volume_id+shift);
|
||||
node_parent->GetChildren().Remove(deleted_node);
|
||||
|
|
|
|||
|
|
@ -1837,7 +1837,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
, main_frame(main_frame)
|
||||
, config(Slic3r::DynamicPrintConfig::new_from_defaults_keys({
|
||||
"bed_shape", "bed_custom_texture", "bed_custom_model", "complete_objects", "duplicate_distance", "extruder_clearance_radius", "skirts", "skirt_distance",
|
||||
"brim_width", "brim_offset", "brim_type", "variable_layer_height", "nozzle_diameter", "single_extruder_multi_material",
|
||||
"brim_width", "brim_separation", "brim_type", "variable_layer_height", "nozzle_diameter", "single_extruder_multi_material",
|
||||
"wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width",
|
||||
"extruder_colour", "filament_colour", "max_print_height", "printer_model", "printer_technology",
|
||||
// These values are necessary to construct SlicingParameters by the Canvas3D variable layer height editor.
|
||||
|
|
@ -2076,6 +2076,8 @@ Plater::priv::~priv()
|
|||
{
|
||||
if (config != nullptr)
|
||||
delete config;
|
||||
if (notification_manager != nullptr)
|
||||
delete notification_manager;
|
||||
}
|
||||
|
||||
void Plater::priv::update(unsigned int flags)
|
||||
|
|
@ -2224,7 +2226,14 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
std::vector<size_t> obj_idxs;
|
||||
|
||||
for (size_t i = 0; i < input_files.size(); ++i) {
|
||||
#ifdef _WIN32
|
||||
auto path = input_files[i];
|
||||
// On Windows, we swap slashes to back slashes, see GH #6803 as read_from_file() does not understand slashes on Windows thus it assignes full path to names of loaded objects.
|
||||
path.make_preferred();
|
||||
#else // _WIN32
|
||||
// Don't make a copy on Posix. Slash is a path separator, back slashes are not accepted as a substitute.
|
||||
const auto &path = input_files[i];
|
||||
#endif // _WIN32
|
||||
const auto filename = path.filename();
|
||||
dlg.Update(static_cast<int>(100.0f * static_cast<float>(i) / static_cast<float>(input_files.size())), _L("Loading file") + ": " + from_path(filename));
|
||||
dlg.Fit();
|
||||
|
|
@ -2339,9 +2348,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
else {
|
||||
model = Slic3r::Model::read_from_file(path.string(), nullptr, nullptr, only_if(load_config, Model::LoadAttribute::CheckVersion));
|
||||
for (auto obj : model.objects)
|
||||
if (obj->name.empty() ||
|
||||
obj->name.find_first_of("/") != std::string::npos) // When file is imported from Fusion360 the path containes "/" instead of "\\" (see https://github.com/prusa3d/PrusaSlicer/issues/6803)
|
||||
// But read_from_file doesn't support that direction separator and as a result object name containes full path
|
||||
if (obj->name.empty())
|
||||
obj->name = fs::path(obj->input_file).filename().string();
|
||||
}
|
||||
} catch (const ConfigurationError &e) {
|
||||
|
|
@ -2460,7 +2467,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
}
|
||||
|
||||
if (load_model) {
|
||||
wxGetApp().app_config->update_skein_dir(input_files[input_files.size() - 1].parent_path().string());
|
||||
wxGetApp().app_config->update_skein_dir(input_files[input_files.size() - 1].parent_path().make_preferred().string());
|
||||
// XXX: Plater.pm had @loaded_files, but didn't seem to fill them with the filenames...
|
||||
statusbar()->set_status_text(_L("Loaded"));
|
||||
}
|
||||
|
|
@ -3252,6 +3259,9 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const
|
|||
|
||||
void Plater::priv::replace_with_stl()
|
||||
{
|
||||
if (! q->canvas3D()->get_gizmos_manager().check_gizmos_closed_except(GLGizmosManager::EType::Undefined))
|
||||
return;
|
||||
|
||||
const Selection& selection = get_selection();
|
||||
|
||||
if (selection.is_wipe_tower() || get_selection().get_volume_idxs().size() != 1)
|
||||
|
|
@ -3631,14 +3641,8 @@ void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* =
|
|||
|
||||
// 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.
|
||||
if (q->canvas3D()->get_gizmos_manager().get_current_type() != GLGizmosManager::Undefined) {
|
||||
notification_manager->push_notification(
|
||||
NotificationType::CustomSupportsAndSeamRemovedAfterRepair,
|
||||
NotificationManager::NotificationLevel::RegularNotification,
|
||||
_u8L("ERROR: Please close all manipulators available from "
|
||||
"the left toolbar before fixing the mesh."));
|
||||
if (! q->canvas3D()->get_gizmos_manager().check_gizmos_closed_except(GLGizmosManager::Undefined))
|
||||
return;
|
||||
}
|
||||
|
||||
// size_t snapshot_time = undo_redo_stack().active_snapshot_time();
|
||||
Plater::TakeSnapshot snapshot(q, _L("Fix through NetFabb"));
|
||||
|
|
@ -4862,7 +4866,7 @@ SLAPrint& Plater::sla_print() { return p->sla_print; }
|
|||
|
||||
void Plater::new_project()
|
||||
{
|
||||
if (!p->save_project_if_dirty())
|
||||
if (p->save_project_if_dirty() == wxID_CANCEL)
|
||||
return;
|
||||
|
||||
p->select_view_3D("3D");
|
||||
|
|
@ -4875,7 +4879,7 @@ void Plater::new_project()
|
|||
|
||||
void Plater::load_project()
|
||||
{
|
||||
if (!p->save_project_if_dirty())
|
||||
if (p->save_project_if_dirty() == wxID_CANCEL)
|
||||
return;
|
||||
|
||||
// Ask user for a project file name.
|
||||
|
|
@ -4895,10 +4899,7 @@ void Plater::load_project(const wxString& filename)
|
|||
|
||||
p->reset();
|
||||
|
||||
std::vector<fs::path> input_paths;
|
||||
input_paths.push_back(into_path(filename));
|
||||
|
||||
if (! load_files(input_paths).empty()) {
|
||||
if (! load_files({ into_path(filename) }).empty()) {
|
||||
// At least one file was loaded.
|
||||
p->set_project_filename(filename);
|
||||
reset_project_dirty_initial_presets();
|
||||
|
|
@ -4915,7 +4916,7 @@ void Plater::add_model(bool imperial_units/* = false*/)
|
|||
|
||||
std::vector<fs::path> paths;
|
||||
for (const auto &file : input_files)
|
||||
paths.push_back(into_path(file));
|
||||
paths.emplace_back(into_path(file));
|
||||
|
||||
wxString snapshot_label;
|
||||
assert(! paths.empty());
|
||||
|
|
@ -4948,12 +4949,8 @@ void Plater::extract_config_from_project()
|
|||
wxString input_file;
|
||||
wxGetApp().load_project(this, input_file);
|
||||
|
||||
if (input_file.empty())
|
||||
return;
|
||||
|
||||
std::vector<fs::path> input_paths;
|
||||
input_paths.push_back(into_path(input_file));
|
||||
load_files(input_paths, false, true);
|
||||
if (! input_file.empty())
|
||||
load_files({ into_path(input_file) }, false, true);
|
||||
}
|
||||
|
||||
void Plater::load_gcode()
|
||||
|
|
@ -4982,10 +4979,9 @@ void Plater::load_gcode(const wxString& filename)
|
|||
|
||||
// process gcode
|
||||
GCodeProcessor processor;
|
||||
processor.enable_producers(true);
|
||||
try
|
||||
{
|
||||
processor.process_file(filename.ToUTF8().data(), false);
|
||||
processor.process_file(filename.ToUTF8().data());
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
|
|
@ -5184,15 +5180,11 @@ bool Plater::load_files(const wxArrayString& filenames)
|
|||
}
|
||||
case LoadType::LoadGeometry: {
|
||||
Plater::TakeSnapshot snapshot(this, _L("Import Object"));
|
||||
std::vector<fs::path> in_paths;
|
||||
in_paths.emplace_back(*it);
|
||||
load_files(in_paths, true, false);
|
||||
load_files({ *it }, true, false);
|
||||
break;
|
||||
}
|
||||
case LoadType::LoadConfig: {
|
||||
std::vector<fs::path> in_paths;
|
||||
in_paths.emplace_back(*it);
|
||||
load_files(in_paths, false, true);
|
||||
load_files({ *it }, false, true);
|
||||
break;
|
||||
}
|
||||
case LoadType::Unknown : {
|
||||
|
|
@ -5699,8 +5691,16 @@ void Plater::export_amf()
|
|||
|
||||
bool Plater::export_3mf(const boost::filesystem::path& output_path)
|
||||
{
|
||||
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
|
||||
if (p->model.objects.empty()) {
|
||||
MessageDialog dialog(nullptr, _L("The plater is empty.\nConfirm you want to save the project ?"), _L("Save project"), wxYES_NO);
|
||||
if (dialog.ShowModal() != wxID_YES)
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (p->model.objects.empty())
|
||||
return false;
|
||||
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
|
||||
|
||||
wxString path;
|
||||
bool export_config = true;
|
||||
|
|
@ -6250,16 +6250,6 @@ BoundingBoxf Plater::bed_shape_bb() const
|
|||
return p->bed_shape_bb();
|
||||
}
|
||||
|
||||
void Plater::start_mapping_gcode_window()
|
||||
{
|
||||
p->preview->get_canvas3d()->start_mapping_gcode_window();
|
||||
}
|
||||
|
||||
void Plater::stop_mapping_gcode_window()
|
||||
{
|
||||
p->preview->get_canvas3d()->stop_mapping_gcode_window();
|
||||
}
|
||||
|
||||
void Plater::arrange()
|
||||
{
|
||||
p->m_ui_jobs.arrange();
|
||||
|
|
@ -6689,6 +6679,11 @@ bool Plater::is_render_statistic_dialog_visible() const
|
|||
return p->show_render_statistic_dialog;
|
||||
}
|
||||
|
||||
|
||||
Plater::TakeSnapshot::TakeSnapshot(Plater *plater, const std::string &snapshot_name)
|
||||
: TakeSnapshot(plater, from_u8(snapshot_name)) {}
|
||||
|
||||
|
||||
// Wrapper around wxWindow::PopupMenu to suppress error messages popping out while tracking the popup menu.
|
||||
bool Plater::PopupMenu(wxMenu *menu, const wxPoint& pos)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -282,9 +282,6 @@ public:
|
|||
GLCanvas3D* get_current_canvas3D();
|
||||
BoundingBoxf bed_shape_bb() const;
|
||||
|
||||
void start_mapping_gcode_window();
|
||||
void stop_mapping_gcode_window();
|
||||
|
||||
void arrange();
|
||||
void find_new_position(const ModelInstancePtrs &instances);
|
||||
|
||||
|
|
@ -383,10 +380,11 @@ public:
|
|||
Plater *m_plater;
|
||||
};
|
||||
|
||||
// ROII wrapper for taking an Undo / Redo snapshot while disabling the snapshot taking by the methods called from inside this snapshot.
|
||||
// RAII wrapper for taking an Undo / Redo snapshot while disabling the snapshot taking by the methods called from inside this snapshot.
|
||||
class TakeSnapshot
|
||||
{
|
||||
public:
|
||||
TakeSnapshot(Plater *plater, const std::string &snapshot_name);
|
||||
TakeSnapshot(Plater *plater, const wxString &snapshot_name) : m_plater(plater)
|
||||
{
|
||||
m_plater->take_snapshot(snapshot_name);
|
||||
|
|
|
|||
|
|
@ -636,8 +636,7 @@ PlaterPresetComboBox::~PlaterPresetComboBox()
|
|||
|
||||
static void run_wizard(ConfigWizard::StartPage sp)
|
||||
{
|
||||
if (wxGetApp().check_and_save_current_preset_changes())
|
||||
wxGetApp().run_wizard(ConfigWizard::RR_USER, sp);
|
||||
wxGetApp().run_wizard(ConfigWizard::RR_USER, sp);
|
||||
}
|
||||
|
||||
void PlaterPresetComboBox::OnSelect(wxCommandEvent &evt)
|
||||
|
|
|
|||
|
|
@ -492,17 +492,15 @@ void Tab::OnActivate()
|
|||
activate_selected_page([](){});
|
||||
m_hsizer->Layout();
|
||||
|
||||
// Workaroud for Menu instead of NoteBook
|
||||
#ifdef _MSW_DARK_MODE
|
||||
// if (wxGetApp().tabs_as_menu())
|
||||
{
|
||||
wxSize sz = m_presets_choice->GetSize();
|
||||
wxSize ok_sz = wxSize(35 * m_em_unit, m_presets_choice->GetBestSize().y+1);
|
||||
if (sz != ok_sz) {
|
||||
m_presets_choice->SetMinSize(ok_sz);
|
||||
m_presets_choice->SetSize(ok_sz);
|
||||
GetSizer()->GetItem(size_t(0))->GetSizer()->Layout();
|
||||
}
|
||||
// Because of DarkMode we use our own Notebook (inherited from wxSiplebook) instead of wxNotebook
|
||||
// And it looks like first Layout of the page doesn't update a size of the m_presets_choice
|
||||
// So we have to set correct size explicitely
|
||||
if (wxSize ok_sz = wxSize(35 * m_em_unit, m_presets_choice->GetBestSize().y);
|
||||
ok_sz != m_presets_choice->GetSize()) {
|
||||
m_presets_choice->SetMinSize(ok_sz);
|
||||
m_presets_choice->SetSize(ok_sz);
|
||||
GetSizer()->GetItem(size_t(0))->GetSizer()->Layout();
|
||||
}
|
||||
#endif // _MSW_DARK_MODE
|
||||
Refresh();
|
||||
|
|
@ -1509,7 +1507,7 @@ void TabPrint::build()
|
|||
optgroup = page->new_optgroup(L("Brim"));
|
||||
optgroup->append_single_option_line("brim_type", category_path + "brim");
|
||||
optgroup->append_single_option_line("brim_width", category_path + "brim");
|
||||
optgroup->append_single_option_line("brim_offset", category_path + "brim");
|
||||
optgroup->append_single_option_line("brim_separation", category_path + "brim");
|
||||
|
||||
page = add_options_page(L("Support material"), "support");
|
||||
category_path = "support-material_1698#";
|
||||
|
|
@ -1565,12 +1563,14 @@ void TabPrint::build()
|
|||
|
||||
optgroup = page->new_optgroup(L("Modifiers"));
|
||||
optgroup->append_single_option_line("first_layer_speed");
|
||||
optgroup->append_single_option_line("first_layer_speed_over_raft");
|
||||
|
||||
optgroup = page->new_optgroup(L("Acceleration control (advanced)"));
|
||||
optgroup->append_single_option_line("perimeter_acceleration");
|
||||
optgroup->append_single_option_line("infill_acceleration");
|
||||
optgroup->append_single_option_line("bridge_acceleration");
|
||||
optgroup->append_single_option_line("first_layer_acceleration");
|
||||
optgroup->append_single_option_line("first_layer_acceleration_over_raft");
|
||||
optgroup->append_single_option_line("default_acceleration");
|
||||
|
||||
optgroup = page->new_optgroup(L("Autospeed (advanced)"));
|
||||
|
|
|
|||
|
|
@ -696,7 +696,12 @@ void DiffViewCtrl::context_menu(wxDataViewEvent& event)
|
|||
auto it = m_items_map.find(item);
|
||||
if (it == m_items_map.end() || !it->second.is_long)
|
||||
return;
|
||||
FullCompareDialog(it->second.opt_name, it->second.old_val, it->second.new_val).ShowModal();
|
||||
|
||||
size_t column_cnt = this->GetColumnCount();
|
||||
const wxString old_value_header = this->GetColumn(column_cnt - 2)->GetTitle();
|
||||
const wxString new_value_header = this->GetColumn(column_cnt - 1)->GetTitle();
|
||||
FullCompareDialog(it->second.opt_name, it->second.old_val, it->second.new_val,
|
||||
old_value_header, new_value_header).ShowModal();
|
||||
|
||||
#ifdef __WXOSX__
|
||||
wxWindow* parent = this->GetParent();
|
||||
|
|
@ -752,8 +757,8 @@ std::vector<std::string> DiffViewCtrl::selected_options()
|
|||
// UnsavedChangesDialog
|
||||
//------------------------------------------
|
||||
|
||||
UnsavedChangesDialog::UnsavedChangesDialog(const wxString& header)
|
||||
: DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, _L("PrusaSlicer is closing: Unsaved Changes"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
UnsavedChangesDialog::UnsavedChangesDialog(const wxString& header, const wxString& caption/* = wxString()*/)
|
||||
: DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, (caption.IsEmpty() ? _L("PrusaSlicer is closing") : caption) + ": " + _L("Unsaved Changes"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
{
|
||||
m_app_config_key = "default_action_on_close_application";
|
||||
|
||||
|
|
@ -1281,7 +1286,8 @@ void UnsavedChangesDialog::on_sys_color_changed()
|
|||
// FullCompareDialog
|
||||
//------------------------------------------
|
||||
|
||||
FullCompareDialog::FullCompareDialog(const wxString& option_name, const wxString& old_value, const wxString& new_value)
|
||||
FullCompareDialog::FullCompareDialog(const wxString& option_name, const wxString& old_value, const wxString& new_value,
|
||||
const wxString& old_value_header, const wxString& new_value_header)
|
||||
: wxDialog(nullptr, wxID_ANY, option_name, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
{
|
||||
wxGetApp().UpdateDarkUI(this);
|
||||
|
|
@ -1302,8 +1308,8 @@ FullCompareDialog::FullCompareDialog(const wxString& option_name, const wxString
|
|||
grid_sizer->Add(text, 0, wxALL, border);
|
||||
};
|
||||
|
||||
add_header(_L("Old value"));
|
||||
add_header(_L("New value"));
|
||||
add_header(old_value_header);
|
||||
add_header(new_value_header);
|
||||
|
||||
auto get_set_from_val = [](wxString str) {
|
||||
if (str.Find("\n") == wxNOT_FOUND)
|
||||
|
|
@ -1327,7 +1333,7 @@ FullCompareDialog::FullCompareDialog(const wxString& option_name, const wxString
|
|||
std::set_difference(new_set.begin(), new_set.end(), old_set.begin(), old_set.end(), std::inserter(new_old_diff_set, new_old_diff_set.begin()));
|
||||
|
||||
auto add_value = [grid_sizer, border, this](wxString label, const std::set<wxString>& diff_set, bool is_colored = false) {
|
||||
wxTextCtrl* text = new wxTextCtrl(this, wxID_ANY, label, wxDefaultPosition, wxSize(400, 400), wxTE_MULTILINE | wxTE_READONLY | wxBORDER_SIMPLE | wxTE_RICH);
|
||||
wxTextCtrl* text = new wxTextCtrl(this, wxID_ANY, label, wxDefaultPosition, wxSize(400, 400), wxTE_MULTILINE | wxTE_READONLY | wxBORDER_DEFAULT | wxTE_RICH);
|
||||
wxGetApp().UpdateDarkUI(text);
|
||||
text->SetStyle(0, label.Len(), wxTextAttr(is_colored ? wxColour(orange) : wxNullColour, wxNullColour, this->GetFont()));
|
||||
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@ class UnsavedChangesDialog : public DPIDialog
|
|||
std::vector<std::pair<std::string, Preset::Type>> names_and_types;
|
||||
|
||||
public:
|
||||
UnsavedChangesDialog(const wxString& header);
|
||||
UnsavedChangesDialog(const wxString& header, const wxString& caption = wxString());
|
||||
UnsavedChangesDialog(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset);
|
||||
~UnsavedChangesDialog() {}
|
||||
|
||||
|
|
@ -299,7 +299,8 @@ protected:
|
|||
class FullCompareDialog : public wxDialog
|
||||
{
|
||||
public:
|
||||
FullCompareDialog(const wxString& option_name, const wxString& old_value, const wxString& new_value);
|
||||
FullCompareDialog(const wxString& option_name, const wxString& old_value, const wxString& new_value,
|
||||
const wxString& old_value_header, const wxString& new_value_header);
|
||||
~FullCompareDialog() {}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue