mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
Added localization API and helpers
This commit is contained in:
parent
663fa47004
commit
d58967710a
11 changed files with 515 additions and 5 deletions
|
|
@ -17,4 +17,7 @@ public:
|
|||
static std::string ToUpper(const std::string &input);
|
||||
static std::string ToLower(const std::string &input);
|
||||
static std::string ReadFile(const std::filesystem::path &filename);
|
||||
static bool FileExists(const std::string& path) {
|
||||
return std::filesystem::exists(path);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -357,6 +357,8 @@ elseif(WIN32)
|
|||
)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/OUTPUT" CACHE PATH "Directory for sbnw installation" FORCE)
|
||||
|
||||
# set_target_properties(${STORY_EDITOR_PROJECT}
|
||||
|
|
|
|||
55
story-editor/locales/de.json
Normal file
55
story-editor/locales/de.json
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"language.name": "Deutsch",
|
||||
"language.flag": "🇩🇪",
|
||||
|
||||
"menu.language": "Sprache",
|
||||
"menu.file": "Datei",
|
||||
"menu.new": "Neu",
|
||||
"menu.open": "Öffnen",
|
||||
"menu.save": "Speichern",
|
||||
"menu.quit": "Beenden",
|
||||
"menu.edit": "Bearbeiten",
|
||||
"menu.undo": "Rückgängig",
|
||||
"menu.redo": "Wiederholen",
|
||||
"menu.cut": "Ausschneiden",
|
||||
"menu.copy": "Kopieren",
|
||||
"menu.paste": "Einfügen",
|
||||
"menu.view": "Ansicht",
|
||||
"menu.help": "Hilfe",
|
||||
"menu.documentation": "Dokumentation",
|
||||
"menu.about": "Über",
|
||||
|
||||
"window.resources": "Ressourcen",
|
||||
"window.emulator": "Emulator",
|
||||
"window.console": "Konsole",
|
||||
"window.library": "Bibliothek",
|
||||
"window.properties": "Eigenschaften",
|
||||
|
||||
"resources.add_sound": "Sound hinzufügen",
|
||||
"resources.add_image": "Bild hinzufügen",
|
||||
"resources.choose_file": "Datei auswählen",
|
||||
"resources.file": "Datei",
|
||||
"resources.format": "Format",
|
||||
"resources.description": "Beschreibung",
|
||||
"resources.type": "Typ",
|
||||
"resources.actions": "Aktionen",
|
||||
|
||||
"emulator.build_nodes": "Knoten erstellen",
|
||||
"emulator.build_code": "Code erstellen",
|
||||
"emulator.play": "Abspielen",
|
||||
"emulator.stop": "Stoppen",
|
||||
"emulator.vm_state": "VM-Status: {0}",
|
||||
"emulator.load_binary": "Binäre Geschichte laden (.c32)",
|
||||
"emulator.set_source": "Quelldatei festlegen (.chip32)",
|
||||
"emulator.choose_binary": "Binäre Geschichte auswählen",
|
||||
|
||||
"dialog.ok": "OK",
|
||||
"dialog.cancel": "Abbrechen",
|
||||
"dialog.save": "Speichern",
|
||||
"dialog.open": "Öffnen",
|
||||
|
||||
"message.file_saved": "Datei erfolgreich gespeichert",
|
||||
"message.file_loaded": "Datei erfolgreich geladen",
|
||||
"message.error": "Fehler: {0}",
|
||||
"message.build_success": "Erfolgreich erstellt"
|
||||
}
|
||||
55
story-editor/locales/en.json
Normal file
55
story-editor/locales/en.json
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"language.name": "English",
|
||||
"language.flag": "🇬🇧",
|
||||
|
||||
"menu.language": "Language",
|
||||
"menu.file": "File",
|
||||
"menu.new": "New",
|
||||
"menu.open": "Open",
|
||||
"menu.save": "Save",
|
||||
"menu.quit": "Quit",
|
||||
"menu.edit": "Edit",
|
||||
"menu.undo": "Undo",
|
||||
"menu.redo": "Redo",
|
||||
"menu.cut": "Cut",
|
||||
"menu.copy": "Copy",
|
||||
"menu.paste": "Paste",
|
||||
"menu.view": "View",
|
||||
"menu.help": "Help",
|
||||
"menu.documentation": "Documentation",
|
||||
"menu.about": "About",
|
||||
|
||||
"window.resources": "Resources",
|
||||
"window.emulator": "Emulator",
|
||||
"window.console": "Console",
|
||||
"window.library": "Library",
|
||||
"window.properties": "Properties",
|
||||
|
||||
"resources.add_sound": "Add sound",
|
||||
"resources.add_image": "Add image",
|
||||
"resources.choose_file": "Choose File",
|
||||
"resources.file": "File",
|
||||
"resources.format": "Format",
|
||||
"resources.description": "Description",
|
||||
"resources.type": "Type",
|
||||
"resources.actions": "Actions",
|
||||
|
||||
"emulator.build_nodes": "Build nodes",
|
||||
"emulator.build_code": "Build code",
|
||||
"emulator.play": "Play",
|
||||
"emulator.stop": "Stop",
|
||||
"emulator.vm_state": "VM state: {0}",
|
||||
"emulator.load_binary": "Load binary story (.c32)",
|
||||
"emulator.set_source": "Set script source file (.chip32)",
|
||||
"emulator.choose_binary": "Choose a binary story",
|
||||
|
||||
"dialog.ok": "OK",
|
||||
"dialog.cancel": "Cancel",
|
||||
"dialog.save": "Save",
|
||||
"dialog.open": "Open",
|
||||
|
||||
"message.file_saved": "File saved successfully",
|
||||
"message.file_loaded": "File loaded successfully",
|
||||
"message.error": "Error: {0}",
|
||||
"message.build_success": "Build successful"
|
||||
}
|
||||
55
story-editor/locales/es.json
Normal file
55
story-editor/locales/es.json
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"language.name": "Español",
|
||||
"language.flag": "🇪🇸",
|
||||
|
||||
"menu.language": "Idioma",
|
||||
"menu.file": "Archivo",
|
||||
"menu.new": "Nuevo",
|
||||
"menu.open": "Abrir",
|
||||
"menu.save": "Guardar",
|
||||
"menu.quit": "Salir",
|
||||
"menu.edit": "Editar",
|
||||
"menu.undo": "Deshacer",
|
||||
"menu.redo": "Rehacer",
|
||||
"menu.cut": "Cortar",
|
||||
"menu.copy": "Copiar",
|
||||
"menu.paste": "Pegar",
|
||||
"menu.view": "Ver",
|
||||
"menu.help": "Ayuda",
|
||||
"menu.documentation": "Documentación",
|
||||
"menu.about": "Acerca de",
|
||||
|
||||
"window.resources": "Recursos",
|
||||
"window.emulator": "Emulador",
|
||||
"window.console": "Consola",
|
||||
"window.library": "Biblioteca",
|
||||
"window.properties": "Propiedades",
|
||||
|
||||
"resources.add_sound": "Añadir sonido",
|
||||
"resources.add_image": "Añadir imagen",
|
||||
"resources.choose_file": "Elegir archivo",
|
||||
"resources.file": "Archivo",
|
||||
"resources.format": "Formato",
|
||||
"resources.description": "Descripción",
|
||||
"resources.type": "Tipo",
|
||||
"resources.actions": "Acciones",
|
||||
|
||||
"emulator.build_nodes": "Compilar nodos",
|
||||
"emulator.build_code": "Compilar código",
|
||||
"emulator.play": "Reproducir",
|
||||
"emulator.stop": "Detener",
|
||||
"emulator.vm_state": "Estado VM: {0}",
|
||||
"emulator.load_binary": "Cargar historia binaria (.c32)",
|
||||
"emulator.set_source": "Establecer archivo fuente (.chip32)",
|
||||
"emulator.choose_binary": "Elegir una historia binaria",
|
||||
|
||||
"dialog.ok": "OK",
|
||||
"dialog.cancel": "Cancelar",
|
||||
"dialog.save": "Guardar",
|
||||
"dialog.open": "Abrir",
|
||||
|
||||
"message.file_saved": "Archivo guardado correctamente",
|
||||
"message.file_loaded": "Archivo cargado correctamente",
|
||||
"message.error": "Error: {0}",
|
||||
"message.build_success": "Compilación exitosa"
|
||||
}
|
||||
55
story-editor/locales/fr.json
Normal file
55
story-editor/locales/fr.json
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"language.name": "Français",
|
||||
"language.flag": "🇫🇷",
|
||||
|
||||
"menu.language": "Langue",
|
||||
"menu.file": "Fichier",
|
||||
"menu.new": "Nouveau",
|
||||
"menu.open": "Ouvrir",
|
||||
"menu.save": "Enregistrer",
|
||||
"menu.quit": "Quitter",
|
||||
"menu.edit": "Édition",
|
||||
"menu.undo": "Annuler",
|
||||
"menu.redo": "Refaire",
|
||||
"menu.cut": "Couper",
|
||||
"menu.copy": "Copier",
|
||||
"menu.paste": "Coller",
|
||||
"menu.view": "Affichage",
|
||||
"menu.help": "Aide",
|
||||
"menu.documentation": "Documentation",
|
||||
"menu.about": "À propos",
|
||||
|
||||
"window.resources": "Ressources",
|
||||
"window.emulator": "Émulateur",
|
||||
"window.console": "Console",
|
||||
"window.library": "Bibliothèque",
|
||||
"window.properties": "Propriétés",
|
||||
|
||||
"resources.add_sound": "Ajouter un son",
|
||||
"resources.add_image": "Ajouter une image",
|
||||
"resources.choose_file": "Choisir un fichier",
|
||||
"resources.file": "Fichier",
|
||||
"resources.format": "Format",
|
||||
"resources.description": "Description",
|
||||
"resources.type": "Type",
|
||||
"resources.actions": "Actions",
|
||||
|
||||
"emulator.build_nodes": "Compiler les nœuds",
|
||||
"emulator.build_code": "Compiler le code",
|
||||
"emulator.play": "Lire",
|
||||
"emulator.stop": "Arrêter",
|
||||
"emulator.vm_state": "État VM : {0}",
|
||||
"emulator.load_binary": "Charger une histoire binaire (.c32)",
|
||||
"emulator.set_source": "Définir le fichier source (.chip32)",
|
||||
"emulator.choose_binary": "Choisir une histoire binaire",
|
||||
|
||||
"dialog.ok": "OK",
|
||||
"dialog.cancel": "Annuler",
|
||||
"dialog.save": "Enregistrer",
|
||||
"dialog.open": "Ouvrir",
|
||||
|
||||
"message.file_saved": "Fichier enregistré avec succès",
|
||||
"message.file_loaded": "Fichier chargé avec succès",
|
||||
"message.error": "Erreur : {0}",
|
||||
"message.build_success": "Compilation réussie"
|
||||
}
|
||||
74
story-editor/src/LanguageSelector.h
Normal file
74
story-editor/src/LanguageSelector.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#ifndef LANGUAGE_SELECTOR_H
|
||||
#define LANGUAGE_SELECTOR_H
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include "imgui.h"
|
||||
#include "Localization.h"
|
||||
|
||||
class LanguageSelector {
|
||||
public:
|
||||
LanguageSelector() = default;
|
||||
~LanguageSelector() = default;
|
||||
|
||||
// Callback appelé quand la langue change
|
||||
using OnLanguageChangedCallback = std::function<void(const std::string& langCode)>;
|
||||
|
||||
void SetOnLanguageChanged(OnLanguageChangedCallback callback) {
|
||||
m_onLanguageChanged = callback;
|
||||
}
|
||||
|
||||
// Dessiner le menu de sélection de langue
|
||||
void DrawMenu() {
|
||||
// Nom du menu qui se met à jour avec la langue
|
||||
const char* menuLabel = TR("menu.language");
|
||||
|
||||
if (ImGui::BeginMenu(menuLabel)) {
|
||||
DrawLanguageOptions();
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void DrawLanguageOptions() {
|
||||
auto& localization = Localization::Instance();
|
||||
const auto& languages = localization.GetAvailableLanguages();
|
||||
const std::string& currentLang = localization.GetCurrentLang();
|
||||
|
||||
if (languages.empty()) {
|
||||
ImGui::TextDisabled("No languages available");
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& lang : languages) {
|
||||
// Vérifier si c'est la langue actuelle
|
||||
bool isSelected = (lang.code == currentLang);
|
||||
|
||||
// Construire le label avec emoji si disponible
|
||||
std::string label;
|
||||
if (!lang.flagEmoji.empty()) {
|
||||
// FIXME: ImGui ne supporte pas en natif les emojis ; chercher sur le net
|
||||
// label = lang.flagEmoji + " " + lang.displayName;
|
||||
label = lang.displayName;
|
||||
} else {
|
||||
label = lang.displayName;
|
||||
}
|
||||
|
||||
// MenuItem avec état de sélection (affiche une coche)
|
||||
if (ImGui::MenuItem(label.c_str(), nullptr, isSelected)) {
|
||||
if (!isSelected) { // Seulement si ce n'est pas déjà la langue active
|
||||
if (localization.LoadLanguage(lang.code)) {
|
||||
// Notifier le changement
|
||||
if (m_onLanguageChanged) {
|
||||
m_onLanguageChanged(lang.code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OnLanguageChangedCallback m_onLanguageChanged;
|
||||
};
|
||||
|
||||
#endif // LANGUAGE_SELECTOR_H
|
||||
156
story-editor/src/Localization.h
Normal file
156
story-editor/src/Localization.h
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
#ifndef LOCALIZATION_H
|
||||
#define LOCALIZATION_H
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
#include "json.hpp"
|
||||
#include "sys_lib.h"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
struct LanguageInfo {
|
||||
std::string code; // "en", "fr", etc.
|
||||
std::string displayName; // "English", "Français", etc.
|
||||
std::string flagEmoji; // "🇬🇧", "🇫🇷", etc. (optionnel)
|
||||
};
|
||||
|
||||
class Localization {
|
||||
public:
|
||||
static Localization& Instance() {
|
||||
static Localization instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
// Scanner le dossier locales/ pour détecter les langues disponibles
|
||||
void ScanAvailableLanguages() {
|
||||
m_availableLanguages.clear();
|
||||
|
||||
std::string localesPath = "locales";
|
||||
|
||||
if (!std::filesystem::exists(localesPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(localesPath)) {
|
||||
if (entry.is_regular_file() && entry.path().extension() == ".json") {
|
||||
std::string langCode = entry.path().stem().string();
|
||||
|
||||
try {
|
||||
std::string content = SysLib::ReadFile(entry.path().string());
|
||||
json j = json::parse(content);
|
||||
|
||||
LanguageInfo info;
|
||||
info.code = langCode;
|
||||
|
||||
// Lire le nom d'affichage depuis le fichier de langue
|
||||
if (j.contains("language.name")) {
|
||||
info.displayName = j["language.name"].get<std::string>();
|
||||
} else {
|
||||
info.displayName = langCode; // Fallback sur le code
|
||||
}
|
||||
|
||||
// Lire l'emoji de drapeau (optionnel)
|
||||
if (j.contains("language.flag")) {
|
||||
info.flagEmoji = j["language.flag"].get<std::string>();
|
||||
}
|
||||
|
||||
m_availableLanguages.push_back(info);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
// Ignorer les fichiers JSON invalides
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trier par code de langue
|
||||
std::sort(m_availableLanguages.begin(), m_availableLanguages.end(),
|
||||
[](const LanguageInfo& a, const LanguageInfo& b) {
|
||||
return a.code < b.code;
|
||||
});
|
||||
}
|
||||
|
||||
const std::vector<LanguageInfo>& GetAvailableLanguages() const {
|
||||
return m_availableLanguages;
|
||||
}
|
||||
|
||||
// Charger un fichier de langue
|
||||
bool LoadLanguage(const std::string& langCode) {
|
||||
std::string filePath = "locales/" + langCode + ".json";
|
||||
|
||||
if (!SysLib::FileExists(filePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
std::string content = SysLib::ReadFile(filePath);
|
||||
json j = json::parse(content);
|
||||
|
||||
m_translations.clear();
|
||||
for (auto& [key, value] : j.items()) {
|
||||
m_translations[key] = value.get<std::string>();
|
||||
}
|
||||
|
||||
m_currentLang = langCode;
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Obtenir une traduction
|
||||
const char* Get(const std::string& key) const {
|
||||
auto it = m_translations.find(key);
|
||||
if (it != m_translations.end()) {
|
||||
return it->second.c_str();
|
||||
}
|
||||
// Retourne la clé si non trouvée (utile pour le debug)
|
||||
return key.c_str();
|
||||
}
|
||||
|
||||
// Obtenir avec des paramètres de format
|
||||
std::string GetF(const std::string& key, const std::vector<std::string>& args) const {
|
||||
std::string text = Get(key);
|
||||
|
||||
for (size_t i = 0; i < args.size(); ++i) {
|
||||
std::string placeholder = "{" + std::to_string(i) + "}";
|
||||
size_t pos = text.find(placeholder);
|
||||
if (pos != std::string::npos) {
|
||||
text.replace(pos, placeholder.length(), args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
const std::string& GetCurrentLang() const {
|
||||
return m_currentLang;
|
||||
}
|
||||
|
||||
private:
|
||||
Localization() : m_currentLang("en") {
|
||||
// Scanner les langues disponibles au démarrage
|
||||
ScanAvailableLanguages();
|
||||
// Charger la langue par défaut
|
||||
LoadLanguage("en");
|
||||
}
|
||||
|
||||
// Empêcher la copie
|
||||
Localization(const Localization&) = delete;
|
||||
Localization& operator=(const Localization&) = delete;
|
||||
|
||||
std::unordered_map<std::string, std::string> m_translations;
|
||||
std::string m_currentLang;
|
||||
std::vector<LanguageInfo> m_availableLanguages;
|
||||
};
|
||||
|
||||
// Macro pour simplifier l'usage
|
||||
#define TR(key) Localization::Instance().Get(key)
|
||||
#define TRF(key, ...) Localization::Instance().GetF(key, {__VA_ARGS__})
|
||||
|
||||
#endif // LOCALIZATION_H
|
||||
|
|
@ -15,9 +15,9 @@
|
|||
#include "json.hpp"
|
||||
#include "variable.h" // Pour Variable
|
||||
#include "all_events.h"
|
||||
#include "Localization.h"
|
||||
|
||||
// Définitions des registres et événements CHIP-32 si non déjà dans chip32_vm.h
|
||||
// Assurez-vous que ces définitions sont accessibles.
|
||||
#ifndef R0
|
||||
#define R0 0
|
||||
#endif
|
||||
|
|
@ -519,6 +519,7 @@ void AppController::SaveParams()
|
|||
j["recents"] = m_recentProjects;
|
||||
j["library_path"] = m_libraryManager.LibraryPath();
|
||||
j["store_url"] = m_libraryManager.GetStoreUrl();
|
||||
j["language"] = Localization::Instance().GetCurrentLang();
|
||||
|
||||
std::string loc = pf::getConfigHome() + "/ost_settings.json";
|
||||
std::ofstream o(loc);
|
||||
|
|
@ -563,6 +564,11 @@ void AppController::LoadParams()
|
|||
m_logger.Log("No 'store_url' found in settings, using default.", false);
|
||||
}
|
||||
|
||||
if (j.contains("language")) {
|
||||
std::string lang = j["language"].get<std::string>();
|
||||
Localization::Instance().LoadLanguage(lang);
|
||||
}
|
||||
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -106,6 +106,13 @@ MainWindow::MainWindow(ILogger& logger, EventBus& eventBus, AppController& appCo
|
|||
m_toastNotifier.addToast("Module", "Module build failed", ToastType::Error);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
m_languageSelector.SetOnLanguageChanged([this](const std::string& langCode) {
|
||||
// Sauvegarder la préférence
|
||||
m_appController.SaveParams();
|
||||
m_logger.Log("Language changed to: " + langCode);
|
||||
});
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
|
|
@ -123,7 +130,7 @@ float MainWindow::DrawMainMenuBar()
|
|||
|
||||
if (ImGui::BeginMainMenuBar())
|
||||
{
|
||||
if (ImGui::BeginMenu("File"))
|
||||
if (ImGui::BeginMenu(TR("menu.file")))
|
||||
{
|
||||
|
||||
if (ImGui::MenuItem("New story project"))
|
||||
|
|
@ -190,7 +197,7 @@ float MainWindow::DrawMainMenuBar()
|
|||
NewModule();
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("Save module"))
|
||||
if (ImGui::MenuItem("Save module (ctrl+s)"))
|
||||
{
|
||||
SaveModule();
|
||||
}
|
||||
|
|
@ -204,6 +211,16 @@ float MainWindow::DrawMainMenuBar()
|
|||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
// if (ImGui::BeginMenu(TR("menu.view"))) {
|
||||
// ImGui::MenuItem(TR("window.console"), nullptr, &m_showConsole);
|
||||
// ImGui::MenuItem(TR("window.resources"), nullptr, &m_showResources);
|
||||
// ImGui::MenuItem(TR("window.properties"), nullptr, &m_showProperties);
|
||||
// ImGui::EndMenu();
|
||||
// }
|
||||
|
||||
m_languageSelector.DrawMenu();
|
||||
|
||||
|
||||
if (ImGui::BeginMenu("Help"))
|
||||
{
|
||||
if (ImGui::MenuItem("About"))
|
||||
|
|
@ -261,7 +278,7 @@ bool MainWindow::ShowQuitConfirm()
|
|||
// ImGui::SetNextWindowSize(ImVec2(200, 150));
|
||||
if (ImGui::BeginPopupModal("QuitConfirm", NULL, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
ImGui::Text("Really qui without saving?");
|
||||
ImGui::Text("Really quit without saving?");
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::Button("OK", ImVec2(120, 0)))
|
||||
|
|
@ -520,7 +537,11 @@ bool MainWindow::Loop()
|
|||
|
||||
if (m_appController.IsLibraryManagerInitialized())
|
||||
{
|
||||
|
||||
|
||||
bool nodeEditorFocused = m_nodeEditorWindow.IsFocused();
|
||||
bool moduleEditorFocused = m_moduleEditorWindow.IsFocused();
|
||||
|
||||
m_consoleWindow.Draw();
|
||||
m_emulatorDock.Draw();
|
||||
m_debuggerWindow.Draw();
|
||||
|
|
@ -528,7 +549,6 @@ bool MainWindow::Loop()
|
|||
m_nodeEditorWindow.Draw();
|
||||
m_moduleEditorWindow.Draw();
|
||||
|
||||
|
||||
auto currentStory = nodeEditorFocused ? m_nodeEditorWindow.GetCurrentStory() : m_moduleEditorWindow.GetCurrentStory();
|
||||
m_variablesWindow.Draw(currentStory);
|
||||
m_cpuWindow.Draw();
|
||||
|
|
@ -546,6 +566,31 @@ bool MainWindow::Loop()
|
|||
// DockingToolbar("Toolbar2", &toolbar2_axis);
|
||||
|
||||
DrawToolBar(height);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_S, false))
|
||||
{
|
||||
if (moduleEditorFocused && m_module)
|
||||
{
|
||||
// Si l'éditeur de module a le focus, sauvegarder le module
|
||||
m_appController.SaveModule();
|
||||
m_toastNotifier.success("Module sauvegardé");
|
||||
m_logger.Log("Module sauvegardé via Ctrl+S");
|
||||
}
|
||||
else if (m_story)
|
||||
{
|
||||
// Sinon, sauvegarder l'histoire principale
|
||||
m_appController.SaveProject();
|
||||
m_toastNotifier.success("Projet sauvegardé");
|
||||
m_logger.Log("Projet sauvegardé via Ctrl+S");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Aucun projet ouvert
|
||||
m_toastNotifier.warning("Aucun projet ou module à sauvegarder");
|
||||
m_logger.Log("Tentative de sauvegarde sans projet ouvert", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_aboutDialog.Draw();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "variables_window.h"
|
||||
#include "library_window.h"
|
||||
#include "cpu_window.h"
|
||||
|
||||
// Dialogs
|
||||
#include "about_dialog.h"
|
||||
#include "project_properties_dialog.h"
|
||||
|
|
@ -26,6 +27,8 @@
|
|||
#include "i_logger.h"
|
||||
#include "imgui_toast_notifier.h"
|
||||
#include "node_widget_factory.h"
|
||||
#include "Localization.h"
|
||||
#include "LanguageSelector.h"
|
||||
|
||||
class MainWindow : public std::enable_shared_from_this<MainWindow>, public ILogSubject
|
||||
{
|
||||
|
|
@ -67,6 +70,7 @@ private:
|
|||
ProjectPropertiesDialog m_projectPropertiesDialog;
|
||||
|
||||
ImGuiToastNotifier m_toastNotifier;
|
||||
LanguageSelector m_languageSelector;
|
||||
|
||||
// From IStoryManager (proxy to StoryProject class)
|
||||
void OpenProject(const std::string &uuid);
|
||||
|
|
|
|||
Loading…
Reference in a new issue