mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-13 02:41:16 +00:00
Translate the web dialogs and pages through the .po catalogs (#16363)
This commit is contained in:
@@ -571,8 +571,6 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/UserNotification.hpp
|
||||
GUI/UVEditorCanvas.cpp
|
||||
GUI/UVEditorCanvas.hpp
|
||||
GUI/WebDownPluginDlg.cpp
|
||||
GUI/WebDownPluginDlg.hpp
|
||||
GUI/WebGuideDialog.cpp
|
||||
GUI/WebGuideDialog.hpp
|
||||
GUI/WebUserLoginDialog.cpp
|
||||
|
||||
@@ -64,6 +64,20 @@ void ExportPresetBundleDialog::Init()
|
||||
wxSize(820, 660), wxSize(640, 640));
|
||||
}
|
||||
|
||||
nlohmann::json ExportPresetBundleDialog::localized_strings() const
|
||||
{
|
||||
return {
|
||||
{"printer", _u8L("Printer")},
|
||||
{"filament", _u8L("Filament")},
|
||||
{"process", _u8L("Process")},
|
||||
{"all", _u8L("All")},
|
||||
{"no_items", _u8L("No items")},
|
||||
{"export_cloud", _u8L("Export to OrcaCloud")},
|
||||
{"export_folder", _u8L("Export to folder")},
|
||||
{"close", _u8L("Close")},
|
||||
};
|
||||
}
|
||||
|
||||
void ExportPresetBundleDialog::on_script_message(const nlohmann::json& j)
|
||||
{
|
||||
if (handle_common_script_command(j))
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
#include "libslic3r/Preset.hpp"
|
||||
#include <slic3r/GUI/GUI.hpp>
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <wx/chartype.h>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
@@ -66,6 +67,7 @@ public:
|
||||
void InitExportData();
|
||||
|
||||
void on_script_message(const nlohmann::json& payload) override;
|
||||
nlohmann::json localized_strings() const override;
|
||||
void OnRequestPresets();
|
||||
void OnExportData(const wxString& path, const wxString& name, nlohmann::json data);
|
||||
|
||||
|
||||
@@ -54,6 +54,20 @@ PluginsConfigDialog::PluginsConfigDialog(wxWindow* parent, Preset::Type type, co
|
||||
|
||||
PluginsConfigDialog::~PluginsConfigDialog() { m_alive->store(false, std::memory_order_release); }
|
||||
|
||||
nlohmann::json PluginsConfigDialog::localized_strings() const
|
||||
{
|
||||
return {
|
||||
{"no_capabilities", _u8L("This preset does not use any plugin capabilities")},
|
||||
{"capabilities_label", _u8L("Capabilities used by this preset")},
|
||||
{"config_json_label", _u8L("Capability configuration (JSON)")},
|
||||
{"config_frame_title", _u8L("Plugin configuration")},
|
||||
{"restore_title", _u8L("Discard this preset's override and use the global configuration again")},
|
||||
{"restore_defaults", _u8L("Restore defaults")},
|
||||
{"save", _u8L("Save")},
|
||||
{"invalid_json", _u8L("Invalid JSON")},
|
||||
};
|
||||
}
|
||||
|
||||
const Preset* PluginsConfigDialog::current_preset() const
|
||||
{
|
||||
const PresetBundle* bundle = wxGetApp().preset_bundle;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <slic3r/GUI/Widgets/WebViewHostDialog.hpp>
|
||||
#include <libslic3r/Preset.hpp>
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <slic3r/plugin/PluginConfig.hpp>
|
||||
|
||||
#include <atomic>
|
||||
@@ -31,6 +32,7 @@ public:
|
||||
|
||||
private:
|
||||
void on_script_message(const nlohmann::json& payload) override;
|
||||
nlohmann::json localized_strings() const override;
|
||||
// Runs one web command on a clean main-loop stack; see on_script_message.
|
||||
void handle_web_command(const nlohmann::json& payload);
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ nlohmann::json build_plugin_payload_item(const PluginDialogItem& dialog_item)
|
||||
for (const PluginCapabilityView& capability : dialog_item.capabilities) {
|
||||
nlohmann::json c;
|
||||
c["name"] = capability.id.name;
|
||||
c["type"] = plugin_capability_type_display_name(capability.id.type);
|
||||
c["type"] = PluginConfig::capability_type_label(capability.id.type);
|
||||
c["type_key"] = plugin_capability_type_to_string(capability.id.type);
|
||||
c["enabled"] = capability.enabled;
|
||||
c["can_toggle"] = capability.can_toggle;
|
||||
@@ -326,7 +326,7 @@ PluginDialogItem build_plugin_dialog_item(const PluginDescriptor& descriptor)
|
||||
item.type_labels.push_back(label);
|
||||
} else {
|
||||
for (const auto& capability : capabilities) {
|
||||
const std::string label = plugin_capability_type_display_name(capability->type());
|
||||
const std::string label = PluginConfig::capability_type_label(capability->type());
|
||||
if (std::find(item.type_labels.begin(), item.type_labels.end(), label) == item.type_labels.end())
|
||||
item.type_labels.push_back(label);
|
||||
}
|
||||
@@ -586,6 +586,97 @@ PluginsDialog::PluginsDialog(wxWindow* parent, wxWindowID id, const wxString&, c
|
||||
: WebViewHostDialog(parent, id, _L("Plugins"), pos, size, style)
|
||||
{ create_webview("web/dialog/PluginsDialog/index.html", _L("Plugins"), wxSize(900, 820), wxSize(760, 715)); }
|
||||
|
||||
nlohmann::json PluginsDialog::localized_strings() const
|
||||
{
|
||||
return {
|
||||
{"search_plugins", _u8L("Search plugins")},
|
||||
{"clear", _u8L("Clear")},
|
||||
{"clear_search", _u8L("Clear search")},
|
||||
{"match_case", _u8L("Match case")},
|
||||
{"match_whole_word", _u8L("Match whole word")},
|
||||
{"refresh", _u8L("Refresh")},
|
||||
{"install_options", _u8L("More plugin install options")},
|
||||
{"install_plugin", _u8L("Install plugin")},
|
||||
{"install_local_plugin", _u8L("Install local plugin")},
|
||||
{"activate", _u8L("Activate")},
|
||||
{"sort_by_name", _u8L("Sort by name")},
|
||||
{"name", _u8L("Name")},
|
||||
{"sort_by_version", _u8L("Sort by version")},
|
||||
{"plugin_version", _u8L("Plugin Version")},
|
||||
{"sort_by_source", _u8L("Sort by source")},
|
||||
{"source", _u8L("Source")},
|
||||
{"sort_by_status", _u8L("Sort by status")},
|
||||
{"status", _u8L_CONTEXT("Status", "Plugin")},
|
||||
{"resize_hint", _u8L("Drag to resize; double-click to reset")},
|
||||
{"resize_list", _u8L("Resize the plugin list")},
|
||||
{"details_label", _u8L("Plugin details")},
|
||||
{"tab_info", _u8L("Plugin Info")},
|
||||
{"description", _u8L("Description")},
|
||||
{"tab_config", _u8L("Config")},
|
||||
{"tab_changelog", _u8L("Changelog")},
|
||||
{"tab_diagnostics", _u8L("Diagnostics")},
|
||||
{"types", _u8L("Types")},
|
||||
{"author", _u8L("Author")},
|
||||
{"installed_version", _u8L("Installed Version")},
|
||||
{"latest_version", _u8L("Latest Version")},
|
||||
{"update_available", _u8L("Update available")},
|
||||
{"update_title", _u8L("Update to the latest version")},
|
||||
{"update", _u8L("Update")},
|
||||
{"no_description", _u8L("No description available")},
|
||||
{"config_select_plugin", _u8L("Select a plugin to configure its capabilities")},
|
||||
{"configurable_capabilities", _u8L("Configurable capabilities")},
|
||||
{"config_json_label", _u8L("Capability configuration (JSON)")},
|
||||
{"config_frame_title", _u8L("Plugin configuration")},
|
||||
{"restore_title", _u8L("Discard the settings saved for this capability and restore the plugin's defaults")},
|
||||
{"restore_defaults", _u8L("Restore defaults")},
|
||||
{"save", _u8L("Save")},
|
||||
{"changelog_label", _u8L("Plugin changelog")},
|
||||
{"version", _u8L("Version")},
|
||||
{"date", _u8L("Date")},
|
||||
{"changes", _u8L("Changes")},
|
||||
{"no_changelog", _u8L("No changelog available")},
|
||||
{"no_issues", _u8L("No issues detected")},
|
||||
{"no_plugins", _u8L("No plugins found")},
|
||||
{"no_match", _u8L("No plugins match \"%s\"")},
|
||||
{"source_mine", _u8L("Mine")},
|
||||
{"source_subscribed", _u8L("Subscribed")},
|
||||
{"source_orphaned", _u8L("Orphaned")},
|
||||
{"source_local", _u8L("Local")},
|
||||
{"mixed_capabilities", _u8L("Some plugin capabilities are enabled")},
|
||||
{"collapse_named", _u8L("Collapse %s capabilities")},
|
||||
{"expand_named", _u8L("Expand %s capabilities")},
|
||||
{"collapse", _u8L("Collapse capabilities")},
|
||||
{"expand", _u8L("Expand capabilities")},
|
||||
{"open_in_browser", _u8L("Open this plugin in your browser")},
|
||||
{"capability_count", _u8L("Capabilities: %s")},
|
||||
{"capabilities", _u8L_CONTEXT("Capabilities", "Plugin")},
|
||||
{"run_named", _u8L("Run \"%s\"")},
|
||||
{"enable_named", _u8L("Enable %s")},
|
||||
{"not_available", _u8L("N/A")},
|
||||
{"unauthorized", _u8L("Unauthorized for updates")},
|
||||
{"not_installed", _u8L("Not installed")},
|
||||
{"config_loading", _u8L("Loading the plugin…")},
|
||||
{"config_no_capabilities", _u8L("This plugin exposes no capabilities")},
|
||||
{"config_activate", _u8L("Activate this plugin to configure its capabilities")},
|
||||
{"invalid_json", _u8L("Invalid JSON")},
|
||||
{"view_on_cloud", _u8L("View on OrcaCloud <a>here</a>")},
|
||||
{"status_activated", _u8L("Activated")},
|
||||
{"status_loading", _u8L("Loading")},
|
||||
{"status_error", _u8L("Error")},
|
||||
{"status_runtime_error", _u8L("Runtime error")},
|
||||
{"status_inactive", _u8L("Inactive")},
|
||||
{"status_activated_desc", _u8L("This plugin is active and ready to be used.")},
|
||||
{"status_loading_desc", _u8L("This plugin is still loading.")},
|
||||
{"status_error_desc", _u8L("This plugin is blocked until its error is fixed.")},
|
||||
{"status_runtime_error_desc", _u8L("This plugin is loaded but a capability reported an error.")},
|
||||
{"status_inactive_desc", _u8L("This plugin is inactive. Activate it to install or load it.")},
|
||||
{"select_plugin", _u8L("Select a plugin to view its status and details.")},
|
||||
{"orphaned_note", _u8L("Orphaned: This plugin is no longer subscribed or available in OrcaCloud. The local copy remains installed and can still be used.")},
|
||||
{"newer_version_note", _u8L("A newer plugin version is available.")},
|
||||
{"unauthorized_note", _u8L("Cloud updates are unavailable because this plugin is unauthorized for updates.")},
|
||||
};
|
||||
}
|
||||
|
||||
PluginsDialog::~PluginsDialog() { m_alive->store(false, std::memory_order_release); }
|
||||
|
||||
void PluginsDialog::set_open_terminal_dlg_fn()
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
@@ -237,6 +238,7 @@ private:
|
||||
void open_plugin_on_cloud(const std::string& sharing_token);
|
||||
void open_plugin_hub();
|
||||
void on_script_message(const nlohmann::json& payload) override;
|
||||
nlohmann::json localized_strings() const override;
|
||||
// Runs one web command on a clean main-loop stack; see on_script_message.
|
||||
void handle_web_command(const nlohmann::json& payload);
|
||||
// Re-raises this dialog after a transient modal it opened (file dialog, message box,
|
||||
|
||||
@@ -208,6 +208,31 @@ void PresetBundleDialog::create()
|
||||
wxSize(820, 660), wxSize(640, 640));
|
||||
}
|
||||
|
||||
nlohmann::json PresetBundleDialog::localized_strings() const
|
||||
{
|
||||
return {
|
||||
{"refresh", _u8L("Refresh")},
|
||||
{"name", _u8L("Name")},
|
||||
{"type", _u8L("Type")},
|
||||
{"version", _u8L("Version")},
|
||||
{"update", _u8L("Update")},
|
||||
{"export_presets", _u8L("Export Presets")},
|
||||
{"close", _u8L("Close")},
|
||||
{"open_folder", _u8L("Open folder in explorer")},
|
||||
{"delete_bundle", _u8L("Delete bundle")},
|
||||
{"unsubscribe_bundle", _u8L("Unsubscribe bundle")},
|
||||
{"update_available", _u8L("Update available")},
|
||||
{"unauthorized_bundle", _u8L("Unauthorized bundle")},
|
||||
{"open_in_browser", _u8L("Open this bundle in your browser")},
|
||||
{"type_subscribed", _u8L("Subscribed")},
|
||||
{"type_local", _u8L("Local")},
|
||||
{"type_default", _u8L("Default")},
|
||||
{"printer", _u8L("Printer")},
|
||||
{"filament", _u8L("Filament")},
|
||||
{"process", _u8L("Process")},
|
||||
};
|
||||
}
|
||||
|
||||
bool PresetBundleDialog::DeleteBundleById(const wxString& id)
|
||||
{
|
||||
auto* b = wxGetApp().preset_bundle;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <atomic>
|
||||
#include <boost/thread/detail/thread.hpp>
|
||||
#include <libslic3r/PresetBundle.hpp>
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <memory>
|
||||
#include <slic3r/GUI/GUI.hpp>
|
||||
#include <string>
|
||||
@@ -63,6 +64,7 @@ public:
|
||||
|
||||
// webview events
|
||||
void on_script_message(const nlohmann::json& payload) override;
|
||||
nlohmann::json localized_strings() const override;
|
||||
|
||||
void StartDialogWorker();
|
||||
void StopDialogWorker();
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
#include <wx/toolbar.h>
|
||||
|
||||
#include <slic3r/GUI/Widgets/WebView.hpp>
|
||||
#include <slic3r/GUI/Widgets/WebViewHostDialog.hpp>
|
||||
#include "I18N.hpp"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <wx/utils.h>
|
||||
#include <wx/webview.h>
|
||||
|
||||
@@ -107,6 +110,17 @@ static void inject_vue_resize_workaround(wxWebView *webView)
|
||||
}
|
||||
#endif
|
||||
|
||||
// The strings of the page shown when the printer has no connection set up
|
||||
// (resources/web/orca/missing_connection.html), keyed by its data-i18n ids.
|
||||
static void add_page_strings(wxWebView *webView)
|
||||
{
|
||||
const nlohmann::json strings = {
|
||||
{"printer_connection", _u8L("Printer Connection")},
|
||||
{"printer_connection_setup", _u8L("Please set up your printer connection to view the device.")},
|
||||
};
|
||||
webView->AddUserScript(wxString::FromUTF8(WebViewHostDialog::localized_strings_script(strings)));
|
||||
}
|
||||
|
||||
PrinterWebView::PrinterWebView(wxWindow *parent)
|
||||
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize)
|
||||
, m_browser(nullptr)
|
||||
@@ -161,6 +175,7 @@ PrinterWebView::~PrinterWebView()
|
||||
void PrinterWebView::create_browser()
|
||||
{
|
||||
m_browser = WebView::CreateWebView(this, "");
|
||||
add_page_strings(m_browser);
|
||||
|
||||
#ifdef __linux__
|
||||
inject_vue_resize_workaround(m_browser);
|
||||
@@ -278,6 +293,7 @@ void PrinterWebView::SendAPIKey()
|
||||
// Re-inject the vue-resize/WebKitGTK workaround that RemoveAllUserScripts just cleared.
|
||||
inject_vue_resize_workaround(m_browser);
|
||||
#endif
|
||||
add_page_strings(m_browser);
|
||||
|
||||
m_browser->AddUserScript(script);
|
||||
m_browser->Reload();
|
||||
|
||||
@@ -51,7 +51,9 @@
|
||||
#include <wx/tglbtn.h>
|
||||
|
||||
#include "GUI_App.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include <slic3r/GUI/Widgets/WebView.hpp>
|
||||
#include <slic3r/GUI/Widgets/WebViewHostDialog.hpp>
|
||||
#include "slic3r/GUI/Jobs/SendJob.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
|
||||
@@ -65,6 +67,29 @@ namespace Slic3r { namespace GUI {
|
||||
|
||||
wxDEFINE_EVENT(EVT_PROJECT_RELOAD, wxCommandEvent);
|
||||
|
||||
// The project page's strings (resources/web/model), keyed by their data-i18n and T() ids.
|
||||
static json project_page_strings()
|
||||
{
|
||||
return {
|
||||
{"no_model_info", _u8L("No model information")},
|
||||
{"edit_project_info", _u8L("Edit Project Info")},
|
||||
{"model_information", _u8L("Model Information")},
|
||||
{"accessories", _u8L("Accessories")},
|
||||
{"profile_information", _u8L("Profile Information")},
|
||||
{"model_name", _u8L("Model name")},
|
||||
{"created_by", _u8L("Created by")},
|
||||
{"remixed_by", _u8L("Remixed by")},
|
||||
{"shared_by", _u8L("Shared by")},
|
||||
{"model_description", _u8L("Model description")},
|
||||
{"bom", _u8L("BOM")},
|
||||
{"assembly_guide", _u8L("Assembly Guide")},
|
||||
{"other", _u8L("Other")},
|
||||
{"profile_name", _u8L("Profile name")},
|
||||
{"profile_author", _u8L("Profile Author")},
|
||||
{"profile_description", _u8L("Profile description")},
|
||||
};
|
||||
}
|
||||
|
||||
const std::vector<std::string> license_list = {
|
||||
"BSD License",
|
||||
"Apache License",
|
||||
@@ -117,10 +142,13 @@ void ProjectPanel::shutdown()
|
||||
|
||||
void ProjectPanel::create_browser()
|
||||
{
|
||||
m_browser = WebView::CreateWebView(this, m_project_home_url);
|
||||
// Created empty and loaded after the strings are added, so the first load already has them.
|
||||
m_browser = WebView::CreateWebView(this, wxEmptyString);
|
||||
m_browser->AddUserScript(wxString::FromUTF8(WebViewHostDialog::localized_strings_script(project_page_strings())));
|
||||
m_browser->Bind(wxEVT_WEBVIEW_NAVIGATED, &ProjectPanel::on_navigated, this);
|
||||
m_browser->Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &ProjectPanel::OnScriptMessage, this, m_browser->GetId());
|
||||
m_browser->Bind(wxEVT_WEBVIEW_NAVIGATING, &ProjectPanel::onWebNavigating, this);
|
||||
WebView::LoadUrl(m_browser, m_project_home_url);
|
||||
}
|
||||
|
||||
void ProjectPanel::reset_browser()
|
||||
|
||||
@@ -84,9 +84,8 @@ void focus_webview(wxWebView* browser, bool page_ready)
|
||||
browser->RunScript("focusInput();");
|
||||
}
|
||||
|
||||
// Localized strings for the Speed Dial page, injected as a document-start user script. The page's
|
||||
// T() reads window.ORCA_UI_STRINGS, so these flow through the same .po pipeline as the rest of the
|
||||
// UI (the JS literals are only a fallback before the script runs / in the node vm test).
|
||||
// Localized strings for the Speed Dial page (see WebViewHostDialog::localized_strings). The page's own T()
|
||||
// reads them; its JS literals are only a fallback before the script runs / in the node vm test.
|
||||
// %% is a literal '%': T() collapses it after substituting %s. Keep the shortcut tokens out of the
|
||||
// translated text so the platform prefix (Alt+/⌥+, Ctrl+/⌘+) stays correct.
|
||||
nlohmann::json speed_dial_ui_strings()
|
||||
@@ -175,17 +174,7 @@ SpeedDialWebDialog::SpeedDialWebDialog(wxWindow* parent)
|
||||
|
||||
SpeedDialWebDialog::~SpeedDialWebDialog() { m_alive->store(false, std::memory_order_release); }
|
||||
|
||||
// Document-start hook: hand the page its translated strings before speeddial.js runs, so the first
|
||||
// paint is already localized. The table is built when the dialog is created; a live language switch
|
||||
// rebuilds the GUI (and with it this dialog), so the next open re-injects the new locale.
|
||||
void SpeedDialWebDialog::add_user_scripts()
|
||||
{
|
||||
if (wxWebView* wv = browser()) {
|
||||
const std::string js = "window.ORCA_UI_STRINGS = " +
|
||||
speed_dial_ui_strings().dump(-1, ' ', false, nlohmann::json::error_handler_t::ignore) + ";";
|
||||
wv->AddUserScript(wxString::FromUTF8(js));
|
||||
}
|
||||
}
|
||||
nlohmann::json SpeedDialWebDialog::localized_strings() const { return speed_dial_ui_strings(); }
|
||||
|
||||
void SpeedDialWebDialog::request_show()
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
void request_show();
|
||||
|
||||
private:
|
||||
void add_user_scripts() override;
|
||||
nlohmann::json localized_strings() const override;
|
||||
void on_script_message(const nlohmann::json& payload) override;
|
||||
void handle_web_command(const nlohmann::json& payload);
|
||||
void resize_to_content(int height);
|
||||
|
||||
@@ -68,6 +68,16 @@ TerminalDialog::TerminalDialog(wxWindow* parent, wxWindowID id, const wxString&
|
||||
wxSize(820, 600), wxSize(640, 480));
|
||||
}
|
||||
|
||||
nlohmann::json TerminalDialog::localized_strings() const
|
||||
{
|
||||
return {
|
||||
{"command_hint", _u8L("python ... or uv ...")},
|
||||
{"run", _u8L("Run")},
|
||||
{"ready", _u8L("Plugin terminal ready.")},
|
||||
{"exit_code", _u8L("Process exited with code: %s")},
|
||||
};
|
||||
}
|
||||
|
||||
TerminalDialog::~TerminalDialog()
|
||||
{
|
||||
if (m_runner && m_runner->is_running())
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Widgets/WebViewHostDialog.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wx/event.h>
|
||||
@@ -32,6 +33,7 @@ public:
|
||||
|
||||
private:
|
||||
void on_script_message(const nlohmann::json& payload) override;
|
||||
nlohmann::json localized_strings() const override;
|
||||
|
||||
void resolve_and_run(const std::string& cmd);
|
||||
|
||||
|
||||
@@ -1,356 +0,0 @@
|
||||
#include "WebDownPluginDlg.hpp"
|
||||
#include "ConfigWizard.hpp"
|
||||
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <exception>
|
||||
#include <string.h>
|
||||
#include "I18N.hpp"
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
#include "slic3r/GUI/wxExtensions.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "libslic3r_version.h"
|
||||
|
||||
#include <wx/log.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/setup.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/toolbar.h>
|
||||
#include <wx/textdlg.h>
|
||||
|
||||
#include <wx/webview.h>
|
||||
#include <wx/utils.h>
|
||||
#include <wx/wx.h>
|
||||
#include <wx/fileconf.h>
|
||||
#include <wx/file.h>
|
||||
#include <wx/wfstream.h>
|
||||
|
||||
#include <boost/cast.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include "MainFrame.hpp"
|
||||
#include <boost/dll.hpp>
|
||||
#include <slic3r/GUI/Widgets/WebView.hpp>
|
||||
#include <slic3r/Utils/Http.hpp>
|
||||
#include <libslic3r/miniz_extension.hpp>
|
||||
#include <libslic3r/Utils.hpp>
|
||||
|
||||
using namespace nlohmann;
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
DownPluginFrame::DownPluginFrame(GUI_App *pGUI) : wxDialog((wxWindow *) (pGUI->mainframe), wxID_ANY, "Orca Slicer"), m_appconfig_new()
|
||||
{
|
||||
// INI
|
||||
m_MainPtr = pGUI;
|
||||
|
||||
// set the frame icon
|
||||
wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
|
||||
wxString TargetUrl = file_url_from_path(boost::filesystem::path(resources_dir()) / "web/guide/6/index.html");
|
||||
|
||||
// Create the webview
|
||||
m_browser = WebView::CreateWebView(this, TargetUrl);
|
||||
if (m_browser == nullptr) {
|
||||
wxLogError("Could not init m_browser");
|
||||
return;
|
||||
}
|
||||
|
||||
SetSizer(topsizer);
|
||||
topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1));
|
||||
|
||||
// Log backend information
|
||||
// wxLogMessage(wxWebView::GetBackendVersionInfo().ToString());
|
||||
// wxLogMessage("Backend: %s Version: %s",
|
||||
// m_browser->GetClassInfo()->GetClassName(),wxWebView::GetBackendVersionInfo().ToString());
|
||||
// wxLogMessage("User Agent: %s", m_browser->GetUserAgent());
|
||||
|
||||
// Set a more sensible size for web browsing
|
||||
wxSize pSize = FromDIP(wxSize(410, 200));
|
||||
SetSize(pSize);
|
||||
|
||||
CenterOnParent();
|
||||
// int screenheight = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y, NULL);
|
||||
// int screenwidth = wxSystemSettings::GetMetric(wxSYS_SCREEN_X, NULL);
|
||||
// int MaxY = (screenheight - pSize.y) > 0 ? (screenheight - pSize.y) / 2 : 0;
|
||||
// MoveWindow(this->m_hWnd, (screenwidth - pSize.x) / 2, MaxY, pSize.x, pSize.y, TRUE);
|
||||
|
||||
// Connect the webview events
|
||||
Bind(wxEVT_WEBVIEW_NAVIGATING, &DownPluginFrame::OnNavigationRequest, this, m_browser->GetId());
|
||||
Bind(wxEVT_WEBVIEW_NAVIGATED, &DownPluginFrame::OnNavigationComplete, this, m_browser->GetId());
|
||||
Bind(wxEVT_WEBVIEW_LOADED, &DownPluginFrame::OnDocumentLoaded, this, m_browser->GetId());
|
||||
Bind(wxEVT_WEBVIEW_ERROR, &DownPluginFrame::OnError, this, m_browser->GetId());
|
||||
Bind(wxEVT_WEBVIEW_NEWWINDOW, &DownPluginFrame::OnNewWindow, this, m_browser->GetId());
|
||||
Bind(wxEVT_WEBVIEW_TITLE_CHANGED, &DownPluginFrame::OnTitleChanged, this, m_browser->GetId());
|
||||
Bind(wxEVT_WEBVIEW_FULLSCREEN_CHANGED, &DownPluginFrame::OnFullScreenChanged, this, m_browser->GetId());
|
||||
Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &DownPluginFrame::OnScriptMessage, this, m_browser->GetId());
|
||||
|
||||
}
|
||||
|
||||
DownPluginFrame::~DownPluginFrame()
|
||||
{
|
||||
if (m_browser) {
|
||||
delete m_browser;
|
||||
m_browser = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void DownPluginFrame::load_url(wxString &url)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(trace) << "app_start: DownPluginFrame url=" << url.ToStdString();
|
||||
this->Show();
|
||||
m_browser->LoadURL(url);
|
||||
m_browser->SetFocus();
|
||||
UpdateState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that retrieves the current state from the web control and updates
|
||||
* the GUI the reflect this current state.
|
||||
*/
|
||||
void DownPluginFrame::UpdateState()
|
||||
{
|
||||
// SetTitle(m_browser->GetCurrentTitle());
|
||||
}
|
||||
|
||||
void DownPluginFrame::OnIdle(wxIdleEvent &WXUNUSED(evt))
|
||||
{
|
||||
if (m_browser->IsBusy()) {
|
||||
wxSetCursor(wxCURSOR_ARROWWAIT);
|
||||
} else {
|
||||
wxSetCursor(wxNullCursor);
|
||||
}
|
||||
}
|
||||
|
||||
// void DownPluginFrame::OnClose(wxCloseEvent& evt)
|
||||
//{
|
||||
// this->Hide();
|
||||
//}
|
||||
|
||||
/**
|
||||
* Callback invoked when there is a request to load a new page (for instance
|
||||
* when the user clicks a link)
|
||||
*/
|
||||
void DownPluginFrame::OnNavigationRequest(wxWebViewEvent &evt)
|
||||
{
|
||||
// wxLogMessage("%s", "Navigation request to '" + evt.GetURL() + "'
|
||||
// (target='" + evt.GetTarget() + "')");
|
||||
|
||||
UpdateState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when a navigation request was accepted
|
||||
*/
|
||||
void DownPluginFrame::OnNavigationComplete(wxWebViewEvent &evt)
|
||||
{
|
||||
// wxLogMessage("%s", "Navigation complete; url='" + evt.GetURL() + "'");
|
||||
|
||||
wxString NewUrl = evt.GetURL();
|
||||
|
||||
UpdateState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when a page is finished loading
|
||||
*/
|
||||
void DownPluginFrame::OnDocumentLoaded(wxWebViewEvent &evt)
|
||||
{
|
||||
// Only notify if the document is the main frame, not a subframe
|
||||
wxString tmpUrl = evt.GetURL();
|
||||
wxString NowUrl = m_browser->GetCurrentURL();
|
||||
|
||||
if (evt.GetURL() == m_browser->GetCurrentURL()) {
|
||||
// wxLogMessage("%s", "Document loaded; url='" + evt.GetURL() + "'");
|
||||
}
|
||||
UpdateState();
|
||||
|
||||
// wxCommandEvent *event = new
|
||||
// wxCommandEvent(EVT_WEB_RESPONSE_MESSAGE,this->GetId()); wxQueueEvent(this,
|
||||
// event);
|
||||
}
|
||||
|
||||
/**
|
||||
* On new window, we veto to stop extra windows appearing
|
||||
*/
|
||||
void DownPluginFrame::OnNewWindow(wxWebViewEvent &evt)
|
||||
{
|
||||
wxString flag = " (other)";
|
||||
|
||||
wxString NewUrl = evt.GetURL();
|
||||
wxLaunchDefaultBrowser(NewUrl);
|
||||
// if (evt.GetNavigationAction() == wxWEBVIEW_NAV_ACTION_USER) { flag = " (user)"; }
|
||||
// wxLogMessage("%s", "New window; url='" + evt.GetURL() + "'" + flag);
|
||||
|
||||
// If we handle new window events then just load them in this window as we
|
||||
// are a single window browser
|
||||
// if (m_tools_handle_new_window->IsChecked())
|
||||
// m_browser->LoadURL(evt.GetURL());
|
||||
|
||||
UpdateState();
|
||||
}
|
||||
|
||||
void DownPluginFrame::OnTitleChanged(wxWebViewEvent &evt)
|
||||
{
|
||||
// SetTitle(evt.GetString());
|
||||
// wxLogMessage("%s", "Title changed; title='" + evt.GetString() + "'");
|
||||
}
|
||||
|
||||
void DownPluginFrame::OnFullScreenChanged(wxWebViewEvent &evt)
|
||||
{
|
||||
// wxLogMessage("Full screen changed; status = %d", evt.GetInt());
|
||||
ShowFullScreen(evt.GetInt() != 0);
|
||||
}
|
||||
|
||||
void DownPluginFrame::OnScriptMessage(wxWebViewEvent &evt)
|
||||
{
|
||||
try {
|
||||
wxString strInput = evt.GetString();
|
||||
json j = json::parse(strInput.utf8_string());
|
||||
|
||||
wxString strCmd = j["command"];
|
||||
|
||||
if (strCmd == "Begin_Download_network_plugin") {
|
||||
wxGetApp().CallAfter([this] { DownloadPlugin(); });
|
||||
}
|
||||
else if (strCmd == "netplugin_download_cancel") {
|
||||
wxGetApp().cancel_networking_install();
|
||||
this->EndModal(wxID_CANCEL);
|
||||
this->Close();
|
||||
}
|
||||
else if (strCmd == "begin_install_plugin") {
|
||||
wxGetApp().CallAfter([this] { InstallPlugin(); });
|
||||
}
|
||||
else if (strCmd == "restart_studio") {
|
||||
wxGetApp().restart_networking();
|
||||
this->EndModal(wxID_OK);
|
||||
this->Close();
|
||||
}
|
||||
else if (strCmd == "close_download_dialog") {
|
||||
this->EndModal(wxID_OK);
|
||||
this->Close();
|
||||
}
|
||||
else if (strCmd == "open_plugin_folder") {
|
||||
auto plugin_folder = (boost::filesystem::path(wxStandardPaths::Get().GetUserDataDir().ToUTF8().data()) / "plugins").make_preferred().string();
|
||||
desktop_open_any_folder(plugin_folder);
|
||||
}
|
||||
} catch (std::exception &) {
|
||||
// wxMessageBox(e.what(), "json Exception", MB_OK);
|
||||
}
|
||||
}
|
||||
|
||||
void DownPluginFrame::RunScript(const wxString &javascript)
|
||||
{
|
||||
// Remember the script we run in any case, so the next time the user opens
|
||||
// the "Run Script" dialog box, it is shown there for convenient updating.
|
||||
// m_javascript = javascript;
|
||||
|
||||
// wxLogMessage("Running JavaScript:\n%s\n", javascript);
|
||||
|
||||
if (!m_browser) return;
|
||||
|
||||
WebView::RunScript(m_browser, javascript);
|
||||
}
|
||||
|
||||
#if wxUSE_WEBVIEW_IE
|
||||
void DownPluginFrame::OnRunScriptObjectWithEmulationLevel(wxCommandEvent &WXUNUSED(evt))
|
||||
{
|
||||
wxWebViewIE::MSWSetModernEmulationLevel();
|
||||
RunScript("function f(){var person = new Object();person.name = 'Foo'; \
|
||||
person.lastName = 'Bar';return person;}f();");
|
||||
wxWebViewIE::MSWSetModernEmulationLevel(false);
|
||||
}
|
||||
|
||||
void DownPluginFrame::OnRunScriptDateWithEmulationLevel(wxCommandEvent &WXUNUSED(evt))
|
||||
{
|
||||
wxWebViewIE::MSWSetModernEmulationLevel();
|
||||
RunScript("function f(){var d = new Date('10/08/2017 21:30:40'); \
|
||||
var tzoffset = d.getTimezoneOffset() * 60000; return \
|
||||
new Date(d.getTime() - tzoffset);}f();");
|
||||
wxWebViewIE::MSWSetModernEmulationLevel(false);
|
||||
}
|
||||
|
||||
void DownPluginFrame::OnRunScriptArrayWithEmulationLevel(wxCommandEvent &WXUNUSED(evt))
|
||||
{
|
||||
wxWebViewIE::MSWSetModernEmulationLevel();
|
||||
RunScript("function f(){ return [\"foo\", \"bar\"]; }f();");
|
||||
wxWebViewIE::MSWSetModernEmulationLevel(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Callback invoked when a loading error occurs
|
||||
*/
|
||||
void DownPluginFrame::OnError(wxWebViewEvent &evt)
|
||||
{
|
||||
#define WX_ERROR_CASE(type) \
|
||||
case type: category = #type; break;
|
||||
|
||||
wxString category;
|
||||
switch (evt.GetInt()) {
|
||||
WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_CONNECTION);
|
||||
WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_CERTIFICATE);
|
||||
WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_AUTH);
|
||||
WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_SECURITY);
|
||||
WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_NOT_FOUND);
|
||||
WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_REQUEST);
|
||||
WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_USER_CANCELLED);
|
||||
WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_OTHER);
|
||||
}
|
||||
|
||||
// wxLogMessage("%s", "Error; url='" + evt.GetURL() + "', error='" +
|
||||
// category + " (" + evt.GetString() + ")'");
|
||||
|
||||
// Show the info bar with an error
|
||||
// m_info->ShowMessage(_L("An error occurred loading ") + evt.GetURL() +
|
||||
// "\n" + "'" + category + "'", wxICON_ERROR);
|
||||
BOOST_LOG_TRIVIAL(info) << "DownPluginFrame::OnError: An error occurred loading " << evt.GetURL() << category;
|
||||
|
||||
UpdateState();
|
||||
}
|
||||
|
||||
void DownPluginFrame::OnScriptResponseMessage(wxCommandEvent &WXUNUSED(evt))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int DownPluginFrame::DownloadPlugin()
|
||||
{
|
||||
return wxGetApp().download_plugin(
|
||||
"plugins", "network_plugin.zip", [this](int status, int percent, bool &cancel) { return ShowPluginStatus(status, percent, cancel); }, nullptr);
|
||||
}
|
||||
|
||||
int DownPluginFrame::InstallPlugin()
|
||||
{
|
||||
return wxGetApp().install_plugin(
|
||||
"plugins", "network_plugin.zip", [this](int status, int percent, bool &cancel) { return ShowPluginStatus(status, percent, cancel); });
|
||||
}
|
||||
|
||||
int DownPluginFrame::ShowPluginStatus(int status, int percent, bool &cancel)
|
||||
{
|
||||
static int nPercent = 0;
|
||||
if (nPercent == percent)
|
||||
return 0;
|
||||
|
||||
nPercent = percent;
|
||||
|
||||
json m_Data = json::object();
|
||||
m_Data["status"] = status;
|
||||
m_Data["percent"] = percent;
|
||||
|
||||
json m_Res = json::object();
|
||||
m_Res["command"] = "ShowStatusPercent";
|
||||
m_Res["sequence_id"] = "10001";
|
||||
m_Res["data"] = m_Data;
|
||||
|
||||
wxString strJS = wxString::Format("HandleStudio(%s)", m_Res.dump(-1, ' ', false, json::error_handler_t::ignore));
|
||||
|
||||
wxGetApp().CallAfter([this, strJS] { RunScript(strJS); });
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
@@ -1,87 +0,0 @@
|
||||
#ifndef slic3r_WebDialytipDialog_hpp_
|
||||
#define slic3r_WebDialytipDialog_hpp_
|
||||
|
||||
#include "wx/artprov.h"
|
||||
#include "wx/cmdline.h"
|
||||
#include "wx/notifmsg.h"
|
||||
#include "wx/settings.h"
|
||||
#include "wx/webview.h"
|
||||
#include <wx/setup.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/event.h>
|
||||
|
||||
#if wxUSE_WEBVIEW_IE
|
||||
#include "wx/msw/webview_ie.h"
|
||||
#endif
|
||||
#if wxUSE_WEBVIEW_EDGE
|
||||
#include "wx/msw/webview_edge.h"
|
||||
#endif
|
||||
|
||||
#include "wx/webviewarchivehandler.h"
|
||||
#include "wx/webviewfshandler.h"
|
||||
#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/frame.h>
|
||||
#include <wx/tbarbase.h>
|
||||
#include "wx/textctrl.h"
|
||||
|
||||
#include "GUI_App.hpp"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
class DownPluginFrame : public wxDialog
|
||||
{
|
||||
public:
|
||||
DownPluginFrame(GUI_App *pGUI);
|
||||
virtual ~DownPluginFrame();
|
||||
|
||||
|
||||
// Web Function
|
||||
void load_url(wxString &url);
|
||||
|
||||
void UpdateState();
|
||||
void OnIdle(wxIdleEvent &evt);
|
||||
// void OnClose(wxCloseEvent &evt);
|
||||
|
||||
void OnNavigationRequest(wxWebViewEvent &evt);
|
||||
void OnNavigationComplete(wxWebViewEvent &evt);
|
||||
void OnDocumentLoaded(wxWebViewEvent &evt);
|
||||
void OnNewWindow(wxWebViewEvent &evt);
|
||||
void OnError(wxWebViewEvent &evt);
|
||||
void OnTitleChanged(wxWebViewEvent &evt);
|
||||
void OnFullScreenChanged(wxWebViewEvent &evt);
|
||||
void OnScriptMessage(wxWebViewEvent &evt);
|
||||
|
||||
void OnScriptResponseMessage(wxCommandEvent &evt);
|
||||
void RunScript(const wxString &javascript);
|
||||
|
||||
// install plugin
|
||||
int DownloadPlugin();
|
||||
int InstallPlugin();
|
||||
int ShowPluginStatus(int status, int percent, bool &cancel);
|
||||
|
||||
private:
|
||||
GUI_App * m_MainPtr;
|
||||
AppConfig m_appconfig_new;
|
||||
|
||||
wxWebView *m_browser;
|
||||
|
||||
#if wxUSE_WEBVIEW_IE
|
||||
wxMenuItem *m_script_object_el;
|
||||
wxMenuItem *m_script_date_el;
|
||||
wxMenuItem *m_script_array_el;
|
||||
#endif
|
||||
// Last executed JavaScript snippet, for convenience.
|
||||
wxString m_javascript;
|
||||
wxString m_response_js;
|
||||
|
||||
// DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
||||
#endif /* slic3r_Tab_hpp_ */
|
||||
@@ -73,6 +73,7 @@
|
||||
#include "Plater.hpp"
|
||||
#include <boost/dll.hpp>
|
||||
#include <slic3r/GUI/Widgets/WebView.hpp>
|
||||
#include <slic3r/GUI/Widgets/WebViewHostDialog.hpp>
|
||||
#include <libslic3r/Utils.hpp>
|
||||
#include "CreatePresetsDialog.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
@@ -85,6 +86,71 @@ using namespace nlohmann;
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
// The strings of every setup wizard page (resources/web/guide), keyed by their data-i18n and T() ids.
|
||||
// The pages share one web view, so they share one table.
|
||||
static json guide_strings()
|
||||
{
|
||||
return {
|
||||
{"loading", _u8L("Loading…")},
|
||||
{"welcome", _u8L("Welcome to Orca Slicer")},
|
||||
{"setup_intro", _u8L("Orca Slicer will be set up in several steps. Let's start!")},
|
||||
{"get_started", _u8L("Get Started")},
|
||||
{"login_region", _u8L("Please select your login region")},
|
||||
{"asia_pacific", _u8L("Asia-Pacific")},
|
||||
{"china", _u8L("China")},
|
||||
{"europe", _u8L("Europe")},
|
||||
{"north_america", _u8L("North America")},
|
||||
{"others", _u8L("Others")},
|
||||
{"back", _u8L_CONTEXT("Back", "Navigation")},
|
||||
{"next", _u8L("Next")},
|
||||
{"finish", _u8L("Finish")},
|
||||
{"confirm", _u8L("Confirm")},
|
||||
{"cancel", _u8L("Cancel")},
|
||||
{"ok", _u8L("OK")},
|
||||
{"yes", _u8L("Yes")},
|
||||
{"no", _u8L("No")},
|
||||
{"error", _u8L("Error")},
|
||||
{"information", _u8L("Information")},
|
||||
{"printer_selection", _u8L("Printer Selection")},
|
||||
{"vendors", _u8L("Vendors")},
|
||||
{"search", _u8L("Search")},
|
||||
{"custom_printer", _u8L("Custom Printer")},
|
||||
{"nozzle", _u8L("Nozzle")},
|
||||
{"create", _u8L("Create")},
|
||||
{"check_new_printers", _u8L("Check for new printers")},
|
||||
{"printer_required", _u8L("At least one printer must be selected.")},
|
||||
{"new_printers_found", _u8L("New printers found")},
|
||||
{"new_vendors_installed", _u8L("New printer vendors installed: %s")},
|
||||
{"vendors_declined", _u8L("New printer vendors were found, but installation was cancelled.")},
|
||||
{"no_new_printers", _u8L("No new printers found.")},
|
||||
{"filament_selection", _u8L("Filament Selection")},
|
||||
{"system_filaments", _u8L("System Filaments")},
|
||||
{"custom_filaments", _u8L("Custom Filaments")},
|
||||
{"create_new", _u8L("Create New")},
|
||||
{"printer", _u8L("Printer")},
|
||||
{"filament_type", _u8L("Filament type")},
|
||||
{"vendor", _u8L("Vendor")},
|
||||
{"all", _u8L("All")},
|
||||
{"no_items", _u8L("No items")},
|
||||
{"filter_items", _u8L("Filter items")},
|
||||
{"checked", _u8L("Checked")},
|
||||
{"unchecked", _u8L("Unchecked")},
|
||||
{"select_filtered", _u8L("Select filtered")},
|
||||
{"select_visible", _u8L("Select visible")},
|
||||
{"clear_all", _u8L("Clear all")},
|
||||
{"filament_required", _u8L("At least one filament must be selected.")},
|
||||
{"use_default_filament", _u8L("Do you want to use the default filament?")},
|
||||
{"stealth_mode", _u8L("Stealth Mode")},
|
||||
{"stealth_mode_desc", _u8L("This disables all cloud features, including Orca Cloud profile syncing. Users who prefer to work entirely offline can enable this option.")},
|
||||
{"stealth_mode_note", _u8L("Note: When Stealth Mode is enabled, your user profiles will not be backed up to Orca Cloud.")},
|
||||
{"enable_stealth_mode", _u8L("Enable Stealth Mode.")},
|
||||
{"proprietary_plugins", _u8L("Proprietary Plugins")},
|
||||
{"proprietary_plugins_desc", _u8L("Some printer vendors require proprietary plugins for communication with their printers. Please select the corresponding plugin if you use such printers.")},
|
||||
{"proprietary_plugins_risk", _u8L("Please be aware that these plugins are not developed or maintained by OrcaSlicer. They should be used at your own discretion and risk.")},
|
||||
{"install_bambu_plugin", _u8L("Install Bambu Network plug-in")},
|
||||
};
|
||||
}
|
||||
|
||||
static wxString update_custom_filaments()
|
||||
{
|
||||
json m_Res = json::object();
|
||||
@@ -157,6 +223,7 @@ GuideFrame::GuideFrame(GUI_App *pGUI, long style)
|
||||
SetBackgroundColour(*wxWHITE);
|
||||
// INI
|
||||
m_SectionName = "firstguide";
|
||||
m_page = BBL_WELCOME;
|
||||
PrivacyUse = false;
|
||||
StealthMode = false;
|
||||
InstallNetplugin = false;
|
||||
@@ -166,15 +233,14 @@ GuideFrame::GuideFrame(GUI_App *pGUI, long style)
|
||||
// set the frame icon
|
||||
wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
wxString TargetUrl = SetStartPage(BBL_WELCOME, false);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", set start page to welcome ");
|
||||
|
||||
// Create the webview
|
||||
m_browser = WebView::CreateWebView(this, TargetUrl);
|
||||
// Created empty and loaded by SetStartPage(BBL_REGION) below, after the strings are added, so the
|
||||
// first load already has them.
|
||||
m_browser = WebView::CreateWebView(this, wxEmptyString);
|
||||
if (m_browser == nullptr) {
|
||||
wxLogError("Could not init m_browser");
|
||||
return;
|
||||
}
|
||||
m_browser->AddUserScript(wxString::FromUTF8(WebViewHostDialog::localized_strings_script(guide_strings())));
|
||||
m_browser->Hide();
|
||||
m_browser->SetSize(0, 0);
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <wx/url.h>
|
||||
|
||||
#include <slic3r/GUI/Widgets/WebView.hpp>
|
||||
#include <slic3r/GUI/Widgets/WebViewHostDialog.hpp>
|
||||
#include <wx/webview.h>
|
||||
#include <wx/utils.h>
|
||||
#include <wx/window.h>
|
||||
@@ -54,6 +55,25 @@ namespace GUI {
|
||||
|
||||
#define LOGIN_INFO_UPDATE_TIMER_ID 10002
|
||||
|
||||
// The home page's strings (resources/web/homepage), keyed by their data-i18n and T() ids.
|
||||
static json home_page_strings()
|
||||
{
|
||||
return {
|
||||
{"login", _u8L("Login")},
|
||||
{"not_signed_in", _u8L("Not signed in")},
|
||||
{"plugin_not_detected", _u8L("Bambu Network plug-in not detected. Click <a>here</a> to install it.")},
|
||||
{"log_out", _u8L("Log Out")},
|
||||
{"recent", _u8L("Recent")},
|
||||
{"new_project", _u8L("New Project")},
|
||||
{"create_new_project", _u8L("Create new project")},
|
||||
{"open_project", _u8L("Open Project")},
|
||||
{"recently_opened", _u8L("Recently opened")},
|
||||
{"clear_all", _u8L("Clear all")},
|
||||
{"remove", _u8L("Remove")},
|
||||
{"open_containing_folder", _u8L("Open Containing Folder")},
|
||||
};
|
||||
}
|
||||
|
||||
BEGIN_EVENT_TABLE(WebViewPanel, wxPanel)
|
||||
EVT_TIMER(LOGIN_INFO_UPDATE_TIMER_ID, WebViewPanel::OnFreshLoginStatus)
|
||||
END_EVENT_TABLE()
|
||||
@@ -263,7 +283,10 @@ WebViewPanel::~WebViewPanel()
|
||||
|
||||
void WebViewPanel::create_browser()
|
||||
{
|
||||
m_browser = WebView::CreateWebView(this, m_home_url);
|
||||
// Created empty and loaded after the strings are added, so the first load already has them.
|
||||
m_browser = WebView::CreateWebView(this, wxEmptyString);
|
||||
m_browser->AddUserScript(wxString::FromUTF8(WebViewHostDialog::localized_strings_script(home_page_strings())));
|
||||
WebView::LoadUrl(m_browser, m_home_url);
|
||||
m_browser->Hide();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <wx/chartype.h>
|
||||
#include <wx/log.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <wx/webview.h>
|
||||
@@ -152,6 +153,11 @@ std::string WebViewHostDialog::document_start_injector(const std::string& markup
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string WebViewHostDialog::localized_strings_script(const nlohmann::json& strings)
|
||||
{
|
||||
return "window.ORCA_UI_STRINGS = " + strings.dump(-1, ' ', false, nlohmann::json::error_handler_t::ignore) + ";";
|
||||
}
|
||||
|
||||
WebViewHostDialog::WebViewHostDialog(wxWindow* parent,
|
||||
wxWindowID id,
|
||||
const wxString& title,
|
||||
@@ -174,7 +180,8 @@ bool WebViewHostDialog::create_webview(const std::string& resource_path,
|
||||
const wxString target_url = build_resource_url(resource_path);
|
||||
wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
m_browser = WebView::CreateWebView(this, target_url);
|
||||
// Created empty and loaded below, after the user scripts are added, so the first load already has them.
|
||||
m_browser = WebView::CreateWebView(this, wxEmptyString);
|
||||
if (m_browser == nullptr) {
|
||||
wxLogError("Could not init m_browser");
|
||||
delete topsizer;
|
||||
@@ -284,6 +291,8 @@ void WebViewHostDialog::register_theme_user_scripts()
|
||||
// some backends RemoveAllUserScripts() drops it too, which would break
|
||||
// window.wx.postMessage / HandleStudio. Live re-theme goes through apply_theme_live().
|
||||
m_browser->AddUserScript(wxString::FromUTF8(theme_user_script()));
|
||||
if (const nlohmann::json strings = localized_strings(); !strings.is_null())
|
||||
m_browser->AddUserScript(wxString::FromUTF8(localized_strings_script(strings)));
|
||||
add_user_scripts();
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,13 @@ public:
|
||||
static std::string element_defaults_user_script();
|
||||
// Re-themes an already-loaded page in place, for web views hosted outside a dialog.
|
||||
static std::string theme_apply_script();
|
||||
// Document-start user script that hands a bundled page its translated strings as
|
||||
// window.ORCA_UI_STRINGS, keyed by the ids its T() lookups and data-i18n attributes use
|
||||
// (resources/web/include/i18n.js). The strings come from _u8L, so they go through the same .po
|
||||
// pipeline as the rest of the UI. They are in place before any page script runs; the page's
|
||||
// static markup shows its English until the page's init calls TranslatePage(). A host builds them
|
||||
// when it creates its web view; a language switch rebuilds the GUI and with it the host.
|
||||
static std::string localized_strings_script(const nlohmann::json& strings);
|
||||
|
||||
protected:
|
||||
wxWebView* browser() const { return m_browser; }
|
||||
@@ -87,6 +94,10 @@ protected:
|
||||
// added, by register_theme_user_scripts(). Default: none.
|
||||
virtual void add_user_scripts() {}
|
||||
|
||||
// The page's translated strings, injected through localized_strings_script() when the
|
||||
// dialog is created. Default: none.
|
||||
virtual nlohmann::json localized_strings() const { return nullptr; }
|
||||
|
||||
// Pushes the current app theme into the already-loaded document without a reload
|
||||
// (updates the injected :root variables and the data-orca-theme attribute).
|
||||
void apply_theme_live();
|
||||
|
||||
@@ -518,6 +518,21 @@ bool capability_save_config(const PluginCapabilityInterface& capability, const n
|
||||
return PluginManager::instance().get_config().store_capability_config(capability_identity(capability, "save_config"), config);
|
||||
}
|
||||
|
||||
std::string PluginConfig::capability_type_label(PluginCapabilityType type)
|
||||
{
|
||||
switch (type) {
|
||||
case PluginCapabilityType::PrinterConnection: return _u8L("Printer connection");
|
||||
case PluginCapabilityType::Pages: return _u8L("Pages");
|
||||
case PluginCapabilityType::Analysis: return _u8L("Analysis");
|
||||
case PluginCapabilityType::Importer: return _u8L("Importer");
|
||||
case PluginCapabilityType::Exporter: return _u8L("Exporter");
|
||||
case PluginCapabilityType::Visualization: return _u8L("Visualization");
|
||||
case PluginCapabilityType::Script: return _u8L("Script");
|
||||
case PluginCapabilityType::SlicingPipeline: return _u8L("Slicing Pipeline");
|
||||
default: return _u8L("Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json PluginConfig::capabilities_payload(const std::vector<PluginCapabilityId>& caps)
|
||||
{
|
||||
nlohmann::json payload = nlohmann::json::array();
|
||||
@@ -530,7 +545,7 @@ nlohmann::json PluginConfig::capabilities_payload(const std::vector<PluginCapabi
|
||||
nlohmann::json entry;
|
||||
entry["plugin_key"] = id.plugin_key;
|
||||
entry["name"] = id.name;
|
||||
entry["type"] = plugin_capability_type_display_name(id.type);
|
||||
entry["type"] = capability_type_label(id.type);
|
||||
entry["type_key"] = plugin_capability_type_to_string(id.type);
|
||||
entry["has_config_ui"] = capability->config_ui_available();
|
||||
payload.push_back(std::move(entry));
|
||||
|
||||
@@ -109,6 +109,9 @@ public:
|
||||
|
||||
bool dirty() const;
|
||||
|
||||
// The capability type as the plugin dialogs show it, translated; plugin_capability_type_display_name()
|
||||
// is the English name the logs use.
|
||||
static std::string capability_type_label(PluginCapabilityType type);
|
||||
static nlohmann::json capabilities_payload(const std::vector<PluginCapabilityId>& caps);
|
||||
static nlohmann::json get_config_response(const PluginCapabilityId& id);
|
||||
static nlohmann::json save_config_response(const PluginCapabilityId& id, const nlohmann::json& config);
|
||||
|
||||
Reference in New Issue
Block a user