Improve theme preferences and make editor static
This commit is contained in:
parent
01edf59446
commit
9c6f69203d
3 changed files with 79 additions and 48 deletions
42
main.cpp
42
main.cpp
|
@ -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
|
||||||
|
@ -215,6 +216,18 @@ int main(int, char**)
|
||||||
}
|
}
|
||||||
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__
|
||||||
// For an Emscripten build we are disabling file-system access, so let's not attempt to do a fopen() of the imgui.ini file.
|
// For an Emscripten build we are disabling file-system access, so let's not attempt to do a fopen() of the imgui.ini file.
|
||||||
|
@ -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();
|
||||||
|
|
73
theme.cpp
73
theme.cpp
|
@ -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
12
theme.h
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue