Merge branch 'master' into fs_emboss

This commit is contained in:
Filip Sykala - NTB T15p 2022-09-16 08:43:27 +02:00
commit 6e15149e7a
15 changed files with 338 additions and 121 deletions

View File

@ -1,5 +1,7 @@
#include "SeamPlacer.hpp" #include "SeamPlacer.hpp"
#include "Point.hpp"
#include "libslic3r.h"
#include "tbb/parallel_for.h" #include "tbb/parallel_for.h"
#include "tbb/blocked_range.h" #include "tbb/blocked_range.h"
#include "tbb/parallel_reduce.h" #include "tbb/parallel_reduce.h"
@ -642,8 +644,8 @@ void compute_global_occlusion(GlobalModelInfo &result, const PrintObject *po,
BOOST_LOG_TRIVIAL(debug) BOOST_LOG_TRIVIAL(debug)
<< "SeamPlacer: decimate: start"; << "SeamPlacer: decimate: start";
its_short_edge_collpase(triangle_set, 25000); its_short_edge_collpase(triangle_set, SeamPlacer::fast_decimation_triangle_count_target);
its_short_edge_collpase(negative_volumes_set, 25000); its_short_edge_collpase(negative_volumes_set, SeamPlacer::fast_decimation_triangle_count_target);
size_t negative_volumes_start_index = triangle_set.indices.size(); size_t negative_volumes_start_index = triangle_set.indices.size();
its_merge(triangle_set, negative_volumes_set); its_merge(triangle_set, negative_volumes_set);
@ -729,8 +731,9 @@ void gather_enforcers_blockers(GlobalModelInfo &result, const PrintObject *po) {
struct SeamComparator { struct SeamComparator {
SeamPosition setup; SeamPosition setup;
float angle_importance; float angle_importance;
explicit SeamComparator(SeamPosition setup) : Vec2f rear_attractor;
setup(setup) { explicit SeamComparator(SeamPosition setup, const Vec2f& rear_attractor = Vec2f::Zero()) :
setup(setup), rear_attractor(rear_attractor) {
angle_importance = angle_importance =
setup == spNearest ? SeamPlacer::angle_importance_nearest : SeamPlacer::angle_importance_aligned; setup == spNearest ? SeamPlacer::angle_importance_nearest : SeamPlacer::angle_importance_aligned;
} }
@ -761,8 +764,9 @@ struct SeamComparator {
return false; return false;
} }
if (setup == SeamPosition::spRear && a.position.y() != b.position.y()) { if (setup == SeamPosition::spRear) {
return a.position.y() > b.position.y(); return (a.position.head<2>() - rear_attractor).squaredNorm() <
(b.position.head<2>() - rear_attractor).squaredNorm();
} }
float distance_penalty_a = 0.0f; float distance_penalty_a = 0.0f;
@ -824,7 +828,8 @@ struct SeamComparator {
} }
if (setup == SeamPosition::spRear) { if (setup == SeamPosition::spRear) {
return a.position.y() + SeamPlacer::seam_align_score_tolerance * 5.0f > b.position.y(); return (a.position.head<2>() - rear_attractor).squaredNorm() - a.perimeter.flow_width <
(b.position.head<2>() - rear_attractor).squaredNorm();
} }
float penalty_a = a.overhang + a.visibility float penalty_a = a.overhang + a.visibility
@ -1452,7 +1457,9 @@ void SeamPlacer::init(const Print &print, std::function<void(void)> throw_if_can
for (const PrintObject *po : print.objects()) { for (const PrintObject *po : print.objects()) {
throw_if_canceled_func(); throw_if_canceled_func();
SeamPosition configured_seam_preference = po->config().seam_position.value; SeamPosition configured_seam_preference = po->config().seam_position.value;
SeamComparator comparator { configured_seam_preference }; Vec2f rear_attractor = unscaled(po->bounding_box().center()).cast<float>() +
1.5f * Vec2f(0.0f, unscale<float>(po->bounding_box().max.y()));
SeamComparator comparator{configured_seam_preference, rear_attractor};
{ {
GlobalModelInfo global_model_info { }; GlobalModelInfo global_model_info { };

View File

@ -110,6 +110,7 @@ class SeamPlacer {
public: public:
// Number of samples generated on the mesh. There are sqr_rays_per_sample_point*sqr_rays_per_sample_point rays casted from each samples // Number of samples generated on the mesh. There are sqr_rays_per_sample_point*sqr_rays_per_sample_point rays casted from each samples
static constexpr size_t raycasting_visibility_samples_count = 30000; static constexpr size_t raycasting_visibility_samples_count = 30000;
static constexpr size_t fast_decimation_triangle_count_target = 16000;
//square of number of rays per sample point //square of number of rays per sample point
static constexpr size_t sqr_rays_per_sample_point = 5; static constexpr size_t sqr_rays_per_sample_point = 5;

View File

@ -924,6 +924,55 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
this->get_selected_preset().save(); this->get_selected_preset().save();
} }
Preset& PresetCollection::get_preset_with_name(const std::string& new_name, const Preset* initial_preset)
{
// 1) Find the preset with a new_name or create a new one,
// initialize it with the preset_to config.
auto it = this->find_preset_internal(new_name);
if (it != m_presets.end() && it->name == new_name) {
// Preset with the same name found.
Preset& preset = *it;
if (!preset.is_default && !preset.is_external && !preset.is_system) {
// Overwriting an existing preset if it isn't default/external/system
preset.config = initial_preset->config;
// The newly saved preset can be activated -> make it visible.
preset.is_visible = true;
}
return preset;
}
// Creating a new preset.
Preset& preset = *m_presets.insert(it, *initial_preset);
std::string& inherits = preset.inherits();
std::string old_name = preset.name;
preset.name = new_name;
preset.file = this->path_from_name(new_name);
preset.vendor = nullptr;
preset.alias.clear();
preset.renamed_from.clear();
if (preset.is_system) {
// Inheriting from a system preset.
inherits = old_name;
}
else if (inherits.empty()) {
// Inheriting from a user preset. Link the new preset to the old preset.
// inherits = old_name;
}
else {
// Inherited from a user preset. Just maintain the "inherited" flag,
// meaning it will inherit from either the system preset, or the inherited user preset.
}
preset.is_default = false;
preset.is_system = false;
preset.is_external = false;
// The newly saved preset can be activated -> make it visible.
preset.is_visible = true;
// Just system presets have aliases
preset.alias.clear();
return preset;
}
bool PresetCollection::delete_current_preset() bool PresetCollection::delete_current_preset()
{ {
const Preset &selected = this->get_selected_preset(); const Preset &selected = this->get_selected_preset();
@ -947,6 +996,11 @@ bool PresetCollection::delete_current_preset()
bool PresetCollection::delete_preset(const std::string& name) bool PresetCollection::delete_preset(const std::string& name)
{ {
if (name == this->get_selected_preset().name)
return delete_current_preset();
const std::string selected_preset_name = this->get_selected_preset_name();
auto it = this->find_preset_internal(name); auto it = this->find_preset_internal(name);
const Preset& preset = *it; const Preset& preset = *it;
@ -957,6 +1011,10 @@ bool PresetCollection::delete_preset(const std::string& name)
boost::nowide::remove(preset.file.c_str()); boost::nowide::remove(preset.file.c_str());
} }
m_presets.erase(it); m_presets.erase(it);
// update selected preset
this->select_preset_by_name(selected_preset_name, true);
return true; return true;
} }

View File

@ -341,6 +341,10 @@ public:
// All presets are marked as not modified and the new preset is activated. // All presets are marked as not modified and the new preset is activated.
void save_current_preset(const std::string &new_name, bool detach = false); void save_current_preset(const std::string &new_name, bool detach = false);
// Find the preset with a new_name or create a new one,
// initialize it with the initial_preset config.
Preset& PresetCollection::get_preset_with_name(const std::string& new_name, const Preset* initial_preset);
// Delete the current preset, activate the first visible preset. // Delete the current preset, activate the first visible preset.
// returns true if the preset was deleted successfully. // returns true if the preset was deleted successfully.
bool delete_current_preset(); bool delete_current_preset();

View File

@ -425,16 +425,24 @@ void PresetBundle::load_installed_printers(const AppConfig &config)
preset.set_visible_from_appconfig(config); preset.set_visible_from_appconfig(config);
} }
const std::string& PresetBundle::get_preset_name_by_alias( const Preset::Type& preset_type, const std::string& alias) const PresetCollection& PresetBundle::get_presets(Preset::Type type)
{
assert(type >= Preset::TYPE_PRINT && type <= Preset::TYPE_PRINTER);
return type == Preset::TYPE_PRINT ? prints :
type == Preset::TYPE_SLA_PRINT ? sla_prints :
type == Preset::TYPE_FILAMENT ? filaments :
type == Preset::TYPE_SLA_MATERIAL ? sla_materials : printers;
}
const std::string& PresetBundle::get_preset_name_by_alias( const Preset::Type& preset_type, const std::string& alias)
{ {
// there are not aliases for Printers profiles // there are not aliases for Printers profiles
if (preset_type == Preset::TYPE_PRINTER || preset_type == Preset::TYPE_INVALID) if (preset_type == Preset::TYPE_PRINTER || preset_type == Preset::TYPE_INVALID)
return alias; return alias;
const PresetCollection& presets = preset_type == Preset::TYPE_PRINT ? prints : const PresetCollection& presets = get_presets(preset_type);
preset_type == Preset::TYPE_SLA_PRINT ? sla_prints :
preset_type == Preset::TYPE_FILAMENT ? filaments :
sla_materials;
return presets.get_preset_name_by_alias(alias); return presets.get_preset_name_by_alias(alias);
} }
@ -442,10 +450,7 @@ const std::string& PresetBundle::get_preset_name_by_alias( const Preset::Type& p
void PresetBundle::save_changes_for_preset(const std::string& new_name, Preset::Type type, void PresetBundle::save_changes_for_preset(const std::string& new_name, Preset::Type type,
const std::vector<std::string>& unselected_options) const std::vector<std::string>& unselected_options)
{ {
PresetCollection& presets = type == Preset::TYPE_PRINT ? prints : PresetCollection& presets = get_presets(type);
type == Preset::TYPE_SLA_PRINT ? sla_prints :
type == Preset::TYPE_FILAMENT ? filaments :
type == Preset::TYPE_SLA_MATERIAL ? sla_materials : printers;
// if we want to save just some from selected options // if we want to save just some from selected options
if (!unselected_options.empty()) { if (!unselected_options.empty()) {
@ -468,6 +473,50 @@ void PresetBundle::save_changes_for_preset(const std::string& new_name, Preset::
} }
} }
bool PresetBundle::transfer_and_save(Preset::Type type, const std::string& preset_from_name, const std::string& preset_to_name,
const std::string& preset_new_name, const std::vector<std::string>& options)
{
if (options.empty())
return false;
PresetCollection& presets = get_presets(type);
const Preset* preset_from = presets.find_preset(preset_from_name, false, false);
const Preset* preset_to = presets.find_preset(preset_to_name, false, false);
if (!preset_from || !preset_to)
return false;
// Find the preset with a new_name or create a new one,
// initialize it with the preset_to config.
Preset& preset = presets.get_preset_with_name(preset_new_name, preset_to);
if (preset.is_default || preset.is_external || preset.is_system)
// Cannot overwrite the default preset.
return false;
// Apply options from the preset_from_name.
preset.config.apply_only(preset_from->config, options);
// Store new_name preset to disk.
preset.save();
// update selection
presets.select_preset_by_name(preset_new_name, true);
// Mark the print & filament enabled if they are compatible with the currently selected preset.
// If saving the preset changes compatibility with other presets, keep the now incompatible dependent presets selected, however with a "red flag" icon showing that they are no more compatible.
update_compatible(PresetSelectCompatibleType::Never);
if (type == Preset::TYPE_PRINTER)
copy_bed_model_and_texture_if_needed(preset.config);
if (type == Preset::TYPE_FILAMENT) {
// synchronize the first filament presets.
set_filament_preset(0, filaments.get_selected_preset_name());
}
return true;
}
void PresetBundle::load_installed_filaments(AppConfig &config) void PresetBundle::load_installed_filaments(AppConfig &config)
{ {
if (! config.has_section(AppConfig::SECTION_FILAMENTS)) { if (! config.has_section(AppConfig::SECTION_FILAMENTS)) {

View File

@ -54,6 +54,8 @@ public:
// extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size() // extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size()
std::vector<std::string> filament_presets; std::vector<std::string> filament_presets;
PresetCollection& get_presets(Preset::Type preset_type);
// The project configuration values are kept separated from the print/filament/printer preset, // The project configuration values are kept separated from the print/filament/printer preset,
// they are being serialized / deserialized from / to the .amf, .3mf, .config, .gcode, // they are being serialized / deserialized from / to the .amf, .3mf, .config, .gcode,
// and they are being used by slicing core. // and they are being used by slicing core.
@ -142,11 +144,15 @@ public:
// If the "vendor" section is missing, enable all models and variants of the particular vendor. // If the "vendor" section is missing, enable all models and variants of the particular vendor.
void load_installed_printers(const AppConfig &config); void load_installed_printers(const AppConfig &config);
const std::string& get_preset_name_by_alias(const Preset::Type& preset_type, const std::string& alias) const; const std::string& get_preset_name_by_alias(const Preset::Type& preset_type, const std::string& alias);
// Save current preset of a provided type under a new name. If the name is different from the old one, // Save current preset of a provided type under a new name. If the name is different from the old one,
// Unselected option would be reverted to the beginning values // Unselected option would be reverted to the beginning values
void save_changes_for_preset(const std::string& new_name, Preset::Type type, const std::vector<std::string>& unselected_options); void save_changes_for_preset(const std::string& new_name, Preset::Type type, const std::vector<std::string>& unselected_options);
// Transfer options form preset_from_name preset to preset_to_name preset and save preset_to_name preset as new new_name preset
// Return false, if new preset wasn't saved
bool transfer_and_save(Preset::Type type, const std::string& preset_from_name, const std::string& preset_to_name,
const std::string& new_name, const std::vector<std::string>& options);
static const char *PRUSA_BUNDLE; static const char *PRUSA_BUNDLE;
private: private:

View File

@ -97,7 +97,8 @@ void its_short_edge_collpase(indexed_triangle_set &mesh, size_t target_triangle_
//shuffle the faces and traverse in random order, this MASSIVELY improves the quality of the result //shuffle the faces and traverse in random order, this MASSIVELY improves the quality of the result
std::shuffle(face_indices.begin(), face_indices.end(), generator); std::shuffle(face_indices.begin(), face_indices.end(), generator);
int allowed_face_removals = int(face_indices.size()) - int(target_triangle_count);
for (const size_t &face_idx : face_indices) { for (const size_t &face_idx : face_indices) {
if (face_removal_flags[face_idx]) { if (face_removal_flags[face_idx]) {
// if face already removed from previous collapses, skip (each collapse removes two triangles [at least] ) // if face already removed from previous collapses, skip (each collapse removes two triangles [at least] )
@ -130,10 +131,13 @@ void its_short_edge_collpase(indexed_triangle_set &mesh, size_t target_triangle_
// remove faces // remove faces
remove_face(face_idx, neighbor_to_remove_face_idx); remove_face(face_idx, neighbor_to_remove_face_idx);
remove_face(neighbor_to_remove_face_idx, face_idx); remove_face(neighbor_to_remove_face_idx, face_idx);
allowed_face_removals-=2;
// break. this triangle is done // break. this triangle is done
break; break;
} }
if (allowed_face_removals <= 0) { break; }
} }
// filter face_indices, remove those that have been collapsed // filter face_indices, remove those that have been collapsed

View File

@ -2541,8 +2541,7 @@ bool GUI_App::check_and_save_current_preset_changes(const wxString& caption, con
// synchronize config.ini with the current selections. // synchronize config.ini with the current selections.
preset_bundle->export_selections(*app_config); preset_bundle->export_selections(*app_config);
MessageDialog(nullptr, _L_PLURAL("The preset modifications are successfully saved", MessageDialog(nullptr, dlg.msg_success_saved_modifications(dlg.get_names_and_types().size())).ShowModal();
"The presets modifications are successfully saved", dlg.get_names_and_types().size())).ShowModal();
} }
} }
@ -2602,8 +2601,7 @@ bool GUI_App::check_and_keep_current_preset_changes(const wxString& caption, con
// synchronize config.ini with the current selections. // synchronize config.ini with the current selections.
preset_bundle->export_selections(*app_config); preset_bundle->export_selections(*app_config);
wxString text = _L_PLURAL("The preset modifications are successfully saved", wxString text = dlg.msg_success_saved_modifications(preset_names_and_types.size());
"The presets modifications are successfully saved", preset_names_and_types.size());
if (!is_called_from_configwizard) if (!is_called_from_configwizard)
text += "\n\n" + _L("For new project all modifications will be reseted"); text += "\n\n" + _L("For new project all modifications will be reseted");

View File

@ -296,13 +296,7 @@ void MainFrame::bind_diff_dialog()
auto transfer = [this, get_tab](Preset::Type type) { auto transfer = [this, get_tab](Preset::Type type) {
get_tab(type)->transfer_options(diff_dialog.get_left_preset_name(type), get_tab(type)->transfer_options(diff_dialog.get_left_preset_name(type),
diff_dialog.get_right_preset_name(type), diff_dialog.get_right_preset_name(type),
std::move(diff_dialog.get_selected_options(type))); diff_dialog.get_selected_options(type));
};
auto save = [this, get_tab](Preset::Type type) {
get_tab(type)->save_options(diff_dialog.get_left_preset_name(type),
diff_dialog.get_right_preset_name(type),
std::move(diff_dialog.get_selected_options(type)));
}; };
auto process_options = [this](std::function<void(Preset::Type)> process) { auto process_options = [this](std::function<void(Preset::Type)> process) {
@ -318,8 +312,6 @@ void MainFrame::bind_diff_dialog()
}; };
diff_dialog.Bind(EVT_DIFF_DIALOG_TRANSFER, [this, process_options, transfer](SimpleEvent&) { process_options(transfer); }); diff_dialog.Bind(EVT_DIFF_DIALOG_TRANSFER, [this, process_options, transfer](SimpleEvent&) { process_options(transfer); });
diff_dialog.Bind(EVT_DIFF_DIALOG_SAVE, [this, process_options, save](SimpleEvent&) { process_options(save); });
} }

View File

@ -38,7 +38,6 @@
#include "../Utils/UndoRedo.hpp" #include "../Utils/UndoRedo.hpp"
#include "BitmapCache.hpp" #include "BitmapCache.hpp"
#include "PhysicalPrinterDialog.hpp" #include "PhysicalPrinterDialog.hpp"
#include "SavePresetDialog.hpp"
#include "MsgDialog.hpp" #include "MsgDialog.hpp"
// A workaround for a set of issues related to text fitting into gtk widgets: // A workaround for a set of issues related to text fitting into gtk widgets:

View File

@ -8,7 +8,6 @@
#include <wx/sizer.h> #include <wx/sizer.h>
#include <wx/stattext.h> #include <wx/stattext.h>
#include <wx/textctrl.h> #include <wx/textctrl.h>
#include <wx/wupdlock.h>
#include "libslic3r/PresetBundle.hpp" #include "libslic3r/PresetBundle.hpp"
@ -22,25 +21,23 @@ using Slic3r::GUI::format_wxstr;
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
#define BORDER_W 10 constexpr auto BORDER_W = 10;
//----------------------------------------------- //-----------------------------------------------
// SavePresetDialog::Item // SavePresetDialog::Item
//----------------------------------------------- //-----------------------------------------------
SavePresetDialog::Item::Item(Preset::Type type, const std::string& suffix, wxBoxSizer* sizer, SavePresetDialog* parent): std::string SavePresetDialog::Item::get_init_preset_name(const std::string &suffix)
m_type(type),
m_parent(parent)
{ {
Tab* tab = wxGetApp().get_tab(m_type); PresetBundle* preset_bundle = m_parent->get_preset_bundle();
assert(tab); if (!preset_bundle)
m_presets = tab->get_presets(); preset_bundle = wxGetApp().preset_bundle;
m_presets = &preset_bundle->get_presets(m_type);
const Preset& sel_preset = m_presets->get_selected_preset(); const Preset& sel_preset = m_presets->get_selected_preset();
std::string preset_name = sel_preset.is_default ? "Untitled" : std::string preset_name = sel_preset.is_default ? "Untitled" :
sel_preset.is_system ? (boost::format(("%1% - %2%")) % sel_preset.name % suffix).str() : sel_preset.is_system ? (boost::format(("%1% - %2%")) % sel_preset.name % suffix).str() :
sel_preset.name; sel_preset.name;
// if name contains extension // if name contains extension
if (boost::iends_with(preset_name, ".ini")) { if (boost::iends_with(preset_name, ".ini")) {
@ -48,18 +45,11 @@ SavePresetDialog::Item::Item(Preset::Type type, const std::string& suffix, wxBox
preset_name.resize(len); preset_name.resize(len);
} }
std::vector<std::string> values; return preset_name;
for (const Preset& preset : *m_presets) { }
if (preset.is_default || preset.is_system || preset.is_external)
continue;
values.push_back(preset.name);
}
std::string label_str = m_parent->is_for_rename() ?_utf8(L("Rename %s to:")) : _utf8(L("Save %s as:"));
wxStaticText* label_top = new wxStaticText(m_parent, wxID_ANY, from_u8((boost::format(label_str) % into_u8(tab->title())).str()));
m_valid_bmp = new wxStaticBitmap(m_parent, wxID_ANY, *get_bmp_bundle("tick_mark"));
void SavePresetDialog::Item::init_input_name_ctrl(wxBoxSizer *input_name_sizer, const std::string preset_name)
{
if (m_parent->is_for_rename()) { if (m_parent->is_for_rename()) {
#ifdef _WIN32 #ifdef _WIN32
long style = wxBORDER_SIMPLE; long style = wxBORDER_SIMPLE;
@ -68,10 +58,19 @@ SavePresetDialog::Item::Item(Preset::Type type, const std::string& suffix, wxBox
#endif #endif
m_text_ctrl = new wxTextCtrl(m_parent, wxID_ANY, from_u8(preset_name), wxDefaultPosition, wxSize(35 * wxGetApp().em_unit(), -1), style); m_text_ctrl = new wxTextCtrl(m_parent, wxID_ANY, from_u8(preset_name), wxDefaultPosition, wxSize(35 * wxGetApp().em_unit(), -1), style);
m_text_ctrl->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { update(); }); m_text_ctrl->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { update(); });
input_name_sizer->Add(m_text_ctrl,1, wxEXPAND, BORDER_W);
} }
else { else {
std::vector<std::string> values;
for (const Preset&preset : *m_presets) {
if (preset.is_default || preset.is_system || preset.is_external)
continue;
values.push_back(preset.name);
}
m_combo = new wxComboBox(m_parent, wxID_ANY, from_u8(preset_name), wxDefaultPosition, wxSize(35 * wxGetApp().em_unit(), -1)); m_combo = new wxComboBox(m_parent, wxID_ANY, from_u8(preset_name), wxDefaultPosition, wxSize(35 * wxGetApp().em_unit(), -1));
for (const std::string& value : values) for (const std::string&value : values)
m_combo->Append(from_u8(value)); m_combo->Append(from_u8(value));
m_combo->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { update(); }); m_combo->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { update(); });
@ -80,20 +79,34 @@ SavePresetDialog::Item::Item(Preset::Type type, const std::string& suffix, wxBox
// So process wxEVT_COMBOBOX too // So process wxEVT_COMBOBOX too
m_combo->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { update(); }); m_combo->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { update(); });
#endif //__WXOSX__ #endif //__WXOSX__
}
m_valid_label = new wxStaticText(m_parent, wxID_ANY, ""); input_name_sizer->Add(m_combo, 1, wxEXPAND, BORDER_W);
}
}
wxString SavePresetDialog::Item::get_top_label_text() const
{
const std::string label_str = m_parent->is_for_rename() ?_u8L("Rename %s to:") : _u8L("Save %s as:");
Tab* tab = wxGetApp().get_tab(m_type);
return from_u8((boost::format(label_str) % into_u8(tab->title())).str());
}
SavePresetDialog::Item::Item(Preset::Type type, const std::string& suffix, wxBoxSizer* sizer, SavePresetDialog* parent):
m_type(type),
m_parent(parent),
m_valid_bmp(new wxStaticBitmap(m_parent, wxID_ANY, *get_bmp_bundle("tick_mark"))),
m_valid_label(new wxStaticText(m_parent, wxID_ANY, ""))
{
m_valid_label->SetFont(wxGetApp().bold_font()); m_valid_label->SetFont(wxGetApp().bold_font());
wxBoxSizer* combo_sizer = new wxBoxSizer(wxHORIZONTAL); wxStaticText* label_top = new wxStaticText(m_parent, wxID_ANY, get_top_label_text());
combo_sizer->Add(m_valid_bmp, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, BORDER_W);
if (m_parent->is_for_rename()) wxBoxSizer* input_name_sizer = new wxBoxSizer(wxHORIZONTAL);
combo_sizer->Add(m_text_ctrl,1, wxEXPAND, BORDER_W); input_name_sizer->Add(m_valid_bmp, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, BORDER_W);
else init_input_name_ctrl(input_name_sizer, get_init_preset_name(suffix));
combo_sizer->Add(m_combo, 1, wxEXPAND, BORDER_W);
sizer->Add(label_top, 0, wxEXPAND | wxTOP| wxBOTTOM, BORDER_W); sizer->Add(label_top, 0, wxEXPAND | wxTOP| wxBOTTOM, BORDER_W);
sizer->Add(combo_sizer, 0, wxEXPAND | wxBOTTOM, BORDER_W); sizer->Add(input_name_sizer,0, wxEXPAND | wxBOTTOM, BORDER_W);
sizer->Add(m_valid_label, 0, wxEXPAND | wxLEFT, 3*BORDER_W); sizer->Add(m_valid_label, 0, wxEXPAND | wxLEFT, 3*BORDER_W);
if (m_type == Preset::TYPE_PRINTER) if (m_type == Preset::TYPE_PRINTER)
@ -107,7 +120,7 @@ void SavePresetDialog::Item::update()
bool rename = m_parent->is_for_rename(); bool rename = m_parent->is_for_rename();
m_preset_name = into_u8(rename ? m_text_ctrl->GetValue() : m_combo->GetValue()); m_preset_name = into_u8(rename ? m_text_ctrl->GetValue() : m_combo->GetValue());
m_valid_type = Valid; m_valid_type = ValidationType::Valid;
wxString info_line; wxString info_line;
const char* unusable_symbols = "<>[]:/\\|?*\""; const char* unusable_symbols = "<>[]:/\\|?*\"";
@ -117,44 +130,44 @@ void SavePresetDialog::Item::update()
if (m_preset_name.find_first_of(unusable_symbols[i]) != std::string::npos) { if (m_preset_name.find_first_of(unusable_symbols[i]) != std::string::npos) {
info_line = _L("The supplied name is not valid;") + "\n" + info_line = _L("The supplied name is not valid;") + "\n" +
_L("the following characters are not allowed:") + " " + unusable_symbols; _L("the following characters are not allowed:") + " " + unusable_symbols;
m_valid_type = NoValid; m_valid_type = ValidationType::NoValid;
break; break;
} }
} }
if (m_valid_type == Valid && m_preset_name.find(unusable_suffix) != std::string::npos) { if (m_valid_type == ValidationType::Valid && m_preset_name.find(unusable_suffix) != std::string::npos) {
info_line = _L("The supplied name is not valid;") + "\n" + info_line = _L("The supplied name is not valid;") + "\n" +
_L("the following suffix is not allowed:") + "\n\t" + _L("the following suffix is not allowed:") + "\n\t" +
from_u8(PresetCollection::get_suffix_modified()); from_u8(PresetCollection::get_suffix_modified());
m_valid_type = NoValid; m_valid_type = ValidationType::NoValid;
} }
if (m_valid_type == Valid && m_preset_name == "- default -") { if (m_valid_type == ValidationType::Valid && m_preset_name == "- default -") {
info_line = _L("The supplied name is not available."); info_line = _L("The supplied name is not available.");
m_valid_type = NoValid; m_valid_type = ValidationType::NoValid;
} }
const Preset* existing = m_presets->find_preset(m_preset_name, false); const Preset* existing = m_presets->find_preset(m_preset_name, false);
if (m_valid_type == Valid && existing && (existing->is_default || existing->is_system)) { if (m_valid_type == ValidationType::Valid && existing && (existing->is_default || existing->is_system)) {
info_line = rename ? _L("The supplied name is used for a system profile.") : info_line = rename ? _L("The supplied name is used for a system profile.") :
_L("Cannot overwrite a system profile."); _L("Cannot overwrite a system profile.");
m_valid_type = NoValid; m_valid_type = ValidationType::NoValid;
} }
if (m_valid_type == Valid && existing && (existing->is_external)) { if (m_valid_type == ValidationType::Valid && existing && (existing->is_external)) {
info_line = rename ? _L("The supplied name is used for a external profile.") : info_line = rename ? _L("The supplied name is used for a external profile.") :
_L("Cannot overwrite an external profile."); _L("Cannot overwrite an external profile.");
m_valid_type = NoValid; m_valid_type = ValidationType::NoValid;
} }
if (m_valid_type == Valid && existing) if (m_valid_type == ValidationType::Valid && existing)
{ {
if (m_preset_name == m_presets->get_selected_preset_name()) { if (m_preset_name == m_presets->get_selected_preset_name()) {
if (!rename && m_presets->get_edited_preset().is_dirty) if (!rename && m_presets->get_edited_preset().is_dirty)
info_line = _L("Just save preset modifications"); info_line = _L("Just save preset modifications");
else else
info_line = _L("Nothing changed"); info_line = _L("Nothing changed");
m_valid_type = Valid; m_valid_type = ValidationType::Valid;
} }
else { else {
if (existing->is_compatible) if (existing->is_compatible)
@ -162,31 +175,31 @@ void SavePresetDialog::Item::update()
else else
info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists and is incompatible with selected printer.")) % m_preset_name).str()); info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists and is incompatible with selected printer.")) % m_preset_name).str());
info_line += "\n" + _L("Note: This preset will be replaced after saving"); info_line += "\n" + _L("Note: This preset will be replaced after saving");
m_valid_type = Warning; m_valid_type = ValidationType::Warning;
} }
} }
if (m_valid_type == Valid && m_preset_name.empty()) { if (m_valid_type == ValidationType::Valid && m_preset_name.empty()) {
info_line = _L("The name cannot be empty."); info_line = _L("The name cannot be empty.");
m_valid_type = NoValid; m_valid_type = ValidationType::NoValid;
} }
if (m_valid_type == Valid && m_preset_name.find_first_of(' ') == 0) { if (m_valid_type == ValidationType::Valid && m_preset_name.find_first_of(' ') == 0) {
info_line = _L("The name cannot start with space character."); info_line = _L("The name cannot start with space character.");
m_valid_type = NoValid; m_valid_type = ValidationType::NoValid;
} }
if (m_valid_type == Valid && m_preset_name.find_last_of(' ') == m_preset_name.length()-1) { if (m_valid_type == ValidationType::Valid && m_preset_name.find_last_of(' ') == m_preset_name.length()-1) {
info_line = _L("The name cannot end with space character."); info_line = _L("The name cannot end with space character.");
m_valid_type = NoValid; m_valid_type = ValidationType::NoValid;
} }
if (m_valid_type == Valid && m_presets->get_preset_name_by_alias(m_preset_name) != m_preset_name) { if (m_valid_type == ValidationType::Valid && m_presets->get_preset_name_by_alias(m_preset_name) != m_preset_name) {
info_line = _L("The name cannot be the same as a preset alias name."); info_line = _L("The name cannot be the same as a preset alias name.");
m_valid_type = NoValid; m_valid_type = ValidationType::NoValid;
} }
if (!m_parent->get_info_line_extention().IsEmpty() && m_valid_type != NoValid) if (!m_parent->get_info_line_extention().IsEmpty() && m_valid_type != ValidationType::NoValid)
info_line += "\n\n" + m_parent->get_info_line_extention(); info_line += "\n\n" + m_parent->get_info_line_extention();
m_valid_label->SetLabel(info_line); m_valid_label->SetLabel(info_line);
@ -202,14 +215,14 @@ void SavePresetDialog::Item::update()
void SavePresetDialog::Item::update_valid_bmp() void SavePresetDialog::Item::update_valid_bmp()
{ {
std::string bmp_name = m_valid_type == Warning ? "exclamation" : std::string bmp_name = m_valid_type == ValidationType::Warning ? "exclamation" :
m_valid_type == NoValid ? "cross" : "tick_mark" ; m_valid_type == ValidationType::NoValid ? "cross" : "tick_mark" ;
m_valid_bmp->SetBitmap(*get_bmp_bundle(bmp_name)); m_valid_bmp->SetBitmap(*get_bmp_bundle(bmp_name));
} }
void SavePresetDialog::Item::accept() void SavePresetDialog::Item::accept()
{ {
if (m_valid_type == Warning) if (m_valid_type == ValidationType::Warning)
m_presets->delete_preset(m_preset_name); m_presets->delete_preset(m_preset_name);
} }
@ -224,8 +237,9 @@ SavePresetDialog::SavePresetDialog(wxWindow* parent, Preset::Type type, std::str
build(std::vector<Preset::Type>{type}, suffix); build(std::vector<Preset::Type>{type}, suffix);
} }
SavePresetDialog::SavePresetDialog(wxWindow* parent, std::vector<Preset::Type> types, std::string suffix) SavePresetDialog::SavePresetDialog(wxWindow* parent, std::vector<Preset::Type> types, std::string suffix, PresetBundle* preset_bundle/* = nullptr*/)
: DPIDialog(parent, wxID_ANY, _L("Save presets"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), 5 * wxGetApp().em_unit()), wxDEFAULT_DIALOG_STYLE | wxICON_WARNING | wxRESIZE_BORDER) : DPIDialog(parent, wxID_ANY, _L("Save presets"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), 5 * wxGetApp().em_unit()), wxDEFAULT_DIALOG_STYLE | wxICON_WARNING | wxRESIZE_BORDER),
m_preset_bundle(preset_bundle)
{ {
build(types, suffix); build(types, suffix);
} }

View File

@ -29,7 +29,7 @@ class SavePresetDialog : public DPIDialog
struct Item struct Item
{ {
enum ValidationType enum class ValidationType
{ {
Valid, Valid,
NoValid, NoValid,
@ -41,15 +41,15 @@ class SavePresetDialog : public DPIDialog
void update_valid_bmp(); void update_valid_bmp();
void accept(); void accept();
bool is_valid() const { return m_valid_type != NoValid; } bool is_valid() const { return m_valid_type != ValidationType::NoValid; }
Preset::Type type() const { return m_type; } Preset::Type type() const { return m_type; }
std::string preset_name() const { return m_preset_name; } std::string preset_name() const { return m_preset_name; }
private: private:
Preset::Type m_type; Preset::Type m_type;
ValidationType m_valid_type;
std::string m_preset_name; std::string m_preset_name;
ValidationType m_valid_type {ValidationType::NoValid};
SavePresetDialog* m_parent {nullptr}; SavePresetDialog* m_parent {nullptr};
wxStaticBitmap* m_valid_bmp {nullptr}; wxStaticBitmap* m_valid_bmp {nullptr};
wxComboBox* m_combo {nullptr}; wxComboBox* m_combo {nullptr};
@ -58,7 +58,11 @@ class SavePresetDialog : public DPIDialog
PresetCollection* m_presets {nullptr}; PresetCollection* m_presets {nullptr};
void update(); std::string get_init_preset_name(const std::string &suffix);
void init_input_name_ctrl(wxBoxSizer *input_name_sizer, std::string preset_name);
wxString get_top_label_text() const ;
void update();
}; };
std::vector<Item*> m_items; std::vector<Item*> m_items;
@ -73,17 +77,22 @@ class SavePresetDialog : public DPIDialog
bool m_use_for_rename{false}; bool m_use_for_rename{false};
wxString m_info_line_extention{wxEmptyString}; wxString m_info_line_extention{wxEmptyString};
PresetBundle* m_preset_bundle{ nullptr };
public: public:
const wxString& get_info_line_extention() { return m_info_line_extention; } const wxString& get_info_line_extention() { return m_info_line_extention; }
SavePresetDialog(wxWindow* parent, Preset::Type type, std::string suffix = ""); SavePresetDialog(wxWindow* parent, Preset::Type type, std::string suffix = "");
SavePresetDialog(wxWindow* parent, std::vector<Preset::Type> types, std::string suffix = ""); SavePresetDialog(wxWindow* parent, std::vector<Preset::Type> types, std::string suffix = "", PresetBundle* preset_bundle = nullptr);
SavePresetDialog(wxWindow* parent, Preset::Type type, bool rename, const wxString& info_line_extention); SavePresetDialog(wxWindow* parent, Preset::Type type, bool rename, const wxString& info_line_extention);
~SavePresetDialog(); ~SavePresetDialog();
void AddItem(Preset::Type type, const std::string& suffix); void AddItem(Preset::Type type, const std::string& suffix);
void set_preset_bundle(PresetBundle* preset_bundle) { m_preset_bundle = preset_bundle; }
PresetBundle* get_preset_bundle() const { return m_preset_bundle; }
std::string get_name(); std::string get_name();
std::string get_name(Preset::Type type); std::string get_name(Preset::Type type);

View File

@ -30,6 +30,8 @@
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include "wxExtensions.hpp" #include "wxExtensions.hpp"
#include "PresetComboBoxes.hpp" #include "PresetComboBoxes.hpp"
#include <wx/wupdlock.h> #include <wx/wupdlock.h>
@ -3710,12 +3712,11 @@ void Tab::rename_preset()
if (m_presets_choice->is_selected_physical_printer()) if (m_presets_choice->is_selected_physical_printer())
return; return;
Preset& selected_preset = m_presets->get_selected_preset();
wxString msg; wxString msg;
if (m_type == Preset::TYPE_PRINTER && !m_preset_bundle->physical_printers.empty()) { if (m_type == Preset::TYPE_PRINTER && !m_preset_bundle->physical_printers.empty()) {
// Check preset for rename in physical printers // Check preset for rename in physical printers
std::vector<std::string> ph_printers = m_preset_bundle->physical_printers.get_printers_with_preset(selected_preset.name); std::vector<std::string> ph_printers = m_preset_bundle->physical_printers.get_printers_with_preset(m_presets->get_selected_preset().name);
if (!ph_printers.empty()) { if (!ph_printers.empty()) {
msg += _L_PLURAL("The physical printer below is based on the preset, you are going to rename.", msg += _L_PLURAL("The physical printer below is based on the preset, you are going to rename.",
"The physical printers below are based on the preset, you are going to rename.", ph_printers.size()); "The physical printers below are based on the preset, you are going to rename.", ph_printers.size());
@ -3732,31 +3733,51 @@ void Tab::rename_preset()
SavePresetDialog dlg(m_parent, m_type, true, msg); SavePresetDialog dlg(m_parent, m_type, true, msg);
if (dlg.ShowModal() != wxID_OK) if (dlg.ShowModal() != wxID_OK)
return; return;
std::string new_name = into_u8(dlg.get_name());
const std::string new_name = into_u8(dlg.get_name());
if (new_name.empty() || new_name == m_presets->get_selected_preset().name) if (new_name.empty() || new_name == m_presets->get_selected_preset().name)
return; return;
// rename selected and edited presets // Note: selected preset can be changed, if in SavePresetDialog was selected name of existing preset
Preset& selected_preset = m_presets->get_selected_preset();
Preset& edited_preset = m_presets->get_edited_preset();
std::string old_name = selected_preset.name; const std::string old_name = selected_preset.name;
std::string old_file_name = selected_preset.file; const std::string old_file_name = selected_preset.file;
selected_preset.name = new_name; assert(old_name == edited_preset.name);
boost::replace_last(selected_preset.file, old_name, new_name);
Preset& edited_preset = m_presets->get_edited_preset(); using namespace boost;
edited_preset.name = new_name; try {
boost::replace_last(edited_preset.file, old_name, new_name); // rename selected and edited presets
// rename file with renamed preset configuration selected_preset.name = new_name;
boost::filesystem::rename(old_file_name, selected_preset.file); replace_last(selected_preset.file, old_name, new_name);
// rename selected preset in printers, if it's needed edited_preset.name = new_name;
if (!msg.IsEmpty()) replace_last(edited_preset.file, old_name, new_name);
m_preset_bundle->physical_printers.rename_preset_in_printers(old_name, new_name);
// rename file with renamed preset configuration
filesystem::rename(old_file_name, selected_preset.file);
// rename selected preset in printers, if it's needed
if (!msg.IsEmpty())
m_preset_bundle->physical_printers.rename_preset_in_printers(old_name, new_name);
}
catch (const exception& ex) {
const std::string exception = diagnostic_information(ex);
printf("Can't rename a preset : %s", exception.c_str());
}
// sort presets after renaming
std::sort(m_presets->begin(), m_presets->end());
// update selection
m_presets->select_preset_by_name(new_name, true);
m_presets_choice->update(); m_presets_choice->update();
on_presets_changed();
} }
// Called for a currently selected preset. // Called for a currently selected preset.

View File

@ -36,7 +36,6 @@ namespace Slic3r {
namespace GUI { namespace GUI {
wxDEFINE_EVENT(EVT_DIFF_DIALOG_TRANSFER, SimpleEvent); wxDEFINE_EVENT(EVT_DIFF_DIALOG_TRANSFER, SimpleEvent);
wxDEFINE_EVENT(EVT_DIFF_DIALOG_SAVE, SimpleEvent);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -1336,6 +1335,12 @@ void UnsavedChangesDialog::update_tree(Preset::Type type, PresetCollection* pres
searcher.sort_options_by_label(); searcher.sort_options_by_label();
} }
wxString UnsavedChangesDialog::msg_success_saved_modifications(size_t saved_presets_cnt)
{
return _L_PLURAL("The preset modifications are successfully saved",
"The presets modifications are successfully saved", static_cast<unsigned int>(saved_presets_cnt));
}
void UnsavedChangesDialog::on_dpi_changed(const wxRect& suggested_rect) void UnsavedChangesDialog::on_dpi_changed(const wxRect& suggested_rect)
{ {
int em = em_unit(); int em = em_unit();
@ -1488,10 +1493,11 @@ void DiffPresetDialog::create_presets_sizer()
PresetComboBox*cb = (*cb_); PresetComboBox*cb = (*cb_);
cb->show_modif_preset_separately(); cb->show_modif_preset_separately();
cb->set_selection_changed_function([this, new_type, preset_bundle, cb](int selection) { cb->set_selection_changed_function([this, new_type, preset_bundle, cb](int selection) {
if (m_view_type == Preset::TYPE_INVALID) { std::string preset_name = Preset::remove_suffix_modified(cb->GetString(selection).ToUTF8().data());
std::string preset_name = Preset::remove_suffix_modified(cb->GetString(selection).ToUTF8().data()); if (m_view_type == Preset::TYPE_INVALID)
update_compatibility(preset_name, new_type, preset_bundle); update_compatibility(preset_name, new_type, preset_bundle);
} // update selection inside of related presets
preset_bundle->get_presets(new_type).select_preset_by_name(preset_name, true);
update_tree(); update_tree();
}); });
if (collection->get_selected_idx() != (size_t)-1) if (collection->get_selected_idx() != (size_t)-1)
@ -2002,10 +2008,47 @@ void DiffPresetDialog::update_compatibility(const std::string& preset_name, Pres
} }
} }
bool DiffPresetDialog::save()
{
presets_to_saves.clear();
std::vector<Preset::Type> types_for_save;
for (const Preset::Type& type : m_pr_technology == ptFFF ? std::initializer_list<Preset::Type>{Preset::TYPE_PRINTER, Preset::TYPE_PRINT, Preset::TYPE_FILAMENT} :
std::initializer_list<Preset::Type>{Preset::TYPE_PRINTER, Preset::TYPE_SLA_PRINT, Preset::TYPE_SLA_MATERIAL })
if (!m_tree->options(type, true).empty()) {
types_for_save.emplace_back(type);
presets_to_saves.emplace_back(PresetToSave{ type, get_left_preset_name(type), get_right_preset_name(type), get_right_preset_name(type) });
}
if (!types_for_save.empty()) {
SavePresetDialog save_dlg(this, types_for_save, _u8L("Modified"), m_preset_bundle_right.get());
if (save_dlg.ShowModal() != wxID_OK)
return false;
for (auto& preset : presets_to_saves) {
const std::string& name = save_dlg.get_name(preset.type);
if (!name.empty())
preset.new_name = name;
}
}
return true;
}
void DiffPresetDialog::button_event(Action act) void DiffPresetDialog::button_event(Action act)
{ {
if (act == Action::Save) { if (act == Action::Save) {
wxPostEvent(this, SimpleEvent(EVT_DIFF_DIALOG_SAVE)); if (save()) {
size_t saved_cnt = 0;
for (const auto& preset : presets_to_saves)
if (wxGetApp().preset_bundle->transfer_and_save(preset.type, preset.from_name, preset.to_name, preset.new_name, m_tree->options(preset.type, true)))
saved_cnt++;
if (saved_cnt > 0)
MessageDialog(nullptr, UnsavedChangesDialog::msg_success_saved_modifications(saved_cnt)).ShowModal();
update_presets();
}
} }
else { else {
Hide(); Hide();
@ -2022,7 +2065,6 @@ std::string DiffPresetDialog::get_left_preset_name(Preset::Type type)
std::string DiffPresetDialog::get_right_preset_name(Preset::Type type) std::string DiffPresetDialog::get_right_preset_name(Preset::Type type)
{ {
PresetComboBox* cb = m_preset_combos[int(type - Preset::TYPE_PRINT)].presets_right; PresetComboBox* cb = m_preset_combos[int(type - Preset::TYPE_PRINT)].presets_right;
return Preset::remove_suffix_modified(get_selection(cb)); return Preset::remove_suffix_modified(get_selection(cb));
} }

View File

@ -16,7 +16,6 @@ namespace Slic3r {
namespace GUI{ namespace GUI{
wxDECLARE_EVENT(EVT_DIFF_DIALOG_TRANSFER, SimpleEvent); wxDECLARE_EVENT(EVT_DIFF_DIALOG_TRANSFER, SimpleEvent);
wxDECLARE_EVENT(EVT_DIFF_DIALOG_SAVE, SimpleEvent);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// ModelNode: a node inside DiffModel // ModelNode: a node inside DiffModel
@ -321,6 +320,8 @@ public:
std::vector<std::string> get_selected_options() { return m_tree->selected_options(); } std::vector<std::string> get_selected_options() { return m_tree->selected_options(); }
bool has_unselected_options() { return m_tree->has_unselected_options(); } bool has_unselected_options() { return m_tree->has_unselected_options(); }
static wxString msg_success_saved_modifications(size_t saved_presets_cnt);
protected: protected:
void on_dpi_changed(const wxRect& suggested_rect) override; void on_dpi_changed(const wxRect& suggested_rect) override;
void on_sys_color_changed() override; void on_sys_color_changed() override;
@ -376,6 +377,7 @@ class DiffPresetDialog : public DPIDialog
void update_compatibility(const std::string& preset_name, Preset::Type type, PresetBundle* preset_bundle); void update_compatibility(const std::string& preset_name, Preset::Type type, PresetBundle* preset_bundle);
void button_event(Action act); void button_event(Action act);
bool save();
struct DiffPresets struct DiffPresets
{ {
@ -386,6 +388,17 @@ class DiffPresetDialog : public DPIDialog
std::vector<DiffPresets> m_preset_combos; std::vector<DiffPresets> m_preset_combos;
// attributes witch are used for save preset
struct PresetToSave
{
Preset::Type type;
std::string from_name;
std::string to_name;
std::string new_name;
};
std::vector<PresetToSave> presets_to_saves;
public: public:
DiffPresetDialog(MainFrame*mainframe); DiffPresetDialog(MainFrame*mainframe);
~DiffPresetDialog() override = default; ~DiffPresetDialog() override = default;