mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	NEW:update the content of the project page
Change-Id: Idb7f8a2564c78a1f062580f6b388ee033238cedf
This commit is contained in:
		
							parent
							
								
									4cb8b1e125
								
							
						
					
					
						commit
						a86d94f2c9
					
				
					 11 changed files with 586 additions and 10 deletions
				
			
		|  | @ -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,6 +854,11 @@ 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
 | ||||
|  | @ -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<ModelProfileInfo>(); | ||||
|         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<ModelInfo>(); | ||||
|         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); | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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<std::string, std::string> 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<ModelDesignInfo> design_info = nullptr; | ||||
|     std::shared_ptr<ModelInfo> model_info = nullptr; | ||||
|     std::shared_ptr<ModelProfileInfo> profile_info = nullptr; | ||||
| 
 | ||||
|     void SetDesigner(std::string designer, std::string designer_user_id) { | ||||
|         if (design_info == nullptr) { | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -3813,7 +3813,7 @@ std::vector<size_t> 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) | ||||
|  |  | |||
							
								
								
									
										412
									
								
								src/slic3r/GUI/Project.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										412
									
								
								src/slic3r/GUI/Project.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 <wx/app.h> | ||||
| #include <wx/button.h> | ||||
| #include <wx/scrolwin.h> | ||||
| #include <wx/sizer.h> | ||||
| 
 | ||||
| #include <wx/bmpcbox.h> | ||||
| #include <wx/bmpbuttn.h> | ||||
| #include <wx/treectrl.h> | ||||
| #include <wx/imaglist.h> | ||||
| #include <wx/settings.h> | ||||
| #include <wx/filedlg.h> | ||||
| #include <wx/wupdlock.h> | ||||
| #include <wx/dataview.h> | ||||
| #include <wx/tokenzr.h> | ||||
| #include <wx/arrstr.h> | ||||
| #include <wx/tglbtn.h> | ||||
| 
 | ||||
| #include "wxExtensions.hpp" | ||||
| #include "GUI_App.hpp" | ||||
| #include "GUI_ObjectList.hpp" | ||||
| #include "MainFrame.hpp" | ||||
| #include <slic3r/GUI/Widgets/WebView.hpp> | ||||
| 
 | ||||
| namespace Slic3r { namespace GUI { | ||||
| 
 | ||||
| wxDEFINE_EVENT(EVT_PROJECT_RELOAD, wxCommandEvent); | ||||
| 
 | ||||
| const std::vector<std::string> 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<std::string, std::vector<json>> 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<std::string, std::vector<json>> ProjectPanel::Reload(wxString aux_path) | ||||
| { | ||||
|     std::vector<fs::path>                           dir_cache; | ||||
|     fs::directory_iterator                          iter_end; | ||||
|     wxString                                        m_root_dir; | ||||
|     std::map<std::string, std::vector<json>> m_paths_list; | ||||
| 
 | ||||
|     const static std::array<wxString, 5> 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<json>{}; | ||||
| 
 | ||||
| 
 | ||||
|     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<std::string, wxBitmapType> 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
 | ||||
							
								
								
									
										99
									
								
								src/slic3r/GUI/Project.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/slic3r/GUI/Project.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 <wx/panel.h> | ||||
| #include <wx/tbarbase.h> | ||||
| #include "wx/textctrl.h" | ||||
| #include <wx/timer.h> | ||||
| 
 | ||||
| #include "nlohmann/json.hpp" | ||||
| #include "slic3r/Utils/json_diff.hpp" | ||||
| 
 | ||||
| #include <map> | ||||
| #include <vector> | ||||
| #include <memory> | ||||
| #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<std::string, std::vector<json>> 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 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 tao wang
						tao wang