Fix loading of toolbox text/tooltips of the current language

This commit is contained in:
David Capello 2018-03-28 11:48:59 -03:00
parent 8d9c3c7c11
commit 473542542e
8 changed files with 116 additions and 63 deletions

View File

@ -89,10 +89,21 @@ public:
Preferences m_preferences; Preferences m_preferences;
}; };
class App::LoadLanguage {
public:
LoadLanguage(Preferences& pref,
Extensions& exts) {
Strings::createInstance(pref, exts);
}
};
class App::Modules { class App::Modules {
public: public:
LoggerModule m_loggerModule; LoggerModule m_loggerModule;
FileSystemModule m_file_system_module; FileSystemModule m_file_system_module;
Extensions m_extensions;
// Load main language (after loading the extensions)
LoadLanguage m_loadLanguage;
tools::ToolBox m_toolbox; tools::ToolBox m_toolbox;
tools::ActiveToolManager m_activeToolManager; tools::ActiveToolManager m_activeToolManager;
Commands m_commands; Commands m_commands;
@ -100,12 +111,13 @@ public:
RecentFiles m_recent_files; RecentFiles m_recent_files;
InputChain m_inputChain; InputChain m_inputChain;
clipboard::ClipboardManager m_clipboardManager; clipboard::ClipboardManager m_clipboardManager;
Extensions m_extensions;
// This is a raw pointer because we want to delete this explicitly. // This is a raw pointer because we want to delete this explicitly.
app::crash::DataRecovery* m_recovery; app::crash::DataRecovery* m_recovery;
Modules(bool createLogInDesktop, Preferences& pref) Modules(const bool createLogInDesktop,
Preferences& pref)
: m_loggerModule(createLogInDesktop) : m_loggerModule(createLogInDesktop)
, m_loadLanguage(pref, m_extensions)
, m_activeToolManager(&m_toolbox) , m_activeToolManager(&m_toolbox)
, m_recent_files(pref.general.recentItems()) , m_recent_files(pref.general.recentItems())
, m_recovery(nullptr) { , m_recovery(nullptr) {
@ -175,6 +187,7 @@ void App::initialize(const AppOptions& options)
break; break;
} }
// Load modules
m_modules = new Modules(createLogInDesktop, preferences()); m_modules = new Modules(createLogInDesktop, preferences());
m_legacy = new LegacyModules(isGui() ? REQUIRE_INTERFACE: 0); m_legacy = new LegacyModules(isGui() ? REQUIRE_INTERFACE: 0);
m_brushes.reset(new AppBrushes); m_brushes.reset(new AppBrushes);
@ -194,9 +207,6 @@ void App::initialize(const AppOptions& options)
if (isGui()) { if (isGui()) {
LOG("APP: GUI mode\n"); LOG("APP: GUI mode\n");
// Load main language (which might be in an extension)
Strings::instance()->loadCurrentLanguage();
// Setup the GUI cursor and redraw screen // Setup the GUI cursor and redraw screen
ui::set_use_native_cursors(preferences().cursor.useNativeCursor()); ui::set_use_native_cursors(preferences().cursor.useNativeCursor());
ui::set_mouse_cursor_scale(preferences().cursor.cursorScale()); ui::set_mouse_cursor_scale(preferences().cursor.cursorScale());

View File

@ -104,6 +104,7 @@ namespace app {
private: private:
class CoreModules; class CoreModules;
class LoadLanguage;
class Modules; class Modules;
static App* m_instance; static App* m_instance;

View File

@ -14,7 +14,6 @@
#include "app/extensions.h" #include "app/extensions.h"
#include "app/pref/preferences.h" #include "app/pref/preferences.h"
#include "app/resource_finder.h" #include "app/resource_finder.h"
#include "app/ui/main_window.h"
#include "app/xml_document.h" #include "app/xml_document.h"
#include "app/xml_exception.h" #include "app/xml_exception.h"
#include "base/fs.h" #include "base/fs.h"
@ -22,20 +21,29 @@
namespace app { namespace app {
static Strings* singleton = nullptr;
static const char* kDefLanguage = "en"; static const char* kDefLanguage = "en";
// static
void Strings::createInstance(Preferences& pref,
Extensions& exts)
{
ASSERT(!singleton);
singleton = new Strings(pref, exts);
}
// static // static
Strings* Strings::instance() Strings* Strings::instance()
{ {
static Strings* singleton = nullptr;
if (!singleton)
singleton = new Strings();
return singleton; return singleton;
} }
Strings::Strings() Strings::Strings(Preferences& pref,
Extensions& exts)
: m_pref(pref)
, m_exts(exts)
{ {
loadLanguage(kDefLanguage); loadLanguage(currentLanguage());
} }
std::set<std::string> Strings::availableLanguages() const std::set<std::string> Strings::availableLanguages() const
@ -56,7 +64,7 @@ std::set<std::string> Strings::availableLanguages() const
} }
// Add languages in extensions // Add languages in extensions
for (const auto& ext : App::instance()->extensions()) { for (const auto& ext : m_exts) {
if (ext->isEnabled() && if (ext->isEnabled() &&
ext->hasLanguages()) { ext->hasLanguages()) {
for (const auto& langId : ext->languages()) for (const auto& langId : ext->languages())
@ -70,7 +78,7 @@ std::set<std::string> Strings::availableLanguages() const
std::string Strings::currentLanguage() const std::string Strings::currentLanguage() const
{ {
return Preferences::instance().general.language(); return m_pref.general.language();
} }
void Strings::setCurrentLanguage(const std::string& langId) void Strings::setCurrentLanguage(const std::string& langId)
@ -79,19 +87,10 @@ void Strings::setCurrentLanguage(const std::string& langId)
if (currentLanguage() == langId) if (currentLanguage() == langId)
return; return;
Preferences::instance().general.language(langId); m_pref.general.language(langId);
loadLanguage(langId); loadLanguage(langId);
// Reload menus LanguageChange();
App::instance()->mainWindow()->reloadMenus();
}
// Called when extensions are available
void Strings::loadCurrentLanguage()
{
std::string langId = currentLanguage();
if (langId != kDefLanguage)
loadLanguage(langId);
} }
void Strings::loadLanguage(const std::string& langId) void Strings::loadLanguage(const std::string& langId)
@ -120,8 +119,7 @@ void Strings::loadStringsFromDataDir(const std::string& langId)
void Strings::loadStringsFromExtension(const std::string& langId) void Strings::loadStringsFromExtension(const std::string& langId)
{ {
Extensions& exts = App::instance()->extensions(); std::string fn = m_exts.languagePath(langId);
std::string fn = exts.languagePath(langId);
if (!fn.empty() && base::is_file(fn)) if (!fn.empty() && base::is_file(fn))
loadStringsFromFile(fn); loadStringsFromFile(fn);
} }

View File

@ -12,30 +12,41 @@
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include "obs/signal.h"
#include "strings.ini.h" #include "strings.ini.h"
namespace app { namespace app {
class Preferences;
class Extensions;
// Singleton class to load and access "strings/en.ini" file. // Singleton class to load and access "strings/en.ini" file.
class Strings : public app::gen::Strings<app::Strings> { class Strings : public app::gen::Strings<app::Strings> {
public: public:
static void createInstance(Preferences& pref,
Extensions& exts);
static Strings* instance(); static Strings* instance();
const std::string& translate(const char* id) const; const std::string& translate(const char* id) const;
void loadCurrentLanguage();
std::set<std::string> availableLanguages() const; std::set<std::string> availableLanguages() const;
std::string currentLanguage() const; std::string currentLanguage() const;
void setCurrentLanguage(const std::string& langId); void setCurrentLanguage(const std::string& langId);
obs::signal<void()> LanguageChange;
private: private:
Strings(); Strings(Preferences& pref,
Extensions& exts);
void loadLanguage(const std::string& langId); void loadLanguage(const std::string& langId);
void loadStringsFromDataDir(const std::string& langId); void loadStringsFromDataDir(const std::string& langId);
void loadStringsFromExtension(const std::string& langId); void loadStringsFromExtension(const std::string& langId);
void loadStringsFromFile(const std::string& fn); void loadStringsFromFile(const std::string& fn);
Preferences& m_pref;
Extensions& m_exts;
mutable std::unordered_map<std::string, std::string> m_strings; mutable std::unordered_map<std::string, std::string> m_strings;
}; };

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2015 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
@ -26,16 +26,10 @@ namespace app {
class Tool { class Tool {
public: public:
Tool(ToolGroup* group, Tool(ToolGroup* group, const std::string& id)
const std::string& id,
const std::string& text,
const std::string& tips,
int default_brush_size)
: m_group(group) : m_group(group)
, m_id(id) , m_id(id)
, m_text(text) , m_default_brush_size(1)
, m_tips(tips)
, m_default_brush_size(default_brush_size)
{ } { }
virtual ~Tool() virtual ~Tool()
@ -47,6 +41,12 @@ namespace app {
const std::string& getTips() const { return m_tips; } const std::string& getTips() const { return m_tips; }
int getDefaultBrushSize() const { return m_default_brush_size; } int getDefaultBrushSize() const { return m_default_brush_size; }
void setText(const std::string& text) { m_text = text; }
void setTips(const std::string& tips) { m_tips = tips; }
void setDefaultBrushSize(const int default_brush_size) {
m_default_brush_size = default_brush_size;
}
Fill getFill(int button) { return m_button[button].m_fill; } Fill getFill(int button) { return m_button[button].m_fill; }
Ink* getInk(int button) { return m_button[button].m_ink; } Ink* getInk(int button) { return m_button[button].m_ink; }
Controller* getController(int button) { return m_button[button].m_controller; } Controller* getController(int button) { return m_button[button].m_controller; }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
@ -31,6 +31,7 @@
#include "fixmath/fixmath.h" #include "fixmath/fixmath.h"
#include <algorithm> #include <algorithm>
#include <cstdlib>
#include "app/tools/controllers.h" #include "app/tools/controllers.h"
#include "app/tools/inks.h" #include "app/tools/inks.h"
@ -91,6 +92,18 @@ const char* WellKnownPointShapes::Brush = "brush";
const char* WellKnownPointShapes::FloodFill = "floodfill"; const char* WellKnownPointShapes::FloodFill = "floodfill";
const char* WellKnownPointShapes::Spray = "spray"; const char* WellKnownPointShapes::Spray = "spray";
namespace {
struct deleter {
template<typename T>
void operator()(T* p) { delete p; }
template<typename A, typename B>
void operator()(std::pair<A,B>& p) { delete p.second; }
};
} // anonymous namespace
ToolBox::ToolBox() ToolBox::ToolBox()
{ {
m_xmlTranslator.setStringIdPrefix("tools"); m_xmlTranslator.setStringIdPrefix("tools");
@ -137,16 +150,12 @@ ToolBox::ToolBox()
m_intertwiners[WellKnownIntertwiners::AsPixelPerfect] = new IntertwineAsPixelPerfect(); m_intertwiners[WellKnownIntertwiners::AsPixelPerfect] = new IntertwineAsPixelPerfect();
loadTools(); loadTools();
// When the language is change, we reload the toolbox stirngs/tooltips.
Strings::instance()->LanguageChange.connect(
[this]{ loadTools(); });
} }
struct deleter {
template<typename T>
void operator()(T* p) { delete p; }
template<typename A, typename B>
void operator()(std::pair<A,B>& p) { delete p.second; }
};
ToolBox::~ToolBox() ToolBox::~ToolBox()
{ {
std::for_each(m_tools.begin(), m_tools.end(), deleter()); std::for_each(m_tools.begin(), m_tools.end(), deleter());
@ -203,7 +212,19 @@ void ToolBox::loadTools()
LOG(VERBOSE) << "TOOL: Group " << groupId << "\n"; LOG(VERBOSE) << "TOOL: Group " << groupId << "\n";
ToolGroup* toolGroup = new ToolGroup(groupId); // Find an existent ToolGroup (this is useful in case we are
// reloading tool text/tooltips).
ToolGroup* toolGroup = nullptr;
for (auto g : m_groups) {
if (g->id() == groupId) {
toolGroup = g;
break;
}
}
if (toolGroup == nullptr) {
toolGroup = new ToolGroup(groupId);
m_groups.push_back(toolGroup);
}
// For each tool // For each tool
TiXmlNode* xmlToolNode = xmlGroup->FirstChild("tool"); TiXmlNode* xmlToolNode = xmlGroup->FirstChild("tool");
@ -214,20 +235,31 @@ void ToolBox::loadTools()
std::string toolTips = m_xmlTranslator(xmlTool, "tooltip"); std::string toolTips = m_xmlTranslator(xmlTool, "tooltip");
const char* defaultBrushSize = xmlTool->Attribute("default_brush_size"); const char* defaultBrushSize = xmlTool->Attribute("default_brush_size");
Tool* tool = new Tool(toolGroup, toolId, toolText, toolTips, Tool* tool = nullptr;
defaultBrushSize ? strtol(defaultBrushSize, NULL, 10): 1); for (auto t : m_tools) {
if (t->getId() == toolId) {
tool = t;
break;
}
}
if (tool == nullptr) {
tool = new Tool(toolGroup, toolId);
m_tools.push_back(tool);
}
tool->setText(toolText);
tool->setTips(toolTips);
tool->setDefaultBrushSize(
defaultBrushSize ? std::strtol(defaultBrushSize, nullptr, 10): 1);
LOG(VERBOSE) << "TOOL: Tool " << toolId << " in group " << groupId << " found\n"; LOG(VERBOSE) << "TOOL: Tool " << toolId << " in group " << groupId << " found\n";
loadToolProperties(xmlTool, tool, 0, "left"); loadToolProperties(xmlTool, tool, 0, "left");
loadToolProperties(xmlTool, tool, 1, "right"); loadToolProperties(xmlTool, tool, 1, "right");
m_tools.push_back(tool);
xmlTool = xmlTool->NextSiblingElement(); xmlTool = xmlTool->NextSiblingElement();
} }
m_groups.push_back(toolGroup);
xmlGroup = xmlGroup->NextSiblingElement(); xmlGroup = xmlGroup->NextSiblingElement();
} }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
@ -13,6 +13,7 @@
#include "app/app.h" #include "app/app.h"
#include "app/app_menus.h" #include "app/app_menus.h"
#include "app/commands/commands.h" #include "app/commands/commands.h"
#include "app/i18n/strings.h"
#include "app/ini_file.h" #include "app/ini_file.h"
#include "app/modules/editors.h" #include "app/modules/editors.h"
#include "app/notification_delegate.h" #include "app/notification_delegate.h"
@ -150,6 +151,15 @@ MainWindow::MainWindow()
remapWindow(); remapWindow();
AppMenus::instance()->rebuildRecentList(); AppMenus::instance()->rebuildRecentList();
// When the language is change, we reload the menu bar strings and
// relayout the whole main window.
Strings::instance()->LanguageChange.connect(
[this]{
m_menuBar->reload();
layout();
invalidate();
});
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
@ -207,14 +217,6 @@ CheckUpdateDelegate* MainWindow::getCheckUpdateDelegate()
} }
#endif #endif
void MainWindow::reloadMenus()
{
m_menuBar->reload();
layout();
invalidate();
}
void MainWindow::showNotification(INotificationDelegate* del) void MainWindow::showNotification(INotificationDelegate* del)
{ {
m_notifications->addLink(del); m_notifications->addLink(del);

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
@ -65,7 +65,6 @@ namespace app {
#endif #endif
void start(); void start();
void reloadMenus();
void showNotification(INotificationDelegate* del); void showNotification(INotificationDelegate* del);
void showHomeOnOpen(); void showHomeOnOpen();
void showHome(); void showHome();