Use more strings and fix theme strings

This commit is contained in:
Zachary Hall 2023-07-25 07:56:56 -07:00
parent 3ea8e9707e
commit 7395357650
5 changed files with 116 additions and 36 deletions

View file

@ -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;

View file

@ -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
View file

@ -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;
}
}
}

View file

@ -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);

View file

@ -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)