From a86d94f2c96642e6b760eb7fe6cbbc5e8b490762 Mon Sep 17 00:00:00 2001 From: tao wang Date: Tue, 14 Feb 2023 15:44:03 +0800 Subject: [PATCH] NEW:update the content of the project page Change-Id: Idb7f8a2564c78a1f062580f6b388ee033238cedf --- src/libslic3r/Format/bbs_3mf.cpp | 43 +++- src/libslic3r/Model.cpp | 5 + src/libslic3r/Model.hpp | 14 ++ src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/Auxiliary.cpp | 1 - src/slic3r/GUI/GUI_App.cpp | 4 +- src/slic3r/GUI/MainFrame.cpp | 8 +- src/slic3r/GUI/MainFrame.hpp | 6 +- src/slic3r/GUI/Plater.cpp | 2 +- src/slic3r/GUI/Project.cpp | 412 +++++++++++++++++++++++++++++++ src/slic3r/GUI/Project.hpp | 99 ++++++++ 11 files changed, 586 insertions(+), 10 deletions(-) create mode 100644 src/slic3r/GUI/Project.cpp create mode 100644 src/slic3r/GUI/Project.hpp diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index ef7bf7f9e..8cc21b43e 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -110,6 +110,7 @@ const std::string BBS_SEAM_PAINTING_VERSION = "BambuStudio:SeamPaintingV const std::string BBS_MM_PAINTING_VERSION = "BambuStudio:MmPaintingVersion"; const std::string BBL_MODEL_ID_TAG = "model_id"; const std::string BBL_MODEL_NAME_TAG = "Title"; +const std::string BBL_ORIGIN_TAG = "Origin"; const std::string BBL_DESIGNER_TAG = "Designer"; const std::string BBL_DESIGNER_USER_ID_TAG = "DesignerUserId"; const std::string BBL_DESIGNER_COVER_FILE_TAG = "DesignerCover"; @@ -121,6 +122,12 @@ const std::string BBL_MODIFICATION_TAG = "ModificationDate"; const std::string BBL_CREATION_DATE_TAG = "CreationDate"; const std::string BBL_APPLICATION_TAG = "Application"; +const std::string BBL_PROFILE_TITLE_TAG = "ProfileTitle"; +const std::string BBL_PROFILE_COVER_TAG = "ProfileCover"; +const std::string BBL_PROFILE_DESCRIPTION_TAG = "ProfileDescription"; +const std::string BBL_PROFILE_USER_ID_TAG = "ProfileUserId"; +const std::string BBL_PROFILE_USER_NAME_TAG = "ProfileUserName"; + const std::string MODEL_FOLDER = "3D/"; const std::string MODEL_EXTENSION = ".model"; const std::string MODEL_FILE = "3D/3dmodel.model"; // << this is the only format of the string which works with CURA @@ -847,7 +854,12 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) std::string m_designer_cover; ModelInfo model_info; BBLProject project_info; - + std::string m_profile_title; + std::string m_profile_cover; + std::string m_Profile_description; + std::string m_profile_user_id; + std::string m_profile_user_name; + XML_Parser m_xml_parser; // Error code returned by the application side of the parser. In that case the expat may not reliably deliver the error state // after returning from XML_Parse() function, thus we keep the error state here. @@ -1379,6 +1391,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) m_model->design_info->Designer = m_designer; } + m_model->profile_info = std::make_shared(); + m_model->profile_info->ProfileTile = m_profile_title; + m_model->profile_info->ProfileCover = m_profile_cover; + m_model->profile_info->ProfileDescription = m_Profile_description; + m_model->profile_info->ProfileUserId = m_profile_user_id; + m_model->profile_info->ProfileUserName = m_profile_user_name; + + m_model->model_info = std::make_shared(); m_model->model_info->load(model_info); @@ -3189,6 +3209,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } else if (m_curr_metadata_name == BBL_MODEL_NAME_TAG) { BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found model name = " << m_curr_characters; model_info.model_name = xml_unescape(m_curr_characters); + } else if (m_curr_metadata_name == BBL_ORIGIN_TAG) { + BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found model name = " << m_curr_characters; + model_info.origin = xml_unescape(m_curr_characters); } else if (m_curr_metadata_name == BBL_DESIGNER_TAG) { BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found designer = " << m_curr_characters; m_designer = xml_unescape(m_curr_characters); @@ -3210,6 +3233,21 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } else if (m_curr_metadata_name == BBL_REGION_TAG) { BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found region = " << m_curr_characters; m_contry_code = xml_unescape(m_curr_characters); + } else if (m_curr_metadata_name == BBL_PROFILE_TITLE_TAG) { + BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found profile_title = " << m_curr_characters; + m_profile_title = xml_unescape(m_curr_characters); + } else if (m_curr_metadata_name == BBL_PROFILE_COVER_TAG) { + BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found profile_cover = " << m_curr_characters; + m_profile_cover = xml_unescape(m_curr_characters); + } else if (m_curr_metadata_name == BBL_PROFILE_DESCRIPTION_TAG) { + BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found profile_description = " << m_curr_characters; + m_Profile_description = xml_unescape(m_curr_characters); + } else if (m_curr_metadata_name == BBL_PROFILE_USER_ID_TAG) { + BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found profile_user_id = " << m_curr_characters; + m_profile_user_id = xml_unescape(m_curr_characters); + }else if (m_curr_metadata_name == BBL_PROFILE_USER_NAME_TAG) { + BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found profile_user_name = " << m_curr_characters; + m_profile_user_name = xml_unescape(m_curr_characters); } else if (m_curr_metadata_name == BBL_CREATION_DATE_TAG) { ; } else if (m_curr_metadata_name == BBL_MODIFICATION_TAG) { @@ -5427,6 +5465,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << " xmlns:p=\"http://schemas.microsoft.com/3dmanufacturing/production/2015/06\" requiredextensions=\"p\""; stream << ">\n"; + std::string origin; std::string name; std::string user_name; std::string user_id; @@ -5455,6 +5494,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) description = model.model_info->description; copyright = model.model_info->copyright; name = model.model_info->model_name; + origin = model.model_info->origin; BOOST_LOG_TRIVIAL(trace) << "design_info, save_3mf found designer_cover = " << design_cover; } // remember to use metadata_item_map to store metadata info @@ -5466,6 +5506,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } metadata_item_map[BBL_MODEL_NAME_TAG] = xml_escape(name); + metadata_item_map[BBL_ORIGIN_TAG] = xml_escape(origin); metadata_item_map[BBL_DESIGNER_TAG] = xml_escape(user_name); metadata_item_map[BBL_DESIGNER_USER_ID_TAG] = user_id; metadata_item_map[BBL_DESIGNER_COVER_FILE_TAG] = xml_escape(design_cover); diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index d710efd74..8fd3d3ce8 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -70,6 +70,7 @@ Model& Model::assign_copy(const Model &rhs) // BBS: for design info this->design_info = rhs.design_info; this->model_info = rhs.model_info; + this->profile_info = rhs.profile_info; return *this; } @@ -104,6 +105,8 @@ Model& Model::assign_copy(Model &&rhs) rhs.design_info.reset(); this->model_info = rhs.model_info; rhs.model_info.reset(); + this->profile_info = rhs.profile_info; + rhs.profile_info.reset(); return *this; } @@ -868,8 +871,10 @@ void Model::load_from(Model& model) next_object_backup_id = model.next_object_backup_id; design_info = model.design_info; model_info = model.model_info; + profile_info = model.profile_info; model.design_info.reset(); model.model_info.reset(); + model.profile_info.reset(); } // BBS: backup diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index d12bf1f7d..0560840a0 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -1257,6 +1257,17 @@ struct GlobalSpeedMap Polygon bed_poly; }; +/* Profile data */ +class ModelProfileInfo +{ +public: + std::string ProfileTile; + std::string ProfileCover; + std::string ProfileDescription; + std::string ProfileUserId; + std::string ProfileUserName; +}; + /* info in ModelDesignInfo can not changed after initialization */ class ModelDesignInfo { @@ -1275,6 +1286,7 @@ public: std::string description; // utf8 format std::string copyright; // utf8 format std::string model_name; // utf8 format + std::string origin; // utf8 format std::map metadata_items; // other meta data items @@ -1284,6 +1296,7 @@ public: this->description = info.description; this->copyright = info.copyright; this->model_name = info.model_name; + this->origin = info.origin; this->metadata_items = info.metadata_items; } }; @@ -1310,6 +1323,7 @@ public: // DesignInfo of Model std::shared_ptr design_info = nullptr; std::shared_ptr model_info = nullptr; + std::shared_ptr profile_info = nullptr; void SetDesigner(std::string designer, std::string designer_user_id) { if (design_info == nullptr) { diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index e4e269d81..3d60c924d 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -82,6 +82,8 @@ set(SLIC3R_GUI_SOURCES GUI/AuxiliaryDialog.hpp GUI/Auxiliary.cpp GUI/Auxiliary.hpp + GUI/Project.cpp + GUI/Project.hpp GUI/BackgroundSlicingProcess.cpp GUI/BackgroundSlicingProcess.hpp GUI/BitmapCache.cpp diff --git a/src/slic3r/GUI/Auxiliary.cpp b/src/slic3r/GUI/Auxiliary.cpp index f94ee1170..614d4f7f4 100644 --- a/src/slic3r/GUI/Auxiliary.cpp +++ b/src/slic3r/GUI/Auxiliary.cpp @@ -1034,7 +1034,6 @@ void AuxiliaryPanel::Reload(wxString aux_path) auto iter = m_paths_list.find(folder.ToStdString()); auto file_path_str = fs::path(file_path.c_str()); - if (iter != m_paths_list.end()) { m_paths_list[folder.ToStdString()].push_back(file_path_str); break; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index a38c3649c..bc3fd433f 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2413,7 +2413,7 @@ bool GUI_App::on_init_inner() sidebar().obj_list()->init(); //sidebar().aux_list()->init_auxiliary(); - mainframe->m_auxiliary->init_auxiliary(); + //mainframe->m_auxiliary->init_auxiliary(); // update_mode(); // !!! do that later SetTopWindow(mainframe); @@ -3042,7 +3042,7 @@ void GUI_App::recreate_GUI(const wxString& msg_name) // Propagate model objects to object list. sidebar().obj_list()->init(); //sidebar().aux_list()->init_auxiliary(); - mainframe->m_auxiliary->init_auxiliary(); + //mainframe->m_auxiliary->init_auxiliary(); SetTopWindow(mainframe); dlg.Update(30, _L("Rebuild") + dots); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index d49e06cb9..3ef44f9ce 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -970,9 +970,9 @@ void MainFrame::init_tabpanel() m_monitor->SetBackgroundColour(*wxWHITE); m_tabpanel->AddPage(m_monitor, _L("Device"), std::string("tab_monitor_active"), std::string("tab_monitor_active")); - m_auxiliary = new AuxiliaryPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); - m_auxiliary->SetBackgroundColour(*wxWHITE); - m_tabpanel->AddPage(m_auxiliary, _L("Project"), std::string("tab_auxiliary_avtice"), std::string("tab_auxiliary_avtice")); + m_project = new ProjectPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); + m_project->SetBackgroundColour(*wxWHITE); + m_tabpanel->AddPage(m_project, _L("Project"), std::string("tab_auxiliary_avtice"), std::string("tab_auxiliary_avtice")); if (m_plater) { // load initial config @@ -1790,7 +1790,7 @@ void MainFrame::on_dpi_changed(const wxRect& suggested_rect) //BBS GUI refactor: remove unused layout new/dlg //if (m_layout != ESettingsLayout::Dlg) // Do not update tabs if the Settings are in the separated dialog m_param_panel->msw_rescale(); - m_auxiliary->msw_rescale(); + m_project->msw_rescale(); m_monitor->msw_rescale(); // BBS diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 81c59fc49..58ed9314c 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -20,6 +20,7 @@ #include "ParamsPanel.hpp" #include "Monitor.hpp" #include "Auxiliary.hpp" +#include "Project.hpp" #include "UnsavedChangesDialog.hpp" #include "Widgets/SideButton.hpp" #include "Widgets/SideMenuPopup.hpp" @@ -330,7 +331,10 @@ public: Plater* m_plater { nullptr }; //BBS: GUI refactor MonitorPanel* m_monitor{ nullptr }; - AuxiliaryPanel* m_auxiliary{ nullptr }; + + //AuxiliaryPanel* m_auxiliary{ nullptr }; + ProjectPanel* m_project{ nullptr }; + WebViewPanel* m_webview { nullptr }; wxLogWindow* m_log_window { nullptr }; // BBS diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 444b7d1d9..1c00290dc 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3813,7 +3813,7 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs& mode void Plater::priv::load_auxiliary_files() { std::string auxiliary_path = encode_path(q->model().get_auxiliary_file_temp_path().c_str()); - wxGetApp().mainframe->m_auxiliary->Reload(auxiliary_path); + //wxGetApp().mainframe->m_project->Reload(auxiliary_path); } fs::path Plater::priv::get_export_file_path(GUI::FileType file_type) diff --git a/src/slic3r/GUI/Project.cpp b/src/slic3r/GUI/Project.cpp new file mode 100644 index 000000000..70ea98f78 --- /dev/null +++ b/src/slic3r/GUI/Project.cpp @@ -0,0 +1,412 @@ +#include "Tab.hpp" +#include "Project.hpp" +#include "libslic3r/Utils.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/Format/bbs_3mf.hpp" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wxExtensions.hpp" +#include "GUI_App.hpp" +#include "GUI_ObjectList.hpp" +#include "MainFrame.hpp" +#include + +namespace Slic3r { namespace GUI { + +wxDEFINE_EVENT(EVT_PROJECT_RELOAD, wxCommandEvent); + +const std::vector license_list = { + "BSD License", + "Apache License", + "GPL License", + "LGPL License", + "MIT License", + "CC License" +}; + +ProjectPanel::ProjectPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style) : wxPanel(parent, id, pos, size, style) +{ + m_project_home_url = wxString::Format("file://%s/web/model/index.html", from_u8(resources_dir())); + std::string strlang = wxGetApp().app_config->get("language"); + if (strlang != "") + m_project_home_url = wxString::Format("file://%s/web/model/index.html?lang=%s", from_u8(resources_dir()), strlang); + + wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); + + m_browser = WebView::CreateWebView(this, m_project_home_url); + if (m_browser == nullptr) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("load web view of project page failed"); + return; + } + //m_browser->Hide(); + main_sizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1)); + m_browser->Bind(wxEVT_WEBVIEW_NAVIGATED, &ProjectPanel::on_navigated, this); + m_browser->Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &ProjectPanel::OnScriptMessage, this, m_browser->GetId()); + + Bind(EVT_PROJECT_RELOAD, &ProjectPanel::on_reload, this); + + SetSizer(main_sizer); + Layout(); + Fit(); +} + +ProjectPanel::~ProjectPanel() {} + +void ProjectPanel::on_reload(wxCommandEvent& evt) +{ + std::string update_type; + std::string license; + std::string model_name; + std::string model_author; + std::string cover_file; + std::string description; + std::map> files; + + std::string p_name; + std::string p_author; + std::string p_description; + std::string p_cover_file; + + Model model = wxGetApp().plater()->model(); + + license = model.model_info->license; + model_name = model.model_info->model_name; + cover_file = model.model_info->cover_file; + description = model.model_info->description; + update_type = model.model_info->origin; + + if (model.design_info != nullptr) + model_author = model.design_info->Designer; + + if (model.profile_info != nullptr) { + p_name = model.profile_info->ProfileTile; + p_description = model.profile_info->ProfileDescription; + p_cover_file = model.profile_info->ProfileCover; + p_author = model.profile_info->ProfileUserName; + } + + //file info + std::string file_path = encode_path(wxGetApp().plater()->model().get_auxiliary_file_temp_path().c_str()); + if (!file_path.empty()) { + files = Reload(file_path); + } + else { + clear_model_info(); + return; + } + + json j; + j["model"]["license"] = license; + j["model"]["name"] = url_encode(model_name); + j["model"]["author"] = url_encode(model_author);; + j["model"]["cover_img"] = url_encode(cover_file); + j["model"]["description"] = url_encode(description); + j["model"]["preview_img"] = files["Model Pictures"]; + j["model"]["upload_type"] = update_type; + + j["file"]["BOM"] = files["Bill of Materials"]; + j["file"]["Assembly"] = files["Assembly Guide"]; + j["file"]["Other"] = files["Others"]; + + j["profile"]["name"] = url_encode(p_name); + j["profile"]["author"] = url_encode(p_author); + j["profile"]["description"] = url_encode(p_description); + j["profile"]["cover_img"] = url_encode(p_cover_file); + j["profile"]["preview_img"] = files["Profile Pictures"]; + + json m_Res = json::object(); + m_Res["command"] = "show_3mf_info"; + m_Res["sequence_id"] = std::to_string(ProjectPanel::m_sequence_id++); + m_Res["model"] = j; + + wxString strJS = wxString::Format("HandleStudio(%s)", m_Res.dump(-1, ' ', false, json::error_handler_t::ignore)); + + if (m_web_init_completed) { + wxGetApp().CallAfter([this, strJS] { + RunScript(strJS.ToStdString()); + }); + } +} + +void ProjectPanel::msw_rescale() +{ +} + +void ProjectPanel::on_size(wxSizeEvent &event) +{ + event.Skip(); +} + +void ProjectPanel::on_navigated(wxWebViewEvent& event) +{ + event.Skip(); +} + +void ProjectPanel::OnScriptMessage(wxWebViewEvent& evt) +{ + try { + wxString strInput = evt.GetString(); + json j = json::parse(strInput); + + wxString strCmd = j["command"]; + + if (strCmd == "open_3mf_accessory") { + wxString accessory_path = j["accessory_path"]; + + if (!accessory_path.empty()) { + std::string decode_path = url_decode(accessory_path.ToStdString()); + fs::path path(decode_path); + + if (fs::exists(path)) { + wxLaunchDefaultApplication(path.wstring(), 0); + } + } + } + else if (strCmd == "request_3mf_info") { + m_web_init_completed = true; + } + else if (strCmd == "debug_info") { + //wxString msg = j["msg"]; + //OutputDebugString(wxString::Format("Model_Web: msg = %s \r\n", msg)); + //BOOST_LOG_TRIVIAL(info) << wxString::Format("Model_Web: msg = %s", msg); + } + + } + catch (std::exception& e) { + // wxMessageBox(e.what(), "json Exception", MB_OK); + } +} + +void ProjectPanel::update_model_data() +{ + Model model = wxGetApp().plater()->model(); + clear_model_info(); + + //basics info + if (model.model_info == nullptr) + return; + + auto event = wxCommandEvent(EVT_PROJECT_RELOAD); + event.SetEventObject(this); + wxPostEvent(this, event); +} + +void ProjectPanel::clear_model_info() +{ + json m_Res = json::object(); + m_Res["command"] = "clear_3mf_info"; + m_Res["sequence_id"] = std::to_string(ProjectPanel::m_sequence_id++); + + wxString strJS = wxString::Format("HandleStudio(%s)", m_Res.dump(-1, ' ', false, json::error_handler_t::ignore)); + + wxGetApp().CallAfter([this, strJS] { + RunScript(strJS.ToStdString()); + }); +} + +std::map> ProjectPanel::Reload(wxString aux_path) +{ + std::vector dir_cache; + fs::directory_iterator iter_end; + wxString m_root_dir; + std::map> m_paths_list; + + const static std::array s_default_folders = { + ("Model Pictures"), + ("Bill of Materials"), + ("Assembly Guide"), + ("Others"), + //(".thumbnails"), + ("Profile Pictures"), + }; + + for (auto folder : s_default_folders) + m_paths_list[folder.ToStdString()] = std::vector{}; + + + fs::path new_aux_path(aux_path.ToStdWstring()); + + try { + fs::remove_all(fs::path(m_root_dir.ToStdWstring())); + } + catch (...) { + BOOST_LOG_TRIVIAL(error) << "Failed removing the auxiliary directory" << m_root_dir.c_str(); + } + + m_root_dir = aux_path; + // Check new path. If not exist, create a new one. + if (!fs::exists(new_aux_path)) { + fs::create_directory(new_aux_path); + // Create default folders if they are not loaded + for (auto folder : s_default_folders) { + wxString folder_path = aux_path + "/" + folder; + if (fs::exists(folder_path.ToStdWstring())) continue; + fs::create_directory(folder_path.ToStdWstring()); + } + return m_paths_list; + } + + // Load from new path + for (fs::directory_iterator iter(new_aux_path); iter != iter_end; iter++) { + wxString path = iter->path().generic_wstring(); + dir_cache.push_back(iter->path()); + } + + + for (auto dir : dir_cache) { + for (fs::directory_iterator iter(dir); iter != iter_end; iter++) { + if (fs::is_directory(iter->path())) continue; + + json pfile_obj; + + std::string file_path = iter->path().string(); + fs::path file_path_obj = fs::path(iter->path().string()); + + for (auto folder : s_default_folders) { + auto idx = file_path.find(folder.ToStdString()); + if (idx != std::string::npos) { + + wxStructStat strucStat; + wxString file_name = encode_path(file_path.c_str()); + wxStat(file_name, &strucStat); + wxFileOffset filelen = strucStat.st_size; + + pfile_obj["filename"] = url_encode(file_path_obj.filename().string().c_str()); + pfile_obj["size"] = formatBytes((unsigned long)filelen); + + //image + if (file_path_obj.extension() == ".jpg" || + file_path_obj.extension() == ".jpeg" || + file_path_obj.extension() == ".png" || + file_path_obj.extension() == ".bmp") + { + + wxString base64_str = to_base64(file_path); + pfile_obj["filepath"] = base64_str.ToStdString(); + m_paths_list[folder.ToStdString()].push_back(pfile_obj); + break; + } + else { + pfile_obj["filepath"] = url_encode(file_path); + m_paths_list[folder.ToStdString()].push_back(pfile_obj); + break; + } + } + } + } + } + + return m_paths_list; +} + +std::string ProjectPanel::formatBytes(unsigned long bytes) +{ + double dValidData = round(double(bytes) / (1024 * 1024) * 1000) / 1000; + return wxString::Format("%.2fMB", dValidData).ToStdString(); +} + +wxString ProjectPanel::to_base64(std::string file_path) +{ + std::map base64_format; + base64_format[".jpg"] = wxBITMAP_TYPE_JPEG; + base64_format[".jpeg"] = wxBITMAP_TYPE_JPEG; + base64_format[".png"] = wxBITMAP_TYPE_PNG; + base64_format[".bmp"] = wxBITMAP_TYPE_BMP; + + std::string extension = file_path.substr(file_path.rfind("."), file_path.length()); + + auto image = new wxImage(encode_path(file_path.c_str())); + wxMemoryOutputStream mem; + image->SaveFile(mem, base64_format[extension]); + + wxString km = wxBase64Encode(mem.GetOutputStreamBuffer()->GetBufferStart(), + mem.GetSize()); + + std::wstringstream wss; + wss << L"data:image/jpg;base64,"; + //wss << wxBase64Encode(km.data(), km.size()); + wss << km; + + wxString base64_str = wss.str(); + return base64_str; +} + +void ProjectPanel::RunScript(std::string content) +{ + WebView::RunScript(m_browser, content); +} + +char ProjectPanel::from_hex(char ch) { + return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10; +} + +std::string ProjectPanel::url_decode(string text) { + char h; + ostringstream escaped; + escaped.fill('0'); + + for (auto i = text.begin(), n = text.end(); i != n; ++i) { + string::value_type c = (*i); + + if (c == '%') { + if (i[1] && i[2]) { + h = from_hex(i[1]) << 4 | from_hex(i[2]); + escaped << h; + i += 2; + } + } + else if (c == '+') { + escaped << ' '; + } + else { + escaped << c; + } + } + + return escaped.str(); +} + +std::string ProjectPanel::url_encode(const std::string& value) { + std::ostringstream escaped; + escaped.fill('0'); + escaped << std::hex; + for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) { + std::string::value_type c = (*i); + + // Keep alphanumeric and other accepted characters intact + if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { + escaped << c; + continue; + } + + // Any other characters are percent-encoded + escaped << std::uppercase; + escaped << '%' << std::setw(2) << int((unsigned char)c); + escaped << std::nouppercase; + } + return escaped.str(); +} + +bool ProjectPanel::Show(bool show) +{ + if (show) update_model_data(); + return wxPanel::Show(show); +} + +}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Project.hpp b/src/slic3r/GUI/Project.hpp new file mode 100644 index 000000000..d001f013e --- /dev/null +++ b/src/slic3r/GUI/Project.hpp @@ -0,0 +1,99 @@ +#ifndef slic3r_Project_hpp_ +#define slic3r_Project_hpp_ + +#include "Tabbook.hpp" +#include "wx/artprov.h" +#include "wx/cmdline.h" +#include "wx/notifmsg.h" +#include "wx/settings.h" +#include "wx/webview.h" + +#if wxUSE_WEBVIEW_EDGE +#include "wx/msw/webview_edge.h" +#endif + +#include "wx/numdlg.h" +#include "wx/infobar.h" +#include "wx/filesys.h" +#include "wx/fs_arc.h" +#include "wx/fs_mem.h" +#include "wx/stdpaths.h" +#include +#include +#include "wx/textctrl.h" +#include + +#include "nlohmann/json.hpp" +#include "slic3r/Utils/json_diff.hpp" + +#include +#include +#include +#include "Event.hpp" +#include "libslic3r/ProjectTask.hpp" +#include "wxExtensions.hpp" + +#define AUFILE_GREY700 wxColour(107, 107, 107) +#define AUFILE_GREY500 wxColour(158, 158, 158) +#define AUFILE_GREY300 wxColour(238, 238, 238) +#define AUFILE_GREY200 wxColour(248, 248, 248) +#define AUFILE_BRAND wxColour(0, 174, 66) +#define AUFILE_BRAND_TRANSPARENT wxColour(215, 232, 222) +//#define AUFILE_PICTURES_SIZE wxSize(FromDIP(300), FromDIP(300)) +//#define AUFILE_PICTURES_PANEL_SIZE wxSize(FromDIP(300), FromDIP(340)) +#define AUFILE_PICTURES_SIZE wxSize(FromDIP(168), FromDIP(168)) +#define AUFILE_PICTURES_PANEL_SIZE wxSize(FromDIP(168), FromDIP(208)) +#define AUFILE_SIZE wxSize(FromDIP(168), FromDIP(168)) +#define AUFILE_PANEL_SIZE wxSize(FromDIP(168), FromDIP(208)) +#define AUFILE_TEXT_HEIGHT FromDIP(40) +#define AUFILE_ROUNDING FromDIP(5) + +namespace Slic3r { namespace GUI { + +struct project_file{ + std::string filepath; + std::string filename; + std::string size; +}; + +class ProjectPanel : public wxPanel +{ +private: + bool m_web_init_completed = {false}; + bool m_reload_already = {false}; + + wxWebView* m_browser = {nullptr}; + wxString m_project_home_url; + wxString m_root_dir; + static inline int m_sequence_id = 8000; + + +public: + ProjectPanel(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = wxTAB_TRAVERSAL); + ~ProjectPanel(); + + + void on_reload(wxCommandEvent& evt); + void on_size(wxSizeEvent &event); + void on_navigated(wxWebViewEvent& event); + + void msw_rescale(); + void update_model_data(); + void clear_model_info(); + + bool Show(bool show); + void OnScriptMessage(wxWebViewEvent& evt); + void RunScript(std::string content); + + char from_hex(char ch); + std::string url_decode(string text); + std::string url_encode(const std::string& value); + std::map> Reload(wxString aux_path); + std::string formatBytes(unsigned long bytes); + wxString to_base64(std::string path); +}; + +wxDECLARE_EVENT(EVT_PROJECT_RELOAD, wxCommandEvent); +}} // namespace Slic3r::GUI + +#endif