Use more strings and fix theme strings
This commit is contained in:
parent
3ea8e9707e
commit
7395357650
5 changed files with 116 additions and 36 deletions
21
main.cpp
21
main.cpp
|
@ -1,5 +1,6 @@
|
|||
#include "config.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_stdlib.h"
|
||||
#include "imgui_impl_sdl2.h"
|
||||
#include "imgui_impl_opengl3.h"
|
||||
#include "file_browser.h"
|
||||
|
@ -276,12 +277,21 @@ int main(int, char**)
|
|||
if (is_empty(Theme::themeDir)) {
|
||||
path lightPath = Theme::themeDir / "light.json";
|
||||
path darkPath = Theme::themeDir / "dark.json";
|
||||
string builtinDescription = _TRS_CTX("Built-in themes > Theme default strings > name", "(built-in)");
|
||||
if (!exists(lightPath)) {
|
||||
Theme light(false);
|
||||
ThemeStrings &strings = light.strings["fallback"];
|
||||
strings.name = _TRS_CTX("Built-in light theme > Theme default strings > name", "Default light");
|
||||
strings.description = builtinDescription;
|
||||
light.strings[CURRENT_LANGUAGE] = strings;
|
||||
light.Save(lightPath);
|
||||
}
|
||||
if (!exists(darkPath)) {
|
||||
Theme dark(true);
|
||||
ThemeStrings &strings = dark.strings["fallback"];
|
||||
strings.name = _TRS_CTX("Built-in dark theme > Theme default strings > name", "Default dark");
|
||||
strings.description = builtinDescription;
|
||||
dark.strings[CURRENT_LANGUAGE] = strings;
|
||||
dark.Save(darkPath);
|
||||
}
|
||||
delete theme;
|
||||
|
@ -431,10 +441,10 @@ int main(int, char**)
|
|||
if (ImGui::Button(_TRI_CTX(ICON_FK_MAGIC, "Preference > Related non-preference button", "Theme Editor"), ImVec2(ImGui::GetWindowWidth() - (ImGui::GetStyle().WindowPadding.x * 2.0f), 0))) {
|
||||
theme_editor = true;
|
||||
}
|
||||
static char filter[1024] = {0};
|
||||
static string filter = "";
|
||||
ImGui::Text(_TR_CTX("Preference > Theme selector > Filter label", "Filter:")); ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - ImGui::GetCursorPosX() - ImGui::GetStyle().WindowPadding.x);
|
||||
ImGui::InputText("##FilterInput", filter, 1024);
|
||||
ImGui::InputText("##FilterInput", &filter);
|
||||
ImGui::Text(_TR_CTX("Preferences > Theme selector > Selector label", "Select a theme..."));
|
||||
ImVec2 ChildSize = ImVec2(ImGui::GetWindowWidth() - (ImGui::GetStyle().WindowPadding.x * 2.0f), -ImGui::GetFrameHeightWithSpacing());
|
||||
if (ImGui::BeginChildFrame(ImGui::GetID("##ThemesContainer"), ChildSize)) {
|
||||
|
@ -444,11 +454,12 @@ int main(int, char**)
|
|||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("Remove", 0);
|
||||
for (auto themePath : Theme::availableThemes) {
|
||||
if (themePath.stem().string().starts_with(filter)) {
|
||||
string themeStem = themePath.stem().string();
|
||||
if (themeStem.starts_with(filter)) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
const bool is_selected = themePath == theme->file_path;
|
||||
if (ImGui::Selectable(themePath.stem().generic_string().c_str(), is_selected, 0)) {
|
||||
if (ImGui::Selectable((theme->themeStrings[themePath].name + string(" (") + string(themeStem) + string(")")).c_str(), is_selected, 0)) {
|
||||
delete theme;
|
||||
theme = new Theme(themePath);
|
||||
theme->Apply(accent_color);
|
||||
|
@ -458,7 +469,7 @@ int main(int, char**)
|
|||
ImGui::SetItemDefaultFocus();
|
||||
} else {
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
if (ImGui::SmallButton((string(ICON_FK_WINDOW_CLOSE "##") + themePath.stem().generic_string()).c_str())) {
|
||||
if (ImGui::SmallButton((string(ICON_FK_WINDOW_CLOSE "##") + themeStem).c_str())) {
|
||||
std::filesystem::remove(themePath);
|
||||
Theme::updateAvailableThemes();
|
||||
break;
|
||||
|
|
|
@ -63,12 +63,14 @@ srcs = [
|
|||
'imgui/imgui_tables.cpp',
|
||||
'imgui/imgui_draw.cpp',
|
||||
'imgui/imgui_demo.cpp',
|
||||
'imgui/misc/cpp/imgui_stdlib.cpp',
|
||||
'imgui/backends/imgui_impl_sdl2.cpp',
|
||||
'imgui/backends/imgui_impl_opengl3.cpp',
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
'imgui',
|
||||
'imgui/misc/cpp',
|
||||
'imgui/backends',
|
||||
'imgui-filebrowser',
|
||||
'IconFontCppHeaders',
|
||||
|
|
123
theme.cpp
123
theme.cpp
|
@ -8,13 +8,16 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include "IconsForkAwesome.h"
|
||||
#include "imgui_stdlib.h"
|
||||
|
||||
using namespace std::filesystem;
|
||||
using namespace std::numbers;
|
||||
const char* Theme::prefPath = NULL;
|
||||
path Theme::themeDir = path();
|
||||
std::set<path> Theme::availableThemes = std::set<path>();
|
||||
std::map<path, ThemeStrings> Theme::themeStrings = std::map<path, ThemeStrings>();
|
||||
|
||||
ImVec4 change_accent_color(ImVec4 in, float hue) {
|
||||
if (in.x == in.y && in.y == in.z) {
|
||||
|
@ -126,6 +129,13 @@ bool Theme::ShowEditor(bool* open, Theme* &theme, ImGuiID dockid, int window_wid
|
|||
|
||||
if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None))
|
||||
{
|
||||
if (ImGui::BeginTabItem(_TR_CTX("Theme Editor > Tab label", "Strings")))
|
||||
{
|
||||
ImGui::InputText(_TR_CTX("Theme Editor > Strings > Name input label", "Name"), &theme->strings["fallback"].name);
|
||||
ImGui::InputText(_TR_CTX("Theme Editor > Strings > Description input label", "Description"), &theme->strings["fallback"].description);
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem(_TR_CTX("Theme Editor > Tab label", "Sizes")))
|
||||
{
|
||||
ImGui::SeparatorText(_TR_CTX("Theme Editor > Sizes > Section label", "Sizing"));
|
||||
|
@ -222,16 +232,17 @@ bool Theme::ShowEditor(bool* open, Theme* &theme, ImGuiID dockid, int window_wid
|
|||
ImGui::SetNextWindowSize(ImVec2(window_width, window_height));
|
||||
if (ImGui::BeginPopupModal(_TR_CTX("Theme Editor > Custom modal dialog title", "Load..."), nullptr, ImGuiWindowFlags_Modal|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize)) {
|
||||
static path selectedThemePath;
|
||||
static char filter[1024] = {0};
|
||||
static string filter = "";
|
||||
ImGui::Text(_TR_CTX("Theme Editor > Load dialog > Theme selector > filter label", "Filter:")); ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - ImGui::GetCursorPosX() - ImGui::GetStyle().WindowPadding.x);
|
||||
ImGui::InputText("##FilterInput", filter, 1024);
|
||||
ImGui::InputText("##FilterInput", &filter);
|
||||
ImGui::Text(_TR_CTX("Theme Editor > Load dialog > Theme selector > label", "Available themes..."));
|
||||
if (ImGui::BeginListBox("##Themes", ImVec2(ImGui::GetWindowWidth() - (ImGui::GetStyle().WindowPadding.x * 2.0f), -ImGui::GetTextLineHeightWithSpacing() - ImGui::GetStyle().WindowPadding.y))) {
|
||||
for (auto themePath : Theme::availableThemes) {
|
||||
if (themePath.stem().string().starts_with(filter)) {
|
||||
string themeStem = themePath.stem().string();
|
||||
if (themeStem.starts_with(filter)) {
|
||||
const bool is_selected = themePath == selectedThemePath;
|
||||
if (ImGui::Selectable(themePath.stem().generic_string().c_str(), is_selected)) {
|
||||
if (ImGui::Selectable((theme->themeStrings[themePath].name + string(" (") + string(themeStem) + string(")")).c_str(), is_selected)) {
|
||||
selectedThemePath = themePath;
|
||||
}
|
||||
if (is_selected) {
|
||||
|
@ -243,7 +254,7 @@ bool Theme::ShowEditor(bool* open, Theme* &theme, ImGuiID dockid, int window_wid
|
|||
}
|
||||
if (ImGui::Button(_TR_CTX("Theme Editor > Load dialog > Load button", "Load"))) {
|
||||
if (!selectedThemePath.empty()) {
|
||||
filter[0] = '\0';
|
||||
filter = "";
|
||||
loadOpen = false;
|
||||
delete theme;
|
||||
theme = new Theme(selectedThemePath);
|
||||
|
@ -255,7 +266,7 @@ bool Theme::ShowEditor(bool* open, Theme* &theme, ImGuiID dockid, int window_wid
|
|||
ImGui::SameLine();
|
||||
if (ImGui::Button(_TR_CTX("Theme Editor > Load dialog > Cancel button", "Cancel"))) {
|
||||
selectedThemePath = path();
|
||||
filter[0] = '\0';
|
||||
filter = "";
|
||||
loadOpen = false;
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
|
@ -266,18 +277,19 @@ bool Theme::ShowEditor(bool* open, Theme* &theme, ImGuiID dockid, int window_wid
|
|||
ImGui::SetNextWindowPos(ImVec2(0, 0));
|
||||
ImGui::SetNextWindowSize(ImVec2(window_width, window_height));
|
||||
if (ImGui::BeginPopupModal(_TR_CTX("Theme Editor > Custom modal dialog title", "Save as..."), nullptr, ImGuiWindowFlags_Modal|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize)) {
|
||||
static char selectedThemeName[1024] = {0};
|
||||
static char filter[1024] = {0};
|
||||
static string selectedThemeName = "";
|
||||
static string filter = "";
|
||||
ImGui::Text(_TR_CTX("Theme Editor > Save as dialog > Theme selector > filter label", "Filter:")); ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - ImGui::GetCursorPosX() - ImGui::GetStyle().WindowPadding.x);
|
||||
ImGui::InputText("##FilterInput", filter, 1024);
|
||||
ImGui::InputText("##FilterInput", &filter, 1024);
|
||||
ImGui::Text(_TR_CTX("Theme Editor > Save as dialog > Theme selector > label", "Available themes..."));
|
||||
if (ImGui::BeginListBox("##Themes", ImVec2(ImGui::GetWindowWidth() - (ImGui::GetStyle().WindowPadding.x * 2.0f), -ImGui::GetFrameHeightWithSpacing() - ImGui::GetTextLineHeightWithSpacing() - ImGui::GetStyle().WindowPadding.y))) {
|
||||
for (auto themePath : Theme::availableThemes) {
|
||||
if (themePath.stem().string().starts_with(filter)) {
|
||||
const bool is_selected = strcmp(themePath.stem().generic_string().c_str(), selectedThemeName) == 0;
|
||||
if (ImGui::Selectable(themePath.stem().generic_string().c_str(), is_selected)) {
|
||||
strncpy(selectedThemeName, themePath.stem().generic_string().c_str(), 1023);
|
||||
string themeStem = themePath.stem().string();
|
||||
if (themeStem.starts_with(filter)) {
|
||||
const bool is_selected = themeStem == selectedThemeName;
|
||||
if (ImGui::Selectable((theme->themeStrings[themePath].name + string(" (") + string(themeStem) + string(")")).c_str(), is_selected)) {
|
||||
selectedThemeName = themeStem;
|
||||
}
|
||||
if (is_selected) {
|
||||
ImGui::SetItemDefaultFocus();
|
||||
|
@ -287,12 +299,12 @@ bool Theme::ShowEditor(bool* open, Theme* &theme, ImGuiID dockid, int window_wid
|
|||
ImGui::EndListBox();
|
||||
}
|
||||
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - (ImGui::GetStyle().WindowPadding.x * 2.0f));
|
||||
ImGui::InputText(_TR_CTX("Theme Editor > Save as dialog > Theme name input label", "Theme name: "), selectedThemeName, 1024);
|
||||
ImGui::InputText(_TR_CTX("Theme Editor > Save as dialog > Theme name input label", "Theme name: "), &selectedThemeName);
|
||||
if (ImGui::Button(_TR_CTX("Theme Editor > Save as dialog > Save button", "Save"))) {
|
||||
path selectedThemePath(selectedThemeName);
|
||||
if (!selectedThemePath.empty() && !selectedThemePath.is_absolute()) {
|
||||
selectedThemeName[0] = '\0'; // This empties the string by taking advantage of C strings.
|
||||
filter[0] = '\0';
|
||||
selectedThemeName = "";
|
||||
filter = "";
|
||||
saveAsOpen = false;
|
||||
theme->Save(Theme::themeDir / selectedThemePath.replace_extension(".json"));
|
||||
theme->file_path = selectedThemePath.generic_string();
|
||||
|
@ -300,8 +312,8 @@ bool Theme::ShowEditor(bool* open, Theme* &theme, ImGuiID dockid, int window_wid
|
|||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(_TR_CTX("Theme Editor > Save as dialog > Cancel button", "Cancel"))) {
|
||||
selectedThemeName[0] = '\0'; // Same as above
|
||||
filter[0] = '\0';
|
||||
selectedThemeName = "";
|
||||
filter = "";
|
||||
saveAsOpen = false;
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
|
@ -337,12 +349,12 @@ void Theme::Save(string path) {
|
|||
{
|
||||
Json::Value stringsList;
|
||||
for (auto kv : strings) {
|
||||
Json::Value stringsEntry;
|
||||
Json::Value stringsEntryJson;
|
||||
string language = kv.first;
|
||||
ThemeStrings strings = kv.second;
|
||||
stringsEntry["Name"] = strings.name;
|
||||
stringsEntry["Description"] = strings.description;
|
||||
stringsList[language] = stringsEntry;
|
||||
ThemeStrings stringsEntry = kv.second;
|
||||
stringsEntryJson["Name"] = stringsEntry.name;
|
||||
stringsEntryJson["Description"] = stringsEntry.description;
|
||||
stringsList[language] = stringsEntryJson;
|
||||
}
|
||||
metadata["Strings"] = stringsList;
|
||||
}
|
||||
|
@ -414,10 +426,19 @@ void Theme::updateAvailableThemes() {
|
|||
themeDir = path(prefPath) / path("themes");
|
||||
create_directories(themeDir);
|
||||
availableThemes.clear();
|
||||
themeStrings.clear();
|
||||
for (auto const& dir_entry : directory_iterator(themeDir)) {
|
||||
if (dir_entry.is_regular_file()) {
|
||||
if (dir_entry.path().extension().string() == ".json") {
|
||||
availableThemes.insert(dir_entry.path());
|
||||
path path = dir_entry.path();
|
||||
availableThemes.insert(path);
|
||||
Json::Value config;
|
||||
std::ifstream stream;
|
||||
stream.open(path);
|
||||
if (stream.is_open()) {
|
||||
stream >> config;
|
||||
themeStrings[path] = ThemeStrings(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -427,6 +448,7 @@ Theme::Theme() {
|
|||
throw std::exception();
|
||||
}
|
||||
updateAvailableThemes();
|
||||
strings["fallback"] = ThemeStrings();
|
||||
}
|
||||
|
||||
Theme::Theme(bool dark) : Theme() {
|
||||
|
@ -451,6 +473,46 @@ ThemeStrings::ThemeStrings() {
|
|||
name = _TRS_CTX("Theme default strings > name", "A theme");
|
||||
description = _TRS_CTX("Theme default strings > description", "(No description)");
|
||||
}
|
||||
ThemeStrings Theme::GetStrings() {
|
||||
char *language_c = CURRENT_LANGUAGE;
|
||||
string language = language_c;
|
||||
if (strings.contains(language)) {
|
||||
return strings[language];
|
||||
} else {
|
||||
if (!strings.contains("fallback")) {
|
||||
strings["fallback"] = ThemeStrings();
|
||||
}
|
||||
return strings["fallback"];
|
||||
}
|
||||
}
|
||||
ThemeStrings::ThemeStrings(Json::Value config) : ThemeStrings() {
|
||||
char *language_c = CURRENT_LANGUAGE;
|
||||
string language = language_c;
|
||||
if (config.isMember("meta")) {
|
||||
Json::Value metadata = config["meta"];
|
||||
//metadata["SchemaVersion"] = 1;
|
||||
if (metadata.isMember("Strings")) {
|
||||
Json::Value stringsList = metadata["Strings"];
|
||||
if (stringsList.isMember(language)) {
|
||||
Json::Value stringsEntryJson = stringsList[language];
|
||||
if (stringsEntryJson.isMember("Name")) {
|
||||
name = stringsEntryJson["Name"].asString();
|
||||
}
|
||||
if (stringsEntryJson.isMember("Description")) {
|
||||
description = stringsEntryJson["Description"].asString();
|
||||
}
|
||||
} else if (metadata.isMember("fallback")) {
|
||||
Json::Value stringsEntryJson = stringsList["fallback"];
|
||||
if (stringsEntryJson.isMember("Name")) {
|
||||
name = stringsEntryJson["Name"].asString();
|
||||
}
|
||||
if (stringsEntryJson.isMember("Description")) {
|
||||
description = stringsEntryJson["Description"].asString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Theme::Theme(string path) : Theme() {
|
||||
Json::Value config;
|
||||
std::ifstream stream;
|
||||
|
@ -463,14 +525,15 @@ Theme::Theme(string path) : Theme() {
|
|||
if (metadata.isMember("Strings")) {
|
||||
Json::Value stringsList = metadata["Strings"];
|
||||
for (string language : stringsList.getMemberNames()) {
|
||||
Json::Value stringsEntry = stringsList[language];
|
||||
ThemeStrings strings;
|
||||
if (stringsEntry.isMember("Name")) {
|
||||
strings.name = stringsEntry["Name"].asString();
|
||||
Json::Value stringsEntryJson = stringsList[language];
|
||||
ThemeStrings stringsEntry;
|
||||
if (stringsEntryJson.isMember("Name")) {
|
||||
stringsEntry.name = stringsEntryJson["Name"].asString();
|
||||
}
|
||||
if (stringsEntry.isMember("Description")) {
|
||||
strings.description = stringsEntry["Description"].asString();
|
||||
if (stringsEntryJson.isMember("Description")) {
|
||||
stringsEntry.description = stringsEntryJson["Description"].asString();
|
||||
}
|
||||
strings[language] = stringsEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
3
theme.h
3
theme.h
|
@ -14,6 +14,7 @@ struct ThemeStrings {
|
|||
string name;
|
||||
string description;
|
||||
ThemeStrings();
|
||||
ThemeStrings(Json::Value config);
|
||||
};
|
||||
|
||||
class Theme {
|
||||
|
@ -21,6 +22,7 @@ class Theme {
|
|||
|
||||
public:
|
||||
static std::set<path> availableThemes;
|
||||
static std::map<path, ThemeStrings> themeStrings;
|
||||
static void updateAvailableThemes();
|
||||
static path themeDir;
|
||||
static const char* prefPath;
|
||||
|
@ -29,6 +31,7 @@ class Theme {
|
|||
string file_path;
|
||||
std::map<string, ThemeStrings> strings;
|
||||
std::set<int> HueEnabledColors;
|
||||
ThemeStrings GetStrings();
|
||||
static bool ShowEditor(bool *open, Theme* &theme, ImGuiID dockid, int window_width, int window_height);
|
||||
void Apply(float hue);
|
||||
void Save(string path);
|
||||
|
|
|
@ -20,3 +20,4 @@ inline static const char *gettext_ctx(const char *ctx, const char *msgid) {
|
|||
#define _TRI(icon, str) _TRIS(icon, str).c_str()
|
||||
#define _TRIS_CTX(icon, ctx, str) (std::string(icon) + _TRS_CTX(ctx, str))
|
||||
#define _TRI_CTX(icon, ctx, str) _TRIS_CTX(icon, ctx, str).c_str()
|
||||
#define CURRENT_LANGUAGE textdomain(NULL)
|
Loading…
Add table
Reference in a new issue