mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-09 07:56:24 -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 BBS_MM_PAINTING_VERSION = "BambuStudio:MmPaintingVersion";
|
||||||
const std::string BBL_MODEL_ID_TAG = "model_id";
|
const std::string BBL_MODEL_ID_TAG = "model_id";
|
||||||
const std::string BBL_MODEL_NAME_TAG = "Title";
|
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_TAG = "Designer";
|
||||||
const std::string BBL_DESIGNER_USER_ID_TAG = "DesignerUserId";
|
const std::string BBL_DESIGNER_USER_ID_TAG = "DesignerUserId";
|
||||||
const std::string BBL_DESIGNER_COVER_FILE_TAG = "DesignerCover";
|
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_CREATION_DATE_TAG = "CreationDate";
|
||||||
const std::string BBL_APPLICATION_TAG = "Application";
|
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_FOLDER = "3D/";
|
||||||
const std::string MODEL_EXTENSION = ".model";
|
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
|
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;
|
std::string m_designer_cover;
|
||||||
ModelInfo model_info;
|
ModelInfo model_info;
|
||||||
BBLProject project_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;
|
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
|
// 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.
|
// 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->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 = std::make_shared<ModelInfo>();
|
||||||
m_model->model_info->load(model_info);
|
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) {
|
} else if (m_curr_metadata_name == BBL_MODEL_NAME_TAG) {
|
||||||
BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found model name = " << m_curr_characters;
|
BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found model name = " << m_curr_characters;
|
||||||
model_info.model_name = xml_unescape(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) {
|
} else if (m_curr_metadata_name == BBL_DESIGNER_TAG) {
|
||||||
BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found designer = " << m_curr_characters;
|
BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found designer = " << m_curr_characters;
|
||||||
m_designer = xml_unescape(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) {
|
} else if (m_curr_metadata_name == BBL_REGION_TAG) {
|
||||||
BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found region = " << m_curr_characters;
|
BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found region = " << m_curr_characters;
|
||||||
m_contry_code = xml_unescape(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_CREATION_DATE_TAG) {
|
||||||
;
|
;
|
||||||
} else if (m_curr_metadata_name == BBL_MODIFICATION_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 << " xmlns:p=\"http://schemas.microsoft.com/3dmanufacturing/production/2015/06\" requiredextensions=\"p\"";
|
||||||
stream << ">\n";
|
stream << ">\n";
|
||||||
|
|
||||||
|
std::string origin;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string user_name;
|
std::string user_name;
|
||||||
std::string user_id;
|
std::string user_id;
|
||||||
|
@ -5455,6 +5494,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||||
description = model.model_info->description;
|
description = model.model_info->description;
|
||||||
copyright = model.model_info->copyright;
|
copyright = model.model_info->copyright;
|
||||||
name = model.model_info->model_name;
|
name = model.model_info->model_name;
|
||||||
|
origin = model.model_info->origin;
|
||||||
BOOST_LOG_TRIVIAL(trace) << "design_info, save_3mf found designer_cover = " << design_cover;
|
BOOST_LOG_TRIVIAL(trace) << "design_info, save_3mf found designer_cover = " << design_cover;
|
||||||
}
|
}
|
||||||
// remember to use metadata_item_map to store metadata info
|
// 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_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_TAG] = xml_escape(user_name);
|
||||||
metadata_item_map[BBL_DESIGNER_USER_ID_TAG] = user_id;
|
metadata_item_map[BBL_DESIGNER_USER_ID_TAG] = user_id;
|
||||||
metadata_item_map[BBL_DESIGNER_COVER_FILE_TAG] = xml_escape(design_cover);
|
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
|
// BBS: for design info
|
||||||
this->design_info = rhs.design_info;
|
this->design_info = rhs.design_info;
|
||||||
this->model_info = rhs.model_info;
|
this->model_info = rhs.model_info;
|
||||||
|
this->profile_info = rhs.profile_info;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -104,6 +105,8 @@ Model& Model::assign_copy(Model &&rhs)
|
||||||
rhs.design_info.reset();
|
rhs.design_info.reset();
|
||||||
this->model_info = rhs.model_info;
|
this->model_info = rhs.model_info;
|
||||||
rhs.model_info.reset();
|
rhs.model_info.reset();
|
||||||
|
this->profile_info = rhs.profile_info;
|
||||||
|
rhs.profile_info.reset();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -868,8 +871,10 @@ void Model::load_from(Model& model)
|
||||||
next_object_backup_id = model.next_object_backup_id;
|
next_object_backup_id = model.next_object_backup_id;
|
||||||
design_info = model.design_info;
|
design_info = model.design_info;
|
||||||
model_info = model.model_info;
|
model_info = model.model_info;
|
||||||
|
profile_info = model.profile_info;
|
||||||
model.design_info.reset();
|
model.design_info.reset();
|
||||||
model.model_info.reset();
|
model.model_info.reset();
|
||||||
|
model.profile_info.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// BBS: backup
|
// BBS: backup
|
||||||
|
|
|
@ -1257,6 +1257,17 @@ struct GlobalSpeedMap
|
||||||
Polygon bed_poly;
|
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 */
|
/* info in ModelDesignInfo can not changed after initialization */
|
||||||
class ModelDesignInfo
|
class ModelDesignInfo
|
||||||
{
|
{
|
||||||
|
@ -1275,6 +1286,7 @@ public:
|
||||||
std::string description; // utf8 format
|
std::string description; // utf8 format
|
||||||
std::string copyright; // utf8 format
|
std::string copyright; // utf8 format
|
||||||
std::string model_name; // 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
|
std::map<std::string, std::string> metadata_items; // other meta data items
|
||||||
|
|
||||||
|
@ -1284,6 +1296,7 @@ public:
|
||||||
this->description = info.description;
|
this->description = info.description;
|
||||||
this->copyright = info.copyright;
|
this->copyright = info.copyright;
|
||||||
this->model_name = info.model_name;
|
this->model_name = info.model_name;
|
||||||
|
this->origin = info.origin;
|
||||||
this->metadata_items = info.metadata_items;
|
this->metadata_items = info.metadata_items;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1310,6 +1323,7 @@ public:
|
||||||
// DesignInfo of Model
|
// DesignInfo of Model
|
||||||
std::shared_ptr<ModelDesignInfo> design_info = nullptr;
|
std::shared_ptr<ModelDesignInfo> design_info = nullptr;
|
||||||
std::shared_ptr<ModelInfo> model_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) {
|
void SetDesigner(std::string designer, std::string designer_user_id) {
|
||||||
if (design_info == nullptr) {
|
if (design_info == nullptr) {
|
||||||
|
|
|
@ -82,6 +82,8 @@ set(SLIC3R_GUI_SOURCES
|
||||||
GUI/AuxiliaryDialog.hpp
|
GUI/AuxiliaryDialog.hpp
|
||||||
GUI/Auxiliary.cpp
|
GUI/Auxiliary.cpp
|
||||||
GUI/Auxiliary.hpp
|
GUI/Auxiliary.hpp
|
||||||
|
GUI/Project.cpp
|
||||||
|
GUI/Project.hpp
|
||||||
GUI/BackgroundSlicingProcess.cpp
|
GUI/BackgroundSlicingProcess.cpp
|
||||||
GUI/BackgroundSlicingProcess.hpp
|
GUI/BackgroundSlicingProcess.hpp
|
||||||
GUI/BitmapCache.cpp
|
GUI/BitmapCache.cpp
|
||||||
|
|
|
@ -1034,7 +1034,6 @@ void AuxiliaryPanel::Reload(wxString aux_path)
|
||||||
auto iter = m_paths_list.find(folder.ToStdString());
|
auto iter = m_paths_list.find(folder.ToStdString());
|
||||||
auto file_path_str = fs::path(file_path.c_str());
|
auto file_path_str = fs::path(file_path.c_str());
|
||||||
|
|
||||||
|
|
||||||
if (iter != m_paths_list.end()) {
|
if (iter != m_paths_list.end()) {
|
||||||
m_paths_list[folder.ToStdString()].push_back(file_path_str);
|
m_paths_list[folder.ToStdString()].push_back(file_path_str);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -2413,7 +2413,7 @@ bool GUI_App::on_init_inner()
|
||||||
|
|
||||||
sidebar().obj_list()->init();
|
sidebar().obj_list()->init();
|
||||||
//sidebar().aux_list()->init_auxiliary();
|
//sidebar().aux_list()->init_auxiliary();
|
||||||
mainframe->m_auxiliary->init_auxiliary();
|
//mainframe->m_auxiliary->init_auxiliary();
|
||||||
|
|
||||||
// update_mode(); // !!! do that later
|
// update_mode(); // !!! do that later
|
||||||
SetTopWindow(mainframe);
|
SetTopWindow(mainframe);
|
||||||
|
@ -3042,7 +3042,7 @@ void GUI_App::recreate_GUI(const wxString& msg_name)
|
||||||
// Propagate model objects to object list.
|
// Propagate model objects to object list.
|
||||||
sidebar().obj_list()->init();
|
sidebar().obj_list()->init();
|
||||||
//sidebar().aux_list()->init_auxiliary();
|
//sidebar().aux_list()->init_auxiliary();
|
||||||
mainframe->m_auxiliary->init_auxiliary();
|
//mainframe->m_auxiliary->init_auxiliary();
|
||||||
SetTopWindow(mainframe);
|
SetTopWindow(mainframe);
|
||||||
|
|
||||||
dlg.Update(30, _L("Rebuild") + dots);
|
dlg.Update(30, _L("Rebuild") + dots);
|
||||||
|
|
|
@ -970,9 +970,9 @@ void MainFrame::init_tabpanel()
|
||||||
m_monitor->SetBackgroundColour(*wxWHITE);
|
m_monitor->SetBackgroundColour(*wxWHITE);
|
||||||
m_tabpanel->AddPage(m_monitor, _L("Device"), std::string("tab_monitor_active"), std::string("tab_monitor_active"));
|
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_project = new ProjectPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize);
|
||||||
m_auxiliary->SetBackgroundColour(*wxWHITE);
|
m_project->SetBackgroundColour(*wxWHITE);
|
||||||
m_tabpanel->AddPage(m_auxiliary, _L("Project"), std::string("tab_auxiliary_avtice"), std::string("tab_auxiliary_avtice"));
|
m_tabpanel->AddPage(m_project, _L("Project"), std::string("tab_auxiliary_avtice"), std::string("tab_auxiliary_avtice"));
|
||||||
|
|
||||||
if (m_plater) {
|
if (m_plater) {
|
||||||
// load initial config
|
// load initial config
|
||||||
|
@ -1790,7 +1790,7 @@ void MainFrame::on_dpi_changed(const wxRect& suggested_rect)
|
||||||
//BBS GUI refactor: remove unused layout new/dlg
|
//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
|
//if (m_layout != ESettingsLayout::Dlg) // Do not update tabs if the Settings are in the separated dialog
|
||||||
m_param_panel->msw_rescale();
|
m_param_panel->msw_rescale();
|
||||||
m_auxiliary->msw_rescale();
|
m_project->msw_rescale();
|
||||||
m_monitor->msw_rescale();
|
m_monitor->msw_rescale();
|
||||||
|
|
||||||
// BBS
|
// BBS
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "ParamsPanel.hpp"
|
#include "ParamsPanel.hpp"
|
||||||
#include "Monitor.hpp"
|
#include "Monitor.hpp"
|
||||||
#include "Auxiliary.hpp"
|
#include "Auxiliary.hpp"
|
||||||
|
#include "Project.hpp"
|
||||||
#include "UnsavedChangesDialog.hpp"
|
#include "UnsavedChangesDialog.hpp"
|
||||||
#include "Widgets/SideButton.hpp"
|
#include "Widgets/SideButton.hpp"
|
||||||
#include "Widgets/SideMenuPopup.hpp"
|
#include "Widgets/SideMenuPopup.hpp"
|
||||||
|
@ -330,7 +331,10 @@ public:
|
||||||
Plater* m_plater { nullptr };
|
Plater* m_plater { nullptr };
|
||||||
//BBS: GUI refactor
|
//BBS: GUI refactor
|
||||||
MonitorPanel* m_monitor{ nullptr };
|
MonitorPanel* m_monitor{ nullptr };
|
||||||
AuxiliaryPanel* m_auxiliary{ nullptr };
|
|
||||||
|
//AuxiliaryPanel* m_auxiliary{ nullptr };
|
||||||
|
ProjectPanel* m_project{ nullptr };
|
||||||
|
|
||||||
WebViewPanel* m_webview { nullptr };
|
WebViewPanel* m_webview { nullptr };
|
||||||
wxLogWindow* m_log_window { nullptr };
|
wxLogWindow* m_log_window { nullptr };
|
||||||
// BBS
|
// BBS
|
||||||
|
|
|
@ -3813,7 +3813,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
|
||||||
void Plater::priv::load_auxiliary_files()
|
void Plater::priv::load_auxiliary_files()
|
||||||
{
|
{
|
||||||
std::string auxiliary_path = encode_path(q->model().get_auxiliary_file_temp_path().c_str());
|
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)
|
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