Improve theme preferences and make editor static

This commit is contained in:
Zachary Hall 2023-07-10 19:27:55 -07:00
parent 01edf59446
commit 9c6f69203d
3 changed files with 79 additions and 48 deletions

View file

@ -17,6 +17,7 @@
#include <string> #include <string>
#include <SDL.h> #include <SDL.h>
#include <SDL_image.h> #include <SDL_image.h>
#include <filesystem>
#if defined(IMGUI_IMPL_OPENGL_ES2) #if defined(IMGUI_IMPL_OPENGL_ES2)
#include <SDL_opengles2.h> #include <SDL_opengles2.h>
#else #else
@ -214,6 +215,18 @@ int main(int, char**)
show_demo_window = config["demo_window"].asBool(); show_demo_window = config["demo_window"].asBool();
} }
stream.close(); stream.close();
}
if (is_empty(Theme::themeDir)) {
path lightPath = Theme::themeDir / "light.json";
path darkPath = Theme::themeDir / "dark.json";
if (!exists(lightPath)) {
Theme light(false);
light.Save(lightPath);
}
if (!exists(darkPath)) {
Theme dark(true);
dark.Save(darkPath);
}
} }
} }
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
@ -312,23 +325,44 @@ int main(int, char**)
if (prefs_window) { if (prefs_window) {
ImVec2 min_size; ImVec2 min_size;
min_size.x = ImGui::GetFontSize() * 18; min_size.x = ImGui::GetFontSize() * 18;
min_size.y = (ImGui::GetStyle().FramePadding.y * 5) + (ImGui::GetFontSize() * 5); min_size.y = (ImGui::GetFrameHeightWithSpacing() * 8) + (ImGui::GetFontSize());
ImVec2 max_size; ImVec2 max_size;
max_size.x = 99999997952; // The compiler says that if this were just 9s it would be turned into this anyways. max_size.x = 99999997952; // The compiler says that if this were just 9s it would be turned into this anyways.
max_size.y = min_size.y; max_size.y = 99999997952;
ImGui::SetNextWindowSizeConstraints(min_size, max_size); ImGui::SetNextWindowSizeConstraints(min_size, max_size);
ImGui::Begin("Preferences...", &prefs_window); ImGui::Begin("Preferences...", &prefs_window);
{ {
if (ImGui::Button(ICON_FK_MAGIC "Theme Editor")) { if (ImGui::Button(ICON_FK_MAGIC "Theme Editor", ImVec2(ImGui::GetWindowWidth() - (ImGui::GetStyle().WindowPadding.x * 2.0f), 0))) {
theme_editor = true; theme_editor = true;
} }
static char filter[1024] = {0};
ImGui::Text("Filter:"); ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - ImGui::GetCursorPosX() - ImGui::GetStyle().WindowPadding.x);
ImGui::InputText("##FilterInput", filter, 1024);
ImGui::Text("Select a theme...");
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)) {
const bool is_selected = themePath == theme->file_path;
if (ImGui::Selectable(themePath.stem().c_str(), is_selected)) {
delete theme;
theme = new Theme(themePath);
break;
}
if (is_selected) {
ImGui::SetItemDefaultFocus();
}
}
}
ImGui::EndListBox();
}
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - (ImGui::GetStyle().FramePadding.x * 4)); ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - (ImGui::GetStyle().FramePadding.x * 4));
ImGui::SliderFloat("##AccentColor", &accent_color, 0.0, 360.0, "UI hue: %.0f°", ImGuiSliderFlags_NoRoundToFormat); ImGui::SliderFloat("##AccentColor", &accent_color, 0.0, 360.0, "UI hue: %.0f°", ImGuiSliderFlags_NoRoundToFormat);
} }
ImGui::End(); ImGui::End();
} }
if (theme_editor) { if (theme_editor) {
theme->ShowEditor(&theme_editor, theme); Theme::ShowEditor(&theme_editor, theme);
} }
theme->Apply(accent_color); theme->Apply(accent_color);
fileDialog.Display(); fileDialog.Display();

View file

@ -12,11 +12,18 @@
using namespace std::filesystem; using namespace std::filesystem;
using namespace std::numbers; using namespace std::numbers;
const char* Theme::prefPath = NULL; const char* Theme::prefPath = NULL;
path Theme::themeDir = path();
std::set<path> Theme::availableThemes = std::set<path>();
bool Theme::ShowEditor(bool* open, Theme* &theme) { bool Theme::ShowEditor(bool* open, Theme* &theme) {
static ImGui::FileBrowser importDialog;
static ImGui::FileBrowser exportDialog;
static bool loadOpen = false;
static bool saveAsOpen = false;
ImGui::Begin("Theme Editor", open); ImGui::Begin("Theme Editor", open);
ImGuiStyle *ref = &style; ImGuiStyle& style = theme->style;
ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f); ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f);
if (ImGui::Button("Create light")) { ImVec2 buttonSize = ImVec2((ImGui::GetWindowWidth() * 0.50f) - (ImGui::GetStyle().WindowPadding.x) - (ImGui::GetStyle().ItemSpacing.x * 0.5f), 0);
if (ImGui::Button("Create light", buttonSize)) {
delete theme; delete theme;
theme = new Theme(false); theme = new Theme(false);
@ -25,7 +32,7 @@ bool Theme::ShowEditor(bool* open, Theme* &theme) {
return true; return true;
} }
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("Create dark")) { if (ImGui::Button("Create dark", buttonSize)) {
delete theme; delete theme;
theme = new Theme(true); theme = new Theme(true);
@ -33,7 +40,7 @@ bool Theme::ShowEditor(bool* open, Theme* &theme) {
ImGui::End(); ImGui::End();
return true; return true;
} }
if (ImGui::Button("Import...")) { if (ImGui::Button("Import...", buttonSize)) {
importDialog.SetTitle("Import theme..."); importDialog.SetTitle("Import theme...");
importDialog.SetTypeFilters({ ".json"}); importDialog.SetTypeFilters({ ".json"});
std::string userdir = std::getenv( std::string userdir = std::getenv(
@ -47,7 +54,7 @@ bool Theme::ShowEditor(bool* open, Theme* &theme) {
importDialog.Open(); importDialog.Open();
} }
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("Export...")) { if (ImGui::Button("Export...", buttonSize)) {
exportDialog = ImGui::FileBrowser(ImGuiFileBrowserFlags_EnterNewFilename|ImGuiFileBrowserFlags_CreateNewDir); exportDialog = ImGui::FileBrowser(ImGuiFileBrowserFlags_EnterNewFilename|ImGuiFileBrowserFlags_CreateNewDir);
exportDialog.SetTitle("Export theme..."); exportDialog.SetTitle("Export theme...");
exportDialog.SetTypeFilters({ ".json"}); exportDialog.SetTypeFilters({ ".json"});
@ -63,9 +70,9 @@ bool Theme::ShowEditor(bool* open, Theme* &theme) {
} }
importDialog.Display(); importDialog.Display();
exportDialog.Display(); exportDialog.Display();
if (!file_path.empty()) { if (!theme->file_path.empty()) {
if (ImGui::Button("Revert")) { if (ImGui::Button("Revert", buttonSize)) {
string file_path_backup = file_path; string file_path_backup = theme->file_path;
delete theme; delete theme;
theme = new Theme(file_path_backup); theme = new Theme(file_path_backup);
ImGui::PopItemWidth(); ImGui::PopItemWidth();
@ -73,15 +80,15 @@ bool Theme::ShowEditor(bool* open, Theme* &theme) {
return true; return true;
} }
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("Save")) { if (ImGui::Button("Save", buttonSize)) {
Save(file_path); theme->Save(theme->file_path);
} }
} }
if (ImGui::Button("Load...")) { if (ImGui::Button("Load...", buttonSize)) {
loadOpen = true; loadOpen = true;
} }
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("Save as...")) { if (ImGui::Button("Save as...", buttonSize)) {
saveAsOpen = true; saveAsOpen = true;
} }
@ -140,22 +147,14 @@ bool Theme::ShowEditor(bool* open, Theme* &theme) {
continue; continue;
ImGui::PushID(i); ImGui::PushID(i);
ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags | ImGuiColorEditFlags_DisplayHSV); ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags | ImGuiColorEditFlags_DisplayHSV);
if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
{
// Tips: in a real user application, you may want to merge and use an icon font into the main font,
// so instead of "Save"/"Revert" you'd use icons!
// Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient!
ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; }
ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; }
}
ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
ImGui::TextUnformatted(name); ImGui::TextUnformatted(name);
bool hueEnabled = HueEnabledColors.contains(i); bool hueEnabled = theme->HueEnabledColors.contains(i);
if (ImGui::Checkbox("Match accent color hue", &hueEnabled)) { if (ImGui::Checkbox("Match accent color hue", &hueEnabled)) {
if (hueEnabled) { if (hueEnabled) {
HueEnabledColors.insert(i); theme->HueEnabledColors.insert(i);
} else { } else {
HueEnabledColors.erase(i); theme->HueEnabledColors.erase(i);
} }
} }
ImGui::PopID(); ImGui::PopID();
@ -174,12 +173,12 @@ bool Theme::ShowEditor(bool* open, Theme* &theme) {
if (importDialog.HasSelected()) { if (importDialog.HasSelected()) {
path selected_path = importDialog.GetSelected(); path selected_path = importDialog.GetSelected();
path filename = selected_path.filename(); path filename = selected_path.filename();
copy_file(selected_path, themeDir / filename); copy_file(selected_path, theme->themeDir / filename);
availableThemes.insert(filename); theme->availableThemes.insert(filename);
} }
if (exportDialog.HasSelected()) { if (exportDialog.HasSelected()) {
path selected_path = importDialog.GetSelected(); path selected_path = importDialog.GetSelected();
Save(selected_path); theme->Save(selected_path);
} }
if (loadOpen) { if (loadOpen) {
ImGui::OpenPopup("Load..."); ImGui::OpenPopup("Load...");
@ -187,11 +186,12 @@ bool Theme::ShowEditor(bool* open, Theme* &theme) {
if (ImGui::BeginPopupModal("Load...", &loadOpen)) { if (ImGui::BeginPopupModal("Load...", &loadOpen)) {
static path selectedThemePath; static path selectedThemePath;
static char filter[1024] = {0}; static char filter[1024] = {0};
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - (ImGui::GetStyle().WindowPadding.x * 2.0f)); ImGui::Text("Filter:"); ImGui::SameLine();
ImGui::InputText("Filter: ", filter, 1024); ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - ImGui::GetCursorPosX() - ImGui::GetStyle().WindowPadding.x);
ImGui::InputText("##FilterInput", filter, 1024);
ImGui::Text("Available themes..."); ImGui::Text("Available themes...");
if (ImGui::BeginListBox("##Themes", ImVec2(ImGui::GetWindowWidth() - (ImGui::GetStyle().WindowPadding.x * 2.0f), -ImGui::GetTextLineHeightWithSpacing() - ImGui::GetStyle().WindowPadding.y))) { if (ImGui::BeginListBox("##Themes", ImVec2(ImGui::GetWindowWidth() - (ImGui::GetStyle().WindowPadding.x * 2.0f), -ImGui::GetTextLineHeightWithSpacing() - ImGui::GetStyle().WindowPadding.y))) {
for (auto themePath : availableThemes) { for (auto themePath : Theme::availableThemes) {
if (themePath.stem().string().starts_with(filter)) { if (themePath.stem().string().starts_with(filter)) {
const bool is_selected = themePath == selectedThemePath; const bool is_selected = themePath == selectedThemePath;
if (ImGui::Selectable(themePath.stem().c_str(), is_selected)) { if (ImGui::Selectable(themePath.stem().c_str(), is_selected)) {
@ -229,11 +229,12 @@ bool Theme::ShowEditor(bool* open, Theme* &theme) {
if (ImGui::BeginPopupModal("Save as...", &saveAsOpen)) { if (ImGui::BeginPopupModal("Save as...", &saveAsOpen)) {
static char selectedThemeName[1024] = {0}; static char selectedThemeName[1024] = {0};
static char filter[1024] = {0}; static char filter[1024] = {0};
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - (ImGui::GetStyle().WindowPadding.x * 2.0f)); ImGui::Text("Filter:"); ImGui::SameLine();
ImGui::InputText("Filter: ", filter, 1024); ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - ImGui::GetCursorPosX() - ImGui::GetStyle().WindowPadding.x);
ImGui::InputText("##FilterInput", filter, 1024);
ImGui::Text("Available themes..."); ImGui::Text("Available themes...");
if (ImGui::BeginListBox("##Themes", ImVec2(ImGui::GetWindowWidth() - (ImGui::GetStyle().WindowPadding.x * 2.0f), -ImGui::GetFrameHeightWithSpacing() - ImGui::GetTextLineHeightWithSpacing() - ImGui::GetStyle().WindowPadding.y))) { if (ImGui::BeginListBox("##Themes", ImVec2(ImGui::GetWindowWidth() - (ImGui::GetStyle().WindowPadding.x * 2.0f), -ImGui::GetFrameHeightWithSpacing() - ImGui::GetTextLineHeightWithSpacing() - ImGui::GetStyle().WindowPadding.y))) {
for (auto themePath : availableThemes) { for (auto themePath : Theme::availableThemes) {
if (themePath.stem().string().starts_with(filter)) { if (themePath.stem().string().starts_with(filter)) {
const bool is_selected = strcmp(themePath.stem().c_str(), selectedThemeName) == 0; const bool is_selected = strcmp(themePath.stem().c_str(), selectedThemeName) == 0;
if (ImGui::Selectable(themePath.stem().c_str(), is_selected)) { if (ImGui::Selectable(themePath.stem().c_str(), is_selected)) {
@ -254,8 +255,8 @@ bool Theme::ShowEditor(bool* open, Theme* &theme) {
selectedThemeName[0] = '\0'; // This empties the string by taking advantage of C strings. selectedThemeName[0] = '\0'; // This empties the string by taking advantage of C strings.
filter[0] = '\0'; filter[0] = '\0';
saveAsOpen = false; saveAsOpen = false;
Save(themeDir / selectedThemePath.replace_extension(".json")); theme->Save(Theme::themeDir / selectedThemePath.replace_extension(".json"));
file_path = selectedThemePath; theme->file_path = selectedThemePath;
} }
} }
ImGui::SameLine(); ImGui::SameLine();
@ -342,6 +343,8 @@ void Theme::Save(string path) {
updateAvailableThemes(); updateAvailableThemes();
} }
void Theme::updateAvailableThemes() { void Theme::updateAvailableThemes() {
themeDir = path(prefPath) / path("themes");
create_directories(themeDir);
availableThemes.clear(); availableThemes.clear();
for (auto const& dir_entry : directory_iterator(themeDir)) { for (auto const& dir_entry : directory_iterator(themeDir)) {
if (dir_entry.is_regular_file()) { if (dir_entry.is_regular_file()) {
@ -355,8 +358,6 @@ Theme::Theme() {
if (prefPath == NULL) { if (prefPath == NULL) {
throw std::exception(); throw std::exception();
} }
themeDir = path(prefPath) / path("themes");
create_directories(themeDir);
updateAvailableThemes(); updateAvailableThemes();
} }

12
theme.h
View file

@ -9,19 +9,15 @@ using namespace std::filesystem;
class Theme { class Theme {
ImGuiStyle style; ImGuiStyle style;
ImGui::FileBrowser importDialog;
ImGui::FileBrowser exportDialog;
bool loadOpen = false;
bool saveAsOpen = false;
std::set<path> availableThemes;
void updateAvailableThemes();
public: public:
path themeDir; static std::set<path> availableThemes;
static void updateAvailableThemes();
static path themeDir;
static const char* prefPath; static const char* prefPath;
string file_path; string file_path;
std::set<int> HueEnabledColors; std::set<int> HueEnabledColors;
bool ShowEditor(bool *open, Theme* &theme); static bool ShowEditor(bool *open, Theme* &theme);
void Apply(float hue); void Apply(float hue);
void Save(string path); void Save(string path);
Theme(); Theme();