diff --git a/editor/editor_system.cpp b/editor/editor_system.cpp index b835f0d1e..63747a664 100644 --- a/editor/editor_system.cpp +++ b/editor/editor_system.cpp @@ -96,6 +96,8 @@ bool EditorSystem::initialize(const JSON::json& systemData) } ImGui_ImplWin32_Init(Application::GetSingleton()->getWindow()->getWindowHandle()); ImGui_ImplDX11_Init(RenderingDevice::GetSingleton()->getDevice(), RenderingDevice::GetSingleton()->getContext()); + + // Apply layout with default values ImGui::StyleColorsDark(); { @@ -170,6 +172,18 @@ bool EditorSystem::initialize(const JSON::json& systemData) colors[ImGuiCol_ModalWindowDimBg] = ImVec4(1.00f, 0.98f, 0.95f, 0.73f); } + // Load json theme data + for (const auto& entry : std::filesystem::directory_iterator("editor/themes")) + { + if (entry.path().extension() == ".json") + { + InputFileStream f(entry.path()); + JSON::json data; + f >> data; + m_ThemeDefinitions.push_back( { data.value("name", entry.path().stem().string()), entry.path().string(), data } ); + } + } + return true; } @@ -416,6 +430,18 @@ void EditorSystem::drawDefaultUI(float deltaMilliseconds) static bool styleEditor = false; if (ImGui::BeginMenu("View")) { + if (ImGui::BeginMenu("Themes")) + { + for (size_t i = 0; i < m_ThemeDefinitions.size(); ++i) + { + if (ImGui::MenuItem(m_ThemeDefinitions[i].m_Name.c_str())) + { + m_ThemeDefinitions[i].apply(); + } + } + ImGui::EndMenu(); + } + if (ImGui::Checkbox("Wireframe Mode", &m_WireframeMode)) { if (m_WireframeMode) diff --git a/editor/editor_system.h b/editor/editor_system.h index 0c894fb58..9756eca52 100644 --- a/editor/editor_system.h +++ b/editor/editor_system.h @@ -11,6 +11,8 @@ #include "Tracy/Tracy.hpp" +#include "themes/theme.h" + ImColor ColorToImColor(Color& c); class SceneDock; @@ -82,6 +84,8 @@ class EditorSystem : public System int exportScene(const String& sceneName, const String& sceneFilePath, Atomic& progress); void postExport(); + Vector m_ThemeDefinitions; + public: static EditorSystem* GetSingleton(); diff --git a/editor/themes/classic.json b/editor/themes/classic.json new file mode 100644 index 000000000..1e826214a --- /dev/null +++ b/editor/themes/classic.json @@ -0,0 +1,74 @@ +{ + "name": "Classic", + "style": { + "WindowPadding": [8.0, 8.0], + "WindowRounding": 0.0, + "FramePadding": [4.0, 3.0], + "FrameRounding": 0.0, + "ItemSpacing": [8.0, 4.0], + "ItemInnerSpacing": [4.0, 4.0], + "IndentSpacing": 20.0, + "ScrollbarSize": 12.0, + "ScrollbarRounding": 0.0, + "GrabMinSize": 8.0, + "GrabRounding": 0.0 + }, + "colors": { + "Text": [0.00, 0.00, 0.00, 1.00], + "TextDisabled": [0.50, 0.50, 0.50, 1.00], + "WindowBg": [0.82, 0.82, 0.82, 1.00], + "ChildBg": [0.85, 0.85, 0.85, 1.00], + "PopupBg": [0.90, 0.90, 0.90, 1.00], + "Border": [0.50, 0.50, 0.50, 1.00], + "BorderShadow": [0.00, 0.00, 0.00, 0.00], + "FrameBg": [0.75, 0.75, 0.75, 1.00], + "FrameBgHovered": [0.70, 0.70, 0.70, 1.00], + "FrameBgActive": [0.60, 0.60, 0.60, 1.00], + "TitleBg": [0.50, 0.50, 0.60, 1.00], + "TitleBgActive": [0.45, 0.45, 0.55, 1.00], + "TitleBgCollapsed": [0.60, 0.60, 0.70, 1.00], + "MenuBarBg": [0.75, 0.75, 0.75, 1.00], + "ScrollbarBg": [0.85, 0.85, 0.85, 1.00], + "ScrollbarGrab": [0.60, 0.60, 0.60, 1.00], + "ScrollbarGrabHovered": [0.55, 0.55, 0.55, 1.00], + "ScrollbarGrabActive": [0.50, 0.50, 0.50, 1.00], + "CheckMark": [0.00, 0.00, 0.00, 1.00], + "SliderGrab": [0.50, 0.50, 0.50, 1.00], + "SliderGrabActive": [0.30, 0.30, 0.30, 1.00], + "Button": [0.82, 0.82, 0.82, 1.00], + "ButtonHovered": [0.90, 0.90, 0.90, 1.00], + "ButtonActive": [0.65, 0.65, 0.65, 1.00], + "Header": [0.70, 0.70, 0.70, 1.00], + "HeaderHovered": [0.80, 0.80, 0.80, 1.00], + "HeaderActive": [0.60, 0.60, 0.60, 1.00], + "Separator": [0.50, 0.50, 0.50, 1.00], + "SeparatorHovered": [0.30, 0.30, 0.30, 1.00], + "SeparatorActive": [0.20, 0.20, 0.20, 1.00], + "ResizeGrip": [0.50, 0.50, 0.50, 1.00], + "ResizeGripHovered": [0.60, 0.60, 0.60, 1.00], + "ResizeGripActive": [0.40, 0.40, 0.40, 1.00], + "Tab": [0.80, 0.80, 0.85, 1.00], + "TabHovered": [0.90, 0.90, 0.95, 1.00], + "TabActive": [0.70, 0.70, 0.90, 1.00], + "TabUnfocused": [0.85, 0.85, 0.85, 1.00], + "TabUnfocusedActive": [0.80, 0.80, 0.90, 1.00], + "DockingPreview": [0.20, 0.40, 0.70, 0.70], + "DockingEmptyBg": [0.90, 0.90, 0.90, 1.00], + "PlotLines": [0.20, 0.20, 0.20, 1.00], + "PlotLinesHovered": [0.00, 0.00, 0.00, 1.00], + "PlotHistogram": [0.25, 0.25, 0.25, 1.00], + "PlotHistogramHovered": [0.00, 0.00, 0.00, 1.00], + "TableHeaderBg": [0.80, 0.80, 0.80, 1.00], + "TableBorderStrong": [0.50, 0.50, 0.50, 1.00], + "TableBorderLight": [0.75, 0.75, 0.75, 1.00], + "TableRowBg": [1.00, 1.00, 1.00, 0.00], + "TableRowBgAlt": [0.90, 0.90, 0.90, 0.30], + "TextSelectedBg": [0.50, 0.50, 1.00, 0.35], + "DragDropTarget": [0.00, 0.00, 1.00, 0.90], + "NavHighlight": [0.00, 0.00, 1.00, 1.00], + "NavWindowingHighlight": [0.25, 0.25, 0.25, 0.70], + "NavWindowingDimBg": [0.80, 0.80, 0.80, 0.20], + "ModalWindowDimBg": [0.90, 0.90, 0.90, 0.60] + } + } + \ No newline at end of file diff --git a/editor/themes/dark.json b/editor/themes/dark.json new file mode 100644 index 000000000..f24573e0a --- /dev/null +++ b/editor/themes/dark.json @@ -0,0 +1,74 @@ +{ + "name": "Dark", + "style": { + "WindowPadding": [15.0, 15.0], + "WindowRounding": 5.0, + "FramePadding": [5.0, 5.0], + "FrameRounding": 4.0, + "ItemSpacing": [12.0, 6.0], + "ItemInnerSpacing": [8.0, 4.0], + "IndentSpacing": 25.0, + "ScrollbarSize": 15.0, + "ScrollbarRounding": 9.0, + "GrabMinSize": 5.0, + "GrabRounding": 3.0 + }, + "colors": { + "Text": [0.80, 0.80, 0.83, 1.00], + "TextDisabled": [0.24, 0.23, 0.29, 1.00], + "WindowBg": [0.05, 0.05, 0.07, 1.00], + "ChildBg": [0.07, 0.07, 0.09, 1.00], + "PopupBg": [0.14, 0.14, 0.14, 1.00], + "Border": [0.23, 0.23, 0.23, 1.00], + "BorderShadow": [0.68, 0.63, 0.63, 1.00], + "FrameBg": [0.10, 0.09, 0.12, 1.00], + "FrameBgHovered": [0.24, 0.23, 0.29, 1.00], + "FrameBgActive": [0.56, 0.56, 0.58, 1.00], + "TitleBg": [0.10, 0.09, 0.12, 1.00], + "TitleBgActive": [0.07, 0.07, 0.09, 1.00], + "TitleBgCollapsed": [1.00, 0.98, 0.95, 0.75], + "MenuBarBg": [0.10, 0.09, 0.12, 1.00], + "ScrollbarBg": [0.10, 0.09, 0.12, 1.00], + "ScrollbarGrab": [0.80, 0.80, 0.83, 0.31], + "ScrollbarGrabHovered": [0.56, 0.56, 0.58, 1.00], + "ScrollbarGrabActive": [0.06, 0.05, 0.07, 1.00], + "CheckMark": [0.20, 0.68, 0.42, 0.83], + "SliderGrab": [0.80, 0.80, 0.83, 0.31], + "SliderGrabActive": [0.06, 0.05, 0.07, 1.00], + "Button": [0.12, 0.43, 0.33, 0.88], + "ButtonHovered": [0.20, 0.68, 0.42, 0.83], + "ButtonActive": [0.56, 0.56, 0.58, 1.00], + "Header": [0.20, 0.68, 0.42, 0.58], + "HeaderHovered": [0.20, 0.68, 0.42, 0.83], + "HeaderActive": [0.06, 0.05, 0.07, 1.00], + "Separator": [0.43, 0.43, 0.50, 0.50], + "SeparatorHovered": [0.20, 0.68, 0.42, 0.83], + "SeparatorActive": [0.36, 0.75, 0.10, 1.00], + "ResizeGrip": [0.00, 0.00, 0.00, 0.00], + "ResizeGripHovered": [0.56, 0.56, 0.58, 1.00], + "ResizeGripActive": [0.06, 0.05, 0.07, 1.00], + "Tab": [0.18, 0.57, 0.58, 0.86], + "TabHovered": [0.20, 0.68, 0.42, 0.83], + "TabActive": [0.20, 0.68, 0.42, 1.00], + "TabUnfocused": [0.14, 0.41, 0.42, 0.46], + "TabUnfocusedActive": [0.14, 0.41, 0.42, 1.00], + "DockingPreview": [0.00, 1.00, 0.21, 0.70], + "DockingEmptyBg": [0.20, 0.20, 0.20, 1.00], + "PlotLines": [0.40, 0.39, 0.38, 0.63], + "PlotLinesHovered": [0.25, 1.00, 0.00, 1.00], + "PlotHistogram": [0.40, 0.39, 0.38, 0.63], + "PlotHistogramHovered": [0.25, 1.00, 0.00, 1.00], + "TableHeaderBg": [0.19, 0.19, 0.20, 1.00], + "TableBorderStrong": [0.31, 0.31, 0.35, 1.00], + "TableBorderLight": [0.23, 0.23, 0.25, 1.00], + "TableRowBg": [0.00, 0.00, 0.00, 0.00], + "TableRowBgAlt": [1.00, 1.00, 1.00, 0.06], + "TextSelectedBg": [0.25, 1.00, 0.00, 0.48], + "DragDropTarget": [1.00, 1.00, 0.00, 0.90], + "NavHighlight": [1.00, 1.00, 1.00, 1.00], + "NavWindowingHighlight": [1.00, 1.00, 1.00, 0.70], + "NavWindowingDimBg": [0.80, 0.80, 0.80, 0.20], + "ModalWindowDimBg": [1.00, 0.98, 0.95, 0.73] + } +} + \ No newline at end of file diff --git a/editor/themes/light.json b/editor/themes/light.json new file mode 100644 index 000000000..225118ea0 --- /dev/null +++ b/editor/themes/light.json @@ -0,0 +1,74 @@ +{ + "name": "Light", + "style": { + "WindowPadding": [15.0, 15.0], + "WindowRounding": 5.0, + "FramePadding": [5.0, 5.0], + "FrameRounding": 4.0, + "ItemSpacing": [12.0, 6.0], + "ItemInnerSpacing": [8.0, 4.0], + "IndentSpacing": 25.0, + "ScrollbarSize": 15.0, + "ScrollbarRounding": 9.0, + "GrabMinSize": 5.0, + "GrabRounding": 3.0 + }, + "colors": { + "Text": [0.10, 0.10, 0.10, 1.00], + "TextDisabled": [0.50, 0.50, 0.50, 1.00], + "WindowBg": [0.95, 0.96, 0.98, 1.00], + "ChildBg": [0.98, 0.98, 0.98, 1.00], + "PopupBg": [0.94, 0.94, 0.94, 1.00], + "Border": [0.70, 0.70, 0.70, 0.50], + "BorderShadow": [0.00, 0.00, 0.00, 0.00], + "FrameBg": [0.90, 0.90, 0.90, 1.00], + "FrameBgHovered": [0.75, 0.75, 0.75, 1.00], + "FrameBgActive": [0.65, 0.65, 0.65, 1.00], + "TitleBg": [0.86, 0.86, 0.90, 1.00], + "TitleBgActive": [0.75, 0.75, 0.80, 1.00], + "TitleBgCollapsed": [0.95, 0.95, 0.95, 0.50], + "MenuBarBg": [0.92, 0.92, 0.95, 1.00], + "ScrollbarBg": [0.95, 0.95, 0.96, 1.00], + "ScrollbarGrab": [0.75, 0.75, 0.80, 0.60], + "ScrollbarGrabHovered": [0.65, 0.65, 0.70, 0.80], + "ScrollbarGrabActive": [0.60, 0.60, 0.65, 1.00], + "CheckMark": [0.25, 0.50, 0.75, 1.00], + "SliderGrab": [0.60, 0.60, 0.70, 0.50], + "SliderGrabActive": [0.25, 0.50, 0.75, 1.00], + "Button": [0.75, 0.75, 0.85, 1.00], + "ButtonHovered": [0.85, 0.85, 0.95, 1.00], + "ButtonActive": [0.65, 0.65, 0.90, 1.00], + "Header": [0.80, 0.80, 0.90, 1.00], + "HeaderHovered": [0.85, 0.85, 0.95, 1.00], + "HeaderActive": [0.65, 0.65, 0.85, 1.00], + "Separator": [0.60, 0.60, 0.70, 1.00], + "SeparatorHovered": [0.30, 0.60, 0.90, 1.00], + "SeparatorActive": [0.10, 0.50, 0.80, 1.00], + "ResizeGrip": [0.90, 0.90, 0.90, 0.30], + "ResizeGripHovered": [0.60, 0.60, 0.70, 0.60], + "ResizeGripActive": [0.30, 0.60, 0.90, 1.00], + "Tab": [0.80, 0.80, 0.85, 1.00], + "TabHovered": [0.90, 0.90, 0.95, 1.00], + "TabActive": [0.70, 0.70, 0.90, 1.00], + "TabUnfocused": [0.92, 0.92, 0.92, 0.90], + "TabUnfocusedActive": [0.75, 0.75, 0.85, 1.00], + "DockingPreview": [0.30, 0.60, 0.90, 0.70], + "DockingEmptyBg": [0.94, 0.94, 0.94, 1.00], + "PlotLines": [0.35, 0.35, 0.35, 1.00], + "PlotLinesHovered": [0.25, 0.50, 0.75, 1.00], + "PlotHistogram": [0.30, 0.45, 0.60, 1.00], + "PlotHistogramHovered": [0.25, 0.50, 0.75, 1.00], + "TableHeaderBg": [0.85, 0.85, 0.90, 1.00], + "TableBorderStrong": [0.70, 0.70, 0.75, 1.00], + "TableBorderLight": [0.85, 0.85, 0.90, 1.00], + "TableRowBg": [1.00, 1.00, 1.00, 0.00], + "TableRowBgAlt": [0.95, 0.95, 0.95, 0.30], + "TextSelectedBg": [0.30, 0.60, 0.90, 0.50], + "DragDropTarget": [0.00, 0.60, 1.00, 0.90], + "NavHighlight": [0.30, 0.60, 0.90, 1.00], + "NavWindowingHighlight": [0.30, 0.60, 0.90, 0.70], + "NavWindowingDimBg": [0.80, 0.80, 0.80, 0.20], + "ModalWindowDimBg": [0.90, 0.90, 0.90, 0.60] + } + } + \ No newline at end of file diff --git a/editor/themes/theme.cpp b/editor/themes/theme.cpp new file mode 100644 index 000000000..5e2867f19 --- /dev/null +++ b/editor/themes/theme.cpp @@ -0,0 +1,130 @@ +#include "theme.h" + +void setVec2(const JSON::json& j, const char* key, ImVec2& ref) +{ + if (j.contains(key)) + { + if (j[key].is_array() && j[key].size() == 2) + { + ref = ImVec2(j[key][0], j[key][1]); + return; + } + WARN("Theme key: " + key + " is not a valid array of size 2"); + } +} + +void setFloat(const JSON::json& j, const char* key, float& ref) +{ + if (j.contains(key)) + { + if (j[key].is_number()) + { + ref = j[key].get(); + return; + } + WARN("Theme key: " + key + " is not a valid number"); + } +} + +void setColor(const JSON::json& j, const char* key, ImVec4& ref) +{ + if (j.contains(key)) + { + if (j[key].is_array() && j[key].size() == 4) + { + ref = ImVec4(j[key][0], j[key][1], j[key][2], j[key][3]); + return; + } + WARN("Theme key: " + key + " is not a valid array of size 4"); + } +} + +void ThemeDefinition::apply() const +{ + ImGui::StyleColorsDark(); // Base reset + + ImGuiStyle& style = ImGui::GetStyle(); + ImVec4* colors = style.Colors; + + if (!m_ThemeData.contains("style") && !m_ThemeData.contains("colors")) + { + return; + } + + if (m_ThemeData.contains("style")) + { + const auto& s = m_ThemeData["style"]; + setVec2(s, "WindowPadding", style.WindowPadding); + setFloat(s, "WindowRounding", style.WindowRounding); + setVec2(s, "FramePadding", style.FramePadding); + setFloat(s, "FrameRounding", style.FrameRounding); + setVec2(s, "ItemSpacing", style.ItemSpacing); + setVec2(s, "ItemInnerSpacing", style.ItemInnerSpacing); + setFloat(s, "IndentSpacing", style.IndentSpacing); + setFloat(s, "ScrollbarSize", style.ScrollbarSize); + setFloat(s, "ScrollbarRounding", style.ScrollbarRounding); + setFloat(s, "GrabMinSize", style.GrabMinSize); + setFloat(s, "GrabRounding", style.GrabRounding); + } + + if (m_ThemeData.contains("colors")) + { + const auto& c = m_ThemeData["colors"]; + + setColor(c, "Text", colors[ImGuiCol_Text]); + setColor(c, "TextDisabled", colors[ImGuiCol_TextDisabled]); + setColor(c, "WindowBg", colors[ImGuiCol_WindowBg]); + setColor(c, "ChildBg", colors[ImGuiCol_ChildBg]); + setColor(c, "PopupBg", colors[ImGuiCol_PopupBg]); + setColor(c, "Border", colors[ImGuiCol_Border]); + setColor(c, "BorderShadow", colors[ImGuiCol_BorderShadow]); + setColor(c, "FrameBg", colors[ImGuiCol_FrameBg]); + setColor(c, "FrameBgHovered", colors[ImGuiCol_FrameBgHovered]); + setColor(c, "FrameBgActive", colors[ImGuiCol_FrameBgActive]); + setColor(c, "TitleBg", colors[ImGuiCol_TitleBg]); + setColor(c, "TitleBgActive", colors[ImGuiCol_TitleBgActive]); + setColor(c, "TitleBgCollapsed", colors[ImGuiCol_TitleBgCollapsed]); + setColor(c, "MenuBarBg", colors[ImGuiCol_MenuBarBg]); + setColor(c, "ScrollbarBg", colors[ImGuiCol_ScrollbarBg]); + setColor(c, "ScrollbarGrab", colors[ImGuiCol_ScrollbarGrab]); + setColor(c, "ScrollbarGrabHovered", colors[ImGuiCol_ScrollbarGrabHovered]); + setColor(c, "ScrollbarGrabActive", colors[ImGuiCol_ScrollbarGrabActive]); + setColor(c, "CheckMark", colors[ImGuiCol_CheckMark]); + setColor(c, "SliderGrab", colors[ImGuiCol_SliderGrab]); + setColor(c, "SliderGrabActive", colors[ImGuiCol_SliderGrabActive]); + setColor(c, "Button", colors[ImGuiCol_Button]); + setColor(c, "ButtonHovered", colors[ImGuiCol_ButtonHovered]); + setColor(c, "ButtonActive", colors[ImGuiCol_ButtonActive]); + setColor(c, "Header", colors[ImGuiCol_Header]); + setColor(c, "HeaderHovered", colors[ImGuiCol_HeaderHovered]); + setColor(c, "HeaderActive", colors[ImGuiCol_HeaderActive]); + setColor(c, "Separator", colors[ImGuiCol_Separator]); + setColor(c, "SeparatorHovered", colors[ImGuiCol_SeparatorHovered]); + setColor(c, "SeparatorActive", colors[ImGuiCol_SeparatorActive]); + setColor(c, "ResizeGrip", colors[ImGuiCol_ResizeGrip]); + setColor(c, "ResizeGripHovered", colors[ImGuiCol_ResizeGripHovered]); + setColor(c, "ResizeGripActive", colors[ImGuiCol_ResizeGripActive]); + setColor(c, "Tab", colors[ImGuiCol_Tab]); + setColor(c, "TabHovered", colors[ImGuiCol_TabHovered]); + setColor(c, "TabActive", colors[ImGuiCol_TabActive]); + setColor(c, "TabUnfocused", colors[ImGuiCol_TabUnfocused]); + setColor(c, "TabUnfocusedActive", colors[ImGuiCol_TabUnfocusedActive]); + setColor(c, "DockingPreview", colors[ImGuiCol_DockingPreview]); + setColor(c, "DockingEmptyBg", colors[ImGuiCol_DockingEmptyBg]); + setColor(c, "PlotLines", colors[ImGuiCol_PlotLines]); + setColor(c, "PlotLinesHovered", colors[ImGuiCol_PlotLinesHovered]); + setColor(c, "PlotHistogram", colors[ImGuiCol_PlotHistogram]); + setColor(c, "PlotHistogramHovered", colors[ImGuiCol_PlotHistogramHovered]); + setColor(c, "TableHeaderBg", colors[ImGuiCol_TableHeaderBg]); + setColor(c, "TableBorderStrong", colors[ImGuiCol_TableBorderStrong]); + setColor(c, "TableBorderLight", colors[ImGuiCol_TableBorderLight]); + setColor(c, "TableRowBg", colors[ImGuiCol_TableRowBg]); + setColor(c, "TableRowBgAlt", colors[ImGuiCol_TableRowBgAlt]); + setColor(c, "TextSelectedBg", colors[ImGuiCol_TextSelectedBg]); + setColor(c, "DragDropTarget", colors[ImGuiCol_DragDropTarget]); + setColor(c, "NavHighlight", colors[ImGuiCol_NavHighlight]); + setColor(c, "NavWindowingHighlight", colors[ImGuiCol_NavWindowingHighlight]); + setColor(c, "NavWindowingDimBg", colors[ImGuiCol_NavWindowingDimBg]); + setColor(c, "ModalWindowDimBg", colors[ImGuiCol_ModalWindowDimBg]); + } +} diff --git a/editor/themes/theme.h b/editor/themes/theme.h new file mode 100644 index 000000000..5c713e234 --- /dev/null +++ b/editor/themes/theme.h @@ -0,0 +1,12 @@ +#pragma once + +#include "common/common.h" + +struct ThemeDefinition +{ + String m_Name; + String m_filePath; + JSON::json m_ThemeData; + + void apply() const; +};