Merge remote-tracking branch 'remote/master' into feature/merge_upstream

# Conflicts:
#	bbl/i18n/OrcaSlicer.pot
#	bbl/i18n/de/OrcaSlicer_de.po
#	bbl/i18n/en/OrcaSlicer_en.po
#	bbl/i18n/es/OrcaSlicer_es.po
#	bbl/i18n/fr/OrcaSlicer_fr.po
#	bbl/i18n/hu/OrcaSlicer_hu.po
#	bbl/i18n/it/OrcaSlicer_it.po
#	bbl/i18n/ja/OrcaSlicer_ja.po
#	bbl/i18n/nl/OrcaSlicer_nl.po
#	bbl/i18n/sv/OrcaSlicer_sv.po
#	bbl/i18n/zh_cn/OrcaSlicer_zh_CN.po
#	resources/config.json
#	resources/i18n/de/BambuStudio.mo
#	resources/i18n/en/BambuStudio.mo
#	resources/i18n/es/BambuStudio.mo
#	resources/i18n/fr/BambuStudio.mo
#	resources/i18n/hu/BambuStudio.mo
#	resources/i18n/it/BambuStudio.mo
#	resources/i18n/ja/OrcaSlicer.mo
#	resources/i18n/nl/BambuStudio.mo
#	resources/i18n/sv/BambuStudio.mo
#	resources/i18n/zh_cn/BambuStudio.mo
#	resources/images/ams_humidity_2.svg
#	resources/images/ams_humidity_3.svg
#	resources/images/ams_humidity_4.svg
#	resources/images/ams_humidity_tips.svg
#	resources/images/monitor_state_on.svg
#	resources/images/sdcard_state_normal.svg
#	resources/profiles/BBL.json
#	resources/profiles/BBL/filament/Bambu PETG-CF @base.json
#	resources/profiles/BBL/filament/Generic PETG-CF @base.json
#	resources/profiles/BBL/machine/Bambu Lab P1P 0.4 nozzle.json
#	resources/web/data/text.js
#	resources/web/guide/3/index.html
#	resources/web/guide/31/index.html
#	src/BambuStudio.cpp
#	src/libslic3r/AABBTreeLines.hpp
#	src/libslic3r/Brim.cpp
#	src/libslic3r/CMakeLists.txt
#	src/libslic3r/ExPolygon.hpp
#	src/libslic3r/Fill/FillBase.hpp
#	src/libslic3r/Format/bbs_3mf.cpp
#	src/libslic3r/GCodeWriter.cpp
#	src/libslic3r/Line.hpp
#	src/libslic3r/PerimeterGenerator.cpp
#	src/libslic3r/Preset.cpp
#	src/libslic3r/Print.cpp
#	src/libslic3r/Print.hpp
#	src/libslic3r/PrintConfig.cpp
#	src/libslic3r/PrintConfig.hpp
#	src/libslic3r/TreeSupport.cpp
#	src/slic3r/GUI/AmsMappingPopup.cpp
#	src/slic3r/GUI/BackgroundSlicingProcess.cpp
#	src/slic3r/GUI/ConfigManipulation.cpp
#	src/slic3r/GUI/GCodeViewer.cpp
#	src/slic3r/GUI/GCodeViewer.hpp
#	src/slic3r/GUI/GLCanvas3D.cpp
#	src/slic3r/GUI/GUI_App.cpp
#	src/slic3r/GUI/MainFrame.cpp
#	src/slic3r/GUI/PartPlate.cpp
#	src/slic3r/GUI/Plater.cpp
#	src/slic3r/GUI/Preferences.cpp
#	src/slic3r/GUI/SelectMachine.cpp
#	src/slic3r/GUI/Widgets/AMSControl.cpp
#	src/slic3r/GUI/wxMediaCtrl2.cpp
#	src/slic3r/Utils/Process.cpp
#	version.inc
This commit is contained in:
SoftFever 2023-04-19 08:48:07 +08:00
commit 9f598046d1
658 changed files with 70312 additions and 4877 deletions

View file

@ -61,6 +61,7 @@
#include "../Utils/Process.hpp"
#include "../Utils/MacDarkMode.hpp"
#include "../Utils/Http.hpp"
#include "../Utils/UndoRedo.hpp"
#include "slic3r/Config/Snapshot.hpp"
#include "Preferences.hpp"
#include "Tab.hpp"
@ -951,28 +952,45 @@ static void generic_exception_handle()
} catch (const std::bad_alloc& ex) {
// bad_alloc in main thread is most likely fatal. Report immediately to the user (wxLogError would be delayed)
// and terminate the app so it is at least certain to happen now.
BOOST_LOG_TRIVIAL(error) << boost::format("std::bad_alloc exception: %1%") % ex.what();
flush_logs();
wxString errmsg = wxString::Format(_L("OrcaSlicer will terminate because of running out of memory."
"It may be a bug. It will be appreciated if you report the issue to our team."));
wxMessageBox(errmsg + "\n\n" + wxString(ex.what()), _L("Fatal error"), wxOK | wxICON_ERROR);
BOOST_LOG_TRIVIAL(error) << boost::format("std::bad_alloc exception: %1%") % ex.what();
std::terminate();
//throw;
} catch (const boost::io::bad_format_string& ex) {
BOOST_LOG_TRIVIAL(error) << boost::format("Uncaught exception: %1%") % ex.what();
flush_logs();
wxString errmsg = _L("OrcaSlicer will terminate because of a localization error. "
"It will be appreciated if you report the specific scenario this issue happened.");
wxMessageBox(errmsg + "\n\n" + wxString(ex.what()), _L("Critical error"), wxOK | wxICON_ERROR);
BOOST_LOG_TRIVIAL(error) << boost::format("Uncaught exception: %1%") % ex.what();
std::terminate();
//throw;
} catch (const std::exception& ex) {
wxLogError(format_wxstr(_L("OrcaSlicer got an unhandled exception: %1%"), ex.what()));
BOOST_LOG_TRIVIAL(error) << boost::format("Uncaught exception: %1%") % ex.what();
flush_logs();
throw;
}
//#endif
}
static std::vector<std::string> split_str(const std::string& src, const std::string& separator)
{
size_t pos;
size_t start_pos = 0;
vector<string> result_str;
while ((pos = src.find(separator, start_pos)) != string::npos)
{
result_str.emplace_back(src.substr(start_pos, pos - start_pos));
start_pos = pos + separator.size();
}
result_str.emplace_back(src.substr(start_pos, src.size() - pos - separator.size()));
return result_str;
}
void GUI_App::post_init()
{
assert(initialized());
@ -981,29 +999,55 @@ void GUI_App::post_init()
bool switch_to_3d = false;
if (!this->init_params->input_files.empty()) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", init with input files, size %1%, input_gcode %2%")
%this->init_params->input_files.size() %this->init_params->input_gcode;
switch_to_3d = true;
if (this->init_params->input_gcode) {
mainframe->select_tab(size_t(MainFrame::tp3DEditor));
plater_->select_view_3D("3D");
this->plater()->load_gcode(from_u8(this->init_params->input_files.front()));
if (this->init_params->input_files.size() == 1 &&
boost::starts_with(this->init_params->input_files.front(), "bambustudio://open")) {
auto input_str_arr = split_str(this->init_params->input_files.front(), "bambustudio://open/?file=");
std::string download_origin_url;
for (auto input_str:input_str_arr) {
if (!input_str.empty()) download_origin_url = input_str;
}
std::string download_file_url = url_decode(download_origin_url);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << download_file_url;
if (!download_file_url.empty() && ( boost::starts_with(download_file_url, "http://") || boost::starts_with(download_file_url, "https://")) ) {
request_model_download(download_origin_url);
}
}
else {
mainframe->select_tab(size_t(MainFrame::tp3DEditor));
plater_->select_view_3D("3D");
const std::vector<size_t> res = this->plater()->load_files(this->init_params->input_files);
if (!res.empty()) {
if (this->init_params->input_files.size() == 1) {
// Update application titlebar when opening a project file
const std::string& filename = this->init_params->input_files.front();
//BBS: remove amf logic as project
if (boost::algorithm::iends_with(filename, ".3mf"))
this->plater()->set_project_filename(from_u8(filename));
switch_to_3d = true;
if (this->init_params->input_gcode) {
mainframe->select_tab(size_t(MainFrame::tp3DEditor));
plater_->select_view_3D("3D");
this->plater()->load_gcode(from_u8(this->init_params->input_files.front()));
}
else {
mainframe->select_tab(size_t(MainFrame::tp3DEditor));
plater_->select_view_3D("3D");
Plater::TakeSnapshot snapshot(this->plater(), "Load Project", UndoRedo::SnapshotType::ProjectSeparator);
const std::vector<size_t> res = this->plater()->load_files(this->init_params->input_files);
if (!res.empty()) {
if (this->init_params->input_files.size() == 1) {
// Update application titlebar when opening a project file
const std::string& filename = this->init_params->input_files.front();
this->plater()->up_to_date(true, false);
this->plater()->up_to_date(true, true);
//BBS: remove amf logic as project
if (boost::algorithm::iends_with(filename, ".3mf"))
this->plater()->set_project_filename(from_u8(filename));
}
}
}
}
}
//#if BBL_HAS_FIRST_PAGE
bool slow_bootup = false;
if (app_config->get("slow_bootup") == "true") {
@ -1017,9 +1061,9 @@ void GUI_App::post_init()
mainframe->select_tab(size_t(MainFrame::tp3DEditor));
plater_->select_view_3D("3D");
//BBS init the opengl resource here
#ifdef __linux__
//#ifdef __linux__
if (plater_->canvas3D()->get_wxglcanvas()->IsShownOnScreen()&&plater_->canvas3D()->make_current_for_postinit()) {
#endif
//#endif
Size canvas_size = plater_->canvas3D()->get_canvas_size();
wxGetApp().imgui()->set_display_size(static_cast<float>(canvas_size.get_width()), static_cast<float>(canvas_size.get_height()));
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", start to init opengl";
@ -1039,9 +1083,12 @@ void GUI_App::post_init()
plater_->canvas3D()->render(false);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", finished rendering a first frame for test";
}
#ifdef __linux__
//#ifdef __linux__
}
#endif
else {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << "Found glcontext not ready, postpone the init";
}
//#endif
if (is_editor())
mainframe->select_tab(size_t(0));
mainframe->Thaw();
@ -1123,7 +1170,8 @@ void GUI_App::post_init()
std::string http_url = get_http_url(app_config->get_country_code());
std::string language = GUI::into_u8(current_language_code());
std::string network_ver = Slic3r::NetworkAgent::get_version();
this->preset_updater->sync(http_url, language, network_ver, preset_bundle);
bool sys_preset = app_config->get("sync_system_preset") == "true";
this->preset_updater->sync(http_url, language, network_ver, sys_preset ? preset_bundle : nullptr);
//BBS: check new version
this->check_new_version_sf();
@ -1296,12 +1344,40 @@ std::string GUI_App::get_http_url(std::string country_code)
return url;
}
std::string GUI_App::get_model_http_url(std::string country_code)
{
std::string url;
if (country_code == "US") {
url = "https://makerhub.bambu-lab.com/";
}
else if (country_code == "CN") {
url = "https://makerhub.bambu-lab.com/zh/";
}
else if (country_code == "ENV_CN_DEV") {
url = "https://makerhub-dev.bambu-lab.com/";
}
else if (country_code == "ENV_CN_QA") {
url = "https://makerhub-qa.bambu-lab.com/";
}
else if (country_code == "ENV_CN_PRE") {
url = "https://makerhub-pre.bambu-lab.com/";
}
else {
url = "https://makerhub.bambu-lab.com/";
}
return url;
}
std::string GUI_App::get_plugin_url(std::string name, std::string country_code)
{
std::string url = get_http_url(country_code);
std::string curr_version = SLIC3R_VERSION;
std::string using_version = curr_version.substr(0, 9) + "00";
if (name == "cameratools")
using_version = curr_version.substr(0, 6) + "00.00";
url += (boost::format("?slicer/%1%/cloud=%2%") % name % using_version).str();
//url += (boost::format("?slicer/plugins/cloud=%1%") % "01.01.00.00").str();
return url;
@ -1325,10 +1401,19 @@ static std::string decode(std::string const& extra, std::string const& path = {}
int GUI_App::download_plugin(std::string name, std::string package_name, InstallProgressFn pro_fn, WasCancelledFn cancel_fn)
{
int result = 0;
json j;
std::string err_msg;
// get country_code
AppConfig* app_config = wxGetApp().app_config;
if (!app_config)
if (!app_config) {
j["result"] = "failed";
j["error_msg"] = "app_config is nullptr";
if (m_agent) {
m_agent->track_event("networkplugin_download", j.dump());
}
return -1;
}
BOOST_LOG_TRIVIAL(info) << "[download_plugin]: enter";
m_networking_cancel_update = false;
@ -1388,21 +1473,32 @@ int GUI_App::download_plugin(std::string name, std::string package_name, Install
;
}
}).on_error(
[&result](std::string body, std::string error, unsigned int status) {
[&result, &err_msg](std::string body, std::string error, unsigned int status) {
BOOST_LOG_TRIVIAL(error) << "[download_plugin 1] on_error: " << error<<", body = " << body;
err_msg += "[download_plugin 1] on_error: " + error + ", body = " + body;
result = -1;
}).perform_sync();
bool cancel = false;
if (result < 0) {
j["result"] = "failed";
j["error_msg"] = err_msg;
if (m_agent) {
m_agent->track_event("networkplugin_download", j.dump());
}
if (pro_fn) pro_fn(InstallStatusDownloadFailed, 0, cancel);
return result;
}
if (download_url.empty()) {
BOOST_LOG_TRIVIAL(info) << "[download_plugin 1]: no availaible plugin found for this app version: " << SLIC3R_VERSION;
BOOST_LOG_TRIVIAL(info) << "[download_plugin 1]: no available plugin found for this app version: " << SLIC3R_VERSION;
if (pro_fn) pro_fn(InstallStatusDownloadFailed, 0, cancel);
j["result"] = "failed";
j["error_msg"] = "[download_plugin 1]: no available plugin found for this app version: " + std::string(SLIC3R_VERSION);
if (m_agent) {
m_agent->track_event("networkplugin_download", j.dump());
}
return -1;
}
else if (pro_fn) {
@ -1411,6 +1507,11 @@ int GUI_App::download_plugin(std::string name, std::string package_name, Install
if (m_networking_cancel_update || cancel) {
BOOST_LOG_TRIVIAL(info) << boost::format("[download_plugin 1]: %1%, cancelled by user") % __LINE__;
j["result"] = "failed";
j["error_msg"] = (boost::format("[download_plugin 1]: %1%, cancelled by user") % __LINE__).str();
if (m_agent) {
m_agent->track_event("networkplugin_download", j.dump());
}
return -1;
}
BOOST_LOG_TRIVIAL(info) << "[download_plugin] get_url = " << download_url;
@ -1419,7 +1520,7 @@ int GUI_App::download_plugin(std::string name, std::string package_name, Install
Slic3r::Http http = Slic3r::Http::get(download_url);
int reported_percent = 0;
http.on_progress(
[this, &pro_fn, cancel_fn, &result, &reported_percent](Slic3r::Http::Progress progress, bool& cancel) {
[this, &pro_fn, cancel_fn, &result, &reported_percent, &err_msg](Slic3r::Http::Progress progress, bool& cancel) {
int percent = 0;
if (progress.dltotal != 0)
percent = progress.dlnow * 50 / progress.dltotal;
@ -1434,8 +1535,10 @@ int GUI_App::download_plugin(std::string name, std::string package_name, Install
if (cancel_fn())
cancel = true;
if (cancel)
if (cancel) {
err_msg += "[download_plugin] cancel";
result = -1;
}
})
.on_complete([&pro_fn, tmp_path, target_file_path](std::string body, unsigned status) {
BOOST_LOG_TRIVIAL(info) << "[download_plugin 2] completed";
@ -1447,13 +1550,19 @@ int GUI_App::download_plugin(std::string name, std::string package_name, Install
fs::rename(tmp_path, target_file_path);
if (pro_fn) pro_fn(InstallStatusDownloadCompleted, 80, cancel);
})
.on_error([&pro_fn, &result](std::string body, std::string error, unsigned int status) {
.on_error([&pro_fn, &result, &err_msg](std::string body, std::string error, unsigned int status) {
bool cancel = false;
if (pro_fn) pro_fn(InstallStatusDownloadFailed, 0, cancel);
BOOST_LOG_TRIVIAL(error) << "[download_plugin 2] on_error: " << error<<", body = " << body;
err_msg += "[download_plugin 2] on_error: " + error + ", body = " + body;
result = -1;
});
http.perform_sync();
j["result"] = result < 0 ? "failed" : "success";
j["error_msg"] = err_msg;
if (m_agent) {
m_agent->track_event("networkplugin_download", j.dump());
}
return result;
}
@ -1605,6 +1714,8 @@ void GUI_App::restart_networking()
mainframe->refresh_plugin_tips();
if (plater_)
plater_->get_notification_manager()->bbl_close_plugin_install_notification();
if (app_config->get("sync_user_preset") == "true") { start_sync_user_preset(); }
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(" exit, m_agent=%1%")%m_agent;
}
@ -1730,7 +1841,7 @@ void GUI_App::init_networking_callbacks()
} else if (state == ConnectStatus::ConnectStatusFailed) {
obj->set_access_code("");
obj->set_user_access_code("");
m_device_manager->set_selected_machine("");
m_device_manager->set_selected_machine("", true);
wxString text;
if (msg == "5") {
text = wxString::Format(_L("Incorrect password"));
@ -1741,7 +1852,7 @@ void GUI_App::init_networking_callbacks()
}
event.SetInt(0);
} else if (state == ConnectStatus::ConnectStatusLost) {
m_device_manager->set_selected_machine("");
m_device_manager->set_selected_machine("", true);
event.SetInt(0);
BOOST_LOG_TRIVIAL(info) << "set_on_local_connect_fn: state = lost";
} else {
@ -1932,6 +2043,19 @@ void GUI_App::init_app_config()
m_datadir_redefined = true;
}
// start log here
std::time_t t = std::time(0);
std::tm * now_time = std::localtime(&t);
std::stringstream buf;
buf << std::put_time(now_time, "debug_%a_%b_%d_%H_%M_%S_");
buf << get_current_pid() << ".log";
std::string log_filename = buf.str();
#if !BBL_RELEASE_TO_PUBLIC
set_log_path_and_level(log_filename, 5);
#else
set_log_path_and_level(log_filename, 3);
#endif
//BBS: remove GCodeViewer as seperate APP logic
if (!app_config)
app_config = new AppConfig();
@ -1983,6 +2107,7 @@ std::map<std::string, std::string> GUI_App::get_extra_header()
{
std::map<std::string, std::string> extra_headers;
extra_headers.insert(std::make_pair("X-BBL-Client-Type", "slicer"));
extra_headers.insert(std::make_pair("X-BBL-Client-Name", SLIC3R_APP_NAME));
extra_headers.insert(std::make_pair("X-BBL-Client-Version", VersionInfo::convert_full_version(SLIC3R_VERSION)));
#if defined(__WINDOWS__)
extra_headers.insert(std::make_pair("X-BBL-OS-Type", "windows"));
@ -2055,19 +2180,6 @@ bool GUI_App::OnInit()
bool GUI_App::on_init_inner()
{
//start log here
std::time_t t = std::time(0);
std::tm* now_time = std::localtime(&t);
std::stringstream buf;
buf << std::put_time(now_time, "debug_%a_%b_%d_%H_%M_%S_");
buf << get_current_pid() << ".log";
std::string log_filename = buf.str();
#if !BBL_RELEASE_TO_PUBLIC
set_log_path_and_level(log_filename, 5);
#else
set_log_path_and_level(log_filename, 3);
#endif
// Set initialization of image handlers before any UI actions - See GH issue #7469
wxInitAllImageHandlers();
#ifdef NDEBUG
@ -2426,7 +2538,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);
@ -2493,12 +2605,18 @@ bool GUI_App::on_init_inner()
if (m_studio_active != curr_studio_active) {
if (curr_studio_active) {
BOOST_LOG_TRIVIAL(info) << "studio is active, start to subscribe";
if (m_agent)
if (m_agent) {
json j = json::object();
m_agent->start_subscribe("app");
m_agent->track_event("mqtt_active", j.dump());
}
} else {
BOOST_LOG_TRIVIAL(info) << "studio is inactive, stop to subscribe";
if (m_agent)
if (m_agent) {
json j = json::object();
m_agent->stop_subscribe("app");
m_agent->track_event("mqtt_inactive", j.dump());
}
}
m_studio_active = curr_studio_active;
}
@ -2528,6 +2646,11 @@ bool GUI_App::on_init_inner()
this->mainframe->register_win32_callbacks();
#endif
this->post_init();
if (!m_download_file_url.empty()) {
request_model_download(m_download_file_url);
m_download_file_url = "";
}
}
});
@ -2741,8 +2864,9 @@ void GUI_App::init_label_colours()
m_color_label_default = is_dark_mode ? wxColour(250, 250, 250) : m_color_label_sys; // wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
m_color_highlight_label_default = is_dark_mode ? wxColour(230, 230, 230): wxSystemSettings::GetColour(/*wxSYS_COLOUR_HIGHLIGHTTEXT*/wxSYS_COLOUR_WINDOWTEXT);
m_color_highlight_default = is_dark_mode ? wxColour(78, 78, 78) : wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
m_color_hovered_btn_label = is_dark_mode ? wxColour(253, 111, 40) : wxColour(252, 77, 1);
m_color_selected_btn_bg = is_dark_mode ? wxColour(95, 73, 62) : wxColour(228, 220, 216);
m_color_hovered_btn_label = is_dark_mode ? wxColour(255, 255, 254) : wxColour(0,0,0);
m_color_default_btn_label = is_dark_mode ? wxColour(255, 255, 254): wxColour(0,0,0);
m_color_selected_btn_bg = is_dark_mode ? wxColour(84, 84, 91) : wxColour(206, 206, 206);
#else
m_color_label_default = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
#endif
@ -2771,11 +2895,59 @@ void GUI_App::update_label_colours()
tab->update_label_colours();
}
#ifdef _WIN32
static bool is_focused(HWND hWnd)
{
HWND hFocusedWnd = ::GetFocus();
return hFocusedWnd && hWnd == hFocusedWnd;
}
static bool is_default(wxWindow* win)
{
wxTopLevelWindow* tlw = find_toplevel_parent(win);
if (!tlw)
return false;
return win == tlw->GetDefaultItem();
}
#endif
void GUI_App::UpdateDarkUI(wxWindow* window, bool highlited/* = false*/, bool just_font/* = false*/)
{
if (wxButton *btn = dynamic_cast<wxButton *>(window)) {
if (wxButton *btn = dynamic_cast<wxButton*>(window)) {
if (btn->GetWindowStyleFlag() & wxBU_AUTODRAW)
return;
else {
#ifdef _WIN32
if (btn->GetId() == wxID_OK || btn->GetId() == wxID_CANCEL) {
bool is_focused_button = false;
bool is_default_button = false;
if (!(btn->GetWindowStyle() & wxNO_BORDER)) {
btn->SetWindowStyle(btn->GetWindowStyle() | wxNO_BORDER);
highlited = true;
}
auto mark_button = [this, btn, highlited](const bool mark) {
btn->SetBackgroundColour(mark ? m_color_selected_btn_bg : highlited ? m_color_highlight_default : m_color_window_default);
btn->SetForegroundColour(mark ? m_color_hovered_btn_label :m_color_default_btn_label);
btn->Refresh();
btn->Update();
};
// hovering
btn->Bind(wxEVT_ENTER_WINDOW, [mark_button](wxMouseEvent& event) { mark_button(true); event.Skip(); });
btn->Bind(wxEVT_LEAVE_WINDOW, [mark_button, btn](wxMouseEvent& event) { mark_button(is_focused(btn->GetHWND())); event.Skip(); });
// focusing
btn->Bind(wxEVT_SET_FOCUS, [mark_button](wxFocusEvent& event) { mark_button(true); event.Skip(); });
btn->Bind(wxEVT_KILL_FOCUS, [mark_button](wxFocusEvent& event) { mark_button(false); event.Skip(); });
is_focused_button = is_focused(btn->GetHWND());
is_default_button = is_default(btn);
mark_button(is_focused_button);
}
#endif
}
}
if (Button* btn = dynamic_cast<Button*>(window)) {
@ -3055,7 +3227,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);
@ -3085,6 +3257,21 @@ void GUI_App::recreate_GUI(const wxString& msg_name)
// config_wizard_startup(true);
// });
//show publish button
if (m_agent && m_agent->is_user_login() && mainframe) {
int identifier;
int result = m_agent->get_user_info(&identifier);
auto publish_identifier = identifier & 1;
#ifdef __WINDOWS__
if (result == 0 && publish_identifier >= 0) {
mainframe->m_topbar->show_publish_button(publish_identifier == 0 ? false : true);
}
#else
mainframe->show_publish_button(publish_identifier == 0 ? false : true);
#endif
}
m_is_recreating_gui = false;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "recreate_GUI exit";
@ -3436,22 +3623,6 @@ std::string GUI_App::handle_web_request(std::string cmd)
{
try {
//BBS use nlohmann json format
json j = json::parse(cmd);
std::string web_cmd = j["command"].get<std::string>();
if (web_cmd == "request_model_download") {
std::string download_url = "";
if (j["data"].contains("download_url"))
download_url = j["data"]["download_url"].get<std::string>();
std::string filename = "";
if (j["data"].contains("filename"))
download_url = j["data"]["filename"].get<std::string>();
this->request_model_download(download_url, filename);
}
std::stringstream ss(cmd), oss;
pt::ptree root, response;
pt::read_json(ss, root);
@ -3631,12 +3802,10 @@ void GUI_App::handle_script_message(std::string msg)
}
}
void GUI_App::request_model_download(std::string url, std::string filename)
void GUI_App::request_model_download(std::string url)
{
if (!check_login()) return;
if (plater_) {
plater_->request_model_download();
plater_->request_model_download(url);
}
}
@ -3771,15 +3940,15 @@ void GUI_App::on_user_login_handle(wxCommandEvent &evt)
wxQueueEvent(this, evt);
});
// if (app_config->get("sync_user_preset") == "true") {
enable_user_preset_folder(true);
// } else {
// enable_user_preset_folder(false);
// }
if (online_login)
GUI::wxGetApp().mainframe->show_sync_dialog();
else if (app_config->get("sync_user_preset") == "true") {
enable_user_preset_folder(true);
} else {
enable_user_preset_folder(false);
}
//show publish button
if (m_agent->is_user_login() && mainframe) {
int identifier;
@ -3796,12 +3965,30 @@ void GUI_App::on_user_login_handle(wxCommandEvent &evt)
}
}
void GUI_App::check_track_enable()
{
if (app_config && app_config->get("firstguide", "privacyuse") == "true") {
//enable track event
json header_json;
header_json["ver"] = SLIC3R_VERSION;
wxString os_desc = wxGetOsDescription();
int major = 0, minor = 0, micro = 0;
header_json["os"] = std::string(os_desc.ToUTF8());
header_json["name"] = std::string(SLIC3R_APP_NAME);
if (m_agent) {
m_agent->track_header(header_json.dump());
m_agent->track_enable(true);
}
}
}
void GUI_App::on_user_login(wxCommandEvent &evt)
{
if (!m_agent) { return; }
int online_login = evt.GetInt();
// check privacy before handle
check_privacy_version(online_login);
check_track_enable();
}
bool GUI_App::is_studio_active()
@ -4295,6 +4482,9 @@ void GUI_App::start_sync_user_preset(bool load_immediately, bool with_progress_d
{
if (!m_agent || !m_agent->is_user_login()) return;
if (load_immediately)
remove_user_presets();
enable_user_preset_folder(true);
// has already start sync
@ -4411,6 +4601,9 @@ void GUI_App::stop_sync_user_preset()
remove_user_presets();
enable_user_preset_folder(false);
preset_bundle->load_user_presets(DEFAULT_USER_FOLDER_NAME, ForwardCompatibilitySubstitutionRule::Enable);
mainframe->update_side_preset_ui();
if (!enable_sync)
return;
@ -4519,6 +4712,7 @@ int GUI_App::GetSingleChoiceIndex(const wxString& message,
{
#ifdef _WIN32
wxSingleChoiceDialog dialog(nullptr, message, caption, choices);
dialog.SetBackgroundColour(*wxWHITE);
wxGetApp().UpdateDlgDarkUI(&dialog);
dialog.SetSelection(initialSelection);
@ -4733,7 +4927,8 @@ bool GUI_App::load_language(wxString language, bool initial)
wxLANGUAGE_SWEDISH,
wxLANGUAGE_DUTCH,
wxLANGUAGE_HUNGARIAN,
wxLANGUAGE_JAPANESE
wxLANGUAGE_JAPANESE,
wxLANGUAGE_ITALIAN
};
std::string cur_language = app_config->get("language");
if (cur_language != "") {
@ -4800,6 +4995,11 @@ Tab* GUI_App::get_model_tab(bool part)
return model_tabs_list[part ? 1 : 0];
}
Tab* GUI_App::get_layer_tab()
{
return model_tabs_list[2];
}
ConfigOptionMode GUI_App::get_mode()
{
if (!app_config->has("user_mode"))
@ -5142,6 +5342,8 @@ bool GUI_App::check_and_save_current_preset_changes(const wxString& caption, con
int act_buttons = UnsavedChangesDialog::ActionButtons::SAVE;
if (dont_save_insted_of_discard)
act_buttons |= UnsavedChangesDialog::ActionButtons::DONT_SAVE;
if (remember_choice)
act_buttons |= UnsavedChangesDialog::ActionButtons::REMEMBER_CHOISE;
UnsavedChangesDialog dlg(caption, header, "", act_buttons);
if (dlg.ShowModal() == wxID_CANCEL)
return false;
@ -5390,6 +5592,33 @@ void GUI_App::OSXStoreOpenFiles(const wxArrayString &fileNames)
}*/
wxApp::OSXStoreOpenFiles(fileNames);
}
void GUI_App::MacOpenURL(const wxString& url)
{
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "get mac url " << url;
if (!url.empty() && boost::starts_with(url, "bambustudioopen://")) {
auto input_str_arr = split_str(url.ToStdString(), "bambustudioopen://");
std::string download_origin_url;
for (auto input_str : input_str_arr) {
if (!input_str.empty()) download_origin_url = input_str;
}
std::string download_file_url = url_decode(download_origin_url);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << download_file_url;
if (!download_file_url.empty() && (boost::starts_with(download_file_url, "http://") || boost::starts_with(download_file_url, "https://"))) {
if (m_post_initialized) {
request_model_download(download_file_url);
}
else {
m_download_file_url = download_file_url;
}
}
}
}
// wxWidgets override to get an event on open files.
void GUI_App::MacOpenFiles(const wxArrayString &fileNames)
{
@ -5455,6 +5684,7 @@ void GUI_App::MacOpenFiles(const wxArrayString &fileNames)
start_new_gcodeviewer(&filename);*/
}
}
#endif /* __APPLE */
Sidebar& GUI_App::sidebar()
@ -5472,6 +5702,11 @@ ObjectList* GUI_App::obj_list()
return sidebar().obj_list();
}
ObjectLayers* GUI_App::obj_layers()
{
return sidebar().obj_layers();
}
Plater* GUI_App::plater()
{
return plater_;
@ -5509,45 +5744,85 @@ void GUI_App::load_url(wxString url)
void GUI_App::open_mall_page_dialog()
{
std::string url;
std::string host_url;
std::string model_url;
std::string link_url;
int result = -1;
//model api url
host_url = get_model_http_url(app_config->get_country_code());
//model url
wxString language_code = this->current_language_code().BeforeFirst('_');
model_url = language_code.ToStdString();
if (getAgent() && mainframe) {
getAgent()->get_model_mall_home_url(&url);
if (!m_mall_home_dialog) {
m_mall_home_dialog = new ModelMallDialog();
m_mall_home_dialog->go_to_mall(url);
}
else {
if (m_mall_home_dialog->IsIconized())
m_mall_home_dialog->Iconize(false);
//login already
if (getAgent()->is_user_login()) {
std::string ticket;
result = getAgent()->request_bind_ticket(&ticket);
//m_mall_home_dialog->go_to_mall(url);
if(result == 0){
link_url = host_url + "api/sign-in/ticket?to=" + host_url + url_encode(model_url) + "&ticket=" + ticket;
}
}
m_mall_home_dialog->Raise();
m_mall_home_dialog->Show();
}
if (result < 0) {
link_url = host_url + model_url;
}
wxLaunchDefaultBrowser(link_url);
}
void GUI_App::open_publish_page_dialog()
{
std::string url;
std::string host_url;
std::string model_url;
std::string link_url;
int result = -1;
//model api url
host_url = get_model_http_url(app_config->get_country_code());
//publish url
wxString language_code = this->current_language_code().BeforeFirst('_');
model_url += (language_code.ToStdString() + "/my/models/publish");
if (getAgent() && mainframe) {
getAgent()->get_model_publish_url(&url);
if (!m_mall_publish_dialog) {
m_mall_publish_dialog = new ModelMallDialog();
m_mall_publish_dialog->go_to_mall(url);
}
else {
if (m_mall_publish_dialog->IsIconized())
m_mall_publish_dialog->Iconize(false);
//login already
if (getAgent()->is_user_login()) {
std::string ticket;
result = getAgent()->request_bind_ticket(&ticket);
//m_mall_publish_dialog->go_to_publish(url);
if (result == 0) {
link_url = host_url + "api/sign-in/ticket?to=" + host_url + url_encode(model_url) + "&ticket=" + ticket;
}
}
m_mall_publish_dialog->Raise();
m_mall_publish_dialog->Show();
}
if (result < 0) {
link_url = host_url + model_url;
}
wxLaunchDefaultBrowser(link_url);
}
char GUI_App::from_hex(char ch) {
return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
}
std::string GUI_App::url_decode(std::string value) {
return Http::url_decode(value);
}
std::string GUI_App::url_encode(std::string value) {
return Http::url_encode(value);
}
void GUI_App::remove_mall_system_dialog()
@ -5556,12 +5831,6 @@ void GUI_App::remove_mall_system_dialog()
m_mall_publish_dialog->Destroy();
delete m_mall_publish_dialog;
}
if (m_mall_home_dialog != nullptr) {
m_mall_home_dialog->Destroy();
delete m_mall_home_dialog;
}
}
void GUI_App::run_script(wxString js)