mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-04-06 00:32:05 +02:00
fix crash when opening preference dialog
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -44,4 +44,5 @@ test.js
|
|||||||
/.cache/
|
/.cache/
|
||||||
.clangd
|
.clangd
|
||||||
internal_docs/
|
internal_docs/
|
||||||
*.flatpak
|
*.flatpak
|
||||||
|
/flatpak-repo/
|
||||||
144
scripts/build_flatpak_with_docker.sh
Executable file
144
scripts/build_flatpak_with_docker.sh
Executable file
@@ -0,0 +1,144 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Build OrcaSlicer Flatpak locally using Docker with the same container image
|
||||||
|
# as the CI (build_all.yml).
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./scripts/build_flatpak_with_docker.sh [--arch <x86_64|aarch64>] [--no-debug-info]
|
||||||
|
#
|
||||||
|
# Requirements:
|
||||||
|
# - Docker (or Podman with docker compatibility)
|
||||||
|
#
|
||||||
|
# The resulting .flatpak bundle is placed in the project root.
|
||||||
|
# A persistent Docker volume "flatpak-builder-cache" is used to cache
|
||||||
|
# downloaded sources across builds. Remove it with:
|
||||||
|
# docker volume rm flatpak-builder-cache
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
|
||||||
|
# ---------- defaults ----------
|
||||||
|
ARCH="$(uname -m)"
|
||||||
|
NO_DEBUG_INFO=false
|
||||||
|
NO_PULL=false
|
||||||
|
FORCE_CLEAN=true
|
||||||
|
CONTAINER_IMAGE="ghcr.io/flathub-infra/flatpak-github-actions:gnome-49"
|
||||||
|
|
||||||
|
# ---------- parse args ----------
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--arch)
|
||||||
|
ARCH="$2"; shift 2 ;;
|
||||||
|
--no-debug-info)
|
||||||
|
NO_DEBUG_INFO=true; shift ;;
|
||||||
|
--no-pull)
|
||||||
|
NO_PULL=true; shift ;;
|
||||||
|
--keep-build)
|
||||||
|
FORCE_CLEAN=false; shift ;;
|
||||||
|
--image)
|
||||||
|
CONTAINER_IMAGE="$2"; shift 2 ;;
|
||||||
|
-h|--help)
|
||||||
|
echo "Usage: $0 [--arch <x86_64|aarch64>] [--no-debug-info] [--no-pull] [--keep-build] [--image <image>]"
|
||||||
|
exit 0 ;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# ---------- version & commit ----------
|
||||||
|
cd "$PROJECT_ROOT"
|
||||||
|
|
||||||
|
VER_PURE=$(grep 'set(SoftFever_VERSION' version.inc | cut -d '"' -f2)
|
||||||
|
if [ -z "$VER_PURE" ]; then
|
||||||
|
echo "Error: could not extract version from version.inc" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
VER="V${VER_PURE}"
|
||||||
|
GIT_COMMIT_HASH=$(git rev-parse HEAD)
|
||||||
|
BUNDLE_NAME="OrcaSlicer-Linux-flatpak_${VER}_${ARCH}.flatpak"
|
||||||
|
|
||||||
|
echo "=== OrcaSlicer Flatpak Build ==="
|
||||||
|
echo " Version: ${VER} (${VER_PURE})"
|
||||||
|
echo " Commit: ${GIT_COMMIT_HASH}"
|
||||||
|
echo " Arch: ${ARCH}"
|
||||||
|
echo " Image: ${CONTAINER_IMAGE}"
|
||||||
|
echo " Bundle: ${BUNDLE_NAME}"
|
||||||
|
echo " Debug info: $([ "$NO_DEBUG_INFO" = true ] && echo "disabled" || echo "enabled")"
|
||||||
|
echo " ccache: enabled"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# ---------- prepare manifest ----------
|
||||||
|
MANIFEST_SRC="scripts/flatpak/io.github.orcaslicer.OrcaSlicer.yml"
|
||||||
|
MANIFEST_DOCKER="scripts/flatpak/io.github.orcaslicer.OrcaSlicer.docker.yml"
|
||||||
|
cp "$MANIFEST_SRC" "$MANIFEST_DOCKER"
|
||||||
|
|
||||||
|
# Ensure cleanup on exit (success or failure)
|
||||||
|
trap 'rm -f "$PROJECT_ROOT/$MANIFEST_DOCKER"' EXIT
|
||||||
|
|
||||||
|
# Optionally strip debug info (matches CI behaviour for faster builds)
|
||||||
|
if [ "$NO_DEBUG_INFO" = true ]; then
|
||||||
|
sed -i '/^build-options:/a\ no-debuginfo: true\n strip: true' "$MANIFEST_DOCKER"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Inject git commit hash (same sed as CI)
|
||||||
|
sed -i "/name: OrcaSlicer/{n;s|buildsystem: simple|buildsystem: simple\n build-options:\n env:\n git_commit_hash: \"$GIT_COMMIT_HASH\"|}" "$MANIFEST_DOCKER"
|
||||||
|
|
||||||
|
# ---------- run build in Docker ----------
|
||||||
|
DOCKER="${DOCKER:-docker}"
|
||||||
|
|
||||||
|
if [ "$NO_PULL" = false ]; then
|
||||||
|
echo "=== Pulling container image ==="
|
||||||
|
"$DOCKER" pull "$CONTAINER_IMAGE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
FORCE_CLEAN_FLAG=""
|
||||||
|
if [ "$FORCE_CLEAN" = true ]; then
|
||||||
|
FORCE_CLEAN_FLAG="--force-clean"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Pass build parameters as env vars so the inner script doesn't need
|
||||||
|
# variable expansion from the outer shell (avoids quoting issues).
|
||||||
|
echo "=== Starting Flatpak build inside container ==="
|
||||||
|
"$DOCKER" run --rm --privileged \
|
||||||
|
-v "$PROJECT_ROOT":/src:Z \
|
||||||
|
-v flatpak-builder-cache:/src/.flatpak-builder \
|
||||||
|
-w /src \
|
||||||
|
-e "BUILD_ARCH=$ARCH" \
|
||||||
|
-e "BUNDLE_NAME=$BUNDLE_NAME" \
|
||||||
|
-e "FORCE_CLEAN_FLAG=$FORCE_CLEAN_FLAG" \
|
||||||
|
"$CONTAINER_IMAGE" \
|
||||||
|
bash -c '
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Install required SDK extensions (not pre-installed in the container image)
|
||||||
|
flatpak install -y --noninteractive flathub \
|
||||||
|
org.freedesktop.Sdk.Extension.llvm21//25.08 || true
|
||||||
|
|
||||||
|
flatpak-builder $FORCE_CLEAN_FLAG \
|
||||||
|
--ccache \
|
||||||
|
--disable-rofiles-fuse \
|
||||||
|
--arch="$BUILD_ARCH" \
|
||||||
|
--repo=flatpak-repo \
|
||||||
|
flatpak-build \
|
||||||
|
scripts/flatpak/io.github.orcaslicer.OrcaSlicer.docker.yml
|
||||||
|
|
||||||
|
flatpak build-bundle \
|
||||||
|
--arch="$BUILD_ARCH" \
|
||||||
|
flatpak-repo \
|
||||||
|
"$BUNDLE_NAME" \
|
||||||
|
io.github.orcaslicer.OrcaSlicer
|
||||||
|
|
||||||
|
# Fix ownership so output files are not root-owned on the host
|
||||||
|
chown "$(stat -c %u:%g /src)" "$BUNDLE_NAME" flatpak-build flatpak-repo
|
||||||
|
|
||||||
|
echo "=== Build complete ==="
|
||||||
|
'
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Flatpak bundle ready ==="
|
||||||
|
echo " ${PROJECT_ROOT}/${BUNDLE_NAME}"
|
||||||
|
echo ""
|
||||||
|
echo "Install with:"
|
||||||
|
echo " flatpak install --user ${BUNDLE_NAME}"
|
||||||
1
scripts/flatpak/.gitignore
vendored
1
scripts/flatpak/.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
builddir
|
builddir
|
||||||
.flatpak-builder
|
.flatpak-builder
|
||||||
|
*.docker.yml
|
||||||
|
|||||||
@@ -333,6 +333,11 @@ modules:
|
|||||||
|
|
||||||
- install -Dm644 LICENSE.txt /app/share/licenses/${FLATPAK_ID}/LICENSE.txt
|
- install -Dm644 LICENSE.txt /app/share/licenses/${FLATPAK_ID}/LICENSE.txt
|
||||||
|
|
||||||
|
- | # Install fonts into fontconfig-scanned directory so Pango finds them
|
||||||
|
# before initialization (avoids ensure_faces crash from AddPrivateFont)
|
||||||
|
install -Dm644 -t /app/share/fonts/OrcaSlicer/ resources/fonts/*.ttf
|
||||||
|
fc-cache -f /app/share/fonts/OrcaSlicer/
|
||||||
|
|
||||||
sources:
|
sources:
|
||||||
# OrcaSlicer source tree (specific dirs to avoid copying .git from worktree)
|
# OrcaSlicer source tree (specific dirs to avoid copying .git from worktree)
|
||||||
- type: dir
|
- type: dir
|
||||||
|
|||||||
@@ -6199,7 +6199,7 @@ static const wxLanguageInfo* linux_get_existing_locale_language(const wxLanguage
|
|||||||
if (! it->empty()) {
|
if (! it->empty()) {
|
||||||
const std::string &locale = *it;
|
const std::string &locale = *it;
|
||||||
const wxLanguageInfo* lang = wxLocale::FindLanguageInfo(from_u8(locale));
|
const wxLanguageInfo* lang = wxLocale::FindLanguageInfo(from_u8(locale));
|
||||||
if (wxLocale::IsAvailable(lang->Language))
|
if (lang != nullptr && wxLocale::IsAvailable(lang->Language))
|
||||||
return lang;
|
return lang;
|
||||||
}
|
}
|
||||||
return language;
|
return language;
|
||||||
@@ -6241,7 +6241,10 @@ bool GUI_App::select_language()
|
|||||||
names.Alloc(language_infos.size());
|
names.Alloc(language_infos.size());
|
||||||
|
|
||||||
// Some valid language should be selected since the application start up.
|
// Some valid language should be selected since the application start up.
|
||||||
const wxLanguage current_language = wxLanguage(m_wxLocale->GetLanguage());
|
const wxString active_language_code = current_language_code();
|
||||||
|
const wxLanguageInfo* active_language_info = wxLocale::FindLanguageInfo(active_language_code);
|
||||||
|
const wxLanguage current_language = active_language_info != nullptr ? wxLanguage(active_language_info->Language) : wxLanguage(m_wxLocale->GetLanguage());
|
||||||
|
const wxString active_lang_prefix = active_language_code.BeforeFirst('_');
|
||||||
int init_selection = -1;
|
int init_selection = -1;
|
||||||
int init_selection_alt = -1;
|
int init_selection_alt = -1;
|
||||||
int init_selection_default = -1;
|
int init_selection_default = -1;
|
||||||
@@ -6249,9 +6252,9 @@ bool GUI_App::select_language()
|
|||||||
if (wxLanguage(language_infos[i]->Language) == current_language)
|
if (wxLanguage(language_infos[i]->Language) == current_language)
|
||||||
// The dictionary matches the active language and country.
|
// The dictionary matches the active language and country.
|
||||||
init_selection = i;
|
init_selection = i;
|
||||||
else if ((language_infos[i]->CanonicalName.BeforeFirst('_') == m_wxLocale->GetCanonicalName().BeforeFirst('_')) ||
|
else if ((language_infos[i]->CanonicalName.BeforeFirst('_') == active_lang_prefix) ||
|
||||||
// if the active language is Slovak, mark the Czech language as active.
|
// if the active language is Slovak, mark the Czech language as active.
|
||||||
(language_infos[i]->CanonicalName.BeforeFirst('_') == "cs" && m_wxLocale->GetCanonicalName().BeforeFirst('_') == "sk"))
|
(language_infos[i]->CanonicalName.BeforeFirst('_') == "cs" && active_lang_prefix == "sk"))
|
||||||
// The dictionary matches the active language, it does not necessarily match the country.
|
// The dictionary matches the active language, it does not necessarily match the country.
|
||||||
init_selection_alt = i;
|
init_selection_alt = i;
|
||||||
if (language_infos[i]->CanonicalName.BeforeFirst('_') == "en")
|
if (language_infos[i]->CanonicalName.BeforeFirst('_') == "en")
|
||||||
@@ -6369,7 +6372,10 @@ bool GUI_App::load_language(wxString language, bool initial)
|
|||||||
language_info = wxLocale::GetLanguageInfo(wxLANGUAGE_ENGLISH_US);
|
language_info = wxLocale::GetLanguageInfo(wxLANGUAGE_ENGLISH_US);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(trace) << boost::format("Switching wxLocales to %1%") % language_info->CanonicalName.ToUTF8().data();
|
const wxLanguageInfo *translation_language_info = language_info;
|
||||||
|
const wxString requested_language_code = translation_language_info->CanonicalName;
|
||||||
|
const wxLanguageInfo *locale_language_info = translation_language_info;
|
||||||
|
BOOST_LOG_TRIVIAL(trace) << boost::format("Requested translation language %1%") % requested_language_code.ToUTF8().data();
|
||||||
|
|
||||||
// Select language for locales. This language may be different from the language of the dictionary.
|
// Select language for locales. This language may be different from the language of the dictionary.
|
||||||
//if (language_info == m_language_info_best || language_info == m_language_info_system) {
|
//if (language_info == m_language_info_best || language_info == m_language_info_system) {
|
||||||
@@ -6382,8 +6388,8 @@ bool GUI_App::load_language(wxString language, bool initial)
|
|||||||
// language_info = m_language_info_system;
|
// language_info = m_language_info_system;
|
||||||
|
|
||||||
// Alternate language code.
|
// Alternate language code.
|
||||||
wxLanguage language_dict = wxLanguage(language_info->Language);
|
wxLanguage language_dict = wxLanguage(translation_language_info->Language);
|
||||||
if (language_info->CanonicalName.BeforeFirst('_') == "sk") {
|
if (translation_language_info->CanonicalName.BeforeFirst('_') == "sk") {
|
||||||
// Slovaks understand Czech well. Give them the Czech translation.
|
// Slovaks understand Czech well. Give them the Czech translation.
|
||||||
language_dict = wxLANGUAGE_CZECH;
|
language_dict = wxLANGUAGE_CZECH;
|
||||||
BOOST_LOG_TRIVIAL(info) << "Using Czech dictionaries for Slovak language";
|
BOOST_LOG_TRIVIAL(info) << "Using Czech dictionaries for Slovak language";
|
||||||
@@ -6392,19 +6398,34 @@ bool GUI_App::load_language(wxString language, bool initial)
|
|||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
// If we can't find this locale , try to use different one for the language
|
// If we can't find this locale , try to use different one for the language
|
||||||
// instead of just reporting that it is impossible to switch.
|
// instead of just reporting that it is impossible to switch.
|
||||||
if (! wxLocale::IsAvailable(language_info->Language) && m_language_info_system) {
|
if (!wxLocale::IsAvailable(locale_language_info->Language) && m_language_info_system) {
|
||||||
std::string original_lang = into_u8(language_info->CanonicalName);
|
std::string original_lang = into_u8(locale_language_info->CanonicalName);
|
||||||
language_info = linux_get_existing_locale_language(language_info, m_language_info_system);
|
locale_language_info = linux_get_existing_locale_language(locale_language_info, m_language_info_system);
|
||||||
BOOST_LOG_TRIVIAL(info) << boost::format("Can't switch language to %1% (missing locales). Using %2% instead.")
|
if (locale_language_info != nullptr && locale_language_info != translation_language_info) {
|
||||||
% original_lang % language_info->CanonicalName.ToUTF8().data();
|
BOOST_LOG_TRIVIAL(info) << boost::format("Can't use locale %1% directly (missing locales). Using locale %2% instead.")
|
||||||
|
% original_lang % locale_language_info->CanonicalName.ToUTF8().data();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locale_language_info == nullptr || !wxLocale::IsAvailable(locale_language_info->Language)) {
|
||||||
|
auto try_locale = [](const wxLanguageInfo* candidate) -> const wxLanguageInfo* {
|
||||||
|
return (candidate && wxLocale::IsAvailable(candidate->Language)) ? candidate : nullptr;
|
||||||
|
};
|
||||||
|
const wxLanguageInfo* fallback_locale_info =
|
||||||
|
try_locale(m_wxLocale ? wxLocale::GetLanguageInfo(wxLanguage(m_wxLocale->GetLanguage())) : nullptr);
|
||||||
|
if (!fallback_locale_info) fallback_locale_info = try_locale(m_language_info_system);
|
||||||
|
if (!fallback_locale_info) fallback_locale_info = try_locale(m_language_info_best);
|
||||||
|
if (!fallback_locale_info) fallback_locale_info = try_locale(wxLocale::GetLanguageInfo(wxLANGUAGE_ENGLISH_US));
|
||||||
|
if (!fallback_locale_info) fallback_locale_info = try_locale(wxLocale::GetLanguageInfo(wxLANGUAGE_ENGLISH_UK));
|
||||||
|
if (fallback_locale_info != nullptr) {
|
||||||
|
BOOST_LOG_TRIVIAL(info) << boost::format("Using fallback locale %1% while keeping translation dictionary %2%.")
|
||||||
|
% fallback_locale_info->CanonicalName.ToUTF8().data() % requested_language_code.ToUTF8().data();
|
||||||
|
locale_language_info = fallback_locale_info;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (! wxLocale::IsAvailable(language_info->Language)&&initial) {
|
if (initial) {
|
||||||
language_info = wxLocale::GetLanguageInfo(wxLANGUAGE_ENGLISH_UK);
|
|
||||||
app_config->set("language", language_info->CanonicalName.ToUTF8().data());
|
|
||||||
}
|
|
||||||
else if (initial) {
|
|
||||||
// bbs supported languages
|
// bbs supported languages
|
||||||
//TODO: use a global one with Preference
|
//TODO: use a global one with Preference
|
||||||
//wxLanguage supported_languages[]{
|
//wxLanguage supported_languages[]{
|
||||||
@@ -6438,9 +6459,11 @@ bool GUI_App::load_language(wxString language, bool initial)
|
|||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! wxLocale::IsAvailable(language_info->Language)) {
|
BOOST_LOG_TRIVIAL(trace) << boost::format("Switching wxLocales to %1%") % locale_language_info->CanonicalName.ToUTF8().data();
|
||||||
|
|
||||||
|
if (!wxLocale::IsAvailable(locale_language_info->Language)) {
|
||||||
// Loading the language dictionary failed.
|
// Loading the language dictionary failed.
|
||||||
wxString message = "Switching Orca Slicer to language " + language_info->CanonicalName + " failed.";
|
wxString message = "Switching Orca Slicer to language " + requested_language_code + " failed.";
|
||||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
#if !defined(_WIN32) && !defined(__APPLE__)
|
||||||
// likely some linux system
|
// likely some linux system
|
||||||
message += "\nYou may need to reconfigure the missing locales, likely by running the \"locale-gen\" and \"dpkg-reconfigure locales\" commands.\n";
|
message += "\nYou may need to reconfigure the missing locales, likely by running the \"locale-gen\" and \"dpkg-reconfigure locales\" commands.\n";
|
||||||
@@ -6458,12 +6481,13 @@ bool GUI_App::load_language(wxString language, bool initial)
|
|||||||
//FIXME wxWidgets cause havoc if the current locale is deleted. We just forget it causing memory leaks for now.
|
//FIXME wxWidgets cause havoc if the current locale is deleted. We just forget it causing memory leaks for now.
|
||||||
m_wxLocale.release();
|
m_wxLocale.release();
|
||||||
m_wxLocale = Slic3r::make_unique<wxLocale>();
|
m_wxLocale = Slic3r::make_unique<wxLocale>();
|
||||||
m_wxLocale->Init(language_info->Language);
|
m_wxLocale->Init(locale_language_info->Language);
|
||||||
// Override language at the active wxTranslations class (which is stored in the active m_wxLocale)
|
// Override language at the active wxTranslations class (which is stored in the active m_wxLocale)
|
||||||
// to load possibly different dictionary, for example, load Czech dictionary for Slovak language.
|
// to load possibly different dictionary, for example, load Czech dictionary for Slovak language.
|
||||||
wxTranslations::Get()->SetLanguage(language_dict);
|
wxTranslations::Get()->SetLanguage(language_dict);
|
||||||
m_wxLocale->AddCatalog(SLIC3R_APP_KEY);
|
m_wxLocale->AddCatalog(SLIC3R_APP_KEY);
|
||||||
m_imgui->set_language(into_u8(language_info->CanonicalName));
|
m_active_language_code = requested_language_code;
|
||||||
|
m_imgui->set_language(into_u8(requested_language_code));
|
||||||
|
|
||||||
//FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only.
|
//FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only.
|
||||||
//wxSetlocale(LC_NUMERIC, "C");
|
//wxSetlocale(LC_NUMERIC, "C");
|
||||||
@@ -6751,49 +6775,57 @@ void GUI_App::show_ip_address_enter_dialog_handler(wxCommandEvent& evt)
|
|||||||
|
|
||||||
void GUI_App::open_preferences(size_t open_on_tab, const std::string& highlight_option)
|
void GUI_App::open_preferences(size_t open_on_tab, const std::string& highlight_option)
|
||||||
{
|
{
|
||||||
bool app_layout_changed = false;
|
bool need_recreate_gui = false;
|
||||||
|
std::string pending_language;
|
||||||
{
|
{
|
||||||
// the dialog needs to be destroyed before the call to recreate_GUI()
|
// the dialog needs to be destroyed before the call to recreate_GUI()
|
||||||
// or sometimes the application crashes into wxDialogBase() destructor
|
// or sometimes the application crashes into wxDialogBase() destructor
|
||||||
// so we put it into an inner scope
|
// so we put it into an inner scope
|
||||||
PreferencesDialog dlg(mainframe, open_on_tab, highlight_option);
|
PreferencesDialog dlg(mainframe, open_on_tab, highlight_option);
|
||||||
dlg.ShowModal();
|
dlg.ShowModal();
|
||||||
this->plater_->get_current_canvas3D()->force_set_focus();
|
need_recreate_gui = dlg.recreate_GUI();
|
||||||
// BBS
|
pending_language = dlg.pending_language();
|
||||||
//app_layout_changed = dlg.settings_layout_changed();
|
if (!need_recreate_gui) {
|
||||||
|
this->plater_->get_current_canvas3D()->force_set_focus();
|
||||||
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||||
if (dlg.seq_top_layer_only_changed() || dlg.seq_seq_top_gcode_indices_changed())
|
if (dlg.seq_top_layer_only_changed() || dlg.seq_seq_top_gcode_indices_changed())
|
||||||
#else
|
#else
|
||||||
if (dlg.seq_top_layer_only_changed())
|
if (dlg.seq_top_layer_only_changed())
|
||||||
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||||
this->plater_->reload_print();
|
this->plater_->reload_print();
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (is_editor()) {
|
if (is_editor()) {
|
||||||
if (app_config->get("associate_3mf") == "true")
|
if (app_config->get("associate_3mf") == "true")
|
||||||
associate_files(L"3mf");
|
associate_files(L"3mf");
|
||||||
if (app_config->get("associate_stl") == "true")
|
if (app_config->get("associate_stl") == "true")
|
||||||
associate_files(L"stl");
|
associate_files(L"stl");
|
||||||
if (app_config->get("associate_step") == "true") {
|
if (app_config->get("associate_step") == "true") {
|
||||||
associate_files(L"step");
|
associate_files(L"step");
|
||||||
associate_files(L"stp");
|
associate_files(L"stp");
|
||||||
|
}
|
||||||
|
associate_url(L"orcaslicer");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (app_config->get("associate_gcode") == "true")
|
||||||
|
associate_files(L"gcode");
|
||||||
}
|
}
|
||||||
associate_url(L"orcaslicer");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (app_config->get("associate_gcode") == "true")
|
|
||||||
associate_files(L"gcode");
|
|
||||||
}
|
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BBS
|
if (!pending_language.empty()) {
|
||||||
/*
|
const std::string previous_language = app_config->get("language");
|
||||||
if (app_layout_changed) {
|
app_config->set("language", pending_language);
|
||||||
// hide full main_sizer for mainFrame
|
if (!load_language(wxString::FromUTF8(pending_language), false)) {
|
||||||
mainframe->GetSizer()->Show(false);
|
app_config->set("language", previous_language);
|
||||||
mainframe->update_layout();
|
if (this->plater_)
|
||||||
mainframe->select_tab(size_t(0));
|
this->plater_->get_current_canvas3D()->force_set_focus();
|
||||||
}*/
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (need_recreate_gui)
|
||||||
|
recreate_GUI(_L("Changing application language"));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GUI_App::has_unsaved_preset_changes() const
|
bool GUI_App::has_unsaved_preset_changes() const
|
||||||
|
|||||||
@@ -273,6 +273,7 @@ private:
|
|||||||
const wxLanguageInfo *m_language_info_system = nullptr;
|
const wxLanguageInfo *m_language_info_system = nullptr;
|
||||||
// Best translation language, provided by Windows or OSX, owned by wxWidgets.
|
// Best translation language, provided by Windows or OSX, owned by wxWidgets.
|
||||||
const wxLanguageInfo *m_language_info_best = nullptr;
|
const wxLanguageInfo *m_language_info_best = nullptr;
|
||||||
|
wxString m_active_language_code;
|
||||||
|
|
||||||
OpenGLManager m_opengl_mgr;
|
OpenGLManager m_opengl_mgr;
|
||||||
std::unique_ptr<RemovableDriveManager> m_removable_drive_manager;
|
std::unique_ptr<RemovableDriveManager> m_removable_drive_manager;
|
||||||
@@ -563,7 +564,7 @@ public:
|
|||||||
void preset_deleted_from_cloud(std::string setting_id);
|
void preset_deleted_from_cloud(std::string setting_id);
|
||||||
|
|
||||||
wxString filter_string(wxString str);
|
wxString filter_string(wxString str);
|
||||||
wxString current_language_code() const { return m_wxLocale->GetCanonicalName(); }
|
wxString current_language_code() const { return m_active_language_code.empty() && m_wxLocale ? m_wxLocale->GetCanonicalName() : m_active_language_code; }
|
||||||
// Translate the language code to a code, for which Prusa Research maintains translations. Defaults to "en_US".
|
// Translate the language code to a code, for which Prusa Research maintains translations. Defaults to "en_US".
|
||||||
wxString current_language_code_safe() const;
|
wxString current_language_code_safe() const;
|
||||||
bool is_localized() const { return m_wxLocale->GetLocale() != "English"; }
|
bool is_localized() const { return m_wxLocale->GetLocale() != "English"; }
|
||||||
|
|||||||
@@ -3145,15 +3145,7 @@ void MainFrame::init_menubar_as_editor()
|
|||||||
append_menu_item(
|
append_menu_item(
|
||||||
parent_menu, wxID_ANY, _L("Preferences") + "\t" + ctrl + ",", "",
|
parent_menu, wxID_ANY, _L("Preferences") + "\t" + ctrl + ",", "",
|
||||||
[this](wxCommandEvent &) {
|
[this](wxCommandEvent &) {
|
||||||
PreferencesDialog dlg(this);
|
wxGetApp().open_preferences();
|
||||||
dlg.ShowModal();
|
|
||||||
plater()->get_current_canvas3D()->force_set_focus();
|
|
||||||
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
|
||||||
if (dlg.seq_top_layer_only_changed() || dlg.seq_seq_top_gcode_indices_changed())
|
|
||||||
#else
|
|
||||||
if (dlg.seq_top_layer_only_changed())
|
|
||||||
#endif
|
|
||||||
plater()->reload_print();
|
|
||||||
},
|
},
|
||||||
"", nullptr, []() { return true; }, this, 1);
|
"", nullptr, []() { return true; }, this, 1);
|
||||||
//parent_menu->Insert(1, preference_item);
|
//parent_menu->Insert(1, preference_item);
|
||||||
@@ -3174,7 +3166,6 @@ void MainFrame::init_menubar_as_editor()
|
|||||||
[this](wxCommandEvent &) {
|
[this](wxCommandEvent &) {
|
||||||
// Orca: Use GUI_App::open_preferences instead of direct call so windows associations are updated on exit
|
// Orca: Use GUI_App::open_preferences instead of direct call so windows associations are updated on exit
|
||||||
wxGetApp().open_preferences();
|
wxGetApp().open_preferences();
|
||||||
plater()->get_current_canvas3D()->force_set_focus();
|
|
||||||
},
|
},
|
||||||
"", nullptr, []() { return true; }, this);
|
"", nullptr, []() { return true; }, this);
|
||||||
//m_topbar->AddDropDownMenuItem(preference_item);
|
//m_topbar->AddDropDownMenuItem(preference_item);
|
||||||
|
|||||||
@@ -318,13 +318,10 @@ wxBoxSizer *PreferencesDialog::create_item_language_combobox(wxString title, wxS
|
|||||||
|
|
||||||
m_current_language_selected = combobox->GetSelection();
|
m_current_language_selected = combobox->GetSelection();
|
||||||
if (m_current_language_selected >= 0 && m_current_language_selected < vlist.size()) {
|
if (m_current_language_selected >= 0 && m_current_language_selected < vlist.size()) {
|
||||||
app_config->set(param, vlist[m_current_language_selected]->CanonicalName.ToUTF8().data());
|
m_pending_language = vlist[m_current_language_selected]->CanonicalName.ToUTF8().data();
|
||||||
|
m_recreate_GUI = true;
|
||||||
wxGetApp().load_language(vlist[m_current_language_selected]->CanonicalName, false);
|
EndModal(wxID_OK);
|
||||||
Close();
|
return;
|
||||||
// Reparent(nullptr);
|
|
||||||
GetParent()->RemoveChild(this);
|
|
||||||
wxGetApp().recreate_GUI(_L("Changing application language"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <wx/dialog.h>
|
#include <wx/dialog.h>
|
||||||
#include <wx/timer.h>
|
#include <wx/timer.h>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -43,10 +44,12 @@ protected:
|
|||||||
// bool m_settings_layout_changed {false};
|
// bool m_settings_layout_changed {false};
|
||||||
bool m_seq_top_layer_only_changed{false};
|
bool m_seq_top_layer_only_changed{false};
|
||||||
bool m_recreate_GUI{false};
|
bool m_recreate_GUI{false};
|
||||||
|
std::string m_pending_language;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool seq_top_layer_only_changed() const { return m_seq_top_layer_only_changed; }
|
bool seq_top_layer_only_changed() const { return m_seq_top_layer_only_changed; }
|
||||||
bool recreate_GUI() const { return m_recreate_GUI; }
|
bool recreate_GUI() const { return m_recreate_GUI; }
|
||||||
|
const std::string& pending_language() const { return m_pending_language; }
|
||||||
void on_dpi_changed(const wxRect &suggested_rect) override;
|
void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
#include <wx/dcclient.h>
|
#include <wx/dcclient.h>
|
||||||
#include <wx/settings.h>
|
#include <wx/settings.h>
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <fontconfig/fontconfig.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
wxFont Label::sysFont(int size, bool bold)
|
wxFont Label::sysFont(int size, bool bold)
|
||||||
@@ -58,27 +61,46 @@ wxFont Label::Body_10;
|
|||||||
wxFont Label::Body_9;
|
wxFont Label::Body_9;
|
||||||
wxFont Label::Body_8;
|
wxFont Label::Body_8;
|
||||||
|
|
||||||
|
// Check if a font family is already available via fontconfig.
|
||||||
|
#ifdef __linux__
|
||||||
|
static bool fc_font_available(const char *family_name)
|
||||||
|
{
|
||||||
|
FcPattern *pat = FcPatternCreate();
|
||||||
|
if (!pat)
|
||||||
|
return false;
|
||||||
|
FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *) family_name);
|
||||||
|
FcResult res;
|
||||||
|
FcPattern *match = FcFontMatch(nullptr, pat, &res);
|
||||||
|
bool available = false;
|
||||||
|
if (match) {
|
||||||
|
FcChar8 *matched_family = nullptr;
|
||||||
|
if (FcPatternGetString(match, FC_FAMILY, 0, &matched_family) == FcResultMatch && matched_family)
|
||||||
|
available = (strcasecmp((const char *) matched_family, family_name) == 0);
|
||||||
|
FcPatternDestroy(match);
|
||||||
|
}
|
||||||
|
FcPatternDestroy(pat);
|
||||||
|
return available;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void Label::initSysFont()
|
void Label::initSysFont()
|
||||||
{
|
{
|
||||||
#if defined(__linux__) || defined(_WIN32)
|
#if defined(__linux__) || defined(_WIN32)
|
||||||
const std::string &resource_path = Slic3r::resources_dir();
|
// On Linux, skip AddPrivateFont for fonts already known to fontconfig
|
||||||
wxString font_path = wxString::FromUTF8(resource_path + "/fonts/HarmonyOS_Sans_SC_Bold.ttf");
|
// (e.g. installed system-wide in a Flatpak). Calling AddPrivateFont
|
||||||
bool result = wxFont::AddPrivateFont(font_path);
|
// triggers a Pango crash in ensure_faces() on Pango >= 1.48 (GNOME 49+),
|
||||||
// BOOST_LOG_TRIVIAL(info) << boost::format("add font of HarmonyOS_Sans_SC_Bold returns %1%")%result;
|
// because FcConfigAppFontAddFile invalidates Pango's cached font map.
|
||||||
// printf("add font of HarmonyOS_Sans_SC_Bold returns %d\n", result);
|
bool load_fonts = true;
|
||||||
font_path = wxString::FromUTF8(resource_path + "/fonts/HarmonyOS_Sans_SC_Regular.ttf");
|
#ifdef __linux__
|
||||||
result = wxFont::AddPrivateFont(font_path);
|
load_fonts = !fc_font_available("HarmonyOS Sans SC") || !fc_font_available("NanumGothic");
|
||||||
// BOOST_LOG_TRIVIAL(info) << boost::format("add font of HarmonyOS_Sans_SC_Regular returns %1%")%result;
|
#endif
|
||||||
// printf("add font of HarmonyOS_Sans_SC_Regular returns %d\n", result);
|
if (load_fonts) {
|
||||||
// Adding NanumGothic Regular and Bold
|
const std::string &resource_path = Slic3r::resources_dir();
|
||||||
font_path = wxString::FromUTF8(resource_path + "/fonts/NanumGothic-Regular.ttf");
|
wxFont::AddPrivateFont(wxString::FromUTF8(resource_path + "/fonts/HarmonyOS_Sans_SC_Bold.ttf"));
|
||||||
result = wxFont::AddPrivateFont(font_path);
|
wxFont::AddPrivateFont(wxString::FromUTF8(resource_path + "/fonts/HarmonyOS_Sans_SC_Regular.ttf"));
|
||||||
// BOOST_LOG_TRIVIAL(info) << boost::format("add font of NanumGothic-Regular returns %1%")%result;
|
wxFont::AddPrivateFont(wxString::FromUTF8(resource_path + "/fonts/NanumGothic-Regular.ttf"));
|
||||||
// printf("add font of NanumGothic-Regular returns %d\n", result);
|
wxFont::AddPrivateFont(wxString::FromUTF8(resource_path + "/fonts/NanumGothic-Bold.ttf"));
|
||||||
font_path = wxString::FromUTF8(resource_path + "/fonts/NanumGothic-Bold.ttf");
|
}
|
||||||
result = wxFont::AddPrivateFont(font_path);
|
|
||||||
// BOOST_LOG_TRIVIAL(info) << boost::format("add font of NanumGothic-Bold returns %1%")%result;
|
|
||||||
// printf("add font of NanumGothic-Bold returns %d\n", result);
|
|
||||||
#endif
|
#endif
|
||||||
Head_48 = Label::sysFont(48, true);
|
Head_48 = Label::sysFont(48, true);
|
||||||
Head_32 = Label::sysFont(32, true);
|
Head_32 = Label::sysFont(32, true);
|
||||||
|
|||||||
Reference in New Issue
Block a user