#include "StepMeshDialog.hpp" #include #include #include #include #include #include "GUI_App.hpp" #include "I18N.hpp" #include "MainFrame.hpp" #include "Widgets/Button.hpp" #include "Widgets/TextInput.hpp" #include using namespace Slic3r; using namespace Slic3r::GUI; static int _scale(const int val) { return val * Slic3r::GUI::wxGetApp().em_unit() / 10; } static int _ITEM_WIDTH() { return _scale(30); } #define MIN_DIALOG_WIDTH FromDIP(400) #define SLIDER_WIDTH FromDIP(200) #define TEXT_CTRL_WIDTH FromDIP(70) #define BUTTON_SIZE wxSize(FromDIP(58), FromDIP(24)) #define BUTTON_BORDER FromDIP(int(400 - 58 * 2) / 8) #define SLIDER_SCALE(val) ((val) / 0.001) #define SLIDER_UNSCALE(val) ((val) * 0.001) #define SLIDER_SCALE_10(val) ((val) / 0.01) #define SLIDER_UNSCALE_10(val) ((val) * 0.01) #define LEFT_RIGHT_PADING FromDIP(20) wxDEFINE_EVENT(wxEVT_THREAD_DONE, wxCommandEvent); class CenteredStaticText : public wxStaticText { public: CenteredStaticText(wxWindow* parent, wxWindowID id, const wxString& label, const wxPoint& position, const wxSize& size = wxDefaultSize, long style = 0) : wxStaticText(parent, id, label, position, size, style) { CenterOnPosition(position); } void CenterOnPosition(const wxPoint& position) { int textWidth, textHeight; GetTextExtent(GetLabel(), &textWidth, &textHeight); int x = position.x - textWidth / 2; int y = position.y - textHeight / 2; SetPosition(wxPoint(x, y)); } }; void StepMeshDialog::on_dpi_changed(const wxRect& suggested_rect) { }; bool StepMeshDialog:: validate_number_range(const wxString& value, double min, double max) { double num = 0.0; if (value.IsEmpty()) { return false; } try { if (!value.ToDouble(&num)) { return false; } } catch (...) { return false; } return (num >= min && num <= max); } StepMeshDialog::StepMeshDialog(wxWindow* parent, Slic3r::Step& file) : DPIDialog(parent ? parent : static_cast(wxGetApp().mainframe), wxID_ANY, _(L("Step file import parameters")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE /* | wxRESIZE_BORDER*/), m_file(file) { Bind(wxEVT_THREAD_DONE, &StepMeshDialog::on_task_done, this); std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico") % Slic3r::resources_dir()).str(); SetIcon(wxIcon(Slic3r::encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); SetBackgroundColour(*wxWHITE); wxBoxSizer* bSizer = new wxBoxSizer(wxVERTICAL); bSizer->SetMinSize(wxSize(MIN_DIALOG_WIDTH, -1)); auto image_bitmap = create_scaled_bitmap("step_mesh_info", this, FromDIP(120), false, std::string(), false, false, true); int image_width = image_bitmap.GetWidth(); int image_height = image_bitmap.GetHeight(); wxPanel* overlay_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, image_bitmap.GetSize(), wxTAB_TRAVERSAL); overlay_panel->SetBackgroundStyle(wxBG_STYLE_PAINT); wxStaticBitmap *image = new wxStaticBitmap(overlay_panel, wxID_ANY, image_bitmap, wxDefaultPosition, wxDefaultSize, 0); CenteredStaticText* text_1 = new CenteredStaticText (overlay_panel, wxID_ANY, _L("Rough"), wxPoint(overlay_panel->GetSize().GetWidth() / 6, overlay_panel->GetSize().GetHeight() / 2)); CenteredStaticText* text_2 = new CenteredStaticText(overlay_panel, wxID_ANY, _L("Smooth"), wxPoint(overlay_panel->GetSize().GetWidth() * 5 / 6, overlay_panel->GetSize().GetHeight() / 2)); CenteredStaticText* text_3 = new CenteredStaticText(overlay_panel, wxID_ANY, _L("Reduce Linear"), wxPoint(overlay_panel->GetSize().GetWidth() / 2, overlay_panel->GetSize().GetHeight() * 1.3 / 3)); CenteredStaticText* text_4 = new CenteredStaticText(overlay_panel, wxID_ANY, _L("Reduce Angle"), wxPoint(overlay_panel->GetSize().GetWidth() / 2, overlay_panel->GetSize().GetHeight() * 2 / 3)); CenteredStaticText* text_5 = new CenteredStaticText(overlay_panel, wxID_ANY, _L("Fewer faces"), wxPoint(overlay_panel->GetSize().GetWidth() / 6, overlay_panel->GetSize().GetHeight() * 2.8 / 3)); CenteredStaticText* text_6 = new CenteredStaticText(overlay_panel, wxID_ANY, _L("More faces"), wxPoint(overlay_panel->GetSize().GetWidth() * 5 / 6, overlay_panel->GetSize().GetHeight() * 2.8 / 3)); bSizer->Add(overlay_panel, 0, wxALIGN_CENTER | wxALL, 10); wxBoxSizer* linear_sizer = new wxBoxSizer(wxHORIZONTAL); //linear_sizer->SetMinSize(wxSize(MIN_DIALOG_WIDTH, -1)); wxStaticText* linear_title = new wxStaticText(this, wxID_ANY, _L("Linear Deflection") + ": "); linear_sizer->Add(linear_title, 0, wxALIGN_LEFT); linear_sizer->AddStretchSpacer(1); wxSlider* linear_slider = new wxSlider(this, wxID_ANY, SLIDER_SCALE(get_linear_defletion()), 1, 100, wxDefaultPosition, wxSize(SLIDER_WIDTH, -1), wxSL_HORIZONTAL); linear_sizer->Add(linear_slider, 0, wxALIGN_RIGHT | wxLEFT, FromDIP(5)); auto linear_input = new ::TextInput(this, m_linear_last, wxEmptyString, wxEmptyString, wxDefaultPosition, wxSize(TEXT_CTRL_WIDTH, -1), wxTE_CENTER); linear_input->GetTextCtrl()->SetFont(Label::Body_12); linear_input->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); linear_sizer->Add(linear_input, 0, wxALIGN_RIGHT | wxLEFT, FromDIP(5)); linear_input->Bind(wxEVT_KILL_FOCUS, ([this, linear_input](wxFocusEvent& e) { wxString value = linear_input->GetTextCtrl()->GetValue(); if (validate_number_range(value, 0.001, 0.1)) { m_linear_last = value; update_mesh_number_text(); } else { MessageDialog msg_dlg(nullptr, _L("Please input a valid value (0.001 < linear deflection < 0.1)"), wxEmptyString, wxICON_WARNING | wxOK); msg_dlg.ShowModal(); linear_input->GetTextCtrl()->SetValue(m_linear_last); } e.Skip(); })); // textctrl bind slider linear_input->Bind(wxEVT_TEXT, ([this, linear_slider, linear_input](wxCommandEvent& e) { double slider_value_long; int slider_value; wxString value = linear_input->GetTextCtrl()->GetValue(); if (value.ToDouble(&slider_value_long)) { slider_value = SLIDER_SCALE(slider_value_long); if (slider_value >= linear_slider->GetMin() && slider_value <= linear_slider->GetMax()) { linear_slider->SetValue(slider_value); } } })); linear_slider->Bind(wxEVT_SLIDER, ([this, linear_slider, linear_input](wxCommandEvent& e) { double slider_value = SLIDER_UNSCALE(linear_slider->GetValue()); linear_input->GetTextCtrl()->SetValue(wxString::Format("%.3f", slider_value)); m_linear_last = wxString::Format("%.3f", slider_value); })); linear_slider->Bind(wxEVT_LEFT_UP, ([this](wxMouseEvent& e) { update_mesh_number_text(); e.Skip(); })); bSizer->Add(linear_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, LEFT_RIGHT_PADING); wxBoxSizer* angle_sizer = new wxBoxSizer(wxHORIZONTAL); wxStaticText* angle_title = new wxStaticText(this, wxID_ANY, _L("Angle Deflection") + ": "); angle_sizer->Add(angle_title, 0, wxALIGN_LEFT); angle_sizer->AddStretchSpacer(1); wxSlider* angle_slider = new wxSlider(this, wxID_ANY, SLIDER_SCALE_10(get_angle_defletion()), 1, 100, wxDefaultPosition, wxSize(SLIDER_WIDTH, -1), wxSL_HORIZONTAL); angle_sizer->Add(angle_slider, 0, wxALIGN_RIGHT | wxLEFT, FromDIP(5)); auto angle_input = new ::TextInput(this, m_angle_last, wxEmptyString, wxEmptyString, wxDefaultPosition, wxSize(TEXT_CTRL_WIDTH, -1), wxTE_CENTER); angle_input->GetTextCtrl()->SetFont(Label::Body_12); angle_input->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); angle_sizer->Add(angle_input, 0, wxALIGN_RIGHT | wxLEFT, FromDIP(5)); angle_input->Bind(wxEVT_KILL_FOCUS, ([this, angle_input](wxFocusEvent& e) { wxString value = angle_input->GetTextCtrl()->GetValue(); if (validate_number_range(value, 0.01, 1)) { m_angle_last = value; update_mesh_number_text(); } else { MessageDialog msg_dlg(nullptr, _L("Please input a valid value (0.01 < angle deflection < 1.0)"), wxEmptyString, wxICON_WARNING | wxOK); msg_dlg.ShowModal(); angle_input->GetTextCtrl()->SetValue(m_angle_last); } e.Skip(); })); // textctrl bind slider angle_input->Bind(wxEVT_TEXT, ([this, angle_slider, angle_input](wxCommandEvent& e) { double slider_value_long; int slider_value; wxString value = angle_input->GetTextCtrl()->GetValue(); if (value.ToDouble(&slider_value_long)) { slider_value = SLIDER_SCALE_10(slider_value_long); if (slider_value >= angle_slider->GetMin() && slider_value <= angle_slider->GetMax()) { angle_slider->SetValue(slider_value); } } })); angle_slider->Bind(wxEVT_SLIDER, ([this, angle_slider, angle_input](wxCommandEvent& e) { double slider_value = SLIDER_UNSCALE_10(angle_slider->GetValue()); angle_input->GetTextCtrl()->SetValue(wxString::Format("%.2f", slider_value)); m_angle_last = wxString::Format("%.2f", slider_value); })); angle_slider->Bind(wxEVT_LEFT_UP, ([this](wxMouseEvent& e) { update_mesh_number_text(); e.Skip(); })); bSizer->Add(angle_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT, LEFT_RIGHT_PADING); wxBoxSizer* mesh_face_number_sizer = new wxBoxSizer(wxHORIZONTAL); wxStaticText *mesh_face_number_title = new wxStaticText(this, wxID_ANY, _L("Number of triangular facets") + ": "); mesh_face_number_text = new wxStaticText(this, wxID_ANY, _L("0")); mesh_face_number_text->SetMinSize(wxSize(FromDIP(150), -1)); mesh_face_number_sizer->Add(mesh_face_number_title, 0, wxALIGN_LEFT); mesh_face_number_sizer->Add(mesh_face_number_text, 0, wxALIGN_LEFT); bSizer->Add(mesh_face_number_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT, LEFT_RIGHT_PADING); wxBoxSizer* bSizer_button = new wxBoxSizer(wxHORIZONTAL); bSizer_button->SetMinSize(wxSize(FromDIP(100), -1)); m_checkbox = new wxCheckBox(this, wxID_ANY, _L("Don't show again"), wxDefaultPosition, wxDefaultSize, 0); bSizer_button->Add(m_checkbox, 0, wxALIGN_LEFT); bSizer_button->AddStretchSpacer(1); StateColor btn_bg_green(std::pair(wxColour(27, 136, 68), StateColor::Pressed), std::pair(wxColour(61, 203, 115), StateColor::Hovered), std::pair(AMS_CONTROL_BRAND_COLOUR, StateColor::Normal)); m_button_ok = new Button(this, _L("OK")); m_button_ok->SetBackgroundColor(btn_bg_green); m_button_ok->SetBorderColor(*wxWHITE); m_button_ok->SetTextColor(wxColour(0xFFFFFE)); m_button_ok->SetFont(Label::Body_12); m_button_ok->SetSize(BUTTON_SIZE); m_button_ok->SetMinSize(BUTTON_SIZE); m_button_ok->SetCornerRadius(FromDIP(12)); bSizer_button->Add(m_button_ok, 0, wxALIGN_RIGHT, BUTTON_BORDER); m_button_ok->Bind(wxEVT_LEFT_DOWN, [this, angle_input, linear_input](wxMouseEvent& e) { stop_task(); if (validate_number_range(angle_input->GetTextCtrl()->GetValue(), 0.01, 1) && validate_number_range(linear_input->GetTextCtrl()->GetValue(), 0.001, 0.1)) { if (m_checkbox->IsChecked()) { wxGetApp().app_config->set_bool("enable_step_mesh_setting", false); } wxGetApp().app_config->set("linear_defletion", std::to_string(get_linear_defletion())); wxGetApp().app_config->set("angle_defletion", std::to_string(get_angle_defletion())); EndModal(wxID_OK); } SetFocusIgnoringChildren(); }); StateColor btn_bg_white(std::pair(wxColour(206, 206, 206), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), std::pair(*wxWHITE, StateColor::Normal)); m_button_cancel = new Button(this, _L("Cancel")); m_button_cancel->SetBackgroundColor(btn_bg_white); m_button_cancel->SetBorderColor(wxColour(38, 46, 48)); m_button_cancel->SetFont(Label::Body_12); m_button_cancel->SetSize(BUTTON_SIZE); m_button_cancel->SetMinSize(BUTTON_SIZE); m_button_cancel->SetCornerRadius(FromDIP(12)); bSizer_button->Add(m_button_cancel, 0, wxALIGN_RIGHT | wxLEFT, BUTTON_BORDER); m_button_cancel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) { stop_task(); EndModal(wxID_CANCEL); }); bSizer->Add(bSizer_button, 1, wxEXPAND | wxALL, LEFT_RIGHT_PADING); this->SetSizer(bSizer); update_mesh_number_text(); this->Layout(); bSizer->Fit(this); this->Bind(wxEVT_LEFT_DOWN, [this](auto& e) { SetFocusIgnoringChildren(); }); mesh_face_number_text->Bind(wxEVT_LEFT_DOWN, [this](auto& e) { SetFocusIgnoringChildren(); }); this->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) { stop_task(); EndModal(wxID_CANCEL); }); wxGetApp().UpdateDlgDarkUI(this); } void StepMeshDialog::on_task_done(wxCommandEvent& event) { wxString text = event.GetString(); mesh_face_number_text->SetLabel(text); if (task.valid()) { task.get(); } } void StepMeshDialog::stop_task() { if (task.valid()) { m_file.m_stop_mesh.store(true); unsigned int test = task.get(); m_file.m_stop_mesh.store(false); std::cout << test << std::endl; } } void StepMeshDialog::update_mesh_number_text() { if (m_last_linear == get_linear_defletion() && m_last_angle == get_angle_defletion()) return; wxString newText = wxString::Format(_L("Calculating, please wait...")); mesh_face_number_text->SetLabel(newText); stop_task(); task = std::async(std::launch::async, [&] { unsigned int number = m_file.get_triangle_num(get_linear_defletion(), get_angle_defletion()); if (number != 0) { wxString number_text = wxString::Format("%d", number); wxCommandEvent event(wxEVT_THREAD_DONE); event.SetString(number_text); wxPostEvent(this, event); m_last_linear = get_linear_defletion(); m_last_angle = get_angle_defletion(); } return number; }); }