mirror of
https://github.com/FULU-Foundation/OrcaSlicer-bambulab.git
synced 2026-09-13 06:08:10 +02:00
Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_gcode_viewer
This commit is contained in:
@@ -105,20 +105,28 @@ void BackgroundSlicingProcess::process_fff()
|
||||
GUI::RemovableDriveManager::get_instance().update();
|
||||
bool with_check = GUI::RemovableDriveManager::get_instance().is_path_on_removable_drive(export_path);
|
||||
int copy_ret_val = copy_file(m_temp_output_path, export_path, with_check);
|
||||
if (with_check && copy_ret_val == -2)
|
||||
{
|
||||
std::string err_msg = "Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at " + export_path + ".tmp.";
|
||||
throw std::runtime_error(_utf8(L(err_msg)));
|
||||
}
|
||||
else if (copy_ret_val == -3)
|
||||
{
|
||||
std::string err_msg = "Renaming of the G-code after copying to the selected destination folder has failed. Current path is " + export_path + ".tmp. Please try exporting again.";
|
||||
throw std::runtime_error(_utf8(L(err_msg)));
|
||||
}
|
||||
else if ( copy_ret_val != 0)
|
||||
{
|
||||
throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?")));
|
||||
switch (copy_ret_val){
|
||||
case SUCCESS: break; // no error
|
||||
case FAIL_COPY_FILE:
|
||||
throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?")));
|
||||
break;
|
||||
case FAIL_FILES_DIFFERENT:
|
||||
throw std::runtime_error((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str());
|
||||
break;
|
||||
case FAIL_RENAMING:
|
||||
throw std::runtime_error((boost::format(_utf8(L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."))) % export_path).str());
|
||||
break;
|
||||
case FAIL_CHECK_ORIGIN_NOT_OPENED:
|
||||
throw std::runtime_error((boost::format(_utf8(L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."))) % m_temp_output_path % export_path).str());
|
||||
break;
|
||||
case FAIL_CHECK_TARGET_NOT_OPENED:
|
||||
throw std::runtime_error((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str());
|
||||
break;
|
||||
default:
|
||||
BOOST_LOG_TRIVIAL(warning) << "Unexpected fail code(" << (int)copy_ret_val << ") durring copy_file() to " << export_path << ".";
|
||||
break;
|
||||
}
|
||||
|
||||
m_print->set_status(95, _utf8(L("Running post-processing scripts")));
|
||||
run_post_process_scripts(export_path, m_fff_print->config());
|
||||
m_print->set_status(100, (boost::format(_utf8(L("G-code file exported to %1%"))) % export_path).str());
|
||||
@@ -216,7 +224,7 @@ void BackgroundSlicingProcess::thread_proc()
|
||||
wxString errmsg = wxString::Format(_(L("%s has encountered an error. It was likely caused by running out of memory. "
|
||||
"If you are sure you have enough RAM on your system, this may also be a bug and we would "
|
||||
"be glad if you reported it.")), SLIC3R_APP_NAME);
|
||||
error = errmsg.ToStdString() + "\n\n" + std::string(ex.what());
|
||||
error = std::string(errmsg.ToUTF8()) + "\n\n" + std::string(ex.what());
|
||||
} catch (std::exception &ex) {
|
||||
error = ex.what();
|
||||
} catch (...) {
|
||||
@@ -484,7 +492,7 @@ void BackgroundSlicingProcess::prepare_upload()
|
||||
|
||||
if (m_print == m_fff_print) {
|
||||
m_print->set_status(95, _utf8(L("Running post-processing scripts")));
|
||||
if (copy_file(m_temp_output_path, source_path.string()) != 0) {
|
||||
if (copy_file(m_temp_output_path, source_path.string()) != SUCCESS) {
|
||||
throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed")));
|
||||
}
|
||||
run_post_process_scripts(source_path.string(), m_fff_print->config());
|
||||
|
||||
@@ -220,7 +220,7 @@ wxPanel* BedShapePanel::init_texture_panel()
|
||||
if (m_custom_texture != NONE)
|
||||
{
|
||||
if (!exists)
|
||||
tooltip_text += _(L("Not found: "));
|
||||
tooltip_text += _(L("Not found:")) + " ";
|
||||
|
||||
tooltip_text += _(m_custom_texture);
|
||||
}
|
||||
@@ -299,7 +299,7 @@ wxPanel* BedShapePanel::init_model_panel()
|
||||
if (m_custom_model != NONE)
|
||||
{
|
||||
if (!exists)
|
||||
tooltip_text += _(L("Not found: "));
|
||||
tooltip_text += _(L("Not found:")) + " ";
|
||||
|
||||
tooltip_text += _(m_custom_model);
|
||||
}
|
||||
|
||||
+26
-54
@@ -43,6 +43,7 @@ Camera::Camera()
|
||||
, m_distance(DefaultDistance)
|
||||
, m_gui_scale(1.0)
|
||||
, m_view_matrix(Transform3d::Identity())
|
||||
, m_view_rotation(1., 0., 0., 0.)
|
||||
, m_projection_matrix(Transform3d::Identity())
|
||||
{
|
||||
set_default_orientation();
|
||||
@@ -85,7 +86,13 @@ void Camera::select_next_type()
|
||||
|
||||
void Camera::set_target(const Vec3d& target)
|
||||
{
|
||||
translate_world(target - m_target);
|
||||
Vec3d new_target = validate_target(target);
|
||||
Vec3d new_displacement = new_target - m_target;
|
||||
if (!new_displacement.isApprox(Vec3d::Zero()))
|
||||
{
|
||||
m_target = new_target;
|
||||
m_view_matrix.translate(-new_displacement);
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::update_zoom(double delta_zoom)
|
||||
@@ -299,17 +306,6 @@ void Camera::debug_render() const
|
||||
}
|
||||
#endif // ENABLE_CAMERA_STATISTICS
|
||||
|
||||
void Camera::translate_world(const Vec3d& displacement)
|
||||
{
|
||||
Vec3d new_target = validate_target(m_target + displacement);
|
||||
Vec3d new_displacement = new_target - m_target;
|
||||
if (!new_displacement.isApprox(Vec3d::Zero()))
|
||||
{
|
||||
m_target += new_displacement;
|
||||
m_view_matrix.translate(-new_displacement);
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, bool apply_limits)
|
||||
{
|
||||
m_zenit += Geometry::rad2deg(delta_zenit_rad);
|
||||
@@ -324,50 +320,23 @@ void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, b
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME -> The following is a HACK !!!
|
||||
// When the value of the zenit rotation is large enough, the following call to rotate() shows
|
||||
// numerical instability introducing some scaling into m_view_matrix (verified by checking
|
||||
// that the camera space unit vectors are no more unit).
|
||||
// See also https://dev.prusa3d.com/browse/SPE-1082
|
||||
// We split the zenit rotation into a set of smaller rotations which are then applied.
|
||||
static const double MAX_ALLOWED = Geometry::deg2rad(0.1);
|
||||
unsigned int zenit_steps_count = 1 + (unsigned int)(std::abs(delta_zenit_rad) / MAX_ALLOWED);
|
||||
double zenit_step = delta_zenit_rad / (double)zenit_steps_count;
|
||||
|
||||
Vec3d target = m_target;
|
||||
translate_world(-target);
|
||||
|
||||
if (zenit_step != 0.0)
|
||||
{
|
||||
Vec3d right = get_dir_right();
|
||||
for (unsigned int i = 0; i < zenit_steps_count; ++i)
|
||||
{
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(zenit_step, right));
|
||||
}
|
||||
}
|
||||
|
||||
if (delta_azimut_rad != 0.0)
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(delta_azimut_rad, Vec3d::UnitZ()));
|
||||
|
||||
translate_world(target);
|
||||
Vec3d translation = m_view_matrix.translation() + m_view_rotation * m_target;
|
||||
auto rot_z = Eigen::AngleAxisd(delta_azimut_rad, Vec3d::UnitZ());
|
||||
m_view_rotation *= rot_z * Eigen::AngleAxisd(delta_zenit_rad, rot_z.inverse() * get_dir_right());
|
||||
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (- m_target) + translation, m_view_rotation, Vec3d(1., 1., 1.));
|
||||
}
|
||||
|
||||
// Virtual trackball, rotate around an axis, where the eucledian norm of the axis gives the rotation angle in radians.
|
||||
void Camera::rotate_local_around_target(const Vec3d& rotation_rad)
|
||||
{
|
||||
rotate_local_around_pivot(rotation_rad, m_target);
|
||||
}
|
||||
|
||||
void Camera::rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& pivot)
|
||||
{
|
||||
// we use a copy of the pivot because a reference to the current m_target may be passed in (see i.e. rotate_local_around_target())
|
||||
// and m_target is modified by the translate_world() calls
|
||||
Vec3d center = pivot;
|
||||
translate_world(-center);
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(0), get_dir_right()));
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(1), get_dir_up()));
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(2), get_dir_forward()));
|
||||
translate_world(center);
|
||||
update_zenit();
|
||||
double angle = rotation_rad.norm();
|
||||
if (std::abs(angle) > EPSILON) {
|
||||
Vec3d translation = m_view_matrix.translation() + m_view_rotation * m_target;
|
||||
Vec3d axis = m_view_rotation.conjugate() * rotation_rad.normalized();
|
||||
m_view_rotation *= Eigen::Quaterniond(Eigen::AngleAxisd(angle, axis));
|
||||
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (-m_target) + translation, m_view_rotation, Vec3d(1., 1., 1.));
|
||||
update_zenit();
|
||||
}
|
||||
}
|
||||
|
||||
double Camera::min_zoom() const
|
||||
@@ -588,6 +557,9 @@ void Camera::look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up
|
||||
m_view_matrix(3, 2) = 0.0;
|
||||
m_view_matrix(3, 3) = 1.0;
|
||||
|
||||
// Initialize the rotation quaternion from the rotation submatrix of of m_view_matrix.
|
||||
m_view_rotation = Eigen::Quaterniond(m_view_matrix.matrix().template block<3, 3>(0, 0));
|
||||
|
||||
update_zenit();
|
||||
}
|
||||
|
||||
@@ -598,8 +570,8 @@ void Camera::set_default_orientation()
|
||||
double phi_rad = Geometry::deg2rad(45.0);
|
||||
double sin_theta = ::sin(theta_rad);
|
||||
Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad));
|
||||
m_view_matrix = Transform3d::Identity();
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(theta_rad, Vec3d::UnitX())).rotate(Eigen::AngleAxisd(phi_rad, Vec3d::UnitZ())).translate(-camera_pos);
|
||||
m_view_rotation = Eigen::AngleAxisd(theta_rad, Vec3d::UnitX()) * Eigen::AngleAxisd(phi_rad, Vec3d::UnitZ());
|
||||
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (- camera_pos), m_view_rotation, Vec3d(1., 1., 1.));
|
||||
}
|
||||
|
||||
Vec3d Camera::validate_target(const Vec3d& target) const
|
||||
|
||||
@@ -43,6 +43,8 @@ private:
|
||||
|
||||
mutable std::array<int, 4> m_viewport;
|
||||
mutable Transform3d m_view_matrix;
|
||||
// We are calculating the rotation part of the m_view_matrix from m_view_rotation.
|
||||
mutable Eigen::Quaterniond m_view_rotation;
|
||||
mutable Transform3d m_projection_matrix;
|
||||
mutable std::pair<double, double> m_frustrum_zs;
|
||||
|
||||
@@ -107,7 +109,7 @@ public:
|
||||
#endif // ENABLE_CAMERA_STATISTICS
|
||||
|
||||
// translate the camera in world space
|
||||
void translate_world(const Vec3d& displacement);
|
||||
void translate_world(const Vec3d& displacement) { this->set_target(m_target + displacement); }
|
||||
|
||||
// rotate the camera on a sphere having center == m_target and radius == m_distance
|
||||
// using the given variations of spherical coordinates
|
||||
@@ -117,9 +119,6 @@ public:
|
||||
// rotate the camera around three axes parallel to the camera local axes and passing through m_target
|
||||
void rotate_local_around_target(const Vec3d& rotation_rad);
|
||||
|
||||
// rotate the camera around three axes parallel to the camera local axes and passing through the given pivot point
|
||||
void rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& pivot);
|
||||
|
||||
// returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis
|
||||
bool is_looking_downward() const { return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; }
|
||||
|
||||
|
||||
@@ -347,6 +347,7 @@ void ConfigManipulation::toggle_print_sla_options(DynamicPrintConfig* config)
|
||||
toggle_field("support_head_penetration", supports_en);
|
||||
toggle_field("support_head_width", supports_en);
|
||||
toggle_field("support_pillar_diameter", supports_en);
|
||||
toggle_field("support_max_bridges_on_pillar", supports_en);
|
||||
toggle_field("support_pillar_connection_mode", supports_en);
|
||||
toggle_field("support_buildplate_only", supports_en);
|
||||
toggle_field("support_base_diameter", supports_en);
|
||||
|
||||
@@ -162,7 +162,7 @@ void ConfigSnapshotDialog::on_dpi_changed(const wxRect &suggested_rect)
|
||||
|
||||
void ConfigSnapshotDialog::onLinkClicked(wxHtmlLinkEvent &event)
|
||||
{
|
||||
m_snapshot_to_activate = event.GetLinkInfo().GetHref();
|
||||
m_snapshot_to_activate = event.GetLinkInfo().GetHref().ToUTF8();
|
||||
this->EndModal(wxID_CLOSE);
|
||||
}
|
||||
|
||||
|
||||
@@ -432,7 +432,7 @@ PageWelcome::PageWelcome(ConfigWizard *parent)
|
||||
, welcome_text(append_text(wxString::Format(
|
||||
_(L("Hello, welcome to %s! This %s helps you with the initial configuration; just a few settings and you will be ready to print.")),
|
||||
SLIC3R_APP_NAME,
|
||||
ConfigWizard::name())
|
||||
_(ConfigWizard::name()))
|
||||
))
|
||||
, cbox_reset(append(
|
||||
new wxCheckBox(this, wxID_ANY, _(L("Remove user profiles - install from scratch (a snapshot will be taken beforehand)")))
|
||||
@@ -748,7 +748,8 @@ PageCustom::PageCustom(ConfigWizard *parent)
|
||||
|
||||
cb_custom->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) {
|
||||
tc_profile_name->Enable(custom_wanted());
|
||||
wizard_p()->on_custom_setup();
|
||||
wizard_p()->on_custom_setup(custom_wanted());
|
||||
|
||||
});
|
||||
|
||||
append(cb_custom);
|
||||
@@ -1396,7 +1397,7 @@ void ConfigWizard::priv::load_pages()
|
||||
if (any_sla_selected) { index->add_page(page_sla_materials); }
|
||||
|
||||
// there should to be selected at least one printer
|
||||
btn_finish->Enable(any_fff_selected || any_sla_selected);
|
||||
btn_finish->Enable(any_fff_selected || any_sla_selected || custom_printer_selected);
|
||||
|
||||
index->add_page(page_update);
|
||||
index->add_page(page_reload_from_disk);
|
||||
@@ -1599,8 +1600,9 @@ void ConfigWizard::priv::update_materials(Technology technology)
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigWizard::priv::on_custom_setup()
|
||||
void ConfigWizard::priv::on_custom_setup(const bool custom_wanted)
|
||||
{
|
||||
custom_printer_selected = custom_wanted;
|
||||
load_pages();
|
||||
}
|
||||
|
||||
@@ -1723,6 +1725,8 @@ bool ConfigWizard::priv::on_bnt_finish()
|
||||
if (any_sla_selected)
|
||||
page_sla_materials->reload_presets();
|
||||
|
||||
// theres no need to check that filament is selected if we have only custom printer
|
||||
if (custom_printer_selected && !any_fff_selected && !any_sla_selected) return true;
|
||||
// check, that there is selected at least one filament/material
|
||||
return check_materials_in_config(T_ANY);
|
||||
}
|
||||
@@ -1751,13 +1755,13 @@ bool ConfigWizard::priv::check_materials_in_config(Technology technology, bool s
|
||||
|
||||
if (any_fff_selected && technology & T_FFF && !exist_preset(AppConfig::SECTION_FILAMENTS, filaments))
|
||||
{
|
||||
if (show_info_msg)
|
||||
{
|
||||
wxString message = _(L("You have to select at least one filament for selected printers")) + "\n\n\t" +
|
||||
_(L("Do you want to automatic select default filaments?"));
|
||||
ask_and_selected_default_materials(message, T_FFF);
|
||||
}
|
||||
return false;
|
||||
if (show_info_msg)
|
||||
{
|
||||
wxString message = _(L("You have to select at least one filament for selected printers")) + "\n\n\t" +
|
||||
_(L("Do you want to automatic select default filaments?"));
|
||||
ask_and_selected_default_materials(message, T_FFF);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (any_sla_selected && technology & T_SLA && !exist_preset(AppConfig::SECTION_MATERIALS, sla_materials))
|
||||
@@ -1875,6 +1879,7 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
|
||||
if (bundle.second.is_prusa_bundle) { continue; }
|
||||
|
||||
const auto config = enabled_vendors.find(bundle.first);
|
||||
if (config == enabled_vendors.end()) { continue; }
|
||||
for (const auto &model : bundle.second.vendor_profile->models) {
|
||||
const auto model_it = config->second.find(model.id);
|
||||
if (model_it != config->second.end() && model_it->second.size() > 0) {
|
||||
@@ -1925,7 +1930,6 @@ bool ConfigWizard::priv::check_fff_selected()
|
||||
for (const auto& printer: pages_3rdparty)
|
||||
if (printer.second.first) // FFF page
|
||||
ret |= printer.second.first->any_selected();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1942,7 +1946,7 @@ bool ConfigWizard::priv::check_sla_selected()
|
||||
// Public
|
||||
|
||||
ConfigWizard::ConfigWizard(wxWindow *parent)
|
||||
: DPIDialog(parent, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(name().ToStdString()), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
: DPIDialog(parent, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(name()), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
, p(new priv(this))
|
||||
{
|
||||
this->SetFont(wxGetApp().normal_font());
|
||||
@@ -1997,6 +2001,8 @@ ConfigWizard::ConfigWizard(wxWindow *parent)
|
||||
// Pages for 3rd party vendors
|
||||
p->create_3rdparty_pages(); // Needs to be done _before_ creating PageVendors
|
||||
p->add_page(p->page_vendors = new PageVendors(this));
|
||||
p->add_page(p->page_custom = new PageCustom(this));
|
||||
p->custom_printer_selected = p->page_custom->custom_wanted();
|
||||
|
||||
p->any_sla_selected = p->check_sla_selected();
|
||||
p->any_fff_selected = p->check_fff_selected();
|
||||
@@ -2008,7 +2014,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent)
|
||||
p->add_page(p->page_sla_materials = new PageMaterials(this, &p->sla_materials,
|
||||
_(L("SLA Material Profiles Selection")) + " ", _(L("SLA Materials")), _(L("Layer height:")) ));
|
||||
|
||||
p->add_page(p->page_custom = new PageCustom(this));
|
||||
|
||||
p->add_page(p->page_update = new PageUpdate(this));
|
||||
p->add_page(p->page_reload_from_disk = new PageReloadFromDisk(this));
|
||||
p->add_page(p->page_mode = new PageMode(this));
|
||||
|
||||
@@ -447,6 +447,7 @@ struct ConfigWizard::priv
|
||||
std::unique_ptr<DynamicPrintConfig> custom_config; // Backing for custom printer definition
|
||||
bool any_fff_selected; // Used to decide whether to display Filaments page
|
||||
bool any_sla_selected; // Used to decide whether to display SLA Materials page
|
||||
bool custom_printer_selected;
|
||||
|
||||
wxScrolledWindow *hscroll = nullptr;
|
||||
wxBoxSizer *hscroll_sizer = nullptr;
|
||||
@@ -497,7 +498,7 @@ struct ConfigWizard::priv
|
||||
void set_run_reason(RunReason run_reason);
|
||||
void update_materials(Technology technology);
|
||||
|
||||
void on_custom_setup();
|
||||
void on_custom_setup(const bool custom_wanted);
|
||||
void on_printer_pick(PagePrinters *page, const PrinterPickerEvent &evt);
|
||||
void select_default_materials_for_printer_model(const std::vector<VendorProfile::PrinterModel> &models,
|
||||
Technology technology,
|
||||
|
||||
@@ -77,6 +77,7 @@ Control::Control( wxWindow *parent,
|
||||
|
||||
m_selection = ssUndef;
|
||||
m_ticks.set_pause_print_msg(_utf8(L("Place bearings in slots and resume printing")));
|
||||
m_ticks.set_extruder_colors(&m_extruder_colors);
|
||||
|
||||
// slider events
|
||||
this->Bind(wxEVT_PAINT, &Control::OnPaint, this);
|
||||
@@ -332,6 +333,13 @@ void Control::SetTicksValues(const CustomGCode::Info& custom_gcode_per_print_z)
|
||||
Update();
|
||||
}
|
||||
|
||||
void Control::SetDrawMode(bool is_sla_print, bool is_sequential_print)
|
||||
{
|
||||
m_draw_mode = is_sla_print ? dmSlaPrint :
|
||||
is_sequential_print ? dmSequentialFffPrint :
|
||||
dmRegular;
|
||||
}
|
||||
|
||||
void Control::SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder)
|
||||
{
|
||||
m_mode = !is_one_extruder_printed_model ? t_mode::MultiExtruder :
|
||||
@@ -344,6 +352,11 @@ void Control::SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, c
|
||||
UseDefaultColors(m_mode == t_mode::SingleExtruder);
|
||||
}
|
||||
|
||||
void Control::SetExtruderColors( const std::vector<std::string>& extruder_colors)
|
||||
{
|
||||
m_extruder_colors = extruder_colors;
|
||||
}
|
||||
|
||||
void Control::get_lower_and_higher_position(int& lower_pos, int& higher_pos)
|
||||
{
|
||||
const double step = get_scroll_step();
|
||||
@@ -441,7 +454,7 @@ void Control::draw_info_line_with_icon(wxDC& dc, const wxPoint& pos, const Selec
|
||||
dc.DrawLine(pt_beg, pt_end);
|
||||
|
||||
//draw action icon
|
||||
if (m_is_enabled_tick_manipulation)
|
||||
if (m_draw_mode == dmRegular)
|
||||
draw_action_icon(dc, pt_beg, pt_end);
|
||||
}
|
||||
}
|
||||
@@ -612,10 +625,10 @@ void Control::draw_thumbs(wxDC& dc, const wxCoord& lower_pos, const wxCoord& hig
|
||||
|
||||
void Control::draw_ticks(wxDC& dc)
|
||||
{
|
||||
if (!m_is_enabled_tick_manipulation)
|
||||
if (m_draw_mode == dmSlaPrint)
|
||||
return;
|
||||
|
||||
dc.SetPen(m_is_enabled_tick_manipulation ? DARK_GREY_PEN : LIGHT_GREY_PEN );
|
||||
dc.SetPen(m_draw_mode == dmRegular ? DARK_GREY_PEN : LIGHT_GREY_PEN );
|
||||
int height, width;
|
||||
get_size(&width, &height);
|
||||
const wxCoord mid = is_horizontal() ? 0.5*height : 0.5*width;
|
||||
@@ -633,7 +646,11 @@ void Control::draw_ticks(wxDC& dc)
|
||||
|
||||
// get icon name if it is
|
||||
std::string icon_name;
|
||||
if (tick.gcode == ColorChangeCode || tick.gcode == ToolChangeCode) {
|
||||
|
||||
// if we have non-regular draw mode, all ticks should be marked with error icon
|
||||
if (m_draw_mode != dmRegular)
|
||||
icon_name = focused_tick ? "error_tick_f" : "error_tick";
|
||||
else if (tick.gcode == ColorChangeCode || tick.gcode == ToolChangeCode) {
|
||||
if (m_ticks.is_conflict_tick(tick, m_mode, m_only_extruder, m_values[tick.tick]))
|
||||
icon_name = focused_tick ? "error_tick_f" : "error_tick";
|
||||
}
|
||||
@@ -666,7 +683,7 @@ std::string Control::get_color_for_tool_change_tick(std::set<TickCode>::const_it
|
||||
return it_n->color;
|
||||
}
|
||||
|
||||
return it->color;
|
||||
return m_extruder_colors[current_extruder-1]; // return a color for a specific extruder from the colors list
|
||||
}
|
||||
|
||||
std::string Control::get_color_for_color_change_tick(std::set<TickCode>::const_iterator it) const
|
||||
@@ -682,6 +699,8 @@ std::string Control::get_color_for_color_change_tick(std::set<TickCode>::const_i
|
||||
return it->color;
|
||||
break;
|
||||
}
|
||||
if (it_n->gcode == ColorChangeCode && it_n->extruder == it->extruder)
|
||||
return it->color;
|
||||
}
|
||||
if (!is_tool_change && it->extruder == def_extruder)
|
||||
return it->color;
|
||||
@@ -705,7 +724,7 @@ wxRect Control::get_colored_band_rect()
|
||||
|
||||
void Control::draw_colored_band(wxDC& dc)
|
||||
{
|
||||
if (!m_is_enabled_tick_manipulation)
|
||||
if (m_draw_mode != dmRegular)
|
||||
return;
|
||||
|
||||
auto draw_band = [](wxDC& dc, const wxColour& clr, const wxRect& band_rc)
|
||||
@@ -725,7 +744,7 @@ void Control::draw_colored_band(wxDC& dc)
|
||||
}
|
||||
|
||||
const int default_color_idx = m_mode==t_mode::MultiAsSingle ? std::max<int>(m_only_extruder - 1, 0) : 0;
|
||||
draw_band(dc, wxColour(GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config()[default_color_idx]), main_band);
|
||||
draw_band(dc, wxColour(m_extruder_colors[default_color_idx]), main_band);
|
||||
|
||||
std::set<TickCode>::const_iterator tick_it = m_ticks.ticks.begin();
|
||||
|
||||
@@ -771,7 +790,7 @@ void Control::draw_one_layer_icon(wxDC& dc)
|
||||
|
||||
void Control::draw_revert_icon(wxDC& dc)
|
||||
{
|
||||
if (m_ticks.empty() || !m_is_enabled_tick_manipulation)
|
||||
if (m_ticks.empty() || m_draw_mode != dmRegular)
|
||||
return;
|
||||
|
||||
int width, height;
|
||||
@@ -804,7 +823,7 @@ void Control::draw_cog_icon(wxDC& dc)
|
||||
|
||||
void Control::update_thumb_rect(const wxCoord& begin_x, const wxCoord& begin_y, const SelectedSlider& selection)
|
||||
{
|
||||
const wxRect& rect = wxRect(begin_x, begin_y, m_thumb_size.x, int(m_thumb_size.y*0.5));
|
||||
const wxRect& rect = wxRect(begin_x, begin_y + (selection == ssLower ? int(m_thumb_size.y * 0.5) : 0), m_thumb_size.x, int(m_thumb_size.y*0.5));
|
||||
if (selection == ssLower)
|
||||
m_rect_lower_thumb = rect;
|
||||
else
|
||||
@@ -822,10 +841,15 @@ int Control::get_value_from_position(const wxCoord x, const wxCoord y)
|
||||
return int(m_min_value + double(height - SLIDER_MARGIN - y) / step + 0.5);
|
||||
}
|
||||
|
||||
void Control::detect_selected_slider(const wxPoint& pt)
|
||||
bool Control::detect_selected_slider(const wxPoint& pt)
|
||||
{
|
||||
m_selection = is_point_in_rect(pt, m_rect_lower_thumb) ? ssLower :
|
||||
is_point_in_rect(pt, m_rect_higher_thumb) ? ssHigher : ssUndef;
|
||||
if (is_point_in_rect(pt, m_rect_lower_thumb))
|
||||
m_selection = ssLower;
|
||||
else if(is_point_in_rect(pt, m_rect_higher_thumb))
|
||||
m_selection = ssHigher;
|
||||
else
|
||||
return false; // pt doesn't referenced to any thumb
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Control::is_point_in_rect(const wxPoint& pt, const wxRect& rect)
|
||||
@@ -880,7 +904,7 @@ void Control::OnLeftDown(wxMouseEvent& event)
|
||||
m_mouse = maOneLayerIconClick;
|
||||
else if (is_point_in_rect(pos, m_rect_cog_icon))
|
||||
m_mouse = maCogIconClick;
|
||||
else if (m_is_enabled_tick_manipulation)
|
||||
else if (m_draw_mode == dmRegular)
|
||||
{
|
||||
if (is_point_in_rect(pos, m_rect_tick_action)) {
|
||||
auto it = m_ticks.ticks.find(TickCode{ m_selection == ssLower ? m_lower_value : m_higher_value });
|
||||
@@ -890,6 +914,9 @@ void Control::OnLeftDown(wxMouseEvent& event)
|
||||
m_mouse = maRevertIconClick;
|
||||
}
|
||||
|
||||
if (m_mouse == maNone)
|
||||
detect_selected_slider(pos);
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
@@ -931,6 +958,8 @@ wxString Control::get_tooltip(int tick/*=-1*/)
|
||||
if (m_focus == fiColorBand)
|
||||
return m_mode != t_mode::SingleExtruder ? "" :
|
||||
_(L("Edit current color - Right click the colored slider segment"));
|
||||
if (m_draw_mode == dmSlaPrint)
|
||||
return ""; // no drawn ticks and no tooltips for them in SlaPrinting mode
|
||||
|
||||
wxString tooltip;
|
||||
const auto tick_code_it = m_ticks.ticks.find(TickCode{tick});
|
||||
@@ -953,9 +982,9 @@ wxString Control::get_tooltip(int tick/*=-1*/)
|
||||
// Show list of actions with new tick
|
||||
tooltip += ( m_mode == t_mode::MultiAsSingle ?
|
||||
_(L("Add extruder change - Left click")) :
|
||||
m_mode == t_mode::SingleExtruder ?
|
||||
_(L("Add color change - Left click for predefined color or"
|
||||
"Shift + Left click for custom color selection")) :
|
||||
m_mode == t_mode::SingleExtruder ?
|
||||
_(L("Add color change - Left click for predefined color or "
|
||||
"Shift + Left click for custom color selection")) :
|
||||
_(L("Add color change - Left click")) ) + " " +
|
||||
_(L("or press \"+\" key")) + "\n" + (
|
||||
is_osx ?
|
||||
@@ -965,18 +994,23 @@ wxString Control::get_tooltip(int tick/*=-1*/)
|
||||
|
||||
if (tick_code_it != m_ticks.ticks.end()) // tick exists
|
||||
{
|
||||
if (m_draw_mode == dmSequentialFffPrint)
|
||||
return _(L("The sequential print is on.\n"
|
||||
"It's impossible to apply any custom G-code for objects printing sequentually.\n"
|
||||
"This code won't be processed during G-code generation."));
|
||||
|
||||
// Show custom Gcode as a first string of tooltop
|
||||
tooltip = " ";
|
||||
tooltip += tick_code_it->gcode == ColorChangeCode ? (
|
||||
m_mode == t_mode::SingleExtruder ?
|
||||
tooltip += tick_code_it->gcode == ColorChangeCode ? ( m_mode == t_mode::SingleExtruder ?
|
||||
from_u8((boost::format(_utf8(L("Color change (\"%1%\")"))) % tick_code_it->gcode ).str()) :
|
||||
from_u8((boost::format(_utf8(L("Color change (\"%1%\") for Extruder %2%"))) %
|
||||
tick_code_it->gcode % tick_code_it->extruder).str()) ) :
|
||||
tick_code_it->gcode % tick_code_it->extruder).str()) ) :
|
||||
tick_code_it->gcode == PausePrintCode ?
|
||||
from_u8((boost::format(_utf8(L("Pause print (\"%1%\")"))) % tick_code_it->gcode ).str()) :
|
||||
from_u8((boost::format(_utf8(L("Pause print (\"%1%\")"))) % tick_code_it->gcode ).str()) :
|
||||
tick_code_it->gcode == ToolChangeCode ?
|
||||
from_u8((boost::format(_utf8(L("Extruder (tool) is changed to Extruder \"%1%\""))) % tick_code_it->extruder ).str()) :
|
||||
from_u8((boost::format(_utf8(L("\"%1%\""))) % tick_code_it->gcode ).str()) ;
|
||||
from_u8((boost::format(_utf8(L("Extruder (tool) is changed to Extruder \"%1%\""))) %
|
||||
tick_code_it->extruder ).str()) :
|
||||
from_u8(tick_code_it->gcode);
|
||||
|
||||
// If tick is marked as a conflict (exclamation icon),
|
||||
// we should to explain why
|
||||
@@ -1031,11 +1065,7 @@ void Control::OnMotion(wxMouseEvent& event)
|
||||
const wxPoint pos = event.GetLogicalPosition(wxClientDC(this));
|
||||
int tick = -1;
|
||||
|
||||
/* Note: Checking "!m_is_one_layer" is commented now because of
|
||||
* it looks like unnecessary and cause a tooltip "One layer" showing when OneLayerLock is on
|
||||
* #ysFIXME : Delete it after testing
|
||||
* */
|
||||
if (!m_is_left_down/* && !m_is_one_layer*/)
|
||||
if (!m_is_left_down && !m_is_right_down)
|
||||
{
|
||||
if (is_point_in_rect(pos, m_rect_one_layer_icon))
|
||||
m_focus = fiOneLayerIcon;
|
||||
@@ -1094,6 +1124,8 @@ void Control::append_change_extruder_menu_item(wxMenu* menu, bool switch_current
|
||||
{
|
||||
std::array<int, 2> active_extruders = get_active_extruders_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value);
|
||||
|
||||
std::vector<wxBitmap*> icons = get_extruder_color_icons(true);
|
||||
|
||||
wxMenu* change_extruder_menu = new wxMenu();
|
||||
|
||||
for (int i = 1; i <= extruders_cnt; i++)
|
||||
@@ -1104,7 +1136,7 @@ void Control::append_change_extruder_menu_item(wxMenu* menu, bool switch_current
|
||||
|
||||
if (m_mode == t_mode::MultiAsSingle)
|
||||
append_menu_item(change_extruder_menu, wxID_ANY, item_name, "",
|
||||
[this, i](wxCommandEvent&) { add_code_as_tick(ToolChangeCode, i); }, "", menu,
|
||||
[this, i](wxCommandEvent&) { add_code_as_tick(ToolChangeCode, i); }, *icons[i-1], menu,
|
||||
[is_active_extruder]() { return !is_active_extruder; }, GUI::wxGetApp().plater());
|
||||
}
|
||||
|
||||
@@ -1169,7 +1201,7 @@ void Control::OnLeftUp(wxMouseEvent& event)
|
||||
add_current_tick();
|
||||
break;
|
||||
case maCogIconClick :
|
||||
if (m_mode == t_mode::MultiAsSingle)
|
||||
if (m_mode == t_mode::MultiAsSingle && m_draw_mode == dmRegular)
|
||||
show_cog_icon_context_menu();
|
||||
else
|
||||
jump_to_print_z();
|
||||
@@ -1320,23 +1352,19 @@ void Control::OnRightDown(wxMouseEvent& event)
|
||||
const wxPoint pos = event.GetLogicalPosition(wxClientDC(this));
|
||||
|
||||
m_mouse = maNone;
|
||||
if (m_is_enabled_tick_manipulation) {
|
||||
if (m_draw_mode == dmRegular) {
|
||||
if (is_point_in_rect(pos, m_rect_tick_action))
|
||||
{
|
||||
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
|
||||
m_mouse = m_ticks.ticks.find(TickCode{ tick }) == m_ticks.ticks.end() ?
|
||||
maAddMenu : maEditMenu;
|
||||
}
|
||||
else if (m_mode == t_mode::SingleExtruder && is_point_in_rect(pos, get_colored_band_rect()))
|
||||
else if (m_mode == t_mode::SingleExtruder && !detect_selected_slider(pos) && is_point_in_rect(pos, get_colored_band_rect()))
|
||||
m_mouse = maForceColorEdit;
|
||||
else if (m_mode == t_mode::MultiAsSingle && is_point_in_rect(pos, m_rect_cog_icon))
|
||||
m_mouse = maCogIconMenu;
|
||||
}
|
||||
if (m_mouse != maNone)
|
||||
return;
|
||||
|
||||
detect_selected_slider(pos);
|
||||
if (!m_selection)
|
||||
if (m_mouse != maNone || !detect_selected_slider(pos))
|
||||
return;
|
||||
|
||||
if (m_selection == ssLower)
|
||||
@@ -1619,7 +1647,7 @@ static std::string get_pause_print_msg(const std::string& msg_in, double height)
|
||||
|
||||
static double get_print_z_to_jump(double active_print_z, double min_z, double max_z)
|
||||
{
|
||||
wxString msg_text = _(L("Enter the height you want to jump to")) + " :";
|
||||
wxString msg_text = _(L("Enter the height you want to jump to")) + ":";
|
||||
wxString msg_header = _(L("Jump to height"));
|
||||
wxString msg_in = GUI::double_to_string(active_print_z);
|
||||
|
||||
@@ -1766,15 +1794,16 @@ void Control::discard_all_thicks()
|
||||
void Control::move_current_thumb_to_pos(wxPoint pos)
|
||||
{
|
||||
const int tick_val = get_tick_near_point(pos);
|
||||
const int mouse_val = tick_val >= 0 && m_is_enabled_tick_manipulation ? tick_val :
|
||||
const int mouse_val = tick_val >= 0 && m_draw_mode == dmRegular ? tick_val :
|
||||
get_value_from_position(pos);
|
||||
if (mouse_val >= 0)
|
||||
{
|
||||
// if (abs(mouse_val - m_lower_value) < abs(mouse_val - m_higher_value)) {
|
||||
if (mouse_val <= m_lower_value) {
|
||||
// if (mouse_val <= m_lower_value) {
|
||||
if (m_selection == ssLower) {
|
||||
SetLowerValue(mouse_val);
|
||||
correct_lower_value();
|
||||
m_selection = ssLower;
|
||||
// m_selection = ssLower;
|
||||
}
|
||||
else {
|
||||
SetHigherValue(mouse_val);
|
||||
@@ -1801,15 +1830,13 @@ void Control::edit_extruder_sequence()
|
||||
int extruder = 0;
|
||||
const int extr_cnt = m_extruders_sequence.extruders.size();
|
||||
|
||||
std::vector<std::string> colors = GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
|
||||
|
||||
while (tick <= m_max_value)
|
||||
{
|
||||
const int cur_extruder = m_extruders_sequence.extruders[extruder];
|
||||
|
||||
bool meaningless_tick = tick == 0.0 && cur_extruder == extruder;
|
||||
if (!meaningless_tick)
|
||||
m_ticks.ticks.emplace(TickCode{tick, ToolChangeCode, cur_extruder + 1, colors[cur_extruder]});
|
||||
m_ticks.ticks.emplace(TickCode{tick, ToolChangeCode, cur_extruder + 1, m_extruder_colors[cur_extruder]});
|
||||
|
||||
extruder++;
|
||||
if (extruder == extr_cnt)
|
||||
@@ -1869,8 +1896,8 @@ bool Control::check_ticks_changed_event(const std::string& gcode)
|
||||
return true;
|
||||
|
||||
wxString message = (m_ticks.mode == t_mode::SingleExtruder ?
|
||||
_(L("The last color change data was saved for a single extruder printer profile.")) :
|
||||
_(L("The last color change data was saved for a multiple extruder printer profile."))
|
||||
_(L("The last color change data was saved for a single extruder printing.")) :
|
||||
_(L("The last color change data was saved for a multi extruder printing."))
|
||||
) + "\n" +
|
||||
_(L("Your current changes will delete all saved color changes.")) + "\n\n\t" +
|
||||
_(L("Are you sure you want to continue?"));
|
||||
@@ -1889,7 +1916,7 @@ bool Control::check_ticks_changed_event(const std::string& gcode)
|
||||
_(L("The last color change data was saved for a multi extruder printing.")) + "\n\n" +
|
||||
_(L("Select YES if you want to delete all saved tool changes, \n\t"
|
||||
"NO if you want all tool changes switch to color changes, \n\t"
|
||||
"or CANCEL to leave it unchanged")) + "\n\n\t" +
|
||||
"or CANCEL to leave it unchanged.")) + "\n\n\t" +
|
||||
_(L("Do you want to delete all saved tool changes?"))
|
||||
) : ( // t_mode::MultiExtruder
|
||||
_(L("The last color change data was saved for a multi extruder printing with tool changes for whole print.")) + "\n\n" +
|
||||
@@ -1924,8 +1951,7 @@ std::string TickCodeInfo::get_color_for_tick(TickCode tick, const std::string& c
|
||||
return colors[m_default_color_idx % colors.size()];
|
||||
}
|
||||
|
||||
std::vector<std::string> colors = GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
|
||||
std::string color = colors[extruder - 1];
|
||||
std::string color = (*m_colors)[extruder - 1];
|
||||
|
||||
if (code == ColorChangeCode)
|
||||
{
|
||||
|
||||
@@ -66,6 +66,13 @@ enum MouseAction
|
||||
maRevertIconClick, // LeftMouseClick on "revert" icon
|
||||
};
|
||||
|
||||
enum DrawMode
|
||||
{
|
||||
dmRegular,
|
||||
dmSlaPrint,
|
||||
dmSequentialFffPrint,
|
||||
};
|
||||
|
||||
using t_mode = CustomGCode::Mode;
|
||||
|
||||
struct TickCode
|
||||
@@ -88,6 +95,8 @@ class TickCodeInfo
|
||||
bool m_use_default_colors= false;
|
||||
int m_default_color_idx = 0;
|
||||
|
||||
std::vector<std::string>* m_colors {nullptr};
|
||||
|
||||
std::string get_color_for_tick(TickCode tick, const std::string& code, const int extruder);
|
||||
|
||||
public:
|
||||
@@ -115,6 +124,8 @@ public:
|
||||
bool suppressed_plus () { return m_suppress_plus; }
|
||||
bool suppressed_minus() { return m_suppress_minus; }
|
||||
void set_default_colors(bool default_colors_on) { m_use_default_colors = default_colors_on; }
|
||||
|
||||
void set_extruder_colors(std::vector<std::string>* extruder_colors) { m_colors = extruder_colors; }
|
||||
};
|
||||
|
||||
|
||||
@@ -197,12 +208,12 @@ public:
|
||||
CustomGCode::Info GetTicksValues() const;
|
||||
void SetTicksValues(const Slic3r::CustomGCode::Info &custom_gcode_per_print_z);
|
||||
|
||||
void EnableTickManipulation(bool enable = true) { m_is_enabled_tick_manipulation = enable; }
|
||||
void DisableTickManipulation() { EnableTickManipulation(false); }
|
||||
void SetDrawMode(bool is_sla_print, bool is_sequential_print);
|
||||
|
||||
void SetManipulationMode(t_mode mode) { m_mode = mode; }
|
||||
t_mode GetManipulationMode() const { return m_mode; }
|
||||
void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder);
|
||||
void SetExtruderColors(const std::vector<std::string>& extruder_colors);
|
||||
|
||||
bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; }
|
||||
bool is_one_layer() const { return m_is_one_layer; }
|
||||
@@ -261,7 +272,7 @@ protected:
|
||||
void draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const;
|
||||
|
||||
void update_thumb_rect(const wxCoord& begin_x, const wxCoord& begin_y, const SelectedSlider& selection);
|
||||
void detect_selected_slider(const wxPoint& pt);
|
||||
bool detect_selected_slider(const wxPoint& pt);
|
||||
void correct_lower_value();
|
||||
void correct_higher_value();
|
||||
void move_current_thumb(const bool condition);
|
||||
@@ -323,9 +334,10 @@ private:
|
||||
bool m_is_right_down = false;
|
||||
bool m_is_one_layer = false;
|
||||
bool m_is_focused = false;
|
||||
bool m_is_enabled_tick_manipulation = true;
|
||||
bool m_force_mode_apply = true;
|
||||
|
||||
DrawMode m_draw_mode = dmRegular;
|
||||
|
||||
t_mode m_mode = t_mode::SingleExtruder;
|
||||
int m_only_extruder = -1;
|
||||
|
||||
@@ -350,6 +362,8 @@ private:
|
||||
std::vector<double> m_values;
|
||||
TickCodeInfo m_ticks;
|
||||
|
||||
std::vector<std::string> m_extruder_colors;
|
||||
|
||||
// control's view variables
|
||||
wxCoord SLIDER_MARGIN; // margin around slider
|
||||
|
||||
|
||||
@@ -79,6 +79,11 @@ void Field::PostInitialize()
|
||||
BUILD();
|
||||
}
|
||||
|
||||
// Values of width to alignments of fields
|
||||
int Field::def_width() { return wxOSX ? 8 : 7; }
|
||||
int Field::def_width_wider() { return 14; }
|
||||
int Field::def_width_thinner() { return 4; }
|
||||
|
||||
void Field::on_kill_focus()
|
||||
{
|
||||
// call the registered function if it is available
|
||||
@@ -240,6 +245,8 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
|
||||
set_value(wxString::Format("%s%%", stVal), false/*true*/);
|
||||
str += "%%";
|
||||
}
|
||||
else
|
||||
set_value(stVal, false); // it's no needed but can be helpful, when inputted value contained "," instead of "."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,14 +374,23 @@ void TextCtrl::BUILD() {
|
||||
temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent& e)
|
||||
{
|
||||
e.Skip();
|
||||
#ifdef __WXOSX__
|
||||
// OSX issue: For some unknown reason wxEVT_KILL_FOCUS is emitted twice in a row
|
||||
// Thus, suppress its second call
|
||||
if (bKilledFocus) {
|
||||
bKilledFocus = false;
|
||||
return;
|
||||
}
|
||||
bKilledFocus = true;
|
||||
#endif // __WXOSX__
|
||||
|
||||
#if !defined(__WXGTK__)
|
||||
temp->GetToolTip()->Enable(true);
|
||||
#endif // __WXGTK__
|
||||
if (bEnterPressed) {
|
||||
if (bEnterPressed)
|
||||
bEnterPressed = false;
|
||||
return;
|
||||
}
|
||||
propagate_value();
|
||||
else
|
||||
propagate_value();
|
||||
}), temp->GetId());
|
||||
|
||||
// select all text using Ctrl+A
|
||||
@@ -423,10 +439,12 @@ bool TextCtrl::value_was_changed()
|
||||
|
||||
void TextCtrl::propagate_value()
|
||||
{
|
||||
if (is_defined_input_value<wxTextCtrl>(window, m_opt.type) && value_was_changed())
|
||||
on_change_field();
|
||||
else
|
||||
if (!is_defined_input_value<wxTextCtrl>(window, m_opt.type) )
|
||||
// on_kill_focus() cause a call of OptionsGroup::reload_config(),
|
||||
// Thus, do it only when it's really needed (when undefined value was input)
|
||||
on_kill_focus();
|
||||
else if (value_was_changed())
|
||||
on_change_field();
|
||||
}
|
||||
|
||||
void TextCtrl::set_value(const boost::any& value, bool change_event/* = false*/) {
|
||||
|
||||
@@ -225,10 +225,10 @@ public:
|
||||
bool get_enter_pressed() const { return bEnterPressed; }
|
||||
void set_enter_pressed(bool pressed) { bEnterPressed = pressed; }
|
||||
|
||||
// Values of width to "systematic" alignments of fields
|
||||
static int def_width() { return 7; }
|
||||
static int def_width_wider() { return 14; }
|
||||
static int def_width_thinner() { return 4; }
|
||||
// Values of width to alignments of fields
|
||||
static int def_width() ;
|
||||
static int def_width_wider() ;
|
||||
static int def_width_thinner() ;
|
||||
|
||||
protected:
|
||||
RevertButton* m_Undo_btn = nullptr;
|
||||
@@ -274,6 +274,11 @@ class TextCtrl : public Field {
|
||||
bool bChangedValueEvent = true;
|
||||
void change_field_value(wxEvent& event);
|
||||
#endif //__WXGTK__
|
||||
|
||||
#ifdef __WXOSX__
|
||||
bool bKilledFocus = false;
|
||||
#endif // __WXOSX__
|
||||
|
||||
public:
|
||||
TextCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
|
||||
TextCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
|
||||
|
||||
@@ -274,7 +274,7 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted(_(L("Higher print quality versus higher print speed.")));
|
||||
ImGui::TextUnformatted(_(L("Higher print quality versus higher print speed.")).ToUTF8());
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
@@ -734,7 +734,7 @@ static void msw_disable_cleartype(wxFont &font)
|
||||
++ startpos_weight;
|
||||
size_t endpos_weight = font_desc.find(sep, startpos_weight);
|
||||
// Parse the weight field.
|
||||
unsigned int weight = atoi(font_desc(startpos_weight, endpos_weight - startpos_weight));
|
||||
unsigned int weight = wxAtoi(font_desc(startpos_weight, endpos_weight - startpos_weight));
|
||||
size_t startpos = endpos_weight;
|
||||
for (size_t i = 0; i < 6; ++ i)
|
||||
startpos = font_desc.find(sep, startpos + 1);
|
||||
@@ -982,12 +982,17 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
|
||||
cp_legend_items.emplace_back(I18N::translate_utf8(L("Pause print or custom G-code")));
|
||||
|
||||
int cnt = custom_gcode_per_print_z.size();
|
||||
int color_change_idx = color_cnt - extruders_cnt;
|
||||
for (int i = cnt-1; i >= 0; --i)
|
||||
if (custom_gcode_per_print_z[i].gcode == ColorChangeCode) {
|
||||
::memcpy((void*)(colors.data() + color_pos), (const void*)(colors_in.data() + color_in_pos), 4 * sizeof(float));
|
||||
color_pos += 4;
|
||||
color_in_pos -= 4;
|
||||
cp_legend_items.emplace_back((boost::format(I18N::translate_utf8(L("Color change for Extruder %d at %.2f mm"))) % custom_gcode_per_print_z[i].extruder % custom_gcode_per_print_z[i].print_z).str());
|
||||
|
||||
// create label for color change item
|
||||
std::string id_str = std::to_string(color_change_idx--) + ": ";
|
||||
|
||||
cp_legend_items.emplace_back(id_str + (boost::format(I18N::translate_utf8(L("Color change for Extruder %d at %.2f mm"))) % custom_gcode_per_print_z[i].extruder % custom_gcode_per_print_z[i].print_z).str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1297,7 +1302,7 @@ void GLCanvas3D::Labels::render(const std::vector<const ModelInstance*>& sorted_
|
||||
return owner.model_instance_id == id;
|
||||
});
|
||||
if (it != owners.end())
|
||||
it->print_order = _(L("Seq.")) + "#: " + std::to_string(i + 1);
|
||||
it->print_order = std::string((_(L("Seq."))).ToUTF8()) + "#: " + std::to_string(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3465,13 +3470,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
// if dragging over blank area with left button, rotate
|
||||
if (m_hover_volume_idxs.empty() && m_mouse.is_start_position_3D_defined())
|
||||
{
|
||||
const Vec3d& orig = m_mouse.drag.start_position_3D;
|
||||
double x = Geometry::deg2rad(pos(0) - orig(0)) * (double)TRACKBALLSIZE;
|
||||
double y = Geometry::deg2rad(pos(1) - orig(1)) * (double)TRACKBALLSIZE;
|
||||
const Vec3d rot = (Vec3d(pos.x(), pos.y(), 0.) - m_mouse.drag.start_position_3D) * (PI * TRACKBALLSIZE / 180.);
|
||||
if (wxGetApp().plater()->get_mouse3d_controller().is_running() || (wxGetApp().app_config->get("use_free_camera") == "1"))
|
||||
m_camera.rotate_local_around_target(Vec3d(y, x, 0.0));
|
||||
// Virtual track ball (similar to the 3DConnexion mouse).
|
||||
m_camera.rotate_local_around_target(Vec3d(rot.y(), rot.x(), 0.));
|
||||
else
|
||||
m_camera.rotate_on_sphere(x, y, wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
|
||||
m_camera.rotate_on_sphere(rot.x(), rot.y(), wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
|
||||
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
// Part of temporary hack to remove crash when closing on OSX 10.9.5
|
||||
#include <wx/platinfo.h>
|
||||
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include "../Utils/MacDarkMode.hpp"
|
||||
#endif // __APPLE__
|
||||
@@ -111,6 +116,9 @@ void GLCanvas3DManager::GLInfo::detect() const
|
||||
|
||||
m_max_tex_size /= 2;
|
||||
|
||||
if (Slic3r::total_physical_memory() / (1024 * 1024 * 1024) < 6)
|
||||
m_max_tex_size /= 2;
|
||||
|
||||
if (GLEW_EXT_texture_filter_anisotropic)
|
||||
glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &m_max_anisotropy));
|
||||
|
||||
@@ -192,6 +200,11 @@ GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas
|
||||
bool GLCanvas3DManager::s_compressed_textures_supported = false;
|
||||
GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::FB_None;
|
||||
GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info;
|
||||
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
#ifdef __APPLE__
|
||||
GLCanvas3DManager::OSInfo GLCanvas3DManager::s_os_info;
|
||||
#endif // __APPLE__
|
||||
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
|
||||
GLCanvas3DManager::GLCanvas3DManager()
|
||||
: m_context(nullptr)
|
||||
@@ -223,6 +236,15 @@ bool GLCanvas3DManager::add(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLTo
|
||||
m_context = new wxGLContext(canvas);
|
||||
if (m_context == nullptr)
|
||||
return false;
|
||||
|
||||
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
#ifdef __APPLE__
|
||||
// Part of temporary hack to remove crash when closing on OSX 10.9.5
|
||||
s_os_info.major = wxPlatformInfo::Get().GetOSMajorVersion();
|
||||
s_os_info.minor = wxPlatformInfo::Get().GetOSMinorVersion();
|
||||
s_os_info.micro = wxPlatformInfo::Get().GetOSMicroVersion();
|
||||
#endif //__APPLE__
|
||||
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
}
|
||||
|
||||
canvas3D->set_context(m_context);
|
||||
@@ -307,6 +329,15 @@ void GLCanvas3DManager::destroy()
|
||||
{
|
||||
if (m_context != nullptr)
|
||||
{
|
||||
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
#ifdef __APPLE__
|
||||
// this is a temporary ugly hack to solve the crash happening when closing the application on OSX 10.9.5
|
||||
// the crash is inside wxGLContext destructor
|
||||
if (s_os_info.major == 10 && s_os_info.minor == 9 && s_os_info.micro == 5)
|
||||
return;
|
||||
#endif //__APPLE__
|
||||
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
|
||||
delete m_context;
|
||||
m_context = nullptr;
|
||||
}
|
||||
|
||||
@@ -68,6 +68,17 @@ public:
|
||||
void detect() const;
|
||||
};
|
||||
|
||||
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
#ifdef __APPLE__
|
||||
struct OSInfo
|
||||
{
|
||||
int major{ 0 };
|
||||
int minor{ 0 };
|
||||
int micro{ 0 };
|
||||
};
|
||||
#endif //__APPLE__
|
||||
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
|
||||
private:
|
||||
enum EMultisampleState : unsigned char
|
||||
{
|
||||
@@ -81,6 +92,11 @@ private:
|
||||
CanvasesMap m_canvases;
|
||||
wxGLContext* m_context;
|
||||
static GLInfo s_gl_info;
|
||||
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
#ifdef __APPLE__
|
||||
static OSInfo s_os_info;
|
||||
#endif //__APPLE__
|
||||
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
bool m_gl_initialized;
|
||||
static EMultisampleState s_multisample;
|
||||
static bool s_compressed_textures_supported;
|
||||
|
||||
+14
-2
@@ -229,18 +229,30 @@ void show_error(wxWindow* parent, const wxString& message)
|
||||
msg.ShowModal();
|
||||
}
|
||||
|
||||
void show_error(wxWindow* parent, const char* message)
|
||||
{
|
||||
assert(message);
|
||||
show_error(parent, wxString::FromUTF8(message));
|
||||
}
|
||||
|
||||
void show_error_id(int id, const std::string& message)
|
||||
{
|
||||
auto *parent = id != 0 ? wxWindow::FindWindowById(id) : nullptr;
|
||||
show_error(parent, from_u8(message));
|
||||
show_error(parent, message);
|
||||
}
|
||||
|
||||
void show_info(wxWindow* parent, const wxString& message, const wxString& title)
|
||||
{
|
||||
wxMessageDialog msg_wingow(parent, message, title.empty() ? _(L("Notice")) : title, wxOK | wxICON_INFORMATION);
|
||||
wxMessageDialog msg_wingow(parent, message, wxString(SLIC3R_APP_NAME " - ") + (title.empty() ? _(L("Notice")) : title), wxOK | wxICON_INFORMATION);
|
||||
msg_wingow.ShowModal();
|
||||
}
|
||||
|
||||
void show_info(wxWindow* parent, const char* message, const char* title)
|
||||
{
|
||||
assert(message);
|
||||
show_info(parent, wxString::FromUTF8(message), title ? wxString::FromUTF8(title) : wxString());
|
||||
}
|
||||
|
||||
void warning_catcher(wxWindow* parent, const wxString& message)
|
||||
{
|
||||
wxMessageDialog msg(parent, message, _(L("Warning")), wxOK | wxICON_WARNING);
|
||||
|
||||
@@ -39,8 +39,12 @@ extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_
|
||||
void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0);
|
||||
|
||||
void show_error(wxWindow* parent, const wxString& message);
|
||||
void show_error(wxWindow* parent, const char* message);
|
||||
inline void show_error(wxWindow* parent, const std::string& message) { show_error(parent, message.c_str()); }
|
||||
void show_error_id(int id, const std::string& message); // For Perl
|
||||
void show_info(wxWindow* parent, const wxString& message, const wxString& title);
|
||||
void show_info(wxWindow* parent, const wxString& message, const wxString& title = wxString());
|
||||
void show_info(wxWindow* parent, const char* message, const char* title = nullptr);
|
||||
inline void show_info(wxWindow* parent, const std::string& message,const std::string& title = std::string()) { show_info(parent, message.c_str(), title.c_str()); }
|
||||
void warning_catcher(wxWindow* parent, const wxString& message);
|
||||
|
||||
// Creates a wxCheckListBoxComboPopup inside the given wxComboCtrl, filled with the given text and items.
|
||||
|
||||
@@ -187,8 +187,8 @@ bool GUI_App::on_init_inner()
|
||||
wxString::Format("Resources path does not exist or is not a directory: %s", resources_dir));
|
||||
|
||||
// Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release.
|
||||
// SetAppName(SLIC3R_APP_KEY);
|
||||
SetAppName(SLIC3R_APP_KEY "-alpha");
|
||||
SetAppName(SLIC3R_APP_KEY);
|
||||
// SetAppName(SLIC3R_APP_KEY "-beta");
|
||||
SetAppDisplayName(SLIC3R_APP_NAME);
|
||||
|
||||
// Enable this to get the default Win32 COMCTRL32 behavior of static boxes.
|
||||
@@ -244,7 +244,7 @@ bool GUI_App::on_init_inner()
|
||||
try {
|
||||
preset_bundle->load_presets(*app_config);
|
||||
} catch (const std::exception &ex) {
|
||||
show_error(nullptr, from_u8(ex.what()));
|
||||
show_error(nullptr, ex.what());
|
||||
}
|
||||
|
||||
register_dpi_event();
|
||||
@@ -332,7 +332,11 @@ unsigned GUI_App::get_colour_approx_luma(const wxColour &colour)
|
||||
bool GUI_App::dark_mode()
|
||||
{
|
||||
#if __APPLE__
|
||||
return mac_dark_mode();
|
||||
// The check for dark mode returns false positive on 10.12 and 10.13,
|
||||
// which allowed setting dark menu bar and dock area, which is
|
||||
// is detected as dark mode. We must run on at least 10.14 where the
|
||||
// proper dark mode was first introduced.
|
||||
return wxPlatformInfo::Get().CheckOSVersion(10, 14) && mac_dark_mode();
|
||||
#else
|
||||
const unsigned luma = get_colour_approx_luma(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
||||
return luma < 128;
|
||||
@@ -754,7 +758,7 @@ Tab* GUI_App::get_tab(Preset::Type type)
|
||||
{
|
||||
for (Tab* tab: tabs_list)
|
||||
if (tab->type() == type)
|
||||
return tab->complited() ? tab : nullptr; // To avoid actions with no-completed Tab
|
||||
return tab->completed() ? tab : nullptr; // To avoid actions with no-completed Tab
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -793,7 +797,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
|
||||
auto local_menu = new wxMenu();
|
||||
wxWindowID config_id_base = wxWindow::NewControlId(int(ConfigMenuCnt));
|
||||
|
||||
const auto config_wizard_name = _(ConfigWizard::name(true).wx_str());
|
||||
const auto config_wizard_name = _(ConfigWizard::name(true));
|
||||
const auto config_wizard_tooltip = wxString::Format(_(L("Run %s")), config_wizard_name);
|
||||
// Cmd+, is standard on OS X - what about other operating systems?
|
||||
local_menu->Append(config_id_base + ConfigMenuWizard, config_wizard_name + dots, config_wizard_tooltip);
|
||||
@@ -819,7 +823,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
|
||||
|
||||
local_menu->AppendSubMenu(mode_menu, _(L("Mode")), wxString::Format(_(L("%s View Mode")), SLIC3R_APP_NAME));
|
||||
local_menu->AppendSeparator();
|
||||
local_menu->Append(config_id_base + ConfigMenuLanguage, _(L("Change Application &Language")));
|
||||
local_menu->Append(config_id_base + ConfigMenuLanguage, _(L("&Language")));
|
||||
local_menu->AppendSeparator();
|
||||
local_menu->Append(config_id_base + ConfigMenuFlashFirmware, _(L("Flash printer &firmware")), _(L("Upload a firmware image into an Arduino based printer")));
|
||||
// TODO: for when we're able to flash dictionaries
|
||||
@@ -1241,7 +1245,7 @@ void GUI_App::check_updates(const bool verbose)
|
||||
}
|
||||
}
|
||||
catch (const std::exception & ex) {
|
||||
show_error(nullptr, from_u8(ex.what()));
|
||||
show_error(nullptr, ex.what());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -77,7 +77,9 @@ static int extruders_count()
|
||||
|
||||
static void take_snapshot(const wxString& snapshot_name)
|
||||
{
|
||||
wxGetApp().plater()->take_snapshot(snapshot_name);
|
||||
Plater* plater = wxGetApp().plater();
|
||||
if (plater)
|
||||
plater->take_snapshot(snapshot_name);
|
||||
}
|
||||
|
||||
ObjectList::ObjectList(wxWindow* parent) :
|
||||
@@ -287,6 +289,7 @@ void ObjectList::create_objects_ctrl()
|
||||
GetColumn(colName)->SetWidth(20*em);
|
||||
GetColumn(colPrint)->SetWidth(3*em);
|
||||
GetColumn(colExtruder)->SetWidth(8*em);
|
||||
GetColumn(colEditing) ->SetWidth(7*em);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1541,7 +1544,8 @@ wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)
|
||||
// If there are selected more then one instance but not all of them
|
||||
// don't add settings menu items
|
||||
const Selection& selection = scene_selection();
|
||||
if (selection.is_multiple_full_instance() && !selection.is_single_full_object())
|
||||
if (selection.is_multiple_full_instance() && !selection.is_single_full_object() ||
|
||||
selection.is_multiple_volume() || selection.is_mixed() ) // more than one volume(part) is selected on the scene
|
||||
return nullptr;
|
||||
|
||||
const auto sel_vol = get_selected_model_volume();
|
||||
@@ -1560,7 +1564,11 @@ wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)
|
||||
|
||||
// Add frequently settings
|
||||
const ItemType item_type = m_objects_model->GetItemType(GetSelection());
|
||||
const bool is_object_settings = item_type & itObject || item_type & itInstance || selection.is_single_full_object();
|
||||
if (item_type == itUndef && !selection.is_single_full_object())
|
||||
return nullptr;
|
||||
const bool is_object_settings = item_type & itObject || item_type & itInstance ||
|
||||
// multi-selection in ObjectList, but full_object in Selection
|
||||
(item_type == itUndef && selection.is_single_full_object());
|
||||
create_freq_settings_popupmenu(menu, is_object_settings);
|
||||
|
||||
if (mode == comAdvanced)
|
||||
@@ -1577,11 +1585,14 @@ wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)
|
||||
return menu->Append(menu_item);
|
||||
}
|
||||
|
||||
wxMenuItem* ObjectList::append_menu_item_change_type(wxMenu* menu)
|
||||
wxMenuItem* ObjectList::append_menu_item_change_type(wxMenu* menu, wxWindow* parent/* = nullptr*/)
|
||||
{
|
||||
return append_menu_item(menu, wxID_ANY, _(L("Change type")), "",
|
||||
[this](wxCommandEvent&) { change_part_type(); }, "", menu);
|
||||
|
||||
[this](wxCommandEvent&) { change_part_type(); }, "", menu,
|
||||
[this]() {
|
||||
wxDataViewItem item = GetSelection();
|
||||
return item.IsOk() || m_objects_model->GetItemType(item) == itVolume;
|
||||
}, parent);
|
||||
}
|
||||
|
||||
wxMenuItem* ObjectList::append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent)
|
||||
@@ -1656,35 +1667,51 @@ void ObjectList::append_menu_item_reload_from_disk(wxMenu* menu) const
|
||||
[]() { return wxGetApp().plater()->can_reload_from_disk(); }, wxGetApp().plater());
|
||||
}
|
||||
|
||||
void ObjectList::append_menu_item_change_extruder(wxMenu* menu) const
|
||||
void ObjectList::append_menu_item_change_extruder(wxMenu* menu)
|
||||
{
|
||||
const wxString name = _(L("Change extruder"));
|
||||
const std::vector<wxString> names = {_(L("Change extruder")), _(L("Set extruder for selected items")) };
|
||||
// Delete old menu item
|
||||
const int item_id = menu->FindItem(name);
|
||||
if (item_id != wxNOT_FOUND)
|
||||
menu->Destroy(item_id);
|
||||
for (const wxString& name : names) {
|
||||
const int item_id = menu->FindItem(name);
|
||||
if (item_id != wxNOT_FOUND)
|
||||
menu->Destroy(item_id);
|
||||
}
|
||||
|
||||
const int extruders_cnt = extruders_count();
|
||||
const wxDataViewItem item = GetSelection();
|
||||
if (item && extruders_cnt > 1)
|
||||
{
|
||||
DynamicPrintConfig& config = get_item_config(item);
|
||||
if (extruders_cnt <= 1)
|
||||
return;
|
||||
|
||||
const int initial_extruder = !config.has("extruder") ? 0 :
|
||||
config.option<ConfigOptionInt>("extruder")->value;
|
||||
wxDataViewItemArray sels;
|
||||
GetSelections(sels);
|
||||
if (sels.IsEmpty())
|
||||
return;
|
||||
|
||||
wxMenu* extruder_selection_menu = new wxMenu();
|
||||
std::vector<wxBitmap*> icons = get_extruder_color_icons(true);
|
||||
wxMenu* extruder_selection_menu = new wxMenu();
|
||||
const wxString& name = sels.Count()==1 ? names[0] : names[1];
|
||||
|
||||
for (int i = 0; i <= extruders_cnt; i++)
|
||||
{
|
||||
const wxString& item_name = i == 0 ? _(L("Default")) : wxString::Format("%d", i);
|
||||
|
||||
append_menu_radio_item(extruder_selection_menu, wxID_ANY, item_name, "",
|
||||
[this, i](wxCommandEvent&) { set_extruder_for_selected_items(i); }, menu)->Check(i == initial_extruder);
|
||||
}
|
||||
|
||||
menu->AppendSubMenu(extruder_selection_menu, name, _(L("Select new extruder for the object/part")));
|
||||
int initial_extruder = -1; // negative value for multiple object/part selection
|
||||
if (sels.Count()==1) {
|
||||
DynamicPrintConfig& config = get_item_config(sels[0]);
|
||||
initial_extruder = !config.has("extruder") ? 0 :
|
||||
config.option<ConfigOptionInt>("extruder")->value;
|
||||
}
|
||||
|
||||
for (int i = 0; i <= extruders_cnt; i++)
|
||||
{
|
||||
bool is_active_extruder = i == initial_extruder;
|
||||
int icon_idx = i == 0 ? 0 : i - 1;
|
||||
|
||||
const wxString& item_name = (i == 0 ? _(L("Default")) : wxString::Format(_(L("Extruder %d")), i)) +
|
||||
(is_active_extruder ? " (" + _(L("active")) + ")" : "");
|
||||
|
||||
append_menu_item(extruder_selection_menu, wxID_ANY, item_name, "",
|
||||
[this, i](wxCommandEvent&) { set_extruder_for_selected_items(i); }, *icons[icon_idx], menu,
|
||||
[is_active_extruder]() { return !is_active_extruder; }, GUI::wxGetApp().plater());
|
||||
|
||||
}
|
||||
|
||||
menu->AppendSubMenu(extruder_selection_menu, name);
|
||||
}
|
||||
|
||||
void ObjectList::append_menu_item_delete(wxMenu* menu)
|
||||
@@ -3159,7 +3186,9 @@ void ObjectList::update_selections()
|
||||
|
||||
for (auto obj_ins : objects_content_list) {
|
||||
if (obj_ins.first == glv_obj_idx) {
|
||||
if (obj_ins.second.find(glv_ins_idx) != obj_ins.second.end()) {
|
||||
if (obj_ins.second.find(glv_ins_idx) != obj_ins.second.end() &&
|
||||
!selection.is_from_single_instance() ) // a case when volumes of different types are selected
|
||||
{
|
||||
if (glv_ins_idx == 0 && (*m_objects)[glv_obj_idx]->instances.size() == 1)
|
||||
sels.Add(m_objects_model->GetItemById(glv_obj_idx));
|
||||
else
|
||||
@@ -3385,7 +3414,7 @@ bool ObjectList::check_last_selection(wxString& msg_str)
|
||||
(type & itInstance && !(m_selection_mode & smInstance))
|
||||
)
|
||||
{
|
||||
// Inform user why selection isn't complited
|
||||
// Inform user why selection isn't completed
|
||||
const wxString item_type = m_selection_mode & smInstance ? _(L("Object or Instance")) :
|
||||
m_selection_mode & smVolume ? _(L("Part")) : _(L("Layer"));
|
||||
|
||||
@@ -3905,7 +3934,9 @@ void ObjectList::OnEditingDone(wxDataViewEvent &event)
|
||||
m_last_selected_column = -1;
|
||||
#endif //__WXMSW__
|
||||
|
||||
wxGetApp().plater()->set_current_canvas_as_dirty();
|
||||
Plater* plater = wxGetApp().plater();
|
||||
if (plater)
|
||||
plater->set_current_canvas_as_dirty();
|
||||
}
|
||||
|
||||
void ObjectList::show_multi_selection_menu()
|
||||
@@ -3921,9 +3952,7 @@ void ObjectList::show_multi_selection_menu()
|
||||
wxMenu* menu = new wxMenu();
|
||||
|
||||
if (extruders_count() > 1)
|
||||
append_menu_item(menu, wxID_ANY, _(L("Set extruder for selected items")),
|
||||
_(L("Select extruder number for selected objects and/or parts")),
|
||||
[this](wxCommandEvent&) { extruder_selection(); }, "", menu);
|
||||
append_menu_item_change_extruder(menu);
|
||||
|
||||
append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected volumes from disk")),
|
||||
[this](wxCommandEvent&) { wxGetApp().plater()->reload_from_disk(); }, "", menu, []() {
|
||||
|
||||
@@ -241,14 +241,14 @@ public:
|
||||
wxMenuItem* append_menu_item_split(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_layers_editing(wxMenu* menu, wxWindow* parent);
|
||||
wxMenuItem* append_menu_item_settings(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_change_type(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_change_type(wxMenu* menu, wxWindow* parent = nullptr);
|
||||
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent);
|
||||
wxMenuItem* append_menu_item_printable(wxMenu* menu, wxWindow* parent);
|
||||
void append_menu_items_osx(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
|
||||
void append_menu_item_export_stl(wxMenu* menu) const;
|
||||
void append_menu_item_reload_from_disk(wxMenu* menu) const;
|
||||
void append_menu_item_change_extruder(wxMenu* menu) const;
|
||||
void append_menu_item_change_extruder(wxMenu* menu);
|
||||
void append_menu_item_delete(wxMenu* menu);
|
||||
void append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu);
|
||||
void create_object_popupmenu(wxMenu *menu);
|
||||
|
||||
@@ -595,7 +595,9 @@ void Preview::update_view_type(bool slice_completed)
|
||||
void Preview::create_double_slider()
|
||||
{
|
||||
m_slider = new DoubleSlider::Control(this, wxID_ANY, 0, 0, 0, 100);
|
||||
m_slider->EnableTickManipulation(wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF);
|
||||
bool sla_print_technology = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA;
|
||||
bool sequential_print = wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_bool("complete_objects");
|
||||
m_slider->SetDrawMode(sla_print_technology, sequential_print);
|
||||
|
||||
m_double_slider_sizer->Add(m_slider, 0, wxEXPAND, 0);
|
||||
|
||||
@@ -709,7 +711,11 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool kee
|
||||
|
||||
m_slider->SetTicksValues(ticks_info_from_model);
|
||||
|
||||
m_slider->EnableTickManipulation(wxGetApp().plater()->printer_technology() == ptFFF);
|
||||
bool sla_print_technology = wxGetApp().plater()->printer_technology() == ptSLA;
|
||||
bool sequential_print = wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_bool("complete_objects");
|
||||
m_slider->SetDrawMode(sla_print_technology, sequential_print);
|
||||
|
||||
m_slider->SetExtruderColors(wxGetApp().plater()->get_extruder_colors_from_plater_config());
|
||||
}
|
||||
|
||||
void Preview::update_double_slider_mode()
|
||||
|
||||
@@ -112,6 +112,9 @@ int get_dpi_for_window(wxWindow *window)
|
||||
#elif defined __APPLE__
|
||||
// TODO
|
||||
return DPI_DEFAULT;
|
||||
#else // freebsd and others
|
||||
// TODO
|
||||
return DPI_DEFAULT;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
#include "slic3r/GUI/MeshUtils.hpp"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -138,7 +134,7 @@ void GLGizmoBase::Grabber::render_face(float half_size) const
|
||||
}
|
||||
|
||||
|
||||
GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* common_data_ptr)
|
||||
GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: m_parent(parent)
|
||||
, m_group_id(-1)
|
||||
, m_state(Off)
|
||||
@@ -149,7 +145,6 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, u
|
||||
, m_dragging(false)
|
||||
, m_imgui(wxGetApp().imgui())
|
||||
, m_first_input_window_render(true)
|
||||
, m_c(common_data_ptr)
|
||||
{
|
||||
::memcpy((void*)m_base_color, (const void*)DEFAULT_BASE_COLOR, 4 * sizeof(float));
|
||||
::memcpy((void*)m_drag_color, (const void*)DEFAULT_DRAG_COLOR, 4 * sizeof(float));
|
||||
@@ -306,88 +301,5 @@ unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char gr
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas, ModelObject* model_object)
|
||||
{
|
||||
recent_update = false;
|
||||
|
||||
if (m_model_object != model_object
|
||||
|| (model_object && m_model_object_id != model_object->id())) {
|
||||
m_model_object = model_object;
|
||||
m_print_object_idx = -1;
|
||||
m_mesh_raycaster.reset();
|
||||
m_object_clipper.reset();
|
||||
m_supports_clipper.reset();
|
||||
m_old_mesh = nullptr;
|
||||
m_mesh = nullptr;
|
||||
m_backend_mesh_transformed.clear();
|
||||
if (m_model_object) {
|
||||
m_active_instance = canvas.get_selection().get_instance_idx();
|
||||
m_active_instance_bb_radius = m_model_object->instance_bounding_box(m_active_instance).radius();
|
||||
}
|
||||
|
||||
recent_update = true;
|
||||
}
|
||||
|
||||
|
||||
if (! m_model_object || ! canvas.get_selection().is_from_single_instance())
|
||||
return false;
|
||||
|
||||
int old_po_idx = m_print_object_idx;
|
||||
|
||||
// First we need a pointer to the respective SLAPrintObject. The index into objects vector is
|
||||
// cached so we don't have todo it on each render. We only search for the po if needed:
|
||||
if (m_print_object_idx < 0 || (int)canvas.sla_print()->objects().size() != m_print_objects_count) {
|
||||
m_print_objects_count = canvas.sla_print()->objects().size();
|
||||
m_print_object_idx = -1;
|
||||
for (const SLAPrintObject* po : canvas.sla_print()->objects()) {
|
||||
++m_print_object_idx;
|
||||
if (po->model_object()->id() == m_model_object->id())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_mesh = nullptr;
|
||||
// Load either the model_object mesh, or one provided by the backend
|
||||
// This mesh does not account for the possible Z up SLA offset.
|
||||
// The backend mesh needs to be transformed and because a pointer to it is
|
||||
// saved, a copy is stored as a member (FIXME)
|
||||
if (m_print_object_idx >=0) {
|
||||
const SLAPrintObject* po = canvas.sla_print()->objects()[m_print_object_idx];
|
||||
if (po->is_step_done(slaposDrillHoles)) {
|
||||
m_backend_mesh_transformed = po->get_mesh_to_print();
|
||||
m_backend_mesh_transformed.transform(canvas.sla_print()->sla_trafo(*m_model_object).inverse());
|
||||
m_mesh = &m_backend_mesh_transformed;
|
||||
m_has_drilled_mesh = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (! m_mesh) {
|
||||
m_mesh = &m_model_object->volumes.front()->mesh();
|
||||
m_backend_mesh_transformed.clear();
|
||||
m_has_drilled_mesh = false;
|
||||
}
|
||||
|
||||
m_model_object_id = m_model_object->id();
|
||||
|
||||
if (m_mesh != m_old_mesh) {
|
||||
wxBusyCursor wait;
|
||||
m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh));
|
||||
m_object_clipper.reset();
|
||||
m_supports_clipper.reset();
|
||||
m_old_mesh = m_mesh;
|
||||
m_clipping_plane_distance = 0.f;
|
||||
m_clipping_plane_distance_stash = 0.f;
|
||||
recent_update = true;
|
||||
return true;
|
||||
}
|
||||
if (! recent_update)
|
||||
recent_update = m_print_object_idx < 0 && old_po_idx >= 0;
|
||||
|
||||
return recent_update;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -30,7 +30,6 @@ static const float CONSTRAINED_COLOR[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
|
||||
|
||||
|
||||
class ImGuiWrapper;
|
||||
class CommonGizmosData;
|
||||
class GLCanvas3D;
|
||||
class ClippingPlane;
|
||||
|
||||
@@ -101,13 +100,11 @@ protected:
|
||||
mutable std::vector<Grabber> m_grabbers;
|
||||
ImGuiWrapper* m_imgui;
|
||||
bool m_first_input_window_render;
|
||||
CommonGizmosData* m_c = nullptr;
|
||||
|
||||
public:
|
||||
GLGizmoBase(GLCanvas3D& parent,
|
||||
const std::string& icon_filename,
|
||||
unsigned int sprite_id,
|
||||
CommonGizmosData* common_data = nullptr);
|
||||
unsigned int sprite_id);
|
||||
virtual ~GLGizmoBase() {}
|
||||
|
||||
bool init() { return on_init(); }
|
||||
@@ -185,57 +182,6 @@ protected:
|
||||
// were not interpolated by alpha blending or multi sampling.
|
||||
extern unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char green, unsigned char blue);
|
||||
|
||||
class MeshRaycaster;
|
||||
class MeshClipper;
|
||||
|
||||
class CommonGizmosData {
|
||||
public:
|
||||
const TriangleMesh* mesh() const {
|
||||
return (! m_mesh ? nullptr : m_mesh); //(m_cavity_mesh ? m_cavity_mesh.get() : m_mesh));
|
||||
}
|
||||
|
||||
bool update_from_backend(GLCanvas3D& canvas, ModelObject* model_object);
|
||||
|
||||
bool recent_update = false;
|
||||
|
||||
|
||||
|
||||
ModelObject* m_model_object = nullptr;
|
||||
const TriangleMesh* m_mesh;
|
||||
std::unique_ptr<MeshRaycaster> m_mesh_raycaster;
|
||||
std::unique_ptr<MeshClipper> m_object_clipper;
|
||||
std::unique_ptr<MeshClipper> m_supports_clipper;
|
||||
|
||||
//std::unique_ptr<TriangleMesh> m_cavity_mesh;
|
||||
//std::unique_ptr<GLVolume> m_volume_with_cavity;
|
||||
|
||||
int m_active_instance = -1;
|
||||
float m_active_instance_bb_radius = 0;
|
||||
ObjectID m_model_object_id = 0;
|
||||
int m_print_object_idx = -1;
|
||||
int m_print_objects_count = -1;
|
||||
int m_old_timestamp = -1;
|
||||
|
||||
float m_clipping_plane_distance = 0.f;
|
||||
std::unique_ptr<ClippingPlane> m_clipping_plane;
|
||||
|
||||
void stash_clipping_plane() {
|
||||
m_clipping_plane_distance_stash = m_clipping_plane_distance;
|
||||
}
|
||||
|
||||
void unstash_clipping_plane() {
|
||||
m_clipping_plane_distance = m_clipping_plane_distance_stash;
|
||||
}
|
||||
|
||||
bool has_drilled_mesh() const { return m_has_drilled_mesh; }
|
||||
|
||||
private:
|
||||
const TriangleMesh* m_old_mesh;
|
||||
TriangleMesh m_backend_mesh_transformed;
|
||||
float m_clipping_plane_distance_stash = 0.f;
|
||||
bool m_has_drilled_mesh = false;
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
|
||||
@@ -17,11 +17,10 @@
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
GLGizmoHollow::GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* cd)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id, cd)
|
||||
GLGizmoHollow::GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
, m_quadric(nullptr)
|
||||
{
|
||||
m_c->m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.));
|
||||
m_quadric = ::gluNewQuadric();
|
||||
if (m_quadric != nullptr)
|
||||
// using GLU_FILL does not work when the instance's transformation
|
||||
@@ -58,19 +57,30 @@ void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&)
|
||||
{
|
||||
if (m_c->recent_update) {
|
||||
|
||||
if (m_state == On)
|
||||
m_c->build_AABB_if_needed();
|
||||
|
||||
update_clipping_plane(m_c->m_clipping_plane_was_moved);
|
||||
|
||||
// This is a temporary and not very nice hack, to make sure that
|
||||
// if the cp was moved by the data returned by backend, it will
|
||||
// remember its direction. FIXME: Refactor this mess and make
|
||||
// the clipping plane itself part of the shared data.
|
||||
if (! m_c->m_clipping_plane_was_moved && m_c->m_clipping_plane_distance == 0.25f)
|
||||
m_c->m_clipping_plane_was_moved = true;
|
||||
|
||||
|
||||
if (m_c->m_model_object) {
|
||||
reload_cache();
|
||||
if (m_c->has_drilled_mesh())
|
||||
m_holes_in_drilled_mesh = m_c->m_model_object->sla_drain_holes;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_state == On) {
|
||||
m_parent.toggle_model_objects_visibility(false);
|
||||
m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
|
||||
m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance);
|
||||
}
|
||||
else
|
||||
m_parent.toggle_model_objects_visibility(true, nullptr, -1);
|
||||
if (m_state == On) {
|
||||
m_parent.toggle_model_objects_visibility(false);
|
||||
m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
|
||||
m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,7 +252,7 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons
|
||||
const sla::DrainHole& drain_hole = m_c->m_model_object->sla_drain_holes[i];
|
||||
const bool& point_selected = m_selected[i];
|
||||
|
||||
if (is_mesh_point_clipped((drain_hole.pos+HoleStickOutLength*drain_hole.normal).cast<double>()))
|
||||
if (is_mesh_point_clipped((drain_hole.pos+m_c->HoleStickOutLength*drain_hole.normal).cast<double>()))
|
||||
continue;
|
||||
|
||||
// First decide about the color of the point.
|
||||
@@ -417,8 +427,8 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
|
||||
pos_and_normal.second(1)/scaling(1),
|
||||
pos_and_normal.second(2)/scaling(2));
|
||||
|
||||
m_c->m_model_object->sla_drain_holes.emplace_back(pos_and_normal.first + HoleStickOutLength * pos_and_normal.second/* normal_transformed.normalized()*/,
|
||||
-pos_and_normal.second, m_new_hole_radius, m_new_hole_height+HoleStickOutLength);
|
||||
m_c->m_model_object->sla_drain_holes.emplace_back(pos_and_normal.first + m_c->HoleStickOutLength * pos_and_normal.second/* normal_transformed.normalized()*/,
|
||||
-pos_and_normal.second, m_new_hole_radius, m_new_hole_height);
|
||||
m_selected.push_back(false);
|
||||
assert(m_selected.size() == m_c->m_model_object->sla_drain_holes.size());
|
||||
m_parent.set_as_dirty();
|
||||
@@ -507,7 +517,8 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
|
||||
|
||||
if (action == SLAGizmoEventType::MouseWheelUp && control_down) {
|
||||
m_c->m_clipping_plane_distance = std::min(1.f, m_c->m_clipping_plane_distance + 0.01f);
|
||||
update_clipping_plane(true);
|
||||
update_clipping_plane(m_c->m_clipping_plane_was_moved);
|
||||
m_c->m_clipping_plane_was_moved = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -545,7 +556,7 @@ void GLGizmoHollow::on_update(const UpdateData& data)
|
||||
std::pair<Vec3f, Vec3f> pos_and_normal;
|
||||
if (! unproject_on_mesh(data.mouse_pos.cast<double>(), pos_and_normal))
|
||||
return;
|
||||
m_c->m_model_object->sla_drain_holes[m_hover_id].pos = pos_and_normal.first + HoleStickOutLength * pos_and_normal.second;
|
||||
m_c->m_model_object->sla_drain_holes[m_hover_id].pos = pos_and_normal.first + m_c->HoleStickOutLength * pos_and_normal.second;
|
||||
m_c->m_model_object->sla_drain_holes[m_hover_id].normal = -pos_and_normal.second;
|
||||
}
|
||||
}
|
||||
@@ -697,9 +708,9 @@ void GLGizmoHollow::on_render_input_window(float x, float y, float bottom_limit)
|
||||
double closing_d_max = opts[2].second->max;
|
||||
ConfigOptionMode closing_d_mode = opts[2].second->mode;
|
||||
|
||||
m_desc["offset"] = _(opts[0].second->label).ToUTF8() + wxString(":");
|
||||
m_desc["quality"] = _(opts[1].second->label).ToUTF8() + wxString(":");
|
||||
m_desc["closing_distance"] = _(opts[2].second->label).ToUTF8() + wxString(":");
|
||||
m_desc["offset"] = _(opts[0].second->label) + ":";
|
||||
m_desc["quality"] = _(opts[1].second->label) + ":";
|
||||
m_desc["closing_distance"] = _(opts[2].second->label) + ":";
|
||||
|
||||
|
||||
RENDER_AGAIN:
|
||||
@@ -743,14 +754,16 @@ RENDER_AGAIN:
|
||||
}
|
||||
|
||||
m_imgui->disabled_begin(! m_enable_hollowing);
|
||||
|
||||
float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
|
||||
m_imgui->text(m_desc.at("offset"));
|
||||
ImGui::SameLine(settings_sliders_left);
|
||||
ImGui::PushItemWidth(window_width - settings_sliders_left);
|
||||
ImGui::SliderFloat(" ", &offset, offset_min, offset_max, "%.1f");
|
||||
ImGui::SliderFloat(" ", &offset, offset_min, offset_max, "%.1f mm");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted(_(opts[0].second->tooltip).ToUTF8());
|
||||
ImGui::PushTextWrapPos(max_tooltip_width);
|
||||
ImGui::TextUnformatted((_utf8(opts[0].second->tooltip)).c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
bool slider_clicked = ImGui::IsItemClicked(); // someone clicked the slider
|
||||
@@ -763,7 +776,9 @@ RENDER_AGAIN:
|
||||
ImGui::SliderFloat(" ", &quality, quality_min, quality_max, "%.1f");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted(_(opts[1].second->tooltip).ToUTF8());
|
||||
ImGui::PushTextWrapPos(max_tooltip_width);
|
||||
ImGui::TextUnformatted((_utf8(opts[1].second->tooltip)).c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
slider_clicked |= ImGui::IsItemClicked();
|
||||
@@ -774,10 +789,12 @@ RENDER_AGAIN:
|
||||
if (current_mode >= closing_d_mode) {
|
||||
m_imgui->text(m_desc.at("closing_distance"));
|
||||
ImGui::SameLine(settings_sliders_left);
|
||||
ImGui::SliderFloat(" ", &closing_d, closing_d_min, closing_d_max, "%.1f");
|
||||
ImGui::SliderFloat(" ", &closing_d, closing_d_min, closing_d_max, "%.1f mm");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted(_(opts[2].second->tooltip).ToUTF8());
|
||||
ImGui::PushTextWrapPos(max_tooltip_width);
|
||||
ImGui::TextUnformatted((_utf8(opts[2].second->tooltip)).c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
slider_clicked |= ImGui::IsItemClicked();
|
||||
@@ -823,7 +840,7 @@ RENDER_AGAIN:
|
||||
ImGui::PushItemWidth(window_width - diameter_slider_left);
|
||||
|
||||
float diam = 2.f * m_new_hole_radius;
|
||||
ImGui::SliderFloat("", &diam, 1.f, diameter_upper_cap, "%.1f");
|
||||
ImGui::SliderFloat("", &diam, 1.f, diameter_upper_cap, "%.1f mm");
|
||||
m_new_hole_radius = diam / 2.f;
|
||||
bool clicked = ImGui::IsItemClicked();
|
||||
bool edited = ImGui::IsItemEdited();
|
||||
@@ -831,9 +848,9 @@ RENDER_AGAIN:
|
||||
|
||||
m_imgui->text(m_desc["hole_depth"]);
|
||||
ImGui::SameLine(diameter_slider_left);
|
||||
m_new_hole_height -= HoleStickOutLength;
|
||||
ImGui::SliderFloat(" ", &m_new_hole_height, 0.f, 10.f, "%.1f");
|
||||
m_new_hole_height += HoleStickOutLength;
|
||||
m_new_hole_height -= m_c->HoleStickOutLength;
|
||||
ImGui::SliderFloat(" ", &m_new_hole_height, 0.f, 10.f, "%.1f mm");
|
||||
m_new_hole_height += m_c->HoleStickOutLength;
|
||||
|
||||
clicked |= ImGui::IsItemClicked();
|
||||
edited |= ImGui::IsItemEdited();
|
||||
@@ -897,8 +914,10 @@ RENDER_AGAIN:
|
||||
|
||||
ImGui::SameLine(clipping_slider_left);
|
||||
ImGui::PushItemWidth(window_width - clipping_slider_left);
|
||||
if (ImGui::SliderFloat(" ", &m_c->m_clipping_plane_distance, 0.f, 1.f, "%.2f"))
|
||||
update_clipping_plane(true);
|
||||
if (ImGui::SliderFloat(" ", &m_c->m_clipping_plane_distance, 0.f, 1.f, "%.2f")) {
|
||||
update_clipping_plane(m_c->m_clipping_plane_was_moved);
|
||||
m_c->m_clipping_plane_was_moved = true;
|
||||
}
|
||||
|
||||
// make sure supports are shown/hidden as appropriate
|
||||
if (m_imgui->checkbox(m_desc["show_supports"], m_show_supports)) {
|
||||
@@ -981,7 +1000,9 @@ void GLGizmoHollow::on_set_state()
|
||||
//Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on")));
|
||||
//m_c->update_from_backend(m_parent, m_c->m_model_object);
|
||||
m_c->unstash_clipping_plane();
|
||||
update_clipping_plane(m_c->m_clipping_plane_distance != 0.f);
|
||||
update_clipping_plane(m_c->m_clipping_plane_was_moved);
|
||||
|
||||
m_c->build_AABB_if_needed();
|
||||
|
||||
// we'll now reload support points:
|
||||
if (m_c->m_model_object)
|
||||
@@ -1082,7 +1103,7 @@ void GLGizmoHollow::select_point(int i)
|
||||
|
||||
if (i == AllPoints) {
|
||||
m_new_hole_radius = m_c->m_model_object->sla_drain_holes[0].radius;
|
||||
m_new_hole_height = m_c->m_model_object->sla_drain_holes[0].height - HoleStickOutLength;
|
||||
m_new_hole_height = m_c->m_model_object->sla_drain_holes[0].height;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1091,7 +1112,7 @@ void GLGizmoHollow::select_point(int i)
|
||||
m_selected[i] = true;
|
||||
m_selection_empty = false;
|
||||
m_new_hole_radius = m_c->m_model_object->sla_drain_holes[i].radius;
|
||||
m_new_hole_height = m_c->m_model_object->sla_drain_holes[i].height - HoleStickOutLength;
|
||||
m_new_hole_height = m_c->m_model_object->sla_drain_holes[i].height;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1128,6 +1149,13 @@ void GLGizmoHollow::update_clipping_plane(bool keep_normal) const
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoHollow::on_set_hover_id()
|
||||
{
|
||||
if (int(m_c->m_model_object->sla_drain_holes.size()) <= m_hover_id)
|
||||
m_hover_id = -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace GUI
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace GUI {
|
||||
class ClippingPlane;
|
||||
class MeshClipper;
|
||||
class MeshRaycaster;
|
||||
class CommonGizmosData;
|
||||
enum class SLAGizmoEventType : unsigned char;
|
||||
|
||||
class GLGizmoHollow : public GLGizmoBase
|
||||
@@ -24,13 +25,11 @@ private:
|
||||
mutable double m_z_shift = 0.;
|
||||
bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal);
|
||||
|
||||
const float HoleStickOutLength = 1.f;
|
||||
|
||||
GLUquadricObj* m_quadric;
|
||||
|
||||
|
||||
public:
|
||||
GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* cd);
|
||||
GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
~GLGizmoHollow() override;
|
||||
void set_sla_support_data(ModelObject* model_object, const Selection& selection);
|
||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||
@@ -44,6 +43,7 @@ public:
|
||||
|
||||
bool is_selection_rectangle_dragging() const { return m_selection_rectangle.is_dragging(); }
|
||||
void update_clipping_plane(bool keep_normal = false) const;
|
||||
void set_common_data_ptr(CommonGizmosData* ptr) { m_c = ptr; }
|
||||
|
||||
private:
|
||||
bool on_init() override;
|
||||
@@ -74,6 +74,8 @@ private:
|
||||
|
||||
sla::DrainHoles m_holes_stash;
|
||||
|
||||
CommonGizmosData* m_c = nullptr;
|
||||
|
||||
//std::unique_ptr<ClippingPlane> m_clipping_plane;
|
||||
|
||||
// This map holds all translated description texts, so they can be easily referenced during layout calculations
|
||||
@@ -101,12 +103,7 @@ private:
|
||||
|
||||
protected:
|
||||
void on_set_state() override;
|
||||
void on_set_hover_id() override
|
||||
|
||||
{
|
||||
if (int(m_c->m_model_object->sla_drain_holes.size()) <= m_hover_id)
|
||||
m_hover_id = -1;
|
||||
}
|
||||
void on_set_hover_id() override;
|
||||
void on_start_dragging() override;
|
||||
void on_stop_dragging() override;
|
||||
void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
|
||||
@@ -22,12 +22,11 @@
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* cd)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id, cd)
|
||||
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
, m_quadric(nullptr)
|
||||
, m_its(nullptr)
|
||||
{
|
||||
m_c->m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.));
|
||||
{
|
||||
m_quadric = ::gluNewQuadric();
|
||||
if (m_quadric != nullptr)
|
||||
// using GLU_FILL does not work when the instance's transformation
|
||||
@@ -64,19 +63,22 @@ bool GLGizmoSlaSupports::on_init()
|
||||
void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const Selection& selection)
|
||||
{
|
||||
if (m_c->recent_update) {
|
||||
if (m_state == On) {
|
||||
m_parent.toggle_model_objects_visibility(false);
|
||||
m_parent.toggle_model_objects_visibility(/*! m_c->m_cavity_mesh*/ true, m_c->m_model_object, m_c->m_active_instance);
|
||||
m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance);
|
||||
}
|
||||
else
|
||||
m_parent.toggle_model_objects_visibility(true, nullptr, -1);
|
||||
if (m_state == On)
|
||||
m_c->build_AABB_if_needed();
|
||||
|
||||
update_clipping_plane(m_c->m_clipping_plane_was_moved);
|
||||
|
||||
disable_editing_mode();
|
||||
if (m_c->m_model_object)
|
||||
reload_cache();
|
||||
}
|
||||
|
||||
if (m_state == On) {
|
||||
m_parent.toggle_model_objects_visibility(false);
|
||||
m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
|
||||
m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance);
|
||||
}
|
||||
|
||||
// If we triggered autogeneration before, check backend and fetch results if they are there
|
||||
if (m_c->m_model_object) {
|
||||
if (m_c->m_model_object->sla_points_status == sla::PointsStatus::Generating)
|
||||
@@ -342,6 +344,9 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
|
||||
render_color[3] = 0.7f;
|
||||
glsafe(::glColor4fv(render_color));
|
||||
for (const sla::DrainHole& drain_hole : m_c->m_model_object->sla_drain_holes) {
|
||||
if (is_mesh_point_clipped((drain_hole.pos+m_c->HoleStickOutLength*drain_hole.normal).cast<double>()))
|
||||
continue;
|
||||
|
||||
// Inverse matrix of the instance scaling is applied so that the mark does not scale with the object.
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glTranslatef(drain_hole.pos(0), drain_hole.pos(1), drain_hole.pos(2)));
|
||||
@@ -587,7 +592,8 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
||||
|
||||
if (action == SLAGizmoEventType::MouseWheelUp && control_down) {
|
||||
m_c->m_clipping_plane_distance = std::min(1.f, m_c->m_clipping_plane_distance + 0.01f);
|
||||
update_clipping_plane(true);
|
||||
update_clipping_plane(m_c->m_clipping_plane_was_moved);
|
||||
m_c->m_clipping_plane_was_moved = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -913,8 +919,10 @@ RENDER_AGAIN:
|
||||
|
||||
ImGui::SameLine(clipping_slider_left);
|
||||
ImGui::PushItemWidth(window_width - clipping_slider_left);
|
||||
if (ImGui::SliderFloat(" ", &m_c->m_clipping_plane_distance, 0.f, 1.f, "%.2f"))
|
||||
update_clipping_plane(true);
|
||||
if (ImGui::SliderFloat(" ", &m_c->m_clipping_plane_distance, 0.f, 1.f, "%.2f")) {
|
||||
update_clipping_plane(m_c->m_clipping_plane_was_moved);
|
||||
m_c->m_clipping_plane_was_moved = true;
|
||||
}
|
||||
|
||||
|
||||
if (m_imgui->button("?")) {
|
||||
@@ -999,7 +1007,9 @@ void GLGizmoSlaSupports::on_set_state()
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on")));
|
||||
|
||||
m_c->unstash_clipping_plane();
|
||||
update_clipping_plane(m_c->m_clipping_plane_distance != 0.f);
|
||||
update_clipping_plane(m_c->m_clipping_plane_was_moved);
|
||||
|
||||
m_c->build_AABB_if_needed();
|
||||
|
||||
|
||||
// we'll now reload support points:
|
||||
@@ -1007,9 +1017,10 @@ void GLGizmoSlaSupports::on_set_state()
|
||||
reload_cache();
|
||||
|
||||
m_parent.toggle_model_objects_visibility(false);
|
||||
if (m_c->m_model_object /*&& ! m_c->m_cavity_mesh*/)
|
||||
if (m_c->m_model_object) {
|
||||
m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
|
||||
m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance);
|
||||
m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance);
|
||||
}
|
||||
|
||||
// Set default head diameter from config.
|
||||
const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace GUI {
|
||||
class ClippingPlane;
|
||||
class MeshClipper;
|
||||
class MeshRaycaster;
|
||||
class CommonGizmosData;
|
||||
enum class SLAGizmoEventType : unsigned char;
|
||||
|
||||
class GLGizmoSlaSupports : public GLGizmoBase
|
||||
@@ -69,7 +70,7 @@ private:
|
||||
};
|
||||
|
||||
public:
|
||||
GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* cd);
|
||||
GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
~GLGizmoSlaSupports() override;
|
||||
void set_sla_support_data(ModelObject* model_object, const Selection& selection);
|
||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||
@@ -81,6 +82,7 @@ public:
|
||||
bool has_backend_supports() const;
|
||||
void reslice_SLA_supports(bool postpone_error_messages = false) const;
|
||||
void update_clipping_plane(bool keep_normal = false) const;
|
||||
void set_common_data_ptr(CommonGizmosData* ptr) { m_c = ptr; }
|
||||
|
||||
private:
|
||||
bool on_init() override;
|
||||
@@ -116,6 +118,8 @@ private:
|
||||
bool m_selection_empty = true;
|
||||
EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state)
|
||||
|
||||
CommonGizmosData* m_c = nullptr;
|
||||
|
||||
//mutable std::unique_ptr<MeshClipper> m_object_clipper;
|
||||
//mutable std::unique_ptr<MeshClipper> m_supports_clipper;
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
|
||||
#include "slic3r/GUI/PresetBundle.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
#include "slic3r/GUI/MeshUtils.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <wx/glcanvas.h>
|
||||
@@ -83,16 +85,18 @@ bool GLGizmosManager::init()
|
||||
return false;
|
||||
}
|
||||
|
||||
m_common_gizmos_data.reset(new CommonGizmosData());
|
||||
|
||||
// Order of gizmos in the vector must match order in EType!
|
||||
m_gizmos.emplace_back(new GLGizmoMove3D(m_parent, "move.svg", 0));
|
||||
m_gizmos.emplace_back(new GLGizmoScale3D(m_parent, "scale.svg", 1));
|
||||
m_gizmos.emplace_back(new GLGizmoRotate3D(m_parent, "rotate.svg", 2));
|
||||
m_gizmos.emplace_back(new GLGizmoFlatten(m_parent, "place.svg", 3));
|
||||
m_gizmos.emplace_back(new GLGizmoCut(m_parent, "cut.svg", 4));
|
||||
m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", 5, m_common_gizmos_data.get()));
|
||||
m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6, m_common_gizmos_data.get()));
|
||||
m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", 5));
|
||||
m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6));
|
||||
|
||||
m_common_gizmos_data.reset(new CommonGizmosData());
|
||||
dynamic_cast<GLGizmoHollow*>(m_gizmos[Hollow].get())->set_common_data_ptr(m_common_gizmos_data.get());
|
||||
dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get())->set_common_data_ptr(m_common_gizmos_data.get());
|
||||
|
||||
for (auto& gizmo : m_gizmos) {
|
||||
if (! gizmo->init()) {
|
||||
@@ -345,25 +349,18 @@ void GLGizmosManager::set_flattening_data(const ModelObject* model_object)
|
||||
|
||||
void GLGizmosManager::set_sla_support_data(ModelObject* model_object)
|
||||
{
|
||||
if (!m_enabled || m_gizmos.empty())
|
||||
if (! m_enabled
|
||||
|| m_gizmos.empty()
|
||||
|| wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
|
||||
return;
|
||||
|
||||
m_common_gizmos_data->update_from_backend(m_parent, model_object);
|
||||
|
||||
auto* gizmo_supports = dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get());
|
||||
auto* gizmo_hollow = dynamic_cast<GLGizmoHollow*>(m_gizmos[Hollow].get());
|
||||
|
||||
|
||||
// Update common data for hollowing and sla support gizmos.
|
||||
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) {
|
||||
if (m_common_gizmos_data->update_from_backend(m_parent, model_object)) {
|
||||
// FIXME: this is a hack to make that the clipping plane is
|
||||
// updated when the update set its position to zero. The clipping
|
||||
// plane itself should be common, including the update_function.
|
||||
// Then update_from_backend could do it itself.
|
||||
gizmo_supports->update_clipping_plane();
|
||||
gizmo_hollow->update_clipping_plane();
|
||||
}
|
||||
}
|
||||
|
||||
// note: sla support gizmo takes care of updating the common data.
|
||||
// following lines are thus dependent
|
||||
gizmo_supports->set_sla_support_data(model_object, m_parent.get_selection());
|
||||
gizmo_hollow->set_sla_support_data(model_object, m_parent.get_selection());
|
||||
}
|
||||
@@ -1058,5 +1055,135 @@ bool GLGizmosManager::grabber_contains_mouse() const
|
||||
return (curr != nullptr) ? (curr->get_hover_id() != -1) : false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CommonGizmosData::CommonGizmosData()
|
||||
{
|
||||
m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.));
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas, ModelObject* model_object)
|
||||
{
|
||||
recent_update = false;
|
||||
bool object_changed = false;
|
||||
|
||||
if (m_model_object != model_object
|
||||
|| (model_object && m_model_object_id != model_object->id())) {
|
||||
m_model_object = model_object;
|
||||
m_print_object_idx = -1;
|
||||
m_mesh_raycaster.reset();
|
||||
m_object_clipper.reset();
|
||||
m_supports_clipper.reset();
|
||||
m_old_mesh = nullptr;
|
||||
m_mesh = nullptr;
|
||||
m_backend_mesh_transformed.clear();
|
||||
|
||||
object_changed = true;
|
||||
recent_update = true;
|
||||
}
|
||||
|
||||
if (m_model_object) {
|
||||
int active_inst = canvas.get_selection().get_instance_idx();
|
||||
if (m_active_instance != active_inst) {
|
||||
m_active_instance = active_inst;
|
||||
m_active_instance_bb_radius = m_model_object->instance_bounding_box(m_active_instance).radius();
|
||||
recent_update = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (! m_model_object || ! canvas.get_selection().is_from_single_instance())
|
||||
return false;
|
||||
|
||||
int old_po_idx = m_print_object_idx;
|
||||
|
||||
// First we need a pointer to the respective SLAPrintObject. The index into objects vector is
|
||||
// cached so we don't have todo it on each render. We only search for the po if needed:
|
||||
if (m_print_object_idx < 0 || (int)canvas.sla_print()->objects().size() != m_print_objects_count) {
|
||||
m_print_objects_count = canvas.sla_print()->objects().size();
|
||||
m_print_object_idx = -1;
|
||||
for (const SLAPrintObject* po : canvas.sla_print()->objects()) {
|
||||
++m_print_object_idx;
|
||||
if (po->model_object()->id() == m_model_object->id())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool mesh_exchanged = false;
|
||||
m_mesh = nullptr;
|
||||
// Load either the model_object mesh, or one provided by the backend
|
||||
// This mesh does not account for the possible Z up SLA offset.
|
||||
// The backend mesh needs to be transformed and because a pointer to it is
|
||||
// saved, a copy is stored as a member (FIXME)
|
||||
if (m_print_object_idx >=0) {
|
||||
const SLAPrintObject* po = canvas.sla_print()->objects()[m_print_object_idx];
|
||||
if (po->is_step_done(slaposDrillHoles)) {
|
||||
m_backend_mesh_transformed = po->get_mesh_to_print();
|
||||
m_backend_mesh_transformed.transform(canvas.sla_print()->sla_trafo(*m_model_object).inverse());
|
||||
m_mesh = &m_backend_mesh_transformed;
|
||||
m_has_drilled_mesh = true;
|
||||
mesh_exchanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (! m_mesh) {
|
||||
m_mesh = &m_model_object->volumes.front()->mesh();
|
||||
m_backend_mesh_transformed.clear();
|
||||
m_has_drilled_mesh = false;
|
||||
}
|
||||
|
||||
m_model_object_id = m_model_object->id();
|
||||
|
||||
if (m_mesh != m_old_mesh) {
|
||||
// Update clipping plane position.
|
||||
float new_clp_pos = m_clipping_plane_distance;
|
||||
if (object_changed) {
|
||||
new_clp_pos = 0.f;
|
||||
m_clipping_plane_was_moved = false;
|
||||
} else {
|
||||
// After we got a drilled mesh, move the cp to 25%. This only applies when
|
||||
// the hollowing gizmo is active and hollowing is enabled
|
||||
if (m_clipping_plane_distance == 0.f && mesh_exchanged && m_has_drilled_mesh) {
|
||||
const DynamicPrintConfig& cfg =
|
||||
(m_model_object && m_model_object->config.has("hollowing_enable"))
|
||||
? m_model_object->config
|
||||
: wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
|
||||
|
||||
if (cfg.has("hollowing_enable") && cfg.opt_bool("hollowing_enable")
|
||||
&& canvas.get_gizmos_manager().get_current_type() == GLGizmosManager::Hollow) {
|
||||
new_clp_pos = 0.25f;
|
||||
m_clipping_plane_was_moved = false; // so it uses current camera direction
|
||||
}
|
||||
}
|
||||
}
|
||||
m_clipping_plane_distance = new_clp_pos;
|
||||
m_clipping_plane_distance_stash = new_clp_pos;
|
||||
|
||||
m_schedule_aabb_calculation = true;
|
||||
recent_update = true;
|
||||
return true;
|
||||
}
|
||||
if (! recent_update)
|
||||
recent_update = m_print_object_idx < 0 && old_po_idx >= 0;
|
||||
|
||||
return recent_update;
|
||||
}
|
||||
|
||||
|
||||
void CommonGizmosData::build_AABB_if_needed()
|
||||
{
|
||||
if (! m_schedule_aabb_calculation)
|
||||
return;
|
||||
|
||||
wxBusyCursor wait;
|
||||
m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh));
|
||||
m_object_clipper.reset();
|
||||
m_supports_clipper.reset();
|
||||
m_old_mesh = m_mesh;
|
||||
m_schedule_aabb_calculation = false;
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -227,6 +227,65 @@ private:
|
||||
bool grabber_contains_mouse() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class MeshRaycaster;
|
||||
class MeshClipper;
|
||||
|
||||
// This class is only for sharing SLA related data between SLA gizmos
|
||||
// and its synchronization with backend data. It should not be misused
|
||||
// for anything else.
|
||||
class CommonGizmosData {
|
||||
public:
|
||||
CommonGizmosData();
|
||||
const TriangleMesh* mesh() const {
|
||||
return (! m_mesh ? nullptr : m_mesh); //(m_cavity_mesh ? m_cavity_mesh.get() : m_mesh));
|
||||
}
|
||||
|
||||
bool update_from_backend(GLCanvas3D& canvas, ModelObject* model_object);
|
||||
bool recent_update = false;
|
||||
static constexpr float HoleStickOutLength = 1.f;
|
||||
|
||||
ModelObject* m_model_object = nullptr;
|
||||
const TriangleMesh* m_mesh;
|
||||
std::unique_ptr<MeshRaycaster> m_mesh_raycaster;
|
||||
std::unique_ptr<MeshClipper> m_object_clipper;
|
||||
std::unique_ptr<MeshClipper> m_supports_clipper;
|
||||
|
||||
//std::unique_ptr<TriangleMesh> m_cavity_mesh;
|
||||
//std::unique_ptr<GLVolume> m_volume_with_cavity;
|
||||
|
||||
int m_active_instance = -1;
|
||||
float m_active_instance_bb_radius = 0;
|
||||
ObjectID m_model_object_id = 0;
|
||||
int m_print_object_idx = -1;
|
||||
int m_print_objects_count = -1;
|
||||
int m_old_timestamp = -1;
|
||||
|
||||
float m_clipping_plane_distance = 0.f;
|
||||
std::unique_ptr<ClippingPlane> m_clipping_plane;
|
||||
bool m_clipping_plane_was_moved = false;
|
||||
|
||||
void stash_clipping_plane() {
|
||||
m_clipping_plane_distance_stash = m_clipping_plane_distance;
|
||||
}
|
||||
|
||||
void unstash_clipping_plane() {
|
||||
m_clipping_plane_distance = m_clipping_plane_distance_stash;
|
||||
}
|
||||
|
||||
bool has_drilled_mesh() const { return m_has_drilled_mesh; }
|
||||
|
||||
void build_AABB_if_needed();
|
||||
|
||||
private:
|
||||
const TriangleMesh* m_old_mesh;
|
||||
TriangleMesh m_backend_mesh_transformed;
|
||||
float m_clipping_plane_distance_stash = 0.f;
|
||||
bool m_has_drilled_mesh = false;
|
||||
bool m_schedule_aabb_calculation = false;
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
|
||||
+10
-4
@@ -40,21 +40,25 @@ namespace I18N {
|
||||
inline wxString translate(const wchar_t *s) { return wxGetTranslation(s); }
|
||||
inline wxString translate(const std::string &s) { return wxGetTranslation(wxString(s.c_str(), wxConvUTF8)); }
|
||||
inline wxString translate(const std::wstring &s) { return wxGetTranslation(s.c_str()); }
|
||||
inline wxString translate(const wxString &s) { return wxGetTranslation(s); }
|
||||
|
||||
inline wxString translate(const char *s, const char *plural, unsigned int n) { return wxGetTranslation(wxString(s, wxConvUTF8), wxString(plural, wxConvUTF8), n); }
|
||||
inline wxString translate(const wchar_t *s, const wchar_t *plural, unsigned int n) { return wxGetTranslation(s, plural, n); }
|
||||
inline wxString translate(const std::string &s, const std::string &plural, unsigned int n) { return wxGetTranslation(wxString(s.c_str(), wxConvUTF8), wxString(plural.c_str(), wxConvUTF8), n); }
|
||||
inline wxString translate(const std::wstring &s, const std::wstring &plural, unsigned int n) { return wxGetTranslation(s.c_str(), plural.c_str(), n); }
|
||||
inline wxString translate(const wxString &s, const wxString &plural, unsigned int n) { return wxGetTranslation(s, plural, n); }
|
||||
|
||||
inline std::string translate_utf8(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)).ToUTF8().data(); }
|
||||
inline std::string translate_utf8(const wchar_t *s) { return wxGetTranslation(s).ToUTF8().data(); }
|
||||
inline std::string translate_utf8(const std::string &s) { return wxGetTranslation(wxString(s.c_str(), wxConvUTF8)).ToUTF8().data(); }
|
||||
inline std::string translate_utf8(const std::wstring &s) { return wxGetTranslation(s.c_str()).ToUTF8().data(); }
|
||||
inline std::string translate_utf8(const wxString &s) { return wxGetTranslation(s).ToUTF8().data(); }
|
||||
|
||||
inline std::string translate_utf8(const char *s, const char *plural, unsigned int n) { return translate(s, plural, n).ToUTF8().data(); }
|
||||
inline std::string translate_utf8(const wchar_t *s, const wchar_t *plural, unsigned int n) { return translate(s, plural, n).ToUTF8().data(); }
|
||||
inline std::string translate_utf8(const std::string &s, const std::string &plural, unsigned int n) { return translate(s, plural, n).ToUTF8().data(); }
|
||||
inline std::string translate_utf8(const std::wstring &s, const std::wstring &plural, unsigned int n) { return translate(s, plural, n).ToUTF8().data(); }
|
||||
inline std::string translate_utf8(const wxString &s, const wxString &plural, unsigned int n) { return translate(s, plural, n).ToUTF8().data(); }
|
||||
|
||||
#if wxCHECK_VERSION(3, 1, 1)
|
||||
#define _wxGetTranslation_ctx(S, CTX) wxGetTranslation((S), wxEmptyString, (CTX))
|
||||
@@ -66,11 +70,13 @@ namespace I18N {
|
||||
inline wxString translate(const wchar_t *s, const char* ctx) { return _wxGetTranslation_ctx(s, ctx); }
|
||||
inline wxString translate(const std::string &s, const char* ctx) { return _wxGetTranslation_ctx(wxString(s.c_str(), wxConvUTF8), ctx); }
|
||||
inline wxString translate(const std::wstring &s, const char* ctx) { return _wxGetTranslation_ctx(s.c_str(), ctx); }
|
||||
inline wxString translate(const wxString &s, const char* ctx) { return _wxGetTranslation_ctx(s, ctx); }
|
||||
|
||||
inline wxString translate_utf8(const char *s, const char* ctx) { return _wxGetTranslation_ctx(wxString(s, wxConvUTF8), ctx).ToUTF8().data(); }
|
||||
inline wxString translate_utf8(const wchar_t *s, const char* ctx) { return _wxGetTranslation_ctx(s, ctx).ToUTF8().data(); }
|
||||
inline wxString translate_utf8(const std::string &s, const char* ctx) { return _wxGetTranslation_ctx(wxString(s.c_str(), wxConvUTF8), ctx).ToUTF8().data(); }
|
||||
inline wxString translate_utf8(const std::wstring &s, const char* ctx) { return _wxGetTranslation_ctx(s.c_str(), ctx).ToUTF8().data(); }
|
||||
inline std::string translate_utf8(const char *s, const char* ctx) { return _wxGetTranslation_ctx(wxString(s, wxConvUTF8), ctx).ToUTF8().data(); }
|
||||
inline std::string translate_utf8(const wchar_t *s, const char* ctx) { return _wxGetTranslation_ctx(s, ctx).ToUTF8().data(); }
|
||||
inline std::string translate_utf8(const std::string &s, const char* ctx) { return _wxGetTranslation_ctx(wxString(s.c_str(), wxConvUTF8), ctx).ToUTF8().data(); }
|
||||
inline std::string translate_utf8(const std::wstring &s, const char* ctx) { return _wxGetTranslation_ctx(s.c_str(), ctx).ToUTF8().data(); }
|
||||
inline std::string translate_utf8(const wxString &s, const char* ctx) { return _wxGetTranslation_ctx(s, ctx).ToUTF8().data(); }
|
||||
|
||||
#undef _wxGetTranslation_ctx
|
||||
} // namespace I18N
|
||||
|
||||
@@ -286,6 +286,12 @@ bool ImGuiWrapper::input_double(const std::string &label, const double &value, c
|
||||
return ImGui::InputDouble(label.c_str(), const_cast<double*>(&value), 0.0f, 0.0f, format.c_str());
|
||||
}
|
||||
|
||||
bool ImGuiWrapper::input_double(const wxString &label, const double &value, const std::string &format)
|
||||
{
|
||||
auto label_utf8 = into_u8(label);
|
||||
return input_double(label_utf8, value, format);
|
||||
}
|
||||
|
||||
bool ImGuiWrapper::input_vec3(const std::string &label, const Vec3d &value, float width, const std::string &format)
|
||||
{
|
||||
bool value_changed = false;
|
||||
|
||||
@@ -63,6 +63,7 @@ public:
|
||||
bool button(const wxString &label);
|
||||
bool radio_button(const wxString &label, bool active);
|
||||
bool input_double(const std::string &label, const double &value, const std::string &format = "%.3f");
|
||||
bool input_double(const wxString &label, const double &value, const std::string &format = "%.3f");
|
||||
bool input_vec3(const std::string &label, const Vec3d &value, float width, const std::string &format = "%.3f");
|
||||
bool checkbox(const wxString &label, bool &value);
|
||||
void text(const char *label);
|
||||
|
||||
@@ -158,7 +158,7 @@ void KBShortcutsDialog::fill_shortcuts()
|
||||
{ "Shift+A", L("Arrange selection") },
|
||||
{ "+", L("Add Instance of the selected object") },
|
||||
{ "-", L("Remove Instance of the selected object") },
|
||||
{ ctrl, L("Press to select multiple object\nor move multiple object with mouse") },
|
||||
{ ctrl, L("Press to select multiple objects\nor move multiple objects with mouse") },
|
||||
{ "Shift+", L("Press to activate selection rectangle") },
|
||||
{ alt, L("Press to activate deselection rectangle") },
|
||||
{ L("Arrow Up"), L("Move selection 10 mm in positive Y direction") },
|
||||
@@ -192,7 +192,7 @@ void KBShortcutsDialog::fill_shortcuts()
|
||||
m_full_shortcuts.push_back(std::make_pair(_(L("Plater")), plater_shortcuts));
|
||||
|
||||
Shortcuts gizmos_shortcuts = {
|
||||
{ "Shift+", L("Press to to snap by 5% in Gizmo scale\nor to snap by 1mm in Gizmo move") },
|
||||
{ "Shift+", L("Press to snap by 5% in Gizmo scale\nor to snap by 1mm in Gizmo move") },
|
||||
{ "F", L("Scale selection to fit print volume\nin Gizmo scale") },
|
||||
{ ctrl, L("Press to activate one direction scaling in Gizmo scale") },
|
||||
{ alt, L("Press to scale (in Gizmo scale) or rotate (in Gizmo rotate)\nselected objects around their own center") },
|
||||
|
||||
@@ -143,6 +143,9 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
|
||||
wxGetApp().persist_window_geometry(this, true);
|
||||
|
||||
update_ui_from_settings(); // FIXME (?)
|
||||
|
||||
if (m_plater != nullptr)
|
||||
m_plater->show_action_buttons(true);
|
||||
}
|
||||
|
||||
void MainFrame::update_title()
|
||||
@@ -419,18 +422,19 @@ void MainFrame::init_menubar()
|
||||
m_plater->load_project(filename);
|
||||
else
|
||||
{
|
||||
wxMessageDialog msg(this, _(L("The selected project is no more available")), _(L("Error")));
|
||||
msg.ShowModal();
|
||||
|
||||
m_recent_projects.RemoveFileFromHistory(file_id);
|
||||
std::vector<std::string> recent_projects;
|
||||
size_t count = m_recent_projects.GetCount();
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
wxMessageDialog msg(this, _(L("The selected project is no longer available.\nDo you want to remove it from the recent projects list ?")), _(L("Error")), wxYES_NO | wxYES_DEFAULT);
|
||||
if (msg.ShowModal() == wxID_YES)
|
||||
{
|
||||
recent_projects.push_back(into_u8(m_recent_projects.GetHistoryFile(i)));
|
||||
m_recent_projects.RemoveFileFromHistory(file_id);
|
||||
std::vector<std::string> recent_projects;
|
||||
size_t count = m_recent_projects.GetCount();
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
recent_projects.push_back(into_u8(m_recent_projects.GetHistoryFile(i)));
|
||||
}
|
||||
wxGetApp().app_config->set_recent_projects(recent_projects);
|
||||
wxGetApp().app_config->save();
|
||||
}
|
||||
wxGetApp().app_config->set_recent_projects(recent_projects);
|
||||
wxGetApp().app_config->save();
|
||||
}
|
||||
}, wxID_FILE1, wxID_FILE9);
|
||||
|
||||
@@ -1148,11 +1152,12 @@ void MainFrame::add_to_recent_projects(const wxString& filename)
|
||||
// Update the UI based on the current preferences.
|
||||
void MainFrame::update_ui_from_settings()
|
||||
{
|
||||
const bool bp_on = wxGetApp().app_config->get("background_processing") == "1";
|
||||
// const bool bp_on = wxGetApp().app_config->get("background_processing") == "1";
|
||||
// m_menu_item_reslice_now->Enable(!bp_on);
|
||||
m_plater->sidebar().show_reslice(!bp_on);
|
||||
m_plater->sidebar().show_export(bp_on);
|
||||
m_plater->sidebar().Layout();
|
||||
// m_plater->sidebar().show_reslice(!bp_on);
|
||||
// m_plater->sidebar().show_export(bp_on);
|
||||
// m_plater->sidebar().Layout();
|
||||
|
||||
if (m_plater)
|
||||
m_plater->update_ui_from_settings();
|
||||
for (auto tab: wxGetApp().tabs_list)
|
||||
|
||||
@@ -162,8 +162,8 @@ bool Mouse3DController::State::apply(Camera& camera)
|
||||
|
||||
if (has_rotation())
|
||||
{
|
||||
Vec3d rotation = (m_rotation_params.scale * m_rotation.queue.front()).cast<double>();
|
||||
camera.rotate_local_around_target(Vec3d(Geometry::deg2rad(rotation(0)), Geometry::deg2rad(-rotation(2)), Geometry::deg2rad(-rotation(1))));
|
||||
Vec3d rot = (m_rotation_params.scale * m_rotation.queue.front()).cast<double>() * (PI / 180.);
|
||||
camera.rotate_local_around_target(Vec3d(rot.x(), - rot.z(), rot.y()));
|
||||
m_rotation.queue.pop();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
@@ -1185,6 +1185,26 @@ void ObjectDataViewModel::SetExtruder(const wxString& extruder, wxDataViewItem i
|
||||
SetValue(value, item, colExtruder);
|
||||
}
|
||||
|
||||
void ObjectDataViewModel::AddAllChildren(const wxDataViewItem& parent)
|
||||
{
|
||||
ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)parent.GetID();
|
||||
if (!node || node->GetChildCount() == 0)
|
||||
return;
|
||||
|
||||
wxDataViewItemArray array;
|
||||
const size_t count = node->GetChildCount();
|
||||
for (size_t pos = 0; pos < count; pos++) {
|
||||
ObjectDataViewModelNode* child = node->GetChildren().Item(pos);
|
||||
array.Add(wxDataViewItem((void*)child));
|
||||
ItemAdded(parent, wxDataViewItem((void*)child));
|
||||
}
|
||||
|
||||
for (const auto item : array)
|
||||
AddAllChildren(item);
|
||||
|
||||
m_ctrl->Expand(parent);
|
||||
};
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::ReorganizeChildren( const int current_volume_id,
|
||||
const int new_volume_id,
|
||||
const wxDataViewItem &parent)
|
||||
@@ -1205,6 +1225,10 @@ wxDataViewItem ObjectDataViewModel::ReorganizeChildren( const int current_volume
|
||||
node_parent->Insert(deleted_node, new_volume_id+shift);
|
||||
ItemAdded(parent, wxDataViewItem(deleted_node));
|
||||
|
||||
// If some item has a children, just to add a deleted item is not enough on Linux
|
||||
// We should to add all its children separately
|
||||
AddAllChildren(wxDataViewItem(deleted_node));
|
||||
|
||||
//update volume_id value for child-nodes
|
||||
auto children = node_parent->GetChildren();
|
||||
int id_frst = current_volume_id < new_volume_id ? current_volume_id : new_volume_id;
|
||||
@@ -1227,6 +1251,10 @@ wxDataViewItem ObjectDataViewModel::ReorganizeObjects( const int current_id, co
|
||||
m_objects.emplace(m_objects.begin() + new_id, deleted_node);
|
||||
ItemAdded(wxDataViewItem(nullptr), wxDataViewItem(deleted_node));
|
||||
|
||||
// If some item has a children, just to add a deleted item is not enough on Linux
|
||||
// We should to add all its children separately
|
||||
AddAllChildren(wxDataViewItem(deleted_node));
|
||||
|
||||
return wxDataViewItem(deleted_node);
|
||||
}
|
||||
|
||||
|
||||
@@ -504,8 +504,9 @@ public:
|
||||
void UpdateExtruderBitmap(wxDataViewItem item);
|
||||
|
||||
private:
|
||||
wxDataViewItem AddRoot(const wxDataViewItem& parent_item, const ItemType root_type);
|
||||
wxDataViewItem AddInstanceRoot(const wxDataViewItem& parent_item);
|
||||
wxDataViewItem AddRoot(const wxDataViewItem& parent_item, const ItemType root_type);
|
||||
wxDataViewItem AddInstanceRoot(const wxDataViewItem& parent_item);
|
||||
void AddAllChildren(const wxDataViewItem& parent);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -129,8 +129,14 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n
|
||||
m_options.emplace(opt.opt_id, opt);
|
||||
|
||||
// Set sidetext width for a better alignment of options in line
|
||||
if (option_set.size() > 1)
|
||||
// "m_show_modified_btns==true" means that options groups are in tabs
|
||||
if (option_set.size() > 1 && m_show_modified_btns) {
|
||||
sidetext_width = Field::def_width_thinner();
|
||||
/* Temporary commented till UI-review will be completed
|
||||
if (m_show_modified_btns) // means that options groups are in tabs
|
||||
sublabel_width = Field::def_width();
|
||||
*/
|
||||
}
|
||||
|
||||
// add mode value for current line to m_options_mode
|
||||
if (!option_set.empty())
|
||||
@@ -248,15 +254,16 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n
|
||||
ConfigOptionDef option = opt.opt;
|
||||
wxSizer* sizer_tmp = sizer;
|
||||
// add label if any
|
||||
if (option.label != "") {
|
||||
if (!option.label.empty()) {
|
||||
//! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1
|
||||
wxString str_label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ?
|
||||
_CTX(option.label, "Layers") :
|
||||
_(option.label);
|
||||
label = new wxStaticText(this->ctrl_parent(), wxID_ANY, str_label + ": ", wxDefaultPosition, wxDefaultSize);
|
||||
label = new wxStaticText(this->ctrl_parent(), wxID_ANY, str_label + ": ", wxDefaultPosition, //wxDefaultSize);
|
||||
wxSize(sublabel_width != -1 ? sublabel_width * wxGetApp().em_unit() : -1, -1), wxALIGN_RIGHT);
|
||||
label->SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
label->SetFont(wxGetApp().normal_font());
|
||||
sizer_tmp->Add(label, 0, /*wxALIGN_RIGHT |*/ wxALIGN_CENTER_VERTICAL, 0);
|
||||
sizer_tmp->Add(label, 0, wxALIGN_CENTER_VERTICAL, 0);
|
||||
}
|
||||
|
||||
// add field
|
||||
|
||||
@@ -97,6 +97,7 @@ public:
|
||||
wxFont sidetext_font {wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) };
|
||||
wxFont label_font {wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) };
|
||||
int sidetext_width{ -1 };
|
||||
int sublabel_width{ -1 };
|
||||
|
||||
/// Returns a copy of the pointer of the parent wxWindow.
|
||||
/// Accessor function is because users are not allowed to change the parent
|
||||
|
||||
+54
-34
@@ -262,6 +262,11 @@ PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)),
|
||||
m_em_unit(wxGetApp().em_unit())
|
||||
{
|
||||
SetFont(wxGetApp().normal_font());
|
||||
#ifdef _WIN32
|
||||
// Workaround for ignoring CBN_EDITCHANGE events, which are processed after the content of the combo box changes, so that
|
||||
// the index of the item inside CBN_EDITCHANGE may no more be valid.
|
||||
EnableTextChangedEvents(false);
|
||||
#endif /* _WIN32 */
|
||||
Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &evt) {
|
||||
auto selected_item = this->GetSelection();
|
||||
|
||||
@@ -322,7 +327,7 @@ PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)),
|
||||
dialog.CenterOnParent();
|
||||
if (dialog.ShowModal() == wxID_OK)
|
||||
{
|
||||
colors->values[extruder_idx] = dialog.GetColourData().GetColour().GetAsString(wxC2S_HTML_SYNTAX);
|
||||
colors->values[extruder_idx] = dialog.GetColourData().GetColour().GetAsString(wxC2S_HTML_SYNTAX).ToStdString();
|
||||
|
||||
DynamicPrintConfig cfg_new = *cfg;
|
||||
cfg_new.set_key_value("extruder_colour", colors);
|
||||
@@ -870,8 +875,8 @@ Sidebar::Sidebar(Plater *parent)
|
||||
(*btn)->Hide();
|
||||
};
|
||||
|
||||
init_scalable_btn(&p->btn_send_gcode , "export_gcode", _(L("Send to printer")));
|
||||
init_scalable_btn(&p->btn_remove_device, "cross" , _(L("Remove device")));
|
||||
init_scalable_btn(&p->btn_send_gcode , "export_gcode", _(L("Send to printer")) + "\tCtrl+Shift+G");
|
||||
init_scalable_btn(&p->btn_remove_device, "eject_sd" , _(L("Remove device")));
|
||||
init_scalable_btn(&p->btn_export_gcode_removable, "export_to_sd", _(L("Export to SD card / Flash drive")));
|
||||
|
||||
// regular buttons "Slice now" and "Export G-code"
|
||||
@@ -1233,42 +1238,59 @@ void Sidebar::update_sliced_info_sizer()
|
||||
p->sliced_info->SetTextAndShow(siFilament_m, info_text, new_label);
|
||||
|
||||
p->sliced_info->SetTextAndShow(siFilament_mm3, wxString::Format("%.2f", ps.total_extruded_volume));
|
||||
p->sliced_info->SetTextAndShow(siFilament_g, wxString::Format("%.2f", ps.total_weight));
|
||||
|
||||
p->sliced_info->SetTextAndShow(siFilament_g, ps.total_weight == 0.0 ? "N/A" : wxString::Format("%.2f", ps.total_weight));
|
||||
|
||||
new_label = _(L("Cost"));
|
||||
if (is_wipe_tower)
|
||||
new_label += wxString::Format(" :\n - %s\n - %s", _(L("objects")), _(L("wipe tower")));
|
||||
|
||||
info_text = is_wipe_tower ?
|
||||
info_text = ps.total_cost == 0.0 ? "N/A" :
|
||||
is_wipe_tower ?
|
||||
wxString::Format("%.2f \n%.2f \n%.2f", ps.total_cost,
|
||||
(ps.total_cost - ps.total_wipe_tower_cost),
|
||||
ps.total_wipe_tower_cost) :
|
||||
wxString::Format("%.2f", ps.total_cost);
|
||||
p->sliced_info->SetTextAndShow(siCost, info_text, new_label);
|
||||
p->sliced_info->SetTextAndShow(siCost, info_text, new_label);
|
||||
|
||||
if (ps.estimated_normal_print_time == "N/A" && ps.estimated_silent_print_time == "N/A")
|
||||
p->sliced_info->SetTextAndShow(siEstimatedTime, "N/A");
|
||||
else {
|
||||
new_label = _(L("Estimated printing time")) +" :";
|
||||
info_text = "";
|
||||
if (ps.estimated_normal_print_time != "N/A") {
|
||||
new_label += wxString::Format("\n - %s", _(L("normal mode")));
|
||||
info_text += wxString::Format("\n%s", ps.estimated_normal_print_time);
|
||||
for (int i = (int)ps.estimated_normal_color_print_times.size() - 1; i >= 0; --i)
|
||||
wxString str_color = _(L("Color"));
|
||||
wxString str_pause = _(L("Pause"));
|
||||
|
||||
auto fill_labels = [str_color, str_pause](const std::vector<std::pair<CustomGcodeType, std::string>>& times,
|
||||
wxString& new_label, wxString& info_text)
|
||||
{
|
||||
int color_change_count = 0;
|
||||
for (auto time : times)
|
||||
if (time.first == cgtColorChange)
|
||||
color_change_count++;
|
||||
|
||||
for (int i = (int)times.size() - 1; i >= 0; --i)
|
||||
{
|
||||
new_label += wxString::Format("\n - %s%d", _(L("Color")) + " ", i + 1);
|
||||
info_text += wxString::Format("\n%s", ps.estimated_normal_color_print_times[i]);
|
||||
if (i == 0 || times[i - 1].first == cgtPausePrint)
|
||||
new_label += wxString::Format("\n - %s%d", str_color + " ", color_change_count);
|
||||
else if (times[i - 1].first == cgtColorChange)
|
||||
new_label += wxString::Format("\n - %s%d", str_color + " ", color_change_count--);
|
||||
|
||||
if (i != (int)times.size() - 1 && times[i].first == cgtPausePrint)
|
||||
new_label += wxString::Format(" -> %s", str_pause);
|
||||
|
||||
info_text += wxString::Format("\n%s", times[i].second);
|
||||
}
|
||||
};
|
||||
|
||||
if (ps.estimated_normal_print_time != "N/A") {
|
||||
new_label += wxString::Format("\n - %s", _(L("normal mode")));
|
||||
info_text += wxString::Format("\n%s", ps.estimated_normal_print_time);
|
||||
fill_labels(ps.estimated_normal_custom_gcode_print_times, new_label, info_text);
|
||||
}
|
||||
if (ps.estimated_silent_print_time != "N/A") {
|
||||
new_label += wxString::Format("\n - %s", _(L("stealth mode")));
|
||||
new_label += wxString::Format("\n - %s", _(L("stealth mode")));
|
||||
info_text += wxString::Format("\n%s", ps.estimated_silent_print_time);
|
||||
for (int i = (int)ps.estimated_silent_color_print_times.size() - 1; i >= 0; --i)
|
||||
{
|
||||
new_label += wxString::Format("\n - %s%d", _(L("Color")) + " ", i + 1);
|
||||
info_text += wxString::Format("\n%s", ps.estimated_silent_color_print_times[i]);
|
||||
}
|
||||
fill_labels(ps.estimated_silent_custom_gcode_print_times, new_label, info_text);
|
||||
}
|
||||
p->sliced_info->SetTextAndShow(siEstimatedTime, info_text, new_label);
|
||||
}
|
||||
@@ -2248,7 +2270,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
|
||||
auto *nozzle_dmrs = config->opt<ConfigOptionFloats>("nozzle_diameter");
|
||||
|
||||
bool one_by_one = input_files.size() == 1 || nozzle_dmrs->values.size() <= 1;
|
||||
bool one_by_one = input_files.size() == 1 || printer_technology == ptSLA || nozzle_dmrs->values.size() <= 1;
|
||||
if (! one_by_one) {
|
||||
for (const auto &path : input_files) {
|
||||
if (std::regex_match(path.string(), pattern_bundle)) {
|
||||
@@ -3067,10 +3089,10 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
|
||||
auto *top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p);
|
||||
if (! postpone_error_messages && top_level_wnd && top_level_wnd->IsActive()) {
|
||||
// The error returned from the Print needs to be translated into the local language.
|
||||
GUI::show_error(this->q, _(err));
|
||||
GUI::show_error(this->q, err);
|
||||
} else {
|
||||
// Show the error message once the main window gets activated.
|
||||
this->delayed_error_message = _(err);
|
||||
this->delayed_error_message = err;
|
||||
}
|
||||
return_state |= UPDATE_BACKGROUND_PROCESS_INVALID;
|
||||
}
|
||||
@@ -3260,7 +3282,7 @@ void Plater::priv::reload_from_disk()
|
||||
else
|
||||
missing_input_paths.push_back(volume->source.input_file);
|
||||
}
|
||||
else if (!object->input_file.empty() && !volume->name.empty())
|
||||
else if (!object->input_file.empty() && volume->is_model_part() && !volume->name.empty())
|
||||
missing_input_paths.push_back(volume->name);
|
||||
}
|
||||
|
||||
@@ -3324,7 +3346,7 @@ void Plater::priv::reload_from_disk()
|
||||
const auto& path = input_paths[i].string();
|
||||
|
||||
wxBusyCursor wait;
|
||||
wxBusyInfo info(_(L("Reload from: ")) + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas());
|
||||
wxBusyInfo info(_(L("Reload from:")) + " " + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas());
|
||||
|
||||
Model new_model;
|
||||
try
|
||||
@@ -4039,7 +4061,7 @@ bool Plater::priv::complit_init_part_menu()
|
||||
part_menu.AppendSeparator();
|
||||
|
||||
auto obj_list = sidebar->obj_list();
|
||||
obj_list->append_menu_item_change_type(&part_menu);
|
||||
obj_list->append_menu_item_change_type(&part_menu, q);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -4736,8 +4758,8 @@ void Plater::set_number_of_copies(/*size_t num*/)
|
||||
|
||||
ModelObject* model_object = p->model.objects[obj_idx];
|
||||
|
||||
const int num = wxGetNumberFromUser( " ", _("Enter the number of copies:"),
|
||||
_("Copies of the selected object"), model_object->instances.size(), 0, 1000, this );
|
||||
const int num = wxGetNumberFromUser( " ", _(L("Enter the number of copies:")),
|
||||
_(L("Copies of the selected object")), model_object->instances.size(), 0, 1000, this );
|
||||
if (num < 0)
|
||||
return;
|
||||
|
||||
@@ -5187,8 +5209,10 @@ void Plater::drive_ejected_callback()
|
||||
if (RemovableDriveManager::get_instance().get_did_eject())
|
||||
{
|
||||
RemovableDriveManager::get_instance().set_did_eject(false);
|
||||
wxString message = "Unmounting successful. The device " + RemovableDriveManager::get_instance().get_ejected_name() + "(" + RemovableDriveManager::get_instance().get_ejected_path() + ")" + " can now be safely removed from the computer.";
|
||||
wxMessageBox(message);
|
||||
show_info(this,
|
||||
(boost::format(_utf8(L("Unmounting successful. The device %s(%s) can now be safely removed from the computer.")))
|
||||
% RemovableDriveManager::get_instance().get_ejected_name()
|
||||
% RemovableDriveManager::get_instance().get_ejected_path()).str());
|
||||
}
|
||||
p->show_action_buttons(false);
|
||||
}
|
||||
@@ -5337,11 +5361,6 @@ void Plater::on_config_change(const DynamicPrintConfig &config)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const auto prin_host_opt = p->config->option<ConfigOptionString>("print_host");
|
||||
p->sidebar->show_send(prin_host_opt != nullptr && !prin_host_opt->value.empty());
|
||||
}
|
||||
|
||||
if (bed_shape_changed)
|
||||
p->set_bed_shape(p->config->option<ConfigOptionPoints>("bed_shape")->values,
|
||||
p->config->option<ConfigOptionString>("bed_custom_texture")->value,
|
||||
@@ -5581,6 +5600,7 @@ void Plater::suppress_background_process(const bool stop_background_process)
|
||||
void Plater::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) { p->fix_through_netfabb(obj_idx, vol_idx); }
|
||||
|
||||
void Plater::update_object_menu() { p->update_object_menu(); }
|
||||
void Plater::show_action_buttons(const bool is_ready_to_slice) const { p->show_action_buttons(is_ready_to_slice); }
|
||||
|
||||
void Plater::copy_selection_to_clipboard()
|
||||
{
|
||||
|
||||
@@ -239,6 +239,7 @@ public:
|
||||
std::vector<std::string> get_colors_for_color_print() const;
|
||||
|
||||
void update_object_menu();
|
||||
void show_action_buttons(const bool is_ready_to_slice) const;
|
||||
|
||||
wxString get_project_filename(const wxString& extension = wxEmptyString) const;
|
||||
void set_project_filename(const wxString& filename);
|
||||
|
||||
+82
-20
@@ -313,9 +313,9 @@ std::string Preset::label() const
|
||||
return this->name + (this->is_dirty ? g_suffix_modified : "");
|
||||
}
|
||||
|
||||
bool is_compatible_with_print(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print)
|
||||
bool is_compatible_with_print(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print, const PresetWithVendorProfile &active_printer)
|
||||
{
|
||||
if (preset.vendor != nullptr && preset.vendor != active_print.vendor)
|
||||
if (preset.vendor != nullptr && preset.vendor != active_printer.vendor)
|
||||
// The current profile has a vendor assigned and it is different from the active print's vendor.
|
||||
return false;
|
||||
auto &condition = preset.preset.compatible_prints_condition();
|
||||
@@ -374,12 +374,23 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config)
|
||||
if (type == TYPE_PRINTER) {
|
||||
const std::string &model = config.opt_string("printer_model");
|
||||
const std::string &variant = config.opt_string("printer_variant");
|
||||
if (model.empty() || variant.empty()) { return; }
|
||||
if (model.empty() || variant.empty())
|
||||
return;
|
||||
is_visible = app_config.get_variant(vendor->id, model, variant);
|
||||
} else if (type == TYPE_FILAMENT) {
|
||||
is_visible = app_config.has("filaments", name);
|
||||
} else if (type == TYPE_SLA_MATERIAL) {
|
||||
is_visible = app_config.has("sla_materials", name);
|
||||
} else if (type == TYPE_FILAMENT || type == TYPE_SLA_MATERIAL) {
|
||||
const char *section_name = (type == TYPE_FILAMENT) ? "filaments" : "sla_materials";
|
||||
if (app_config.has_section(section_name)) {
|
||||
// Check whether this profile is marked as "installed" in PrusaSlicer.ini,
|
||||
// or whether a profile is marked as "installed", which this profile may have been renamed from.
|
||||
const std::map<std::string, std::string> &installed = app_config.get_section(section_name);
|
||||
auto has = [&installed](const std::string &name) {
|
||||
auto it = installed.find(name);
|
||||
return it != installed.end() && ! it->second.empty();
|
||||
};
|
||||
is_visible = has(this->name);
|
||||
for (auto it = this->renamed_from.begin(); ! is_visible && it != this->renamed_from.end(); ++ it)
|
||||
is_visible = has(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,6 +491,7 @@ const std::vector<std::string>& Preset::sla_print_options()
|
||||
"support_head_penetration",
|
||||
"support_head_width",
|
||||
"support_pillar_diameter",
|
||||
"support_max_bridges_on_pillar",
|
||||
"support_pillar_connection_mode",
|
||||
"support_buildplate_only",
|
||||
"support_pillar_widening_factor",
|
||||
@@ -557,6 +569,8 @@ const std::vector<std::string>& Preset::sla_printer_options()
|
||||
"fast_tilt_time", "slow_tilt_time", "area_fill",
|
||||
"relative_correction",
|
||||
"absolute_correction",
|
||||
"elefant_foot_compensation",
|
||||
"elefant_foot_min_width",
|
||||
"gamma_correction",
|
||||
"min_exposure_time", "max_exposure_time",
|
||||
"min_initial_exposure_time", "max_initial_exposure_time",
|
||||
@@ -683,19 +697,51 @@ Preset& PresetCollection::load_preset(const std::string &path, const std::string
|
||||
return this->load_preset(path, name, std::move(cfg), select);
|
||||
}
|
||||
|
||||
static bool profile_print_params_same(const DynamicPrintConfig &cfg1, const DynamicPrintConfig &cfg2)
|
||||
enum class ProfileHostParams
|
||||
{
|
||||
t_config_option_keys diff = cfg1.diff(cfg2);
|
||||
Same,
|
||||
Different,
|
||||
Anonymized,
|
||||
};
|
||||
|
||||
static ProfileHostParams profile_host_params_same_or_anonymized(const DynamicPrintConfig &cfg_old, const DynamicPrintConfig &cfg_new)
|
||||
{
|
||||
auto opt_print_host_old = cfg_old.option<ConfigOptionString>("print_host");
|
||||
auto opt_printhost_apikey_old = cfg_old.option<ConfigOptionString>("printhost_apikey");
|
||||
auto opt_printhost_cafile_old = cfg_old.option<ConfigOptionString>("printhost_cafile");
|
||||
|
||||
auto opt_print_host_new = cfg_new.option<ConfigOptionString>("print_host");
|
||||
auto opt_printhost_apikey_new = cfg_new.option<ConfigOptionString>("printhost_apikey");
|
||||
auto opt_printhost_cafile_new = cfg_new.option<ConfigOptionString>("printhost_cafile");
|
||||
|
||||
// If the new print host data is undefined, use the old data.
|
||||
bool new_print_host_undefined = (opt_print_host_new == nullptr || opt_print_host_new ->empty()) &&
|
||||
(opt_printhost_apikey_new == nullptr || opt_printhost_apikey_new ->empty()) &&
|
||||
(opt_printhost_cafile_new == nullptr || opt_printhost_cafile_new ->empty());
|
||||
if (new_print_host_undefined)
|
||||
return ProfileHostParams::Anonymized;
|
||||
|
||||
auto opt_same = [](const ConfigOptionString *l, const ConfigOptionString *r) {
|
||||
return ((l == nullptr || l->empty()) && (r == nullptr || r->empty())) ||
|
||||
(l != nullptr && r != nullptr && l->value == r->value);
|
||||
};
|
||||
return (opt_same(opt_print_host_old, opt_print_host_new) && opt_same(opt_printhost_apikey_old, opt_printhost_apikey_new) &&
|
||||
opt_same(opt_printhost_cafile_old, opt_printhost_cafile_new)) ? ProfileHostParams::Same : ProfileHostParams::Different;
|
||||
}
|
||||
|
||||
static bool profile_print_params_same(const DynamicPrintConfig &cfg_old, const DynamicPrintConfig &cfg_new)
|
||||
{
|
||||
t_config_option_keys diff = cfg_old.diff(cfg_new);
|
||||
// Following keys are used by the UI, not by the slicing core, therefore they are not important
|
||||
// when comparing profiles for equality. Ignore them.
|
||||
for (const char *key : { "compatible_prints", "compatible_prints_condition",
|
||||
"compatible_printers", "compatible_printers_condition", "inherits",
|
||||
"print_settings_id", "filament_settings_id", "sla_print_settings_id", "sla_material_settings_id", "printer_settings_id",
|
||||
"printer_model", "printer_variant", "default_print_profile", "default_filament_profile", "default_sla_print_profile", "default_sla_material_profile",
|
||||
"printhost_apikey", "printhost_cafile" })
|
||||
"print_host", "printhost_apikey", "printhost_cafile" })
|
||||
diff.erase(std::remove(diff.begin(), diff.end(), key), diff.end());
|
||||
// Preset with the same name as stored inside the config exists.
|
||||
return diff.empty();
|
||||
return diff.empty() && profile_host_params_same_or_anonymized(cfg_old, cfg_new) != ProfileHostParams::Different;
|
||||
}
|
||||
|
||||
// Load a preset from an already parsed config file, insert it into the sorted sequence of presets
|
||||
@@ -724,11 +770,25 @@ Preset& PresetCollection::load_external_preset(
|
||||
it = this->find_preset_renamed(original_name);
|
||||
found = it != m_presets.end();
|
||||
}
|
||||
if (found && profile_print_params_same(it->config, cfg)) {
|
||||
// The preset exists and it matches the values stored inside config.
|
||||
if (select)
|
||||
this->select_preset(it - m_presets.begin());
|
||||
return *it;
|
||||
if (found) {
|
||||
if (profile_print_params_same(it->config, cfg)) {
|
||||
// The preset exists and it matches the values stored inside config.
|
||||
if (select)
|
||||
this->select_preset(it - m_presets.begin());
|
||||
return *it;
|
||||
}
|
||||
if (profile_host_params_same_or_anonymized(it->config, cfg) == ProfileHostParams::Anonymized) {
|
||||
// The project being loaded is anonymized. Replace the empty host keys of the loaded profile with the data from the original profile.
|
||||
// See "Octoprint Settings when Opening a .3MF file" GH issue #3244
|
||||
auto opt_update = [it, &cfg](const std::string &opt_key) {
|
||||
auto opt = it->config.option<ConfigOptionString>(opt_key);
|
||||
if (opt != nullptr)
|
||||
cfg.set_key_value(opt_key, opt->clone());
|
||||
};
|
||||
opt_update("print_host");
|
||||
opt_update("printhost_apikey");
|
||||
opt_update("printhost_cafile");
|
||||
}
|
||||
}
|
||||
// Update the "inherits" field.
|
||||
std::string &inherits = Preset::inherits(cfg);
|
||||
@@ -994,7 +1054,7 @@ void PresetCollection::set_default_suppressed(bool default_suppressed)
|
||||
}
|
||||
}
|
||||
|
||||
size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool unselect_if_incompatible)
|
||||
size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType unselect_if_incompatible)
|
||||
{
|
||||
DynamicPrintConfig config;
|
||||
config.set_key_value("printer_preset", new ConfigOptionString(active_printer.preset.name));
|
||||
@@ -1006,10 +1066,12 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil
|
||||
Preset &preset_selected = m_presets[idx_preset];
|
||||
Preset &preset_edited = selected ? m_edited_preset : preset_selected;
|
||||
const PresetWithVendorProfile this_preset_with_vendor_profile = this->get_preset_with_vendor_profile(preset_edited);
|
||||
bool was_compatible = preset_edited.is_compatible;
|
||||
preset_edited.is_compatible = is_compatible_with_printer(this_preset_with_vendor_profile, active_printer, &config);
|
||||
if (active_print != nullptr)
|
||||
preset_edited.is_compatible &= is_compatible_with_print(this_preset_with_vendor_profile, *active_print);
|
||||
if (! preset_edited.is_compatible && selected && unselect_if_incompatible)
|
||||
preset_edited.is_compatible &= is_compatible_with_print(this_preset_with_vendor_profile, *active_print, active_printer);
|
||||
if (! preset_edited.is_compatible && selected &&
|
||||
(unselect_if_incompatible == PresetSelectCompatibleType::Always || (unselect_if_incompatible == PresetSelectCompatibleType::OnlyIfWasCompatible && was_compatible)))
|
||||
m_idx_selected = -1;
|
||||
if (selected)
|
||||
preset_selected.is_compatible = preset_edited.is_compatible;
|
||||
@@ -1324,7 +1386,7 @@ inline t_config_option_keys deep_diff(const ConfigBase &config_this, const Confi
|
||||
const ConfigOption *other_opt = config_other.option(opt_key);
|
||||
if (this_opt != nullptr && other_opt != nullptr && *this_opt != *other_opt)
|
||||
{
|
||||
if (opt_key == "bed_shape" || opt_key == "compatible_prints" || opt_key == "compatible_printers") {
|
||||
if (opt_key == "bed_shape" || opt_key == "thumbnails" || opt_key == "compatible_prints" || opt_key == "compatible_printers") {
|
||||
diff.emplace_back(opt_key);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -247,10 +247,19 @@ protected:
|
||||
static std::string remove_suffix_modified(const std::string &name);
|
||||
};
|
||||
|
||||
bool is_compatible_with_print (const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print);
|
||||
bool is_compatible_with_print (const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print, const PresetWithVendorProfile &active_printer);
|
||||
bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer, const DynamicPrintConfig *extra_config);
|
||||
bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer);
|
||||
|
||||
enum class PresetSelectCompatibleType {
|
||||
// Never select a compatible preset if the newly selected profile is not compatible.
|
||||
Never,
|
||||
// Only select a compatible preset if the active profile used to be compatible, but it is no more.
|
||||
OnlyIfWasCompatible,
|
||||
// Always select a compatible preset if the active profile is no more compatible.
|
||||
Always
|
||||
};
|
||||
|
||||
// Collections of presets of the same type (one of the Print, Filament or Printer type).
|
||||
class PresetCollection
|
||||
{
|
||||
@@ -412,13 +421,13 @@ public:
|
||||
|
||||
// For Print / Filament presets, disable those, which are not compatible with the printer.
|
||||
template<typename PreferedCondition>
|
||||
void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool select_other_if_incompatible, PreferedCondition prefered_condition)
|
||||
void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType select_other_if_incompatible, PreferedCondition prefered_condition)
|
||||
{
|
||||
if (this->update_compatible_internal(active_printer, active_print, select_other_if_incompatible) == (size_t)-1)
|
||||
// Find some other compatible preset, or the "-- default --" preset.
|
||||
this->select_preset(this->first_compatible_idx(prefered_condition));
|
||||
}
|
||||
void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool select_other_if_incompatible)
|
||||
void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType select_other_if_incompatible)
|
||||
{ this->update_compatible(active_printer, active_print, select_other_if_incompatible, [](const std::string&){return true;}); }
|
||||
|
||||
size_t num_visible() const { return std::count_if(m_presets.begin(), m_presets.end(), [](const Preset &preset){return preset.is_visible;}); }
|
||||
@@ -515,7 +524,7 @@ private:
|
||||
std::deque<Preset>::const_iterator find_preset_renamed(const std::string &name) const
|
||||
{ return const_cast<PresetCollection*>(this)->find_preset_renamed(name); }
|
||||
|
||||
size_t update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool unselect_if_incompatible);
|
||||
size_t update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType unselect_if_incompatible);
|
||||
|
||||
static std::vector<std::string> dirty_options(const Preset *edited, const Preset *reference, const bool is_printer_type = false);
|
||||
|
||||
|
||||
@@ -238,7 +238,7 @@ void PresetBundle::load_presets(AppConfig &config, const std::string &preferred_
|
||||
errors_cummulative += err.what();
|
||||
}
|
||||
this->update_multi_material_filament_presets();
|
||||
this->update_compatible(false);
|
||||
this->update_compatible(PresetSelectCompatibleType::Never);
|
||||
if (! errors_cummulative.empty())
|
||||
throw std::runtime_error(errors_cummulative);
|
||||
|
||||
@@ -424,7 +424,7 @@ void PresetBundle::load_selections(AppConfig &config, const std::string &preferr
|
||||
// or from the preferred_model_id suggestion passed in by ConfigWizard.
|
||||
// If the printer profile enumerated by the config are not visible, select an alternate preset.
|
||||
// Do not select alternate profiles for the print / filament profiles as those presets
|
||||
// will be selected by the following call of this->update_compatible(true).
|
||||
// will be selected by the following call of this->update_compatible(PresetSelectCompatibleType::Always).
|
||||
|
||||
const Preset *initial_printer = printers.find_preset(initial_printer_profile_name);
|
||||
const Preset *preferred_printer = printers.find_by_model_id(preferred_model_id);
|
||||
@@ -457,7 +457,7 @@ void PresetBundle::load_selections(AppConfig &config, const std::string &preferr
|
||||
// Always try to select a compatible print and filament preset to the current printer preset,
|
||||
// as the application may have been closed with an active "external" preset, which does not
|
||||
// exist.
|
||||
this->update_compatible(true);
|
||||
this->update_compatible(PresetSelectCompatibleType::Always);
|
||||
this->update_multi_material_filament_presets();
|
||||
}
|
||||
|
||||
@@ -889,7 +889,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
default: break;
|
||||
}
|
||||
|
||||
this->update_compatible(false);
|
||||
this->update_compatible(PresetSelectCompatibleType::Never);
|
||||
}
|
||||
|
||||
// Load the active configuration of a config bundle from a boost property_tree. This is a private method called from load_config_file.
|
||||
@@ -951,7 +951,7 @@ void PresetBundle::load_config_file_config_bundle(const std::string &path, const
|
||||
for (size_t i = 1; i < std::min(tmp_bundle.filament_presets.size(), this->filament_presets.size()); ++ i)
|
||||
this->filament_presets[i] = load_one(this->filaments, tmp_bundle.filaments, tmp_bundle.filament_presets[i], false);
|
||||
|
||||
this->update_compatible(false);
|
||||
this->update_compatible(PresetSelectCompatibleType::Never);
|
||||
}
|
||||
|
||||
// Process the Config Bundle loaded as a Boost property tree.
|
||||
@@ -1351,7 +1351,7 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla
|
||||
this->update_multi_material_filament_presets();
|
||||
for (size_t i = 0; i < std::min(this->filament_presets.size(), active_filaments.size()); ++ i)
|
||||
this->filament_presets[i] = filaments.find_preset(active_filaments[i], true)->name;
|
||||
this->update_compatible(false);
|
||||
this->update_compatible(PresetSelectCompatibleType::Never);
|
||||
}
|
||||
|
||||
return presets_loaded;
|
||||
@@ -1399,7 +1399,7 @@ void PresetBundle::update_multi_material_filament_presets()
|
||||
}
|
||||
}
|
||||
|
||||
void PresetBundle::update_compatible(bool select_other_if_incompatible)
|
||||
void PresetBundle::update_compatible(PresetSelectCompatibleType select_other_print_if_incompatible, PresetSelectCompatibleType select_other_filament_if_incompatible)
|
||||
{
|
||||
const Preset &printer_preset = this->printers.get_edited_preset();
|
||||
const PresetWithVendorProfile printer_preset_with_vendor_profile = this->printers.get_preset_with_vendor_profile(printer_preset);
|
||||
@@ -1412,25 +1412,32 @@ void PresetBundle::update_compatible(bool select_other_if_incompatible)
|
||||
const std::string &prefered_print_profile = printer_preset.config.opt_string("default_print_profile");
|
||||
const std::vector<std::string> &prefered_filament_profiles = printer_preset.config.option<ConfigOptionStrings>("default_filament_profile")->values;
|
||||
prefered_print_profile.empty() ?
|
||||
this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_if_incompatible) :
|
||||
this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_if_incompatible,
|
||||
this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible) :
|
||||
this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible,
|
||||
[&prefered_print_profile](const std::string& profile_name) { return profile_name == prefered_print_profile; });
|
||||
const PresetWithVendorProfile print_preset_with_vendor_profile = this->prints.get_edited_preset_with_vendor_profile();
|
||||
// Remember whether the filament profiles were compatible before updating the filament compatibility.
|
||||
std::vector<char> filament_preset_was_compatible(this->filament_presets.size(), false);
|
||||
for (size_t idx = 0; idx < this->filament_presets.size(); ++ idx) {
|
||||
std::string &filament_name = this->filament_presets[idx];
|
||||
Preset *preset = this->filaments.find_preset(filament_name, false);
|
||||
filament_preset_was_compatible[idx] = preset != nullptr && preset->is_compatible;
|
||||
}
|
||||
prefered_filament_profiles.empty() ?
|
||||
this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_if_incompatible) :
|
||||
this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_if_incompatible,
|
||||
this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_filament_if_incompatible) :
|
||||
this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_filament_if_incompatible,
|
||||
[&prefered_filament_profiles](const std::string& profile_name)
|
||||
{ return std::find(prefered_filament_profiles.begin(), prefered_filament_profiles.end(), profile_name) != prefered_filament_profiles.end(); });
|
||||
if (select_other_if_incompatible) {
|
||||
if (select_other_filament_if_incompatible != PresetSelectCompatibleType::Never) {
|
||||
// Verify validity of the current filament presets.
|
||||
if (this->filament_presets.size() == 1)
|
||||
this->filament_presets.front() = this->filaments.get_edited_preset().name;
|
||||
else
|
||||
{
|
||||
for (size_t idx = 0; idx < this->filament_presets.size(); ++idx) {
|
||||
if (this->filament_presets.size() == 1) {
|
||||
if (select_other_filament_if_incompatible == PresetSelectCompatibleType::Always || filament_preset_was_compatible.front())
|
||||
this->filament_presets.front() = this->filaments.get_edited_preset().name;
|
||||
} else {
|
||||
for (size_t idx = 0; idx < this->filament_presets.size(); ++ idx) {
|
||||
std::string &filament_name = this->filament_presets[idx];
|
||||
Preset *preset = this->filaments.find_preset(filament_name, false);
|
||||
if (preset == nullptr || !preset->is_compatible) {
|
||||
if (preset == nullptr || (! preset->is_compatible && (select_other_filament_if_incompatible == PresetSelectCompatibleType::Always || filament_preset_was_compatible[idx]))) {
|
||||
// Pick a compatible profile. If there are prefered_filament_profiles, use them.
|
||||
if (prefered_filament_profiles.empty())
|
||||
filament_name = this->filaments.first_compatible().name;
|
||||
@@ -1453,13 +1460,13 @@ void PresetBundle::update_compatible(bool select_other_if_incompatible)
|
||||
const PresetWithVendorProfile sla_print_preset_with_vendor_profile = this->sla_prints.get_edited_preset_with_vendor_profile();
|
||||
const std::string &prefered_sla_print_profile = printer_preset.config.opt_string("default_sla_print_profile");
|
||||
(prefered_sla_print_profile.empty()) ?
|
||||
this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_if_incompatible) :
|
||||
this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_if_incompatible,
|
||||
this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible) :
|
||||
this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible,
|
||||
[&prefered_sla_print_profile](const std::string& profile_name){ return profile_name == prefered_sla_print_profile; });
|
||||
const std::string &prefered_sla_material_profile = printer_preset.config.opt_string("default_sla_material_profile");
|
||||
prefered_sla_material_profile.empty() ?
|
||||
this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_if_incompatible) :
|
||||
this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_if_incompatible,
|
||||
this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_filament_if_incompatible) :
|
||||
this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_filament_if_incompatible,
|
||||
[&prefered_sla_material_profile](const std::string& profile_name){ return profile_name == prefered_sla_material_profile; });
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -127,7 +127,8 @@ public:
|
||||
// Also updates the is_visible flag of each preset.
|
||||
// If select_other_if_incompatible is true, then the print or filament preset is switched to some compatible
|
||||
// preset if the current print or filament preset is not compatible.
|
||||
void update_compatible(bool select_other_if_incompatible);
|
||||
void update_compatible(PresetSelectCompatibleType select_other_print_if_incompatible, PresetSelectCompatibleType select_other_filament_if_incompatible);
|
||||
void update_compatible(PresetSelectCompatibleType select_other_if_incompatible) { this->update_compatible(select_other_if_incompatible, select_other_if_incompatible); }
|
||||
|
||||
void load_default_preset_bitmaps();
|
||||
|
||||
|
||||
@@ -262,12 +262,16 @@ std::string PresetHints::recommended_thin_wall_thickness(const PresetBundle &pre
|
||||
int num_lines = std::min(num_perimeters * 2, 10);
|
||||
out += (boost::format(_utf8(L("Recommended object thin wall thickness for layer height %.2f and"))) % layer_height).str() + " ";
|
||||
// Start with the width of two closely spaced
|
||||
double width = external_perimeter_flow.width + external_perimeter_flow.spacing();
|
||||
for (int i = 2; i <= num_lines; thin_walls ? ++ i : i += 2) {
|
||||
if (i > 2)
|
||||
out += ", ";
|
||||
out += (boost::format(_utf8(L("%d lines: %.2f mm"))) % i % width).str() + " ";
|
||||
width += perimeter_flow.spacing() * (thin_walls ? 1.f : 2.f);
|
||||
try {
|
||||
double width = external_perimeter_flow.width + external_perimeter_flow.spacing();
|
||||
for (int i = 2; i <= num_lines; thin_walls ? ++ i : i += 2) {
|
||||
if (i > 2)
|
||||
out += ", ";
|
||||
out += (boost::format(_utf8(L("%d lines: %.2f mm"))) % i % width).str() + " ";
|
||||
width += perimeter_flow.spacing() * (thin_walls ? 1.f : 2.f);
|
||||
}
|
||||
} catch (const FlowErrorNegativeSpacing &) {
|
||||
out = _utf8(L("Recommended object thin wall thickness: Not available due to excessively small extrusion width."));
|
||||
}
|
||||
}
|
||||
return out;
|
||||
|
||||
@@ -275,7 +275,7 @@ void PrintHostQueueDialog::on_error(Event &evt)
|
||||
|
||||
on_list_select();
|
||||
|
||||
GUI::show_error(nullptr, std::move(errormsg));
|
||||
GUI::show_error(nullptr, errormsg);
|
||||
}
|
||||
|
||||
void PrintHostQueueDialog::on_cancel(Event &evt)
|
||||
|
||||
+28
-15
@@ -38,8 +38,6 @@ namespace GUI {
|
||||
wxDEFINE_EVENT(EVT_TAB_VALUE_CHANGED, wxCommandEvent);
|
||||
wxDEFINE_EVENT(EVT_TAB_PRESETS_CHANGED, SimpleEvent);
|
||||
|
||||
// Tab::Tab(wxNotebook* parent, const wxString& title, const char* name) :
|
||||
// m_parent(parent), m_title(title), m_name(name)
|
||||
Tab::Tab(wxNotebook* parent, const wxString& title, Preset::Type type) :
|
||||
m_parent(parent), m_title(title), m_type(type)
|
||||
{
|
||||
@@ -49,14 +47,14 @@ Tab::Tab(wxNotebook* parent, const wxString& title, Preset::Type type) :
|
||||
m_compatible_printers.type = Preset::TYPE_PRINTER;
|
||||
m_compatible_printers.key_list = "compatible_printers";
|
||||
m_compatible_printers.key_condition = "compatible_printers_condition";
|
||||
m_compatible_printers.dialog_title = _(L("Compatible printers"));
|
||||
m_compatible_printers.dialog_label = _(L("Select the printers this profile is compatible with."));
|
||||
m_compatible_printers.dialog_title = _(L("Compatible printers")).ToUTF8();
|
||||
m_compatible_printers.dialog_label = _(L("Select the printers this profile is compatible with.")).ToUTF8();
|
||||
|
||||
m_compatible_prints.type = Preset::TYPE_PRINT;
|
||||
m_compatible_prints.key_list = "compatible_prints";
|
||||
m_compatible_prints.key_condition = "compatible_prints_condition";
|
||||
m_compatible_prints.dialog_title = _(L("Compatible print profiles"));
|
||||
m_compatible_prints.dialog_label = _(L("Select the print profiles this profile is compatible with."));
|
||||
m_compatible_prints.dialog_title = _(L("Compatible print profiles")).ToUTF8();
|
||||
m_compatible_prints.dialog_label = _(L("Select the print profiles this profile is compatible with.")).ToUTF8();
|
||||
|
||||
wxGetApp().tabs_list.push_back(this);
|
||||
|
||||
@@ -264,7 +262,7 @@ void Tab::create_preset_tab()
|
||||
// Initialize the DynamicPrintConfig by default keys/values.
|
||||
build();
|
||||
rebuild_page_tree();
|
||||
m_complited = true;
|
||||
m_completed = true;
|
||||
}
|
||||
|
||||
void Tab::add_scaled_button(wxWindow* parent,
|
||||
@@ -833,7 +831,7 @@ void Tab::load_key_value(const std::string& opt_key, const boost::any& value, bo
|
||||
// Mark the print & filament enabled if they are compatible with the currently selected preset.
|
||||
if (opt_key == "compatible_printers" || opt_key == "compatible_prints") {
|
||||
// Don't select another profile if this profile happens to become incompatible.
|
||||
m_preset_bundle->update_compatible(false);
|
||||
m_preset_bundle->update_compatible(PresetSelectCompatibleType::Never);
|
||||
}
|
||||
m_presets->update_dirty_ui(m_presets_choice);
|
||||
on_presets_changed();
|
||||
@@ -2112,8 +2110,10 @@ void TabPrinter::build_sla()
|
||||
}
|
||||
optgroup->append_line(line);
|
||||
optgroup->append_single_option_line("absolute_correction");
|
||||
optgroup->append_single_option_line("elefant_foot_compensation");
|
||||
optgroup->append_single_option_line("elefant_foot_min_width");
|
||||
optgroup->append_single_option_line("gamma_correction");
|
||||
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Exposure")));
|
||||
optgroup->append_single_option_line("min_exposure_time");
|
||||
optgroup->append_single_option_line("max_exposure_time");
|
||||
@@ -2776,6 +2776,7 @@ void Tab::select_preset(std::string preset_name, bool delete_current)
|
||||
bool print_tab = m_presets->type() == Preset::TYPE_PRINT || m_presets->type() == Preset::TYPE_SLA_PRINT;
|
||||
bool printer_tab = m_presets->type() == Preset::TYPE_PRINTER;
|
||||
bool canceled = false;
|
||||
bool technology_changed = false;
|
||||
m_dependent_tabs = {};
|
||||
if (current_dirty && ! may_discard_current_dirty_preset()) {
|
||||
canceled = true;
|
||||
@@ -2784,16 +2785,18 @@ void Tab::select_preset(std::string preset_name, bool delete_current)
|
||||
// are compatible with the new print.
|
||||
// If it is not compatible and the current filament or SLA material are dirty, let user decide
|
||||
// whether to discard the changes or keep the current print selection.
|
||||
PrinterTechnology printer_technology = m_preset_bundle->printers.get_edited_preset().printer_technology();
|
||||
PresetWithVendorProfile printer_profile = m_preset_bundle->printers.get_edited_preset_with_vendor_profile();
|
||||
PrinterTechnology printer_technology = printer_profile.preset.printer_technology();
|
||||
PresetCollection &dependent = (printer_technology == ptFFF) ? m_preset_bundle->filaments : m_preset_bundle->sla_materials;
|
||||
bool old_preset_dirty = dependent.current_is_dirty();
|
||||
bool new_preset_compatible = is_compatible_with_print(dependent.get_edited_preset_with_vendor_profile(), m_presets->get_preset_with_vendor_profile(*m_presets->find_preset(preset_name, true)));
|
||||
bool new_preset_compatible = is_compatible_with_print(dependent.get_edited_preset_with_vendor_profile(),
|
||||
m_presets->get_preset_with_vendor_profile(*m_presets->find_preset(preset_name, true)), printer_profile);
|
||||
if (! canceled)
|
||||
canceled = old_preset_dirty && ! new_preset_compatible && ! may_discard_current_dirty_preset(&dependent, preset_name);
|
||||
if (! canceled) {
|
||||
// The preset will be switched to a different, compatible preset, or the '-- default --'.
|
||||
m_dependent_tabs.emplace_back((printer_technology == ptFFF) ? Preset::Type::TYPE_FILAMENT : Preset::Type::TYPE_SLA_MATERIAL);
|
||||
if (old_preset_dirty)
|
||||
if (old_preset_dirty && ! new_preset_compatible)
|
||||
dependent.discard_current_changes();
|
||||
}
|
||||
} else if (printer_tab) {
|
||||
@@ -2840,6 +2843,8 @@ void Tab::select_preset(std::string preset_name, bool delete_current)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (! canceled)
|
||||
technology_changed = old_printer_technology != new_printer_technology;
|
||||
}
|
||||
|
||||
if (! canceled && delete_current) {
|
||||
@@ -2868,8 +2873,15 @@ void Tab::select_preset(std::string preset_name, bool delete_current)
|
||||
// Mark the print & filament enabled if they are compatible with the currently selected preset.
|
||||
// The following method should not discard changes of current print or filament presets on change of a printer profile,
|
||||
// if they are compatible with the current printer.
|
||||
auto update_compatible_type = [](bool technology_changed, bool on_page, bool show_incompatible_presets) {
|
||||
return technology_changed ? PresetSelectCompatibleType::Always :
|
||||
on_page ? PresetSelectCompatibleType::Never :
|
||||
(show_incompatible_presets ? PresetSelectCompatibleType::OnlyIfWasCompatible : PresetSelectCompatibleType::Always);
|
||||
};
|
||||
if (current_dirty || delete_current || print_tab || printer_tab)
|
||||
m_preset_bundle->update_compatible(true);
|
||||
m_preset_bundle->update_compatible(
|
||||
update_compatible_type(technology_changed, print_tab, (print_tab ? this : wxGetApp().get_tab(Preset::TYPE_PRINT))->m_show_incompatible_presets),
|
||||
update_compatible_type(technology_changed, false, wxGetApp().get_tab(Preset::TYPE_FILAMENT)->m_show_incompatible_presets));
|
||||
// Initialize the UI from the current preset.
|
||||
if (printer_tab)
|
||||
static_cast<TabPrinter*>(this)->update_pages();
|
||||
@@ -3082,7 +3094,7 @@ void Tab::save_preset(std::string name /*= ""*/)
|
||||
// Save the preset into Slic3r::data_dir / presets / section_name / preset_name.ini
|
||||
m_presets->save_current_preset(name);
|
||||
// Mark the print & filament enabled if they are compatible with the currently selected preset.
|
||||
m_preset_bundle->update_compatible(false);
|
||||
m_preset_bundle->update_compatible(PresetSelectCompatibleType::Never);
|
||||
// Add the new item into the UI component, remove dirty flags and activate the saved item.
|
||||
update_tab_ui();
|
||||
// Update the selection boxes at the plater.
|
||||
@@ -3505,7 +3517,6 @@ void TabSLAMaterial::build()
|
||||
optgroup->append_single_option_line("initial_exposure_time");
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Corrections")));
|
||||
optgroup->label_width = 19;//190;
|
||||
std::vector<std::string> corrections = {"material_correction"};
|
||||
// std::vector<std::string> axes{ "X", "Y", "Z" };
|
||||
std::vector<std::string> axes{ "XY", "Z" };
|
||||
@@ -3601,6 +3612,8 @@ void TabSLAPrint::build()
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Support pillar")));
|
||||
optgroup->append_single_option_line("support_pillar_diameter");
|
||||
optgroup->append_single_option_line("support_max_bridges_on_pillar");
|
||||
|
||||
optgroup->append_single_option_line("support_pillar_connection_mode");
|
||||
optgroup->append_single_option_line("support_buildplate_only");
|
||||
// TODO: This parameter is not used at the moment.
|
||||
|
||||
@@ -218,7 +218,7 @@ protected:
|
||||
|
||||
int m_em_unit;
|
||||
// To avoid actions with no-completed Tab
|
||||
bool m_complited { false };
|
||||
bool m_completed { false };
|
||||
ConfigOptionMode m_mode = comExpert; // to correct first Tab update_visibility() set mode to Expert
|
||||
|
||||
public:
|
||||
@@ -244,7 +244,8 @@ public:
|
||||
// std::string name() const { return m_name; }
|
||||
std::string name() const { return m_presets->name(); }
|
||||
Preset::Type type() const { return m_type; }
|
||||
bool complited() const { return m_complited; }
|
||||
// The tab is already constructed.
|
||||
bool completed() const { return m_completed; }
|
||||
virtual bool supports_printer_technology(const PrinterTechnology tech) = 0;
|
||||
|
||||
void create_preset_tab();
|
||||
|
||||
@@ -145,7 +145,7 @@ MsgUpdateConfig::~MsgUpdateConfig() {}
|
||||
//MsgUpdateForced
|
||||
|
||||
MsgUpdateForced::MsgUpdateForced(const std::vector<Update>& updates) :
|
||||
MsgDialog(nullptr, wxString::Format(_(L("%s incompatibility")), SLIC3R_APP_NAME), _(L("Configuration update is necessary to install")), wxID_NONE)
|
||||
MsgDialog(nullptr, wxString::Format(_(L("%s incompatibility")), SLIC3R_APP_NAME), _(L("You must install a configuration update.")) + " ", wxID_NONE)
|
||||
{
|
||||
auto* text = new wxStaticText(this, wxID_ANY, wxString::Format(_(L(
|
||||
"%s will now start updates. Otherwise it won't be able to start.\n\n"
|
||||
@@ -277,7 +277,7 @@ MsgDataLegacy::MsgDataLegacy() :
|
||||
"Please proceed with the %s that follows to set up the new presets "
|
||||
"and to choose whether to enable automatic preset updates."
|
||||
)),
|
||||
SLIC3R_APP_NAME, ConfigWizard::name()
|
||||
SLIC3R_APP_NAME, _(ConfigWizard::name())
|
||||
));
|
||||
text->Wrap(CONTENT_WIDTH * wxGetApp().em_unit());
|
||||
content_sizer->Add(text);
|
||||
@@ -300,14 +300,14 @@ MsgDataLegacy::~MsgDataLegacy() {}
|
||||
// MsgNoUpdate
|
||||
|
||||
MsgNoUpdates::MsgNoUpdates() :
|
||||
MsgDialog(nullptr, _(L("Configuration updates")), _(L("No updates aviable")))
|
||||
MsgDialog(nullptr, _(L("Configuration updates")), _(L("No updates available")))
|
||||
{
|
||||
|
||||
auto* text = new wxStaticText(this, wxID_ANY, wxString::Format(
|
||||
_(L(
|
||||
"%s has no configuration updates aviable."
|
||||
"%s has no configuration updates available."
|
||||
)),
|
||||
SLIC3R_APP_NAME, ConfigWizard::name()
|
||||
SLIC3R_APP_NAME
|
||||
));
|
||||
text->Wrap(CONTENT_WIDTH * wxGetApp().em_unit());
|
||||
content_sizer->Add(text);
|
||||
|
||||
@@ -543,7 +543,7 @@ std::vector<wxBitmap*> get_extruder_color_icons(bool thin_icon/* = false*/)
|
||||
* and scale them in respect to em_unit value
|
||||
*/
|
||||
const double em = Slic3r::GUI::wxGetApp().em_unit();
|
||||
const int icon_width = lround((thin_icon ? 1 : 3.2) * em);
|
||||
const int icon_width = lround((thin_icon ? 1.6 : 3.2) * em);
|
||||
const int icon_height = lround(1.6 * em);
|
||||
|
||||
for (const std::string& color : colors)
|
||||
@@ -603,7 +603,7 @@ void apply_extruder_selector(wxBitmapComboBox** ctrl,
|
||||
++i;
|
||||
}
|
||||
|
||||
(*ctrl)->Append(use_full_item_name ? wxString::Format("%s %d", str, i) : std::to_string(i), *bmp);
|
||||
(*ctrl)->Append(use_full_item_name ? wxString::Format("%s %d", str, i) : wxString::Format("%d", i), *bmp);
|
||||
++i;
|
||||
}
|
||||
(*ctrl)->SetSelection(0);
|
||||
|
||||
Reference in New Issue
Block a user