Merge branch 'master' into lm_tm_hollowing

This commit is contained in:
Lukas Matena 2019-12-20 10:33:53 +01:00
commit b3f15b1c98
68 changed files with 1399 additions and 917 deletions

View file

@ -191,7 +191,6 @@ Bed3D::Bed3D()
: m_type(Custom)
, m_custom_texture("")
, m_custom_model("")
, m_requires_canvas_update(false)
, m_vbo_id(0)
, m_scale_factor(1.0f)
{
@ -205,7 +204,6 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c
std::string cst_texture(custom_texture);
if (!cst_texture.empty())
{
std::replace(cst_texture.begin(), cst_texture.end(), '\\', '/');
if ((!boost::algorithm::iends_with(custom_texture, ".png") && !boost::algorithm::iends_with(custom_texture, ".svg")) || !boost::filesystem::exists(custom_texture))
cst_texture = "";
}
@ -214,7 +212,6 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c
std::string cst_model(custom_model);
if (!cst_model.empty())
{
std::replace(cst_model.begin(), cst_model.end(), '\\', '/');
if (!boost::algorithm::iends_with(custom_model, ".stl") || !boost::filesystem::exists(custom_model))
cst_model = "";
}
@ -438,6 +435,7 @@ void Bed3D::render_texture(const std::string& filename, bool bottom, GLCanvas3D&
render_default(bottom);
return;
}
canvas.request_extra_frame();
}
// starts generating the main texture, compression will run asynchronously
@ -457,6 +455,7 @@ void Bed3D::render_texture(const std::string& filename, bool bottom, GLCanvas3D&
render_default(bottom);
return;
}
canvas.request_extra_frame();
}
// starts generating the main texture, compression will run asynchronously
@ -481,13 +480,9 @@ void Bed3D::render_texture(const std::string& filename, bool bottom, GLCanvas3D&
if (m_temp_texture.get_id() != 0)
m_temp_texture.reset();
m_requires_canvas_update = true;
}
else if (m_requires_canvas_update && m_texture.all_compressed_data_sent_to_gpu())
m_requires_canvas_update = false;
canvas.request_extra_frame();
if (m_texture.all_compressed_data_sent_to_gpu() && canvas.is_keeping_dirty())
canvas.stop_keeping_dirty();
}
if (m_triangles.get_vertices_count() > 0)
{

View file

@ -86,8 +86,6 @@ private:
mutable GLTexture m_texture;
// temporary texture shown until the main texture has still no levels compressed
mutable GLTexture m_temp_texture;
// used to trigger 3D scene update once all compressed textures have been sent to GPU
mutable bool m_requires_canvas_update;
mutable Shader m_shader;
mutable unsigned int m_vbo_id;
mutable GLBed m_model;

View file

@ -94,12 +94,13 @@ void BackgroundSlicingProcess::process_fff()
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data);
#endif // ENABLE_THUMBNAIL_GENERATOR
if (m_fff_print->model().custom_gcode_per_height != GUI::wxGetApp().model().custom_gcode_per_height) {
GUI::wxGetApp().model().custom_gcode_per_height = m_fff_print->model().custom_gcode_per_height;
// #ys_FIXME : controll text
/* #ys_FIXME_no_exported_codes
if (m_fff_print->model().custom_gcode_per_print_z != GUI::wxGetApp().model().custom_gcode_per_print_z) {
GUI::wxGetApp().model().custom_gcode_per_print_z = m_fff_print->model().custom_gcode_per_print_z;
GUI::show_info(nullptr, _(L("To except of redundant tool manipulation, \n"
"Color change(s) for unused extruder(s) was(were) deleted")), _(L("Info")));
}
*/
if (this->set_step_started(bspsGCodeFinalize)) {
if (! m_export_path.empty()) {

View file

@ -61,9 +61,7 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf
{
m_shape = default_pt.values;
m_custom_texture = custom_texture.value.empty() ? NONE : custom_texture.value;
std::replace(m_custom_texture.begin(), m_custom_texture.end(), '\\', '/');
m_custom_model = custom_model.value.empty() ? NONE : custom_model.value;
std::replace(m_custom_model.begin(), m_custom_model.end(), '\\', '/');
auto sbsizer = new wxStaticBoxSizer(wxVERTICAL, this, _(L("Shape")));
sbsizer->GetStaticBox()->SetFont(wxGetApp().bold_font());
@ -546,8 +544,6 @@ void BedShapePanel::load_texture()
return;
}
std::replace(file_name.begin(), file_name.end(), '\\', '/');
wxBusyCursor wait;
m_custom_texture = file_name;
@ -571,8 +567,6 @@ void BedShapePanel::load_model()
return;
}
std::replace(file_name.begin(), file_name.end(), '\\', '/');
wxBusyCursor wait;
m_custom_model = file_name;

View file

@ -133,7 +133,7 @@ GLCanvas3D::LayersEditing::LayersEditing()
, m_slicing_parameters(nullptr)
, m_layer_height_profile_modified(false)
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
, m_adaptive_cusp(0.0f)
, m_adaptive_quality(0.5f)
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
, state(Unknown)
, band_width(2.0f)
@ -268,24 +268,24 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
ImGui::Separator();
if (imgui.button(_(L("Adaptive"))))
wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), Event<float>(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, m_adaptive_cusp));
wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), Event<float>(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, m_adaptive_quality));
ImGui::SameLine();
float text_align = ImGui::GetCursorPosX();
ImGui::AlignTextToFramePadding();
imgui.text(_(L("Cusp (mm)")));
imgui.text(_(L("Quality / Speed")));
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::TextUnformatted(_(L("I am a tooltip")));
ImGui::TextUnformatted(_(L("Higher print quality versus higher print speed.")));
ImGui::EndTooltip();
}
ImGui::SameLine();
float widget_align = ImGui::GetCursorPosX();
ImGui::PushItemWidth(imgui.get_style_scaling() * 120.0f);
m_adaptive_cusp = clamp(0.0f, 0.5f * (float)m_slicing_parameters->layer_height, m_adaptive_cusp);
ImGui::SliderFloat("", &m_adaptive_cusp, 0.0f, 0.5f * (float)m_slicing_parameters->layer_height, "%.3f");
m_adaptive_quality = clamp(0.0f, 1.f, m_adaptive_quality);
ImGui::SliderFloat("", &m_adaptive_quality, 0.0f, 1.f, "%.2f");
ImGui::Separator();
if (imgui.button(_(L("Smooth"))))
@ -645,10 +645,10 @@ void GLCanvas3D::LayersEditing::reset_layer_height_profile(GLCanvas3D& canvas)
}
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas, float cusp)
void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor)
{
this->update_slicing_parameters();
m_layer_height_profile = layer_height_profile_adaptive(*m_slicing_parameters, *m_model_object, cusp);
m_layer_height_profile = layer_height_profile_adaptive(*m_slicing_parameters, *m_model_object, quality_factor);
const_cast<ModelObject*>(m_model_object)->layer_height_profile = m_layer_height_profile;
m_layers_texture.valid = false;
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
@ -712,11 +712,6 @@ void GLCanvas3D::LayersEditing::update_slicing_parameters()
m_slicing_parameters = new SlicingParameters();
*m_slicing_parameters = PrintObject::slicing_parameters(*m_config, *m_model_object, m_object_max_z);
}
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
if (m_adaptive_cusp == 0.0f)
m_adaptive_cusp = 0.25f * m_slicing_parameters->layer_height;
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
}
float GLCanvas3D::LayersEditing::thickness_bar_width(const GLCanvas3D &canvas)
@ -1016,24 +1011,25 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
std::vector<float>& colors,
std::vector<std::string>& cp_legend_items)
{
std::vector<Model::CustomGCode> custom_gcode_per_height = wxGetApp().plater()->model().custom_gcode_per_height;
std::vector<Model::CustomGCode> custom_gcode_per_print_z = wxGetApp().plater()->model().custom_gcode_per_print_z;
const int extruders_cnt = wxGetApp().extruders_edited_cnt();
if (extruders_cnt == 1)
{
if (custom_gcode_per_height.empty()) {
cp_legend_items.push_back(I18N::translate_utf8(L("Default print color")));
if (custom_gcode_per_print_z.empty()) {
cp_legend_items.emplace_back(I18N::translate_utf8(L("Default print color")));
colors = colors_in;
return;
}
std::vector<std::pair<double, double>> cp_values;
cp_values.reserve(custom_gcode_per_print_z.size());
std::vector<double> print_zs = canvas.get_current_print_zs(true);
for (auto custom_code : custom_gcode_per_height)
for (auto custom_code : custom_gcode_per_print_z)
{
if (custom_code.gcode != ColorChangeCode)
continue;
auto lower_b = std::lower_bound(print_zs.begin(), print_zs.end(), custom_code.height - DoubleSlider::epsilon());
auto lower_b = std::lower_bound(print_zs.begin(), print_zs.end(), custom_code.print_z - DoubleSlider::epsilon());
if (lower_b == print_zs.end())
continue;
@ -1044,14 +1040,14 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
// to avoid duplicate values, check adding values
if (cp_values.empty() ||
!(cp_values.back().first == previous_z && cp_values.back().second == current_z))
cp_values.push_back(std::pair<double, double>(previous_z, current_z));
cp_values.emplace_back(std::pair<double, double>(previous_z, current_z));
}
const auto items_cnt = (int)cp_values.size();
if (items_cnt == 0) // There is no one color change, but there is/are some pause print or custom Gcode
{
cp_legend_items.push_back(I18N::translate_utf8(L("Default print color")));
cp_legend_items.push_back(I18N::translate_utf8(L("Pause print or custom G-code")));
cp_legend_items.emplace_back(I18N::translate_utf8(L("Default print color")));
cp_legend_items.emplace_back(I18N::translate_utf8(L("Pause print or custom G-code")));
colors = colors_in;
return;
}
@ -1060,7 +1056,7 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
colors.resize(colors_in.size(), 0.0);
::memcpy((void*)(colors.data()), (const void*)(colors_in.data() + (color_cnt - 1) * 4), 4 * sizeof(float));
cp_legend_items.push_back(I18N::translate_utf8(L("Pause print or custom G-code")));
cp_legend_items.emplace_back(I18N::translate_utf8(L("Pause print or custom G-code")));
size_t color_pos = 4;
for (int i = items_cnt; i >= 0; --i, color_pos+=4)
@ -1072,15 +1068,15 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
std::string id_str = std::to_string(i + 1) + ": ";
if (i == 0) {
cp_legend_items.push_back(id_str + (boost::format(I18N::translate_utf8(L("up to %.2f mm"))) % cp_values[0].first).str());
cp_legend_items.emplace_back(id_str + (boost::format(I18N::translate_utf8(L("up to %.2f mm"))) % cp_values[0].first).str());
break;
}
if (i == items_cnt) {
cp_legend_items.push_back(id_str + (boost::format(I18N::translate_utf8(L("above %.2f mm"))) % cp_values[i - 1].second).str());
cp_legend_items.emplace_back(id_str + (boost::format(I18N::translate_utf8(L("above %.2f mm"))) % cp_values[i - 1].second).str());
continue;
}
cp_legend_items.push_back(id_str + (boost::format(I18N::translate_utf8(L("%.2f - %.2f mm"))) % cp_values[i - 1].second % cp_values[i].first).str());
cp_legend_items.emplace_back(id_str + (boost::format(I18N::translate_utf8(L("%.2f - %.2f mm"))) % cp_values[i - 1].second % cp_values[i].first).str());
}
}
else
@ -1094,20 +1090,20 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
size_t color_in_pos = 4 * (color_cnt - 1);
for (unsigned int i = 0; i < (unsigned int)extruders_cnt; ++i)
cp_legend_items.push_back((boost::format(I18N::translate_utf8(L("Extruder %d"))) % (i + 1)).str());
cp_legend_items.emplace_back((boost::format(I18N::translate_utf8(L("Extruder %d"))) % (i + 1)).str());
::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.push_back(I18N::translate_utf8(L("Pause print or custom G-code")));
cp_legend_items.emplace_back(I18N::translate_utf8(L("Pause print or custom G-code")));
int cnt = custom_gcode_per_height.size();
int cnt = custom_gcode_per_print_z.size();
for (int i = cnt-1; i >= 0; --i)
if (custom_gcode_per_height[i].gcode == ColorChangeCode) {
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.push_back((boost::format(I18N::translate_utf8(L("Color change for Extruder %d at %.2f mm"))) % custom_gcode_per_height[i].extruder % custom_gcode_per_height[i].height).str());
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());
}
}
}
@ -1398,7 +1394,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
, m_gizmos(*this)
, m_use_clipping_planes(false)
, m_sidebar_field("")
, m_keep_dirty(false)
, m_extra_frame_requested(false)
, m_config(nullptr)
, m_process(nullptr)
, m_model(nullptr)
@ -1640,8 +1636,6 @@ void GLCanvas3D::bed_shape_changed()
refresh_camera_scene_box();
m_camera.requires_zoom_to_bed = true;
m_dirty = true;
if (m_bed.is_prusa())
start_keeping_dirty();
}
void GLCanvas3D::set_color_by(const std::string& value)
@ -1694,10 +1688,10 @@ void GLCanvas3D::reset_layer_height_profile()
m_dirty = true;
}
void GLCanvas3D::adaptive_layer_height_profile(float cusp)
void GLCanvas3D::adaptive_layer_height_profile(float quality_factor)
{
wxGetApp().plater()->take_snapshot(_(L("Variable layer height - Adaptive")));
m_layers_editing.adaptive_layer_height_profile(*this, cusp);
m_layers_editing.adaptive_layer_height_profile(*this, quality_factor);
m_layers_editing.state = LayersEditing::Completed;
m_dirty = true;
}
@ -1931,7 +1925,11 @@ void GLCanvas3D::render()
m_camera.debug_render();
#endif // ENABLE_CAMERA_STATISTICS
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog(*this);
#else
wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height());
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
wxGetApp().imgui()->render();
@ -2636,9 +2634,10 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
_refresh_if_shown_on_screen();
if (m_keep_dirty || mouse3d_controller_applied)
if (m_extra_frame_requested || mouse3d_controller_applied)
{
m_dirty = true;
m_extra_frame_requested = false;
evt.RequestMore();
}
else
@ -5395,7 +5394,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
// For coloring by a color_print(M600), return a parsed color.
bool color_by_color_print() const { return color_print_values!=nullptr; }
const size_t color_print_color_idx_by_layer_idx(const size_t layer_idx) const {
const Model::CustomGCode value(layers[layer_idx]->print_z + EPSILON, "", 0, "");
const Model::CustomGCode value{layers[layer_idx]->print_z + EPSILON, "", 0, ""};
auto it = std::lower_bound(color_print_values->begin(), color_print_values->end(), value);
return (it - color_print_values->begin()) % number_tools();
}
@ -5406,7 +5405,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
auto it = std::find_if(color_print_values->begin(), color_print_values->end(),
[print_z](const Model::CustomGCode& code)
{ return fabs(code.height - print_z) < EPSILON; });
{ return fabs(code.print_z - print_z) < EPSILON; });
if (it != color_print_values->end())
{
const std::string& code = it->gcode;
@ -5426,7 +5425,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
}
}
const Model::CustomGCode value(print_z + EPSILON, "", 0, "");
const Model::CustomGCode value{print_z + EPSILON, "", 0, ""};
it = std::lower_bound(color_print_values->begin(), color_print_values->end(), value);
while (it != color_print_values->begin())
{

View file

@ -185,7 +185,7 @@ private:
bool m_layer_height_profile_modified;
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
mutable float m_adaptive_cusp;
mutable float m_adaptive_quality;
mutable HeightProfileSmoothingParams m_smooth_params;
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
@ -236,8 +236,8 @@ private:
void accept_changes(GLCanvas3D& canvas);
void reset_layer_height_profile(GLCanvas3D& canvas);
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void adaptive_layer_height_profile(GLCanvas3D& canvas, float cusp);
void smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_paramsn);
void adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor);
void smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_params);
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
static float get_cursor_z_relative(const GLCanvas3D& canvas);
@ -436,7 +436,9 @@ private:
bool m_use_clipping_planes;
mutable SlaCap m_sla_caps[2];
std::string m_sidebar_field;
bool m_keep_dirty;
// when true renders an extra frame by not resetting m_dirty to false
// see request_extra_frame()
bool m_extra_frame_requested;
mutable GLVolumeCollection m_volumes;
Selection m_selection;
@ -540,7 +542,7 @@ public:
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void reset_layer_height_profile();
void adaptive_layer_height_profile(float cusp);
void adaptive_layer_height_profile(float quality_factor);
void smooth_layer_height_profile(const HeightProfileSmoothingParams& smoothing_params);
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
@ -665,9 +667,7 @@ public:
void set_cursor(ECursorType type);
void msw_rescale();
bool is_keeping_dirty() const { return m_keep_dirty; }
void start_keeping_dirty() { m_keep_dirty = true; }
void stop_keeping_dirty() { m_keep_dirty = false; }
void request_extra_frame() { m_extra_frame_requested = true; }
int get_main_toolbar_item_id(const std::string& name) const { return m_main_toolbar.get_item_id(name); }
void force_main_toolbar_left_action(int item_id) { m_main_toolbar.force_left_action(item_id, *this); }

View file

@ -333,17 +333,12 @@ unsigned GUI_App::get_colour_approx_luma(const wxColour &colour)
}
bool GUI_App::dark_mode()
{
const unsigned luma = get_colour_approx_luma(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
return luma < 128;
}
bool GUI_App::dark_mode_menus()
{
#if __APPLE__
return mac_dark_mode();
#else
return dark_mode();
const unsigned luma = get_colour_approx_luma(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
return luma < 128;
#endif
}

View file

@ -109,7 +109,6 @@ public:
static unsigned get_colour_approx_luma(const wxColour &colour);
static bool dark_mode();
static bool dark_mode_menus();
void init_label_colours();
void update_label_colours_from_appconfig();
void init_fonts();

View file

@ -1193,7 +1193,13 @@ void ObjectList::get_settings_choice(const wxString& category_name)
{
wxArrayString names;
wxArrayInt selections;
wxDataViewItem item = GetSelection();
/* If we try to add settings for object/part from 3Dscene,
* for the second try there is selected ItemSettings in ObjectList.
* So, check if selected item isn't SettingsItem. And get a SettingsItem's parent item, if yes
*/
const wxDataViewItem selected_item = GetSelection();
wxDataViewItem item = m_objects_model->GetItemType(selected_item) & itSettings ? m_objects_model->GetParent(selected_item) : selected_item;
const ItemType item_type = m_objects_model->GetItemType(item);
@ -1319,11 +1325,17 @@ void ObjectList::get_freq_settings_choice(const wxString& bundle_name)
{
std::vector<std::string> options = get_options_for_bundle(bundle_name);
const Selection& selection = scene_selection();
wxDataViewItem item = GetSelectedItemsCount() > 1 && selection.is_single_full_object() ?
m_objects_model->GetItemById(selection.get_object_idx()) :
GetSelection();
const wxDataViewItem sel_item = // when all instances in object are selected
GetSelectedItemsCount() > 1 && selection.is_single_full_object() ?
m_objects_model->GetItemById(selection.get_object_idx()) :
GetSelection();
ItemType item_type = m_objects_model->GetItemType(item);
/* If we try to add settings for object/part from 3Dscene,
* for the second try there is selected ItemSettings in ObjectList.
* So, check if selected item isn't SettingsItem. And get a SettingsItem's parent item, if yes
*/
wxDataViewItem item = m_objects_model->GetItemType(sel_item) & itSettings ? m_objects_model->GetParent(sel_item) : sel_item;
const ItemType item_type = m_objects_model->GetItemType(item);
/* Because of we couldn't edited layer_height for ItVolume from settings list,
* correct options according to the selected item type :
@ -1547,17 +1559,21 @@ wxMenuItem* ObjectList::append_menu_item_change_type(wxMenu* menu)
wxMenuItem* ObjectList::append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent)
{
wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _(L("Set as a Separated Object")), "",
[this](wxCommandEvent&) { split_instances(); }, "", menu, [](){return wxGetApp().plater()->can_set_instance_to_object(); }, parent);
[this](wxCommandEvent&) { split_instances(); }, "", menu);
/* New behavior logic:
* 1. Split Object to several separated object, if ALL instances are selected
* 2. Separate selected instances from the initial object to the separated object,
* if some (not all) instances are selected
*/
parent->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt) {
evt.SetText(wxGetApp().plater()->canvas3D()->get_selection().is_single_full_object() ?
_(L("Set as a Separated Objects")) : _(L("Set as a Separated Object")));
}, menu_item->GetId());
parent->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt)
{
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
evt.SetText(selection.is_single_full_object() ?
_(L("Set as a Separated Objects")) : _(L("Set as a Separated Object")));
evt.Enable(wxGetApp().plater()->can_set_instance_to_object());
}, menu_item->GetId());
return menu_item;
}
@ -1608,7 +1624,8 @@ void ObjectList::append_menu_item_export_stl(wxMenu* menu) const
void ObjectList::append_menu_item_reload_from_disk(wxMenu* menu) const
{
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, []() { return wxGetApp().plater()->can_reload_from_disk(); }, wxGetApp().plater());
[this](wxCommandEvent&) { wxGetApp().plater()->reload_from_disk(); }, "", menu,
[]() { return wxGetApp().plater()->can_reload_from_disk(); }, wxGetApp().plater());
}
void ObjectList::append_menu_item_change_extruder(wxMenu* menu) const
@ -1727,13 +1744,22 @@ wxMenu* ObjectList::create_settings_popupmenu(wxMenu *parent_menu)
wxMenu *menu = new wxMenu;
settings_menu_hierarchy settings_menu;
const bool is_part = !(m_objects_model->GetItemType(GetSelection()) == itObject || scene_selection().is_single_full_object());
/* If we try to add settings for object/part from 3Dscene,
* for the second try there is selected ItemSettings in ObjectList.
* So, check if selected item isn't SettingsItem. And get a SettingsItem's parent item, if yes
*/
const wxDataViewItem selected_item = GetSelection();
wxDataViewItem item = m_objects_model->GetItemType(selected_item) & itSettings ? m_objects_model->GetParent(selected_item) : selected_item;
const bool is_part = !(m_objects_model->GetItemType(item) == itObject || scene_selection().is_single_full_object());
get_options_menu(settings_menu, is_part);
for (auto cat : settings_menu) {
append_menu_item(menu, wxID_ANY, _(cat.first), "",
[menu, this](wxCommandEvent& event) { get_settings_choice(menu->GetLabel(event.GetId())); },
CATEGORY_ICON.find(cat.first) == CATEGORY_ICON.end() ? wxNullBitmap : CATEGORY_ICON.at(cat.first), parent_menu);
CATEGORY_ICON.find(cat.first) == CATEGORY_ICON.end() ? wxNullBitmap : CATEGORY_ICON.at(cat.first), parent_menu,
[this]() { return true; }, wxGetApp().plater());
}
return menu;
@ -1753,7 +1779,8 @@ void ObjectList::create_freq_settings_popupmenu(wxMenu *menu, const bool is_obje
append_menu_item(menu, wxID_ANY, _(it.first), "",
[menu, this](wxCommandEvent& event) { get_freq_settings_choice(menu->GetLabel(event.GetId())); },
CATEGORY_ICON.find(it.first) == CATEGORY_ICON.end() ? wxNullBitmap : CATEGORY_ICON.at(it.first), menu);
CATEGORY_ICON.find(it.first) == CATEGORY_ICON.end() ? wxNullBitmap : CATEGORY_ICON.at(it.first), menu,
[this]() { return true; }, wxGetApp().plater());
}
#if 0
// Add "Quick" settings bundles
@ -1766,7 +1793,8 @@ void ObjectList::create_freq_settings_popupmenu(wxMenu *menu, const bool is_obje
append_menu_item(menu, wxID_ANY, wxString::Format(_(L("Quick Add Settings (%s)")), _(it.first)), "",
[menu, this](wxCommandEvent& event) { get_freq_settings_choice(menu->GetLabel(event.GetId())); },
CATEGORY_ICON.find(it.first) == CATEGORY_ICON.end() ? wxNullBitmap : CATEGORY_ICON.at(it.first), menu);
CATEGORY_ICON.find(it.first) == CATEGORY_ICON.end() ? wxNullBitmap : CATEGORY_ICON.at(it.first), menu,
[this]() { return true; }, wxGetApp().plater());
}
#endif
}
@ -3006,7 +3034,8 @@ void ObjectList::update_selections()
else if (selection.is_single_full_object() || selection.is_multiple_full_object())
{
const Selection::ObjectIdxsToInstanceIdxsMap& objects_content = selection.get_content();
if (m_selection_mode & (smSettings | smLayer | smLayerRoot))
// it's impossible to select Settings, Layer or LayerRoot for several objects
if (!selection.is_multiple_full_object() && (m_selection_mode & (smSettings | smLayer | smLayerRoot)))
{
auto obj_idx = objects_content.begin()->first;
wxDataViewItem obj_item = m_objects_model->GetItemById(obj_idx);
@ -3850,8 +3879,8 @@ void ObjectList::show_multi_selection_menu()
GetSelections(sels);
for (const wxDataViewItem& item : sels)
if (!(m_objects_model->GetItemType(item) & (itVolume | itObject)))
// show this menu only for Object(s)/Volume(s) selection
if (!(m_objects_model->GetItemType(item) & (itVolume | itObject | itInstance)))
// show this menu only for Objects(Instances mixed with Objects)/Volumes selection
return;
wxMenu* menu = new wxMenu();
@ -3861,7 +3890,12 @@ void ObjectList::show_multi_selection_menu()
_(L("Select extruder number for selected objects and/or parts")),
[this](wxCommandEvent&) { extruder_selection(); }, "", menu);
PopupMenu(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, []() {
return wxGetApp().plater()->can_reload_from_disk();
}, wxGetApp().plater());
wxGetApp().plater()->PopupMenu(menu);
}
void ObjectList::extruder_selection()
@ -3939,8 +3973,15 @@ void ObjectList::update_after_undo_redo()
Plater::SuppressSnapshots suppress(wxGetApp().plater());
// Unselect all objects before deleting them, so that no change of selection is emitted during deletion.
unselect_objects();//this->UnselectAll();
/* To avoid execution of selection_changed()
* from wxEVT_DATAVIEW_SELECTION_CHANGED emitted from DeleteAll(),
* wrap this two functions into m_prevent_list_events *
* */
m_prevent_list_events = true;
this->UnselectAll();
m_objects_model->DeleteAll();
m_prevent_list_events = false;
size_t obj_idx = 0;
std::vector<size_t> obj_idxs;

View file

@ -366,6 +366,8 @@ public:
void update_printable_state(int obj_idx, int instance_idx);
void toggle_printable_state(wxDataViewItem item);
void show_multi_selection_menu();
private:
#ifdef __WXOSX__
// void OnChar(wxKeyEvent& event);
@ -384,8 +386,6 @@ private:
void OnEditingStarted(wxDataViewEvent &event);
#endif /* __WXMSW__ */
void OnEditingDone(wxDataViewEvent &event);
void show_multi_selection_menu();
void extruder_selection();
void set_extruder_for_selected_items(const int extruder) const ;

View file

@ -569,7 +569,7 @@ void Preview::update_view_type(bool slice_completed)
{
const DynamicPrintConfig& config = wxGetApp().preset_bundle->project_config;
const wxString& choice = !wxGetApp().plater()->model().custom_gcode_per_height.empty() /*&&
const wxString& choice = !wxGetApp().plater()->model().custom_gcode_per_print_z.empty() /*&&
(wxGetApp().extruders_edited_cnt()==1 || !slice_completed) */?
_(L("Color Print")) :
config.option<ConfigOptionFloats>("wiping_volumes_matrix")->values.size() > 1 ?
@ -600,7 +600,7 @@ void Preview::create_double_slider()
Bind(wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) {
Model& model = wxGetApp().plater()->model();
model.custom_gcode_per_height = m_slider->GetTicksValues();
model.custom_gcode_per_print_z = m_slider->GetTicksValues();
m_schedule_background_process();
update_view_type(false);
@ -646,7 +646,7 @@ void Preview::check_slider_values(std::vector<Model::CustomGCode>& ticks_from_mo
ticks_from_model.erase(std::remove_if(ticks_from_model.begin(), ticks_from_model.end(),
[layers_z](Model::CustomGCode val)
{
auto it = std::lower_bound(layers_z.begin(), layers_z.end(), val.height - DoubleSlider::epsilon());
auto it = std::lower_bound(layers_z.begin(), layers_z.end(), val.print_z - DoubleSlider::epsilon());
return it == layers_z.end();
}),
ticks_from_model.end());
@ -669,7 +669,7 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool kee
bool snap_to_min = force_sliders_full_range || m_slider->is_lower_at_min();
bool snap_to_max = force_sliders_full_range || m_slider->is_higher_at_max();
std::vector<Model::CustomGCode> &ticks_from_model = wxGetApp().plater()->model().custom_gcode_per_height;
std::vector<Model::CustomGCode> &ticks_from_model = wxGetApp().plater()->model().custom_gcode_per_print_z;
check_slider_values(ticks_from_model, layers_z);
m_slider->SetSliderValues(layers_z);
@ -789,7 +789,7 @@ void Preview::load_print_as_fff(bool keep_z_range)
colors.push_back("#808080"); // gray color for pause print or custom G-code
if (!gcode_preview_data_valid)
color_print_values = wxGetApp().plater()->model().custom_gcode_per_height;
color_print_values = wxGetApp().plater()->model().custom_gcode_per_print_z;
}
else if (gcode_preview_data_valid || (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::Tool) )
{

View file

@ -136,12 +136,25 @@ void GLGizmoCut::on_render_for_picking() const
void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit)
{
const float approx_height = m_imgui->scaled(11.0f);
y = std::min(y, bottom_limit - approx_height);
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
static float last_y = 0.0f;
static float last_h = 0.0f;
m_imgui->begin(_(L("Cut")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
// adjust window position to avoid overlap the view toolbar
float win_h = ImGui::GetWindowHeight();
y = std::min(y, bottom_limit - win_h);
ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always);
if ((last_h != win_h) || (last_y != y))
{
// ask canvas for another frame to render the window in the correct position
m_parent.request_extra_frame();
if (last_h != win_h)
last_h = win_h;
if (last_y != y)
last_y = y;
}
ImGui::AlignTextToFramePadding();
m_imgui->text("Z");
ImGui::SameLine();

View file

@ -749,17 +749,36 @@ void GLGizmoSlaSupports::make_line_segments() const
void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_limit)
{
if (!m_c->m_model_object)
static float last_y = 0.0f;
static float last_h = 0.0f;
if (! m_c->m_model_object)
return;
bool first_run = true; // This is a hack to redraw the button when all points are removed,
// so it is not delayed until the background process finishes.
RENDER_AGAIN:
const float approx_height = m_imgui->scaled(18.0f);
y = std::min(y, bottom_limit - approx_height);
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
//m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
//const ImVec2 window_size(m_imgui->scaled(18.f, 16.f));
//ImGui::SetNextWindowPos(ImVec2(x, y - std::max(0.f, y+window_size.y-bottom_limit) ));
//ImGui::SetNextWindowSize(ImVec2(window_size));
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
// adjust window position to avoid overlap the view toolbar
float win_h = ImGui::GetWindowHeight();
y = std::min(y, bottom_limit - win_h);
ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always);
if ((last_h != win_h) || (last_y != y))
{
// ask canvas for another frame to render the window in the correct position
m_parent.request_extra_frame();
if (last_h != win_h)
last_h = win_h;
if (last_y != y)
last_y = y;
}
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
const float settings_sliders_left = std::max(m_imgui->calc_text_size(m_desc.at("minimal_distance")).x, m_imgui->calc_text_size(m_desc.at("points_density")).x) + m_imgui->scaled(1.f);

View file

@ -20,10 +20,6 @@ GLGizmosManager::GLGizmosManager(GLCanvas3D& parent)
, m_enabled(false)
, m_icons_texture_dirty(true)
, m_current(Undefined)
, m_overlay_icons_size(Default_Icons_Size)
, m_overlay_scale(1.0f)
, m_overlay_border(5.0f)
, m_overlay_gap_y(5.0f)
, m_tooltip("")
, m_serializing(false)
{
@ -53,19 +49,18 @@ size_t GLGizmosManager::get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const
return Undefined;
float cnv_h = (float)m_parent.get_canvas_size().get_height();
float height = get_total_overlay_height();
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
float scaled_border = m_overlay_border * m_overlay_scale;
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
float top_y = 0.5f * (cnv_h - height) + scaled_border;
float height = get_scaled_total_height();
float icons_size = m_layout.scaled_icons_size();
float border = m_layout.scaled_border();
float stride_y = m_layout.scaled_stride_y();
float top_y = 0.5f * (cnv_h - height) + border;
// is mouse horizontally in the area?
if ((scaled_border <= (float)mouse_pos(0) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size))) {
if ((border <= (float)mouse_pos(0) && ((float)mouse_pos(0) <= border + icons_size))) {
// which icon is it on?
size_t from_top = (size_t)((float)mouse_pos(1) - top_y)/scaled_stride_y;
size_t from_top = (size_t)((float)mouse_pos(1) - top_y) / stride_y;
// is it really on the icon or already past the border?
if ((float)mouse_pos(1) <= top_y + from_top*scaled_stride_y + scaled_icons_size) {
if ((float)mouse_pos(1) <= top_y + from_top * stride_y + icons_size) {
std::vector<size_t> selectable = get_selectable_idxs();
if (from_top < selectable.size())
return selectable[from_top];
@ -113,18 +108,18 @@ bool GLGizmosManager::init()
void GLGizmosManager::set_overlay_icon_size(float size)
{
if (m_overlay_icons_size != size)
if (m_layout.icons_size != size)
{
m_overlay_icons_size = size;
m_layout.icons_size = size;
m_icons_texture_dirty = true;
}
}
void GLGizmosManager::set_overlay_scale(float scale)
{
if (m_overlay_scale != scale)
if (m_layout.scale != scale)
{
m_overlay_scale = scale;
m_layout.scale = scale;
m_icons_texture_dirty = true;
}
}
@ -873,26 +868,27 @@ void GLGizmosManager::do_render_overlay() const
float zoom = (float)m_parent.get_camera().get_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
float height = get_total_overlay_height();
float width = get_total_overlay_width();
float scaled_border = m_overlay_border * m_overlay_scale * inv_zoom;
float height = get_scaled_total_height();
float width = get_scaled_total_width();
float zoomed_border = m_layout.scaled_border() * inv_zoom;
float top_x = (-0.5f * cnv_w) * inv_zoom;
float top_y = (0.5f * height) * inv_zoom;
float zoomed_top_x = (-0.5f * cnv_w) * inv_zoom;
float zoomed_top_y = (0.5f * height) * inv_zoom;
float left = top_x;
float top = top_y;
float right = left + width * inv_zoom;
float bottom = top - height * inv_zoom;
float zoomed_left = zoomed_top_x;
float zoomed_top = zoomed_top_y;
float zoomed_right = zoomed_left + width * inv_zoom;
float zoomed_bottom = zoomed_top - height * inv_zoom;
render_background(left, top, right, bottom, scaled_border);
render_background(zoomed_left, zoomed_top, zoomed_right, zoomed_bottom, zoomed_border);
top_x += scaled_border;
top_y -= scaled_border;
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale * inv_zoom;
zoomed_top_x += zoomed_border;
zoomed_top_y -= zoomed_border;
float icons_size = m_layout.scaled_icons_size();
float zoomed_icons_size = icons_size * inv_zoom;
float zoomed_stride_y = m_layout.scaled_stride_y() * inv_zoom;
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale * inv_zoom;
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
unsigned int icons_texture_id = m_icons_texture.get_id();
int tex_width = m_icons_texture.get_width();
int tex_height = m_icons_texture.get_height();
@ -913,53 +909,36 @@ void GLGizmosManager::do_render_overlay() const
int icon_idx = m_current == idx ? 2 : (m_hover == idx ? 1 : 0);
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
float u_icon_size = m_overlay_icons_size * m_overlay_scale * inv_tex_width;
float v_icon_size = m_overlay_icons_size * m_overlay_scale * inv_tex_height;
float u_icon_size = icons_size * inv_tex_width;
float v_icon_size = icons_size * inv_tex_height;
float v_top = sprite_id * v_icon_size;
float u_left = icon_idx * u_icon_size;
float v_bottom = v_top + v_icon_size;
float u_right = u_left + u_icon_size;
GLTexture::render_sub_texture(icons_texture_id, top_x, top_x + scaled_icons_size, top_y - scaled_icons_size, top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } });
GLTexture::render_sub_texture(icons_texture_id, zoomed_top_x, zoomed_top_x + zoomed_icons_size, zoomed_top_y - zoomed_icons_size, zoomed_top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } });
if (idx == m_current) {
float toolbar_top = cnv_h - m_parent.get_view_toolbar_height();
gizmo->render_input_window(width, 0.5f * cnv_h - top_y * zoom, toolbar_top);
gizmo->render_input_window(width, 0.5f * cnv_h - zoomed_top_y * zoom, toolbar_top);
}
top_y -= scaled_stride_y;
zoomed_top_y -= zoomed_stride_y;
}
}
float GLGizmosManager::get_total_overlay_height() const
float GLGizmosManager::get_scaled_total_height() const
{
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
float scaled_border = m_overlay_border * m_overlay_scale;
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
float height = 2.0f * scaled_border;
/*for (size_t idx=0; idx<m_gizmos.size(); ++idx)
{
if ((m_gizmos[idx] == nullptr) || !m_gizmos[idx]->is_selectable())
continue;
height += scaled_stride_y;
}*/
height += get_selectable_idxs().size() * scaled_stride_y;
return height - scaled_gap_y;
return m_layout.scale * (2.0f * m_layout.border + (float)get_selectable_idxs().size() * m_layout.stride_y() - m_layout.gap_y);
}
float GLGizmosManager::get_total_overlay_width() const
float GLGizmosManager::get_scaled_total_width() const
{
return (2.0f * m_overlay_border + m_overlay_icons_size) * m_overlay_scale;
return 2.0f * m_layout.scaled_border() + m_layout.scaled_icons_size();
}
GLGizmoBase* GLGizmosManager::get_current() const
{
if (m_current==Undefined || m_gizmos.empty())
return nullptr;
else
return m_gizmos[m_current].get();
return ((m_current == Undefined) || m_gizmos.empty()) ? nullptr : m_gizmos[m_current].get();
}
bool GLGizmosManager::generate_icons_texture() const
@ -984,7 +963,7 @@ bool GLGizmosManager::generate_icons_texture() const
states.push_back(std::make_pair(2, false)); // Disabled
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
unsigned int sprite_size_px = (unsigned int)(m_overlay_icons_size * m_overlay_scale);
unsigned int sprite_size_px = (unsigned int)m_layout.scaled_icons_size();
// // force even size
// if (sprite_size_px % 2 != 0)
// sprite_size_px += 1;

View file

@ -65,12 +65,28 @@ public:
};
private:
struct Layout
{
float scale{ 1.0f };
float icons_size{ Default_Icons_Size };
float border{ 5.0f };
float gap_y{ 5.0f };
float stride_y() const { return icons_size + gap_y;}
float scaled_icons_size() const { return scale * icons_size; }
float scaled_border() const { return scale * border; }
float scaled_gap_y() const { return scale * gap_y; }
float scaled_stride_y() const { return scale * stride_y(); }
};
GLCanvas3D& m_parent;
bool m_enabled;
std::vector<std::unique_ptr<GLGizmoBase>> m_gizmos;
mutable GLTexture m_icons_texture;
mutable bool m_icons_texture_dirty;
BackgroundTexture m_background_texture;
Layout m_layout;
EType m_current;
EType m_hover;
@ -80,11 +96,6 @@ private:
void activate_gizmo(EType type);
float m_overlay_icons_size;
float m_overlay_scale;
float m_overlay_border;
float m_overlay_gap_y;
struct MouseCapture
{
bool left;
@ -205,8 +216,8 @@ private:
void render_background(float left, float top, float right, float bottom, float border) const;
void do_render_overlay() const;
float get_total_overlay_height() const;
float get_total_overlay_width() const;
float get_scaled_total_height() const;
float get_scaled_total_width() const;
bool generate_icons_texture() const;

View file

@ -254,6 +254,16 @@ bool ImGuiWrapper::begin(const wxString &name, int flags)
return begin(into_u8(name), flags);
}
bool ImGuiWrapper::begin(const std::string& name, bool* close, int flags)
{
return ImGui::Begin(name.c_str(), close, (ImGuiWindowFlags)flags);
}
bool ImGuiWrapper::begin(const wxString& name, bool* close, int flags)
{
return begin(into_u8(name), close, flags);
}
void ImGuiWrapper::end()
{
ImGui::End();

View file

@ -56,6 +56,8 @@ public:
bool begin(const std::string &name, int flags = 0);
bool begin(const wxString &name, int flags = 0);
bool begin(const std::string& name, bool* close, int flags = 0);
bool begin(const wxString& name, bool* close, int flags = 0);
void end();
bool button(const wxString &label);

View file

@ -380,16 +380,6 @@ void MainFrame::on_dpi_changed(const wxRect &suggested_rect)
this->Maximize(is_maximized);
}
static std::string menu_icon(const std::string& icon_name)
{
#ifdef __WXMSW__
const std::string folder = "white\\";
#else
const std::string folder = "white/";
#endif
return wxGetApp().dark_mode_menus() ? folder+icon_name : icon_name;
}
void MainFrame::init_menubar()
{
#ifdef __APPLE__
@ -403,7 +393,7 @@ void MainFrame::init_menubar()
[this](wxCommandEvent&) { if (m_plater) m_plater->new_project(); }, "", nullptr,
[this](){return m_plater != nullptr && can_start_new_project(); }, this);
append_menu_item(fileMenu, wxID_ANY, _(L("&Open Project")) + dots + "\tCtrl+O", _(L("Open a project file")),
[this](wxCommandEvent&) { if (m_plater) m_plater->load_project(); }, menu_icon("open"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->load_project(); }, "open", nullptr,
[this](){return m_plater != nullptr; }, this);
wxMenu* recent_projects_menu = new wxMenu();
@ -441,60 +431,65 @@ void MainFrame::init_menubar()
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(m_recent_projects.GetCount() > 0); }, recent_projects_submenu->GetId());
append_menu_item(fileMenu, wxID_ANY, _(L("&Save Project")) + "\tCtrl+S", _(L("Save current project file")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(into_path(m_plater->get_project_filename(".3mf"))); }, menu_icon("save"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(into_path(m_plater->get_project_filename(".3mf"))); }, "save", nullptr,
[this](){return m_plater != nullptr && can_save(); }, this);
#ifdef __APPLE__
append_menu_item(fileMenu, wxID_ANY, _(L("Save Project &as")) + dots + "\tCtrl+Shift+S", _(L("Save current project file as")),
#else
append_menu_item(fileMenu, wxID_ANY, _(L("Save Project &as")) + dots + "\tCtrl+Alt+S", _(L("Save current project file as")),
#endif // __APPLE__
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(); }, menu_icon("save"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(); }, "save", nullptr,
[this](){return m_plater != nullptr && can_save(); }, this);
fileMenu->AppendSeparator();
wxMenu* import_menu = new wxMenu();
append_menu_item(import_menu, wxID_ANY, _(L("Import STL/OBJ/AM&F/3MF")) + dots + "\tCtrl+I", _(L("Load a model")),
[this](wxCommandEvent&) { if (m_plater) m_plater->add_model(); }, menu_icon("import_plater"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->add_model(); }, "import_plater", nullptr,
[this](){return m_plater != nullptr; }, this);
import_menu->AppendSeparator();
append_menu_item(import_menu, wxID_ANY, _(L("Import &Config")) + dots + "\tCtrl+L", _(L("Load exported configuration file")),
[this](wxCommandEvent&) { load_config_file(); }, menu_icon("import_config"));
[this](wxCommandEvent&) { load_config_file(); }, "import_config", nullptr,
[this]() {return true; }, this);
append_menu_item(import_menu, wxID_ANY, _(L("Import Config from &project")) + dots +"\tCtrl+Alt+L", _(L("Load configuration from project file")),
[this](wxCommandEvent&) { if (m_plater) m_plater->extract_config_from_project(); }, menu_icon("import_config"));
[this](wxCommandEvent&) { if (m_plater) m_plater->extract_config_from_project(); }, "import_config", nullptr,
[this]() {return true; }, this);
import_menu->AppendSeparator();
append_menu_item(import_menu, wxID_ANY, _(L("Import Config &Bundle")) + dots, _(L("Load presets from a bundle")),
[this](wxCommandEvent&) { load_configbundle(); }, menu_icon("import_config_bundle"));
[this](wxCommandEvent&) { load_configbundle(); }, "import_config_bundle", nullptr,
[this]() {return true; }, this);
append_submenu(fileMenu, import_menu, wxID_ANY, _(L("&Import")), "");
wxMenu* export_menu = new wxMenu();
wxMenuItem* item_export_gcode = append_menu_item(export_menu, wxID_ANY, _(L("Export &G-code")) + dots +"\tCtrl+G", _(L("Export current plate as G-code")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(); }, menu_icon("export_gcode"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(); }, "export_gcode", nullptr,
[this](){return can_export_gcode(); }, this);
m_changeable_menu_items.push_back(item_export_gcode);
wxMenuItem* item_send_gcode = append_menu_item(export_menu, wxID_ANY, _(L("S&end G-code")) + dots +"\tCtrl+Shift+G", _(L("Send to print current plate as G-code")),
[this](wxCommandEvent&) { if (m_plater) m_plater->send_gcode(); }, menu_icon("export_gcode"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->send_gcode(); }, "export_gcode", nullptr,
[this](){return can_send_gcode(); }, this);
m_changeable_menu_items.push_back(item_send_gcode);
export_menu->AppendSeparator();
append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &STL")) + dots, _(L("Export current plate as STL")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, menu_icon("export_plater"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, "export_plater", nullptr,
[this](){return can_export_model(); }, this);
append_menu_item(export_menu, wxID_ANY, _(L("Export plate as STL &including supports")) + dots, _(L("Export current plate as STL including supports")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(true); }, menu_icon("export_plater"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(true); }, "export_plater", nullptr,
[this](){return can_export_supports(); }, this);
append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &AMF")) + dots, _(L("Export current plate as AMF")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_amf(); }, menu_icon("export_plater"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->export_amf(); }, "export_plater", nullptr,
[this](){return can_export_model(); }, this);
export_menu->AppendSeparator();
append_menu_item(export_menu, wxID_ANY, _(L("Export &toolpaths as OBJ")) + dots, _(L("Export toolpaths as OBJ")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_toolpaths_to_obj(); }, menu_icon("export_plater"), nullptr,
[this](wxCommandEvent&) { if (m_plater) m_plater->export_toolpaths_to_obj(); }, "export_plater", nullptr,
[this]() {return can_export_toolpaths(); }, this);
export_menu->AppendSeparator();
append_menu_item(export_menu, wxID_ANY, _(L("Export &Config")) +dots +"\tCtrl+E", _(L("Export current configuration to file")),
[this](wxCommandEvent&) { export_config(); }, menu_icon("export_config"));
[this](wxCommandEvent&) { export_config(); }, "export_config", nullptr,
[this]() {return true; }, this);
append_menu_item(export_menu, wxID_ANY, _(L("Export Config &Bundle")) + dots, _(L("Export all presets to file")),
[this](wxCommandEvent&) { export_configbundle(); }, menu_icon("export_config_bundle"));
[this](wxCommandEvent&) { export_configbundle(); }, "export_config_bundle", nullptr,
[this]() {return true; }, this);
append_submenu(fileMenu, export_menu, wxID_ANY, _(L("&Export")), "");
fileMenu->AppendSeparator();
@ -522,11 +517,12 @@ void MainFrame::init_menubar()
fileMenu->AppendSeparator();
#endif
m_menu_item_reslice_now = append_menu_item(fileMenu, wxID_ANY, _(L("(Re)Slice No&w")) + "\tCtrl+R", _(L("Start new slicing process")),
[this](wxCommandEvent&) { reslice_now(); }, menu_icon("re_slice"), nullptr,
[this](wxCommandEvent&) { reslice_now(); }, "re_slice", nullptr,
[this](){return m_plater != nullptr && can_reslice(); }, this);
fileMenu->AppendSeparator();
append_menu_item(fileMenu, wxID_ANY, _(L("&Repair STL file")) + dots, _(L("Automatically repair an STL file")),
[this](wxCommandEvent&) { repair_stl(); }, menu_icon("wrench"));
[this](wxCommandEvent&) { repair_stl(); }, "wrench", nullptr,
[this]() {return true; }, this);
fileMenu->AppendSeparator();
append_menu_item(fileMenu, wxID_EXIT, _(L("&Quit")), wxString::Format(_(L("Quit %s")), SLIC3R_APP_NAME),
[this](wxCommandEvent&) { Close(false); });
@ -562,10 +558,10 @@ void MainFrame::init_menubar()
editMenu->AppendSeparator();
append_menu_item(editMenu, wxID_ANY, _(L("&Delete selected")) + sep + hotkey_delete,
_(L("Deletes the current selection")),[this](wxCommandEvent&) { m_plater->remove_selected(); },
menu_icon("remove_menu"), nullptr, [this](){return can_delete(); }, this);
"remove_menu", nullptr, [this](){return can_delete(); }, this);
append_menu_item(editMenu, wxID_ANY, _(L("Delete &all")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + hotkey_delete,
_(L("Deletes all objects")), [this](wxCommandEvent&) { m_plater->reset_with_confirm(); },
menu_icon("delete_all_menu"), nullptr, [this](){return can_delete_all(); }, this);
"delete_all_menu", nullptr, [this](){return can_delete_all(); }, this);
editMenu->AppendSeparator();
append_menu_item(editMenu, wxID_ANY, _(L("&Undo")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "Z",
@ -578,10 +574,10 @@ void MainFrame::init_menubar()
editMenu->AppendSeparator();
append_menu_item(editMenu, wxID_ANY, _(L("&Copy")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "C",
_(L("Copy selection to clipboard")), [this](wxCommandEvent&) { m_plater->copy_selection_to_clipboard(); },
menu_icon("copy_menu"), nullptr, [this](){return m_plater->can_copy_to_clipboard(); }, this);
"copy_menu", nullptr, [this](){return m_plater->can_copy_to_clipboard(); }, this);
append_menu_item(editMenu, wxID_ANY, _(L("&Paste")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "V",
_(L("Paste clipboard")), [this](wxCommandEvent&) { m_plater->paste_from_clipboard(); },
menu_icon("paste_menu"), nullptr, [this](){return m_plater->can_paste_from_clipboard(); }, this);
"paste_menu", nullptr, [this](){return m_plater->can_paste_from_clipboard(); }, this);
}
// Window menu
@ -590,26 +586,30 @@ void MainFrame::init_menubar()
size_t tab_offset = 0;
if (m_plater) {
append_menu_item(windowMenu, wxID_HIGHEST + 1, _(L("&Plater Tab")) + "\tCtrl+1", _(L("Show the plater")),
[this](wxCommandEvent&) { select_tab(0); }, menu_icon("plater"));
[this](wxCommandEvent&) { select_tab(0); }, "plater", nullptr,
[this]() {return true; }, this);
tab_offset += 1;
}
if (tab_offset > 0) {
windowMenu->AppendSeparator();
}
append_menu_item(windowMenu, wxID_HIGHEST + 2, _(L("P&rint Settings Tab")) + "\tCtrl+2", _(L("Show the print settings")),
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 0); }, menu_icon("cog"));
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 0); }, "cog", nullptr,
[this]() {return true; }, this);
wxMenuItem* item_material_tab = append_menu_item(windowMenu, wxID_HIGHEST + 3, _(L("&Filament Settings Tab")) + "\tCtrl+3", _(L("Show the filament settings")),
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 1); }, menu_icon("spool"));
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 1); }, "spool", nullptr,
[this]() {return true; }, this);
m_changeable_menu_items.push_back(item_material_tab);
append_menu_item(windowMenu, wxID_HIGHEST + 4, _(L("Print&er Settings Tab")) + "\tCtrl+4", _(L("Show the printer settings")),
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 2); }, menu_icon("printer"));
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 2); }, "printer", nullptr,
[this]() {return true; }, this);
if (m_plater) {
windowMenu->AppendSeparator();
append_menu_item(windowMenu, wxID_HIGHEST + 5, _(L("3&D")) + "\tCtrl+5", _(L("Show the 3D editing view")),
[this](wxCommandEvent&) { m_plater->select_view_3D("3D"); }, menu_icon("editor_menu"), nullptr,
[this](wxCommandEvent&) { m_plater->select_view_3D("3D"); }, "editor_menu", nullptr,
[this](){return can_change_view(); }, this);
append_menu_item(windowMenu, wxID_HIGHEST + 6, _(L("Pre&view")) + "\tCtrl+6", _(L("Show the 3D slices preview")),
[this](wxCommandEvent&) { m_plater->select_view_3D("Preview"); }, menu_icon("preview_menu"), nullptr,
[this](wxCommandEvent&) { m_plater->select_view_3D("Preview"); }, "preview_menu", nullptr,
[this](){return can_change_view(); }, this);
}
@ -628,7 +628,8 @@ void MainFrame::init_menubar()
windowMenu->AppendSeparator();
append_menu_item(windowMenu, wxID_ANY, _(L("Print &Host Upload Queue")) + "\tCtrl+J", _(L("Display the Print Host Upload Queue window")),
[this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, menu_icon("upload_queue"));
[this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, "upload_queue", nullptr,
[this]() {return true; }, this);
}
// View menu
@ -727,7 +728,7 @@ void MainFrame::update_menubar()
m_changeable_menu_items[miSend] ->SetItemLabel((is_fff ? _(L("S&end G-code")) : _(L("S&end to print"))) + dots + "\tCtrl+Shift+G");
m_changeable_menu_items[miMaterialTab] ->SetItemLabel((is_fff ? _(L("&Filament Settings Tab")) : _(L("Mate&rial Settings Tab"))) + "\tCtrl+3");
m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(this, menu_icon(is_fff ? "spool": "resin")));
m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(this, is_fff ? "spool": "resin"));
}
// To perform the "Quck Slice", "Quick Slice and Save As", "Repeat last Quick Slice" and "Slice to SVG".

View file

@ -5,6 +5,9 @@
#include "GUI_App.hpp"
#include "PresetBundle.hpp"
#include "AppConfig.hpp"
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
#include "GLCanvas3D.hpp"
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
#include <wx/glcanvas.h>
@ -184,7 +187,10 @@ Mouse3DController::Mouse3DController()
, m_device(nullptr)
, m_device_str("")
, m_running(false)
, m_settings_dialog(false)
, m_show_settings_dialog(false)
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
, m_settings_dialog_closed_by_user(false)
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
{
m_last_time = std::chrono::high_resolution_clock::now();
}
@ -229,8 +235,11 @@ bool Mouse3DController::apply(Camera& camera)
if (!m_running && is_device_connected())
{
disconnect_device();
// hides the settings dialog if the user re-plug the device
m_settings_dialog = false;
// hides the settings dialog if the user un-plug the device
m_show_settings_dialog = false;
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
m_settings_dialog_closed_by_user = false;
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
}
// check if the user plugged the device
@ -240,88 +249,144 @@ bool Mouse3DController::apply(Camera& camera)
return is_device_connected() ? m_state.apply(camera) : false;
}
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
#else
void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
{
if (!m_running || !m_settings_dialog)
if (!m_running || !m_show_settings_dialog)
return;
ImGuiWrapper& imgui = *wxGetApp().imgui();
imgui.set_next_window_pos(0.5f * (float)canvas_width, 0.5f * (float)canvas_height, ImGuiCond_Always, 0.5f, 0.5f);
imgui.begin(_(L("3Dconnexion settings")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
const ImVec4& color = ImGui::GetStyleColorVec4(ImGuiCol_Separator);
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text(_(L("Device:")));
ImGui::PopStyleColor();
ImGui::SameLine();
imgui.text(m_device_str);
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text(_(L("Speed:")));
ImGui::PopStyleColor();
float translation_scale = (float)m_state.get_translation_scale() / State::DefaultTranslationScale;
if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.5f, 2.0f, "%.1f"))
m_state.set_translation_scale(State::DefaultTranslationScale * (double)translation_scale);
float rotation_scale = m_state.get_rotation_scale() / State::DefaultRotationScale;
if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.5f, 2.0f, "%.1f"))
m_state.set_rotation_scale(State::DefaultRotationScale * rotation_scale);
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text(_(L("Deadzone:")));
ImGui::PopStyleColor();
float translation_deadzone = (float)m_state.get_translation_deadzone();
if (imgui.slider_float(_(L("Translation")) + "##2", &translation_deadzone, 0.0f, (float)State::MaxTranslationDeadzone, "%.2f"))
m_state.set_translation_deadzone((double)translation_deadzone);
float rotation_deadzone = m_state.get_rotation_deadzone();
if (imgui.slider_float(_(L("Rotation")) + "##2", &rotation_deadzone, 0.0f, State::MaxRotationDeadzone, "%.2f"))
m_state.set_rotation_deadzone(rotation_deadzone);
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
ImGui::Separator();
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text("DEBUG:");
imgui.text("Vectors:");
ImGui::PopStyleColor();
Vec3f translation = m_state.get_translation().cast<float>();
Vec3f rotation = m_state.get_rotation();
ImGui::InputFloat3("Translation##3", translation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
ImGui::InputFloat3("Rotation##3", rotation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text("Queue size:");
ImGui::PopStyleColor();
int translation_size[2] = { (int)m_state.get_translation_queue_size(), (int)m_state.get_translation_queue_max_size() };
int rotation_size[2] = { (int)m_state.get_rotation_queue_size(), (int)m_state.get_rotation_queue_max_size() };
int buttons_size[2] = { (int)m_state.get_buttons_queue_size(), (int)m_state.get_buttons_queue_max_size() };
ImGui::InputInt2("Translation##4", translation_size, ImGuiInputTextFlags_ReadOnly);
ImGui::InputInt2("Rotation##4", rotation_size, ImGuiInputTextFlags_ReadOnly);
ImGui::InputInt2("Buttons", buttons_size, ImGuiInputTextFlags_ReadOnly);
int queue_size = (int)m_state.get_queues_max_size();
if (ImGui::InputInt("Max size", &queue_size, 1, 1, ImGuiInputTextFlags_ReadOnly))
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
// when the user clicks on [X] or [Close] button we need to trigger
// an extra frame to let the dialog disappear
if (m_settings_dialog_closed_by_user)
{
if (queue_size > 0)
m_state.set_queues_max_size(queue_size);
m_show_settings_dialog = false;
m_settings_dialog_closed_by_user = false;
canvas.request_extra_frame();
return;
}
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text("Camera:");
ImGui::PopStyleColor();
Vec3f target = wxGetApp().plater()->get_camera().get_target().cast<float>();
ImGui::InputFloat3("Target", target.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
Size cnv_size = canvas.get_canvas_size();
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
ImGuiWrapper& imgui = *wxGetApp().imgui();
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
imgui.set_next_window_pos(0.5f * (float)cnv_size.get_width(), 0.5f * (float)cnv_size.get_height(), ImGuiCond_Always, 0.5f, 0.5f);
#else
imgui.set_next_window_pos(0.5f * (float)canvas_width, 0.5f * (float)canvas_height, ImGuiCond_Always, 0.5f, 0.5f);
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
static ImVec2 last_win_size(0.0f, 0.0f);
bool shown = true;
if (imgui.begin(_(L("3Dconnexion settings")), &shown, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse))
{
if (shown)
{
ImVec2 win_size = ImGui::GetWindowSize();
if ((last_win_size.x != win_size.x) || (last_win_size.y != win_size.y))
{
// when the user clicks on [X] button, the next time the dialog is shown
// has a dummy size, so we trigger an extra frame to let it have the correct size
last_win_size = win_size;
canvas.request_extra_frame();
}
#else
imgui.begin(_(L("3Dconnexion settings")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
const ImVec4& color = ImGui::GetStyleColorVec4(ImGuiCol_Separator);
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text(_(L("Device:")));
ImGui::PopStyleColor();
ImGui::SameLine();
imgui.text(m_device_str);
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text(_(L("Speed:")));
ImGui::PopStyleColor();
float translation_scale = (float)m_state.get_translation_scale() / State::DefaultTranslationScale;
if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.5f, 2.0f, "%.1f"))
m_state.set_translation_scale(State::DefaultTranslationScale * (double)translation_scale);
float rotation_scale = m_state.get_rotation_scale() / State::DefaultRotationScale;
if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.5f, 2.0f, "%.1f"))
m_state.set_rotation_scale(State::DefaultRotationScale * rotation_scale);
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text(_(L("Deadzone:")));
ImGui::PopStyleColor();
float translation_deadzone = (float)m_state.get_translation_deadzone();
if (imgui.slider_float(_(L("Translation")) + "##2", &translation_deadzone, 0.0f, (float)State::MaxTranslationDeadzone, "%.2f"))
m_state.set_translation_deadzone((double)translation_deadzone);
float rotation_deadzone = m_state.get_rotation_deadzone();
if (imgui.slider_float(_(L("Rotation")) + "##2", &rotation_deadzone, 0.0f, State::MaxRotationDeadzone, "%.2f"))
m_state.set_rotation_deadzone(rotation_deadzone);
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
ImGui::Separator();
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text("DEBUG:");
imgui.text("Vectors:");
ImGui::PopStyleColor();
Vec3f translation = m_state.get_translation().cast<float>();
Vec3f rotation = m_state.get_rotation();
ImGui::InputFloat3("Translation##3", translation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
ImGui::InputFloat3("Rotation##3", rotation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text("Queue size:");
ImGui::PopStyleColor();
int translation_size[2] = { (int)m_state.get_translation_queue_size(), (int)m_state.get_translation_queue_max_size() };
int rotation_size[2] = { (int)m_state.get_rotation_queue_size(), (int)m_state.get_rotation_queue_max_size() };
int buttons_size[2] = { (int)m_state.get_buttons_queue_size(), (int)m_state.get_buttons_queue_max_size() };
ImGui::InputInt2("Translation##4", translation_size, ImGuiInputTextFlags_ReadOnly);
ImGui::InputInt2("Rotation##4", rotation_size, ImGuiInputTextFlags_ReadOnly);
ImGui::InputInt2("Buttons", buttons_size, ImGuiInputTextFlags_ReadOnly);
int queue_size = (int)m_state.get_queues_max_size();
if (ImGui::InputInt("Max size", &queue_size, 1, 1, ImGuiInputTextFlags_ReadOnly))
{
if (queue_size > 0)
m_state.set_queues_max_size(queue_size);
}
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, color);
imgui.text("Camera:");
ImGui::PopStyleColor();
Vec3f target = wxGetApp().plater()->get_camera().get_target().cast<float>();
ImGui::InputFloat3("Target", target.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
ImGui::Separator();
if (imgui.button(_(L("Close"))))
{
// the user clicked on the [Close] button
m_settings_dialog_closed_by_user = true;
canvas.set_as_dirty();
}
}
else
{
// the user clicked on the [X] button
m_settings_dialog_closed_by_user = true;
canvas.set_as_dirty();
}
}
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
imgui.end();
}

View file

@ -18,6 +18,9 @@ namespace Slic3r {
namespace GUI {
struct Camera;
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
class GLCanvas3D;
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
class Mouse3DController
{
@ -130,7 +133,13 @@ class Mouse3DController
hid_device* m_device;
std::string m_device_str;
bool m_running;
bool m_settings_dialog;
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
mutable bool m_show_settings_dialog;
// set to true when ther user closes the dialog by clicking on [X] or [Close] buttons
mutable bool m_settings_dialog_closed_by_user;
#else
bool m_show_settings_dialog;
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
std::chrono::time_point<std::chrono::high_resolution_clock> m_last_time;
public:
@ -146,9 +155,13 @@ public:
bool apply(Camera& camera);
bool is_settings_dialog_shown() const { return m_settings_dialog; }
void show_settings_dialog(bool show) { m_settings_dialog = show && is_running(); }
bool is_settings_dialog_shown() const { return m_show_settings_dialog; }
void show_settings_dialog(bool show) { m_show_settings_dialog = show && is_running(); }
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
void render_settings_dialog(GLCanvas3D& canvas) const;
#else
void render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const;
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
private:
bool connect_device();

View file

@ -2252,7 +2252,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
config += std::move(config_loaded);
}
this->model.custom_gcode_per_height = model.custom_gcode_per_height;
this->model.custom_gcode_per_print_z = model.custom_gcode_per_print_z;
}
if (load_config)
@ -2671,7 +2671,7 @@ void Plater::priv::reset()
// The hiding of the slicing results, if shown, is not taken care by the background process, so we do it here
this->sidebar->show_sliced_info_sizer(false);
model.custom_gcode_per_height.clear();
model.custom_gcode_per_print_z.clear();
}
void Plater::priv::mirror(Axis axis)
@ -3219,34 +3219,48 @@ void Plater::priv::reload_from_disk()
while (!missing_input_paths.empty())
{
// ask user to select the missing file
std::string search = missing_input_paths.back().string();
wxFileDialog dialog(q, _(L("Please select the file to reload:")), "", search, file_wildcards(FT_MODEL), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
fs::path search = missing_input_paths.back();
wxString title = _(L("Please select the file to reload"));
#if defined(__APPLE__)
title += " (" + from_u8(search.filename().string()) + "):";
#else
title += ":";
#endif // __APPLE__
wxFileDialog dialog(q, title, "", from_u8(search.filename().string()), file_wildcards(FT_MODEL), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if (dialog.ShowModal() != wxID_OK)
return;
std::string sel_filename_path = dialog.GetPath().ToUTF8().data();
std::string sel_filename = fs::path(sel_filename_path).filename().string();
if (boost::algorithm::iends_with(search, sel_filename))
if (boost::algorithm::iequals(search.filename().string(), sel_filename))
{
input_paths.push_back(sel_filename_path);
missing_input_paths.pop_back();
std::string sel_path = fs::path(sel_filename_path).remove_filename().string();
fs::path sel_path = fs::path(sel_filename_path).remove_filename().string();
std::vector<fs::path>::iterator it = missing_input_paths.begin();
while (it != missing_input_paths.end())
{
// try to use the path of the selected file with all remaining missing files
std::string repathed_filename = sel_path + "/" + it->filename().string();
fs::path repathed_filename = sel_path;
repathed_filename /= it->filename();
if (fs::exists(repathed_filename))
{
input_paths.push_back(repathed_filename);
input_paths.push_back(repathed_filename.string());
it = missing_input_paths.erase(it);
}
else
++it;
}
}
else
{
wxString message = _(L("It is not allowed to change the file to reload")) + " (" + from_u8(search.filename().string()) + ").\n" + _(L("Do you want to retry")) + " ?";
wxMessageDialog dlg(q, message, wxMessageBoxCaptionStr, wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION);
if (dlg.ShowModal() != wxID_YES)
return;
}
}
#endif // ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
@ -3281,7 +3295,8 @@ void Plater::priv::reload_from_disk()
int new_volume_idx = old_volume->source.volume_idx;
int new_object_idx = old_volume->source.object_idx;
if (old_volume->source.input_file == path)
if (boost::algorithm::iequals(fs::path(old_volume->source.input_file).filename().string(),
fs::path(path).filename().string()))
{
assert(new_object_idx < (int)new_model.objects.size());
ModelObject* new_model_object = new_model.objects[new_object_idx];
@ -3295,6 +3310,7 @@ void Plater::priv::reload_from_disk()
new_volume->set_material_id(old_volume->material_id());
new_volume->set_transformation(old_volume->get_transformation());
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
new_volume->source.input_file = path;
std::swap(old_model_object->volumes[old_v.volume_idx], old_model_object->volumes.back());
old_model_object->delete_volume(old_model_object->volumes.size() - 1);
}
@ -3593,7 +3609,10 @@ void Plater::priv::on_right_click(RBtnEvent& evt)
if (evt.data.second) // right button was clicked on empty space
menu = &default_menu;
else
{
sidebar->obj_list()->show_multi_selection_menu();
return;
}
}
else
{
@ -4623,6 +4642,13 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_uppe
remove(obj_idx);
p->load_model_objects(new_objects);
Selection& selection = p->get_selection();
size_t last_id = p->model.objects.size() - 1;
for (size_t i = 0; i < new_objects.size(); ++i)
{
selection.add_object((unsigned int)(last_id - i), i == 0);
}
}
void Plater::export_gcode()
@ -5157,6 +5183,7 @@ const DynamicPrintConfig* Plater::get_plater_config() const
return p->config;
}
// Get vector of extruder colors considering filament color, if extruder color is undefined.
std::vector<std::string> Plater::get_extruder_colors_from_plater_config() const
{
const Slic3r::DynamicPrintConfig* config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
@ -5176,13 +5203,17 @@ std::vector<std::string> Plater::get_extruder_colors_from_plater_config() const
return extruder_colors;
}
/* Get vector of colors used for rendering of a Preview scene in "Color print" mode
* It consists of extruder colors and colors, saved in model.custom_gcode_per_print_z
*/
std::vector<std::string> Plater::get_colors_for_color_print() const
{
std::vector<std::string> colors = get_extruder_colors_from_plater_config();
colors.reserve(colors.size() + p->model.custom_gcode_per_print_z.size());
for (const Model::CustomGCode& code : p->model.custom_gcode_per_height)
for (const Model::CustomGCode& code : p->model.custom_gcode_per_print_z)
if (code.gcode == ColorChangeCode)
colors.push_back(code.color);
colors.emplace_back(code.color);
return colors;
}

View file

@ -29,6 +29,7 @@
#include "libslic3r/libslic3r.h"
#include "libslic3r/Utils.hpp"
#include "GUI_App.hpp"
// Store the print/filament/printer presets into a "presets" subdirectory of the Slic3rPE config dir.
// This breaks compatibility with the upstream Slic3r if the --datadir is used to switch between the two versions.
@ -868,6 +869,9 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
}
// 4) Load the project config values (the per extruder wipe matrix etc).
this->project_config.apply_only(config, s_project_options);
update_custom_gcode_per_print_z_from_config(GUI::wxGetApp().plater()->model().custom_gcode_per_print_z, &this->project_config);
break;
}
case ptSLA:

View file

@ -14,6 +14,7 @@
#include <wx/colordlg.h>
#include <boost/algorithm/string/replace.hpp>
#include <boost/nowide/cstdio.hpp>
#include "BitmapCache.hpp"
#include "GUI.hpp"
@ -57,7 +58,7 @@ void msw_rescale_menu(wxMenu* menu)
#endif /* __WXMSW__ */
#endif /* no __WXGTK__ */
void enable_menu_item(wxUpdateUIEvent& evt, std::function<bool()> const cb_condition, wxMenuItem* item)
void enable_menu_item(wxUpdateUIEvent& evt, std::function<bool()> const cb_condition, wxMenuItem* item, wxWindow* win)
{
const bool enable = cb_condition();
evt.Enable(enable);
@ -66,7 +67,7 @@ void enable_menu_item(wxUpdateUIEvent& evt, std::function<bool()> const cb_condi
const auto it = msw_menuitem_bitmaps.find(item->GetId());
if (it != msw_menuitem_bitmaps.end())
{
const wxBitmap& item_icon = create_scaled_bitmap(nullptr, it->second, 16, false, !enable);
const wxBitmap& item_icon = create_scaled_bitmap(win, it->second, 16, false, !enable);
if (item_icon.IsOk())
item->SetBitmap(item_icon);
}
@ -94,8 +95,8 @@ wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const
menu->Bind(wxEVT_MENU, cb, id);
if (parent) {
parent->Bind(wxEVT_UPDATE_UI, [cb_condition, item](wxUpdateUIEvent& evt) {
enable_menu_item(evt, cb_condition, item); }, id);
parent->Bind(wxEVT_UPDATE_UI, [cb_condition, item, parent](wxUpdateUIEvent& evt) {
enable_menu_item(evt, cb_condition, item, parent); }, id);
}
return item;
@ -108,7 +109,7 @@ wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const
if (id == wxID_ANY)
id = wxNewId();
const wxBitmap& bmp = !icon.empty() ? create_scaled_bitmap(nullptr, icon) : wxNullBitmap; // FIXME: pass window ptr
const wxBitmap& bmp = !icon.empty() ? create_scaled_bitmap(parent, icon) : wxNullBitmap; // FIXME: pass window ptr
//#ifdef __WXMSW__
#ifndef __WXGTK__
if (bmp.IsOk())
@ -126,7 +127,7 @@ wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxStrin
wxMenuItem* item = new wxMenuItem(menu, id, string, description);
if (!icon.empty()) {
item->SetBitmap(create_scaled_bitmap(nullptr, icon)); // FIXME: pass window ptr
item->SetBitmap(create_scaled_bitmap(parent, icon)); // FIXME: pass window ptr
//#ifdef __WXMSW__
#ifndef __WXGTK__
msw_menuitem_bitmaps[id] = icon;
@ -137,8 +138,8 @@ wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxStrin
menu->Append(item);
if (parent) {
parent->Bind(wxEVT_UPDATE_UI, [cb_condition, item](wxUpdateUIEvent& evt) {
enable_menu_item(evt, cb_condition, item); }, id);
parent->Bind(wxEVT_UPDATE_UI, [cb_condition, item, parent](wxUpdateUIEvent& evt) {
enable_menu_item(evt, cb_condition, item, parent); }, id);
}
return item;
@ -424,6 +425,28 @@ static float get_svg_scale_factor(wxWindow *win)
#endif
}
// in the Dark mode of any platform, we should draw icons in respect to OS background
static std::string icon_name_respected_to_mode(const std::string& bmp_name_in)
{
#ifdef __WXMSW__
const std::string folder = "white\\";
#else
const std::string folder = "white/";
#endif
std::string bmp_name = Slic3r::GUI::wxGetApp().dark_mode() ? folder + bmp_name_in : bmp_name_in;
boost::replace_last(bmp_name, ".png", "");
FILE* fp = NULL;
fp = boost::nowide::fopen(Slic3r::var(bmp_name + ".svg").c_str(), "rb");
if (!fp)
{
bmp_name = bmp_name_in;
boost::replace_last(bmp_name, ".png", "");
if (fp) fclose(fp);
}
return bmp_name;
}
// If an icon has horizontal orientation (width > height) call this function with is_horizontal = true
wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in,
const int px_cnt/* = 16*/, const bool is_horizontal /* = false*/, const bool grayscale/* = false*/)
@ -450,8 +473,10 @@ wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in,
scale_base = (unsigned int)(em_unit(win) * px_cnt * 0.1f + 0.5f);
std::string bmp_name = bmp_name_in;
boost::replace_last(bmp_name, ".png", "");
// std::string bmp_name = bmp_name_in;
// boost::replace_last(bmp_name, ".png", "");
std::string bmp_name = icon_name_respected_to_mode(bmp_name_in);
// Try loading an SVG first, then PNG if SVG is not found:
wxBitmap *bmp = cache.load_svg(bmp_name, width, height, scale_factor, grayscale);
@ -2538,7 +2563,7 @@ std::vector<t_custom_code> DoubleSlider::GetTicksValues() const
for (const TICK_CODE& tick : m_ticks_) {
if (tick.tick > val_size)
break;
values.push_back(t_custom_code(m_values[tick.tick], tick.gcode, tick.extruder, tick.color));
values.emplace_back(t_custom_code{m_values[tick.tick], tick.gcode, tick.extruder, tick.color});
}
return values;
@ -2553,12 +2578,12 @@ void DoubleSlider::SetTicksValues(const std::vector<t_custom_code>& heights)
m_ticks_.clear();
for (auto h : heights) {
auto it = std::lower_bound(m_values.begin(), m_values.end(), h.height - epsilon());
auto it = std::lower_bound(m_values.begin(), m_values.end(), h.print_z - epsilon());
if (it == m_values.end())
continue;
m_ticks_.insert(TICK_CODE(it-m_values.begin(), h.gcode, h.extruder, h.color));
m_ticks_.emplace(TICK_CODE{int(it-m_values.begin()), h.gcode, h.extruder, h.color});
}
if (!was_empty && m_ticks_.empty())
@ -2642,7 +2667,7 @@ void DoubleSlider::draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoin
return;
wxBitmap* icon = m_is_action_icon_focesed ? &m_bmp_add_tick_off.bmp() : &m_bmp_add_tick_on.bmp();
if (m_ticks_.find(tick) != m_ticks_.end())
if (m_ticks_.find(TICK_CODE{tick}) != m_ticks_.end())
icon = m_is_action_icon_focesed ? &m_bmp_del_tick_off.bmp() : &m_bmp_del_tick_on.bmp();
wxCoord x_draw, y_draw;
@ -3081,7 +3106,7 @@ wxString DoubleSlider::get_tooltip(IconFocus icon_focus)
else if (m_is_action_icon_focesed)
{
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
const auto tick_code_it = m_ticks_.find(tick);
const auto tick_code_it = m_ticks_.find(TICK_CODE{tick});
tooltip = tick_code_it == m_ticks_.end() ? (m_state == msSingleExtruder ?
_(L("For add color change use left mouse button click")) :
_(L("For add change extruder use left mouse button click"))) + "\n" +
@ -3240,13 +3265,13 @@ void DoubleSlider::action_tick(const TicksAction action)
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
const auto it = m_ticks_.find(tick);
const auto it = m_ticks_.find(TICK_CODE{tick});
if (it != m_ticks_.end()) // erase this tick
{
if (action == taAdd)
return;
m_ticks_.erase(TICK_CODE(tick));
m_ticks_.erase(TICK_CODE{tick});
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
Refresh();
@ -3350,7 +3375,7 @@ void DoubleSlider::OnRightDown(wxMouseEvent& event)
{
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
// if on this Z doesn't exist tick
auto it = m_ticks_.find(tick);
auto it = m_ticks_.find(TICK_CODE{ tick });
if (it == m_ticks_.end())
{
// show context menu on OnRightUp()
@ -3387,7 +3412,7 @@ int DoubleSlider::get_extruder_for_tick(int tick)
if (m_ticks_.empty())
return 0;
auto it = m_ticks_.lower_bound(tick);
auto it = m_ticks_.lower_bound(TICK_CODE{tick});
while (it != m_ticks_.begin()) {
--it;
if(it->gcode == Slic3r::ExtruderChangeCode)
@ -3454,7 +3479,7 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event)
else if (m_show_edit_menu) {
wxMenu menu;
std::set<TICK_CODE>::iterator it = m_ticks_.find(m_selection == ssLower ? m_lower_value : m_higher_value);
std::set<TICK_CODE>::iterator it = m_ticks_.find(TICK_CODE{ m_selection == ssLower ? m_lower_value : m_higher_value });
const bool is_color_change = it->gcode == Slic3r::ColorChangeCode;
append_menu_item(&menu, wxID_ANY, it->gcode == Slic3r::ColorChangeCode ? _(L("Edit color")) :
@ -3526,7 +3551,7 @@ void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/)
{
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
// if on this Z doesn't exist tick
auto it = m_ticks_.find(tick);
auto it = m_ticks_.find(TICK_CODE{ tick });
if (it == m_ticks_.end())
{
std::string color = "";
@ -3535,7 +3560,7 @@ void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/)
std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
if (m_state == msSingleExtruder && !m_ticks_.empty()) {
auto before_tick_it = std::lower_bound(m_ticks_.begin(), m_ticks_.end(), tick);
auto before_tick_it = std::lower_bound(m_ticks_.begin(), m_ticks_.end(), TICK_CODE{ tick });
while (before_tick_it != m_ticks_.begin()) {
--before_tick_it;
if (before_tick_it->gcode == Slic3r::ColorChangeCode) {
@ -3580,7 +3605,7 @@ void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/)
extruder = get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value);
}
m_ticks_.insert(TICK_CODE(tick, code, extruder, color));
m_ticks_.emplace(TICK_CODE{tick, code, extruder, color});
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
Refresh();
@ -3592,7 +3617,7 @@ void DoubleSlider::edit_tick()
{
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
// if on this Z exists tick
std::set<TICK_CODE>::iterator it = m_ticks_.find(tick);
std::set<TICK_CODE>::iterator it = m_ticks_.find(TICK_CODE{ tick });
if (it != m_ticks_.end())
{
std::string edited_value;
@ -3619,7 +3644,7 @@ void DoubleSlider::edit_tick()
}
m_ticks_.erase(it);
m_ticks_.insert(changed_tick);
m_ticks_.emplace(changed_tick);
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
}
@ -3632,9 +3657,9 @@ void DoubleSlider::change_extruder(int extruder)
std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
// if on this Y doesn't exist tick
if (m_ticks_.find(tick) == m_ticks_.end())
if (m_ticks_.find(TICK_CODE{tick}) == m_ticks_.end())
{
m_ticks_.insert(TICK_CODE(tick, Slic3r::ExtruderChangeCode, extruder, extruder == 0 ? "" : colors[extruder-1]));
m_ticks_.emplace(TICK_CODE{tick, Slic3r::ExtruderChangeCode, extruder, extruder == 0 ? "" : colors[extruder-1]});
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
Refresh();
@ -3672,7 +3697,7 @@ void DoubleSlider::edit_extruder_sequence()
while (tick <= m_max_value)
{
int cur_extruder = m_extruders_sequence.extruders[extruder];
m_ticks_.insert(TICK_CODE(tick, Slic3r::ExtruderChangeCode, cur_extruder + 1, colors[cur_extruder]));
m_ticks_.emplace(TICK_CODE{tick, Slic3r::ExtruderChangeCode, cur_extruder + 1, colors[cur_extruder]});
extruder++;
if (extruder == extr_cnt)
@ -3680,12 +3705,12 @@ void DoubleSlider::edit_extruder_sequence()
if (m_extruders_sequence.is_mm_intervals)
{
value += m_extruders_sequence.interval_by_mm;
auto it = std::lower_bound(m_values.begin(), m_values.end(), value - epsilon());
auto val_it = std::lower_bound(m_values.begin(), m_values.end(), value - epsilon());
if (it == m_values.end())
if (val_it == m_values.end())
break;
tick = it - m_values.begin();
tick = val_it - m_values.begin();
}
else
tick += m_extruders_sequence.interval_by_layers;

View file

@ -17,6 +17,7 @@
#include <set>
#include <functional>
#include "libslic3r/Model.hpp"
#include "libslic3r/GCodeWriter.hpp"
namespace Slic3r {
enum class ModelVolumeType : int;
@ -958,24 +959,12 @@ private:
struct TICK_CODE
{
TICK_CODE(int tick):tick(tick), gcode(Slic3r::ColorChangeCode), extruder(0), color("") {}
TICK_CODE(int tick, const std::string& code) :
tick(tick), gcode(code), extruder(0) {}
TICK_CODE(int tick, int extruder) :
tick(tick), gcode(Slic3r::ColorChangeCode), extruder(extruder) {}
TICK_CODE(int tick, const std::string& code, int extruder, const std::string& color) :
tick(tick), gcode(code), extruder(extruder), color(color) {}
bool operator<(const TICK_CODE& other) const { return other.tick > this->tick; }
bool operator>(const TICK_CODE& other) const { return other.tick < this->tick; }
TICK_CODE operator=(const TICK_CODE& other) const {
TICK_CODE ret_val(other.tick, other.gcode, other.extruder, other.color);
return ret_val;
}
int tick;
std::string gcode;
int extruder;
int tick = 0;
std::string gcode = Slic3r::ColorChangeCode;
int extruder = 0;
std::string color;
};