mirror of
https://github.com/obsqrbtz/clrsync.git
synced 2026-04-08 20:19:04 +03:00
chore: split color_scheme_editor
This commit is contained in:
13
flake.nix
13
flake.nix
@@ -17,9 +17,10 @@
|
||||
baseVersion = nixpkgs.lib.removeSuffix "\n" (builtins.readFile ./VERSION);
|
||||
|
||||
semver =
|
||||
if self ? rev
|
||||
then "${baseVersion}+git.${builtins.substring 0 7 self.rev}"
|
||||
else "${baseVersion}+dev";
|
||||
if self ? rev then
|
||||
"${baseVersion}+git.${builtins.substring 0 7 self.rev}"
|
||||
else
|
||||
"${baseVersion}+dev";
|
||||
in
|
||||
{
|
||||
packages = forAllSystems (
|
||||
@@ -66,12 +67,12 @@
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgsFor.${system};
|
||||
clrsync = self.packages.${system}.clrsync;
|
||||
in
|
||||
{
|
||||
default = pkgs.mkShell {
|
||||
inputsFrom = [ self.packages.${system}.clrsync ];
|
||||
|
||||
buildInputs = with pkgs; [
|
||||
inputsFrom = [ clrsync ];
|
||||
packages = with pkgs; [
|
||||
cmake
|
||||
ninja
|
||||
clang-tools
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
#endif
|
||||
#include <iostream>
|
||||
|
||||
namespace clrsync::core
|
||||
{
|
||||
@@ -22,7 +23,8 @@ void config::initialize(std::unique_ptr<clrsync::core::io::file> file)
|
||||
{
|
||||
copy_default_configs();
|
||||
m_file = std::move(file);
|
||||
if (m_file)
|
||||
if (!m_file)
|
||||
throw std::runtime_error{"Config file is missing"};
|
||||
if (!m_file->parse())
|
||||
throw std::runtime_error{"Could not parse config file"};
|
||||
}
|
||||
@@ -62,13 +64,32 @@ void config::copy_file(const std::filesystem::path &src, const std::filesystem::
|
||||
if (std::filesystem::exists(dst))
|
||||
return;
|
||||
|
||||
if (!std::filesystem::exists(src))
|
||||
{
|
||||
std::cerr << "Warning: Source file does not exist: " << src << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::ifstream in(src, std::ios::binary);
|
||||
std::ofstream out(dst, std::ios::binary);
|
||||
|
||||
if (!in || !out)
|
||||
{
|
||||
std::cerr << "Warning: Failed to copy file from " << src << " to " << dst << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
out << in.rdbuf();
|
||||
}
|
||||
|
||||
void config::copy_dir(const std::filesystem::path &src, const std::filesystem::path &dst)
|
||||
{
|
||||
if (!std::filesystem::exists(src))
|
||||
{
|
||||
std::cerr << "Warning: Source directory does not exist: " << src << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto const &entry : std::filesystem::recursive_directory_iterator(src))
|
||||
{
|
||||
auto rel = std::filesystem::relative(entry.path(), src);
|
||||
@@ -92,6 +113,12 @@ void config::copy_default_configs()
|
||||
|
||||
std::filesystem::create_directories(user_dir);
|
||||
|
||||
if (system_dir.empty())
|
||||
{
|
||||
std::cerr << "Warning: No system data directory found, skipping default config copy\n";
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto src = system_dir / "config.toml";
|
||||
auto dst = user_dir / "config.toml";
|
||||
|
||||
@@ -47,12 +47,15 @@ void theme_template::load_template()
|
||||
{
|
||||
if (!std::filesystem::exists(m_template_path))
|
||||
{
|
||||
std::cerr << "Template file '" << m_template_path << "' is missing\n";
|
||||
std::cerr << "Warning: Template file '" << m_template_path << "' is missing\n";
|
||||
return;
|
||||
}
|
||||
std::ifstream input(m_template_path, std::ios::binary);
|
||||
if (!input)
|
||||
throw std::runtime_error("Failed to open template file: " + m_template_path);
|
||||
{
|
||||
std::cerr << "Warning: Failed to open template file: " << m_template_path << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
m_template_data.assign(std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>());
|
||||
}
|
||||
@@ -89,10 +92,22 @@ void theme_template::apply_palette(const core::palette &palette)
|
||||
|
||||
void theme_template::save_output() const
|
||||
{
|
||||
try
|
||||
{
|
||||
std::filesystem::create_directories(std::filesystem::path(m_output_path).parent_path());
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "Warning: Failed to create output directory for " << m_output_path << ": " << e.what() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::ofstream output(m_output_path, std::ios::binary);
|
||||
if (!output)
|
||||
throw std::runtime_error("Failed to write output file: " + m_output_path);
|
||||
{
|
||||
std::cerr << "Warning: Failed to write output file: " << m_output_path << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
output << m_processed_data;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ void print_color_keys()
|
||||
|
||||
std::string get_default_config_path()
|
||||
{
|
||||
const char* env_path = std::getenv("CLRSYNC_CONFIG_PATH");
|
||||
if (env_path && env_path[0] != '\0')
|
||||
return expand_user(env_path);
|
||||
|
||||
auto home = expand_user("~");
|
||||
#ifdef _WIN32
|
||||
return home + "\\.config\\clrsync\\config.toml";
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
namespace clrsync::core
|
||||
{
|
||||
|
||||
const std::string GIT_SEMVER = "0.1.4+git.gcd81744";
|
||||
const std::string GIT_SEMVER = "0.1.4+git.g659c5f2";
|
||||
|
||||
const std::string version_string();
|
||||
} // namespace clrsync::core
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
set(GUI_SOURCES
|
||||
main.cpp
|
||||
color_scheme_editor.cpp
|
||||
color_table_renderer.cpp
|
||||
preview_renderer.cpp
|
||||
theme_applier.cpp
|
||||
template_editor.cpp
|
||||
palette_controller.cpp
|
||||
template_controller.cpp
|
||||
|
||||
@@ -1,86 +1,18 @@
|
||||
#include "color_scheme_editor.hpp"
|
||||
#include "template_editor.hpp"
|
||||
#include "color_text_edit/TextEditor.h"
|
||||
#include "theme_applier.hpp"
|
||||
#include "imgui.h"
|
||||
#include <iostream>
|
||||
#include <ranges>
|
||||
|
||||
color_scheme_editor::color_scheme_editor()
|
||||
{
|
||||
m_editor.SetLanguageDefinition(TextEditor::LanguageDefinition::CPlusPlus());
|
||||
m_editor.SetText(R"(#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
// Expands ~ to the user's home directory
|
||||
std::string expand_user(const std::string &path)
|
||||
{
|
||||
if (path.empty()) return "";
|
||||
|
||||
std::string result;
|
||||
if (path[0] == '~')
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const char* home = std::getenv("USERPROFILE");
|
||||
#else
|
||||
const char* home = std::getenv("HOME");
|
||||
#endif
|
||||
result = home ? std::string(home) : "~";
|
||||
result += path.substr(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = path;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Lists all files in a directory
|
||||
std::vector<std::string> list_files(const std::string &dir_path)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
try
|
||||
{
|
||||
for (const auto &entry : fs::directory_iterator(dir_path))
|
||||
{
|
||||
if (entry.is_regular_file())
|
||||
files.push_back(entry.path().string());
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::string path = expand_user("~/Documents");
|
||||
std::cout << "Listing files in: " << path << std::endl;
|
||||
|
||||
auto files = list_files(path);
|
||||
for (const auto &f : files)
|
||||
std::cout << " " << f << std::endl;
|
||||
|
||||
return 0;
|
||||
})");
|
||||
|
||||
m_editor.SetShowWhitespaces(false);
|
||||
|
||||
const auto &palettes = m_controller.palettes();
|
||||
|
||||
const auto ¤t = m_controller.current_palette();
|
||||
|
||||
if (!current.colors().empty())
|
||||
{
|
||||
apply_palette_to_imgui();
|
||||
apply_palette_to_editor();
|
||||
theme_applier::apply_to_imgui(current);
|
||||
m_preview.apply_palette(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -96,6 +28,14 @@ void color_scheme_editor::notify_palette_changed()
|
||||
}
|
||||
}
|
||||
|
||||
void color_scheme_editor::apply_themes()
|
||||
{
|
||||
const auto ¤t = m_controller.current_palette();
|
||||
theme_applier::apply_to_imgui(current);
|
||||
m_preview.apply_palette(current);
|
||||
notify_palette_changed();
|
||||
}
|
||||
|
||||
void color_scheme_editor::render_controls_and_colors()
|
||||
{
|
||||
ImGui::Begin("Color Schemes");
|
||||
@@ -104,7 +44,8 @@ void color_scheme_editor::render_controls_and_colors()
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::BeginChild("ColorTableContent", ImVec2(0, 0), false);
|
||||
render_color_table();
|
||||
m_color_table.render(m_controller.current_palette(), m_controller,
|
||||
[this]() { apply_themes(); });
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::End();
|
||||
@@ -114,7 +55,7 @@ void color_scheme_editor::render_preview()
|
||||
{
|
||||
ImGui::Begin("Color Preview");
|
||||
|
||||
render_preview_content();
|
||||
m_preview.render(m_controller.current_palette());
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
@@ -137,9 +78,7 @@ void color_scheme_editor::render_controls()
|
||||
if (ImGui::Selectable(name.c_str(), selected))
|
||||
{
|
||||
m_controller.select_palette(name);
|
||||
apply_palette_to_imgui();
|
||||
apply_palette_to_editor();
|
||||
notify_palette_changed();
|
||||
apply_themes();
|
||||
}
|
||||
if (selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
@@ -169,10 +108,8 @@ void color_scheme_editor::render_controls()
|
||||
if (strlen(new_palette_name_buf) > 0)
|
||||
{
|
||||
m_controller.create_palette(new_palette_name_buf);
|
||||
apply_palette_to_imgui();
|
||||
apply_palette_to_editor();
|
||||
notify_palette_changed();
|
||||
m_controller.select_palette(new_palette_name_buf);
|
||||
apply_themes();
|
||||
new_palette_name_buf[0] = 0;
|
||||
}
|
||||
ImGui::CloseCurrentPopup();
|
||||
@@ -207,349 +144,3 @@ void color_scheme_editor::render_controls()
|
||||
m_controller.apply_current_theme();
|
||||
}
|
||||
}
|
||||
|
||||
void color_scheme_editor::render_color_table()
|
||||
{
|
||||
const auto ¤t = m_controller.current_palette();
|
||||
|
||||
if (current.colors().empty())
|
||||
{
|
||||
ImGui::Text("No palette loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::Text("Color Variables");
|
||||
ImGui::Separator();
|
||||
|
||||
auto render_color_row = [&](const std::string &name) {
|
||||
const auto &colors = current.colors();
|
||||
auto it = colors.find(name);
|
||||
if (it == colors.end())
|
||||
return;
|
||||
|
||||
const clrsync::core::color &col = it->second;
|
||||
|
||||
ImGui::TableNextRow();
|
||||
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
ImGui::TextUnformatted(name.c_str());
|
||||
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
{
|
||||
std::string hex_str = col.to_hex_string();
|
||||
char buf[9];
|
||||
strncpy(buf, hex_str.c_str(), sizeof(buf));
|
||||
buf[8] = 0;
|
||||
|
||||
ImGui::SetNextItemWidth(-FLT_MIN);
|
||||
if (ImGui::InputText(("##hex_" + name).c_str(), buf, sizeof(buf),
|
||||
ImGuiInputTextFlags_CharsUppercase))
|
||||
{
|
||||
try
|
||||
{
|
||||
clrsync::core::color new_color;
|
||||
new_color.from_hex_string(buf);
|
||||
m_controller.set_color(name, new_color);
|
||||
apply_palette_to_imgui();
|
||||
apply_palette_to_editor();
|
||||
notify_palette_changed();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
ImGui::PushID(name.c_str());
|
||||
float c[4] = {((col.hex() >> 24) & 0xFF) / 255.0f, ((col.hex() >> 16) & 0xFF) / 255.0f,
|
||||
((col.hex() >> 8) & 0xFF) / 255.0f, (col.hex() & 0xFF) / 255.0f};
|
||||
|
||||
ImGui::SetNextItemWidth(-FLT_MIN);
|
||||
if (ImGui::ColorEdit4(("##color_" + name).c_str(), c,
|
||||
ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel |
|
||||
ImGuiColorEditFlags_AlphaBar))
|
||||
{
|
||||
uint32_t r = (uint32_t)(c[0] * 255.0f);
|
||||
uint32_t g = (uint32_t)(c[1] * 255.0f);
|
||||
uint32_t b = (uint32_t)(c[2] * 255.0f);
|
||||
uint32_t a = (uint32_t)(c[3] * 255.0f);
|
||||
uint32_t hex = (r << 24) | (g << 16) | (b << 8) | a;
|
||||
|
||||
m_controller.set_color(name, clrsync::core::color(hex));
|
||||
apply_palette_to_imgui();
|
||||
apply_palette_to_editor();
|
||||
notify_palette_changed();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
};
|
||||
|
||||
auto draw_table = [&](const char *title, const std::vector<const char *> &keys) {
|
||||
ImGui::TextUnformatted(title);
|
||||
|
||||
if (ImGui::BeginTable(title, 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
|
||||
{
|
||||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 160.0f);
|
||||
ImGui::TableSetupColumn("HEX", ImGuiTableColumnFlags_WidthFixed, 90.0f);
|
||||
ImGui::TableSetupColumn("Preview", ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (auto *k : keys)
|
||||
render_color_row(k);
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
};
|
||||
|
||||
draw_table("General UI", {"background", "on_background", "surface", "on_surface",
|
||||
"surface_variant", "on_surface_variant", "foreground",
|
||||
"cursor", "accent"});
|
||||
|
||||
draw_table("Borders", {"border_focused", "border"});
|
||||
|
||||
draw_table("Semantic Colors", {"success", "info", "warning", "error",
|
||||
"on_success", "on_info", "on_warning", "on_error"});
|
||||
|
||||
draw_table("Editor", {"editor_background", "editor_command", "editor_comment",
|
||||
"editor_disabled", "editor_emphasis", "editor_error",
|
||||
"editor_inactive", "editor_line_number", "editor_link",
|
||||
"editor_main", "editor_selected", "editor_selection_inactive",
|
||||
"editor_string", "editor_success", "editor_warning"});
|
||||
|
||||
draw_table("Terminal (Base16)", {"base00", "base01", "base02", "base03",
|
||||
"base04", "base05", "base06", "base07",
|
||||
"base08", "base09", "base0A", "base0B",
|
||||
"base0C", "base0D", "base0E", "base0F"});
|
||||
}
|
||||
|
||||
void color_scheme_editor::render_preview_content()
|
||||
{
|
||||
const auto ¤t = m_controller.current_palette();
|
||||
|
||||
if (current.colors().empty())
|
||||
{
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f), "Current palette is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
auto get_color = [&](const std::string &key) -> ImVec4 {
|
||||
auto it = current.colors().find(key);
|
||||
if (it != current.colors().end())
|
||||
{
|
||||
const auto &col = it->second;
|
||||
const uint32_t hex = col.hex();
|
||||
return {((hex >> 24) & 0xFF) / 255.0f, ((hex >> 16) & 0xFF) / 255.0f,
|
||||
((hex >> 8) & 0xFF) / 255.0f, ((hex) & 0xFF) / 255.0f};
|
||||
}
|
||||
return {1, 1, 1, 1};
|
||||
};
|
||||
|
||||
const ImVec4 editor_bg = get_color("editor_background");
|
||||
const ImVec4 fg = get_color("foreground");
|
||||
const ImVec4 accent = get_color("accent");
|
||||
const ImVec4 border = get_color("border");
|
||||
const ImVec4 error = get_color("error");
|
||||
const ImVec4 warning = get_color("warning");
|
||||
const ImVec4 success = get_color("success");
|
||||
const ImVec4 info = get_color("info");
|
||||
|
||||
const float avail_height = ImGui::GetContentRegionAvail().y;
|
||||
const float code_preview_height = std::max(250.0f, avail_height * 0.55f);
|
||||
|
||||
ImGui::Text("Code Editor:");
|
||||
|
||||
m_editor.Render("##CodeEditor", ImVec2(0, code_preview_height), true);
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Text("Terminal Preview:");
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, editor_bg);
|
||||
ImGui::BeginChild("TerminalPreview", ImVec2(0, 0), true);
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, border);
|
||||
|
||||
struct term_line
|
||||
{
|
||||
const char *text{};
|
||||
ImVec4 col;
|
||||
};
|
||||
term_line term_lines[] = {
|
||||
{"$ ls -la", fg},
|
||||
{"drwxr-xr-x 5 user group 4096 Dec 2 10:30 .", accent},
|
||||
{"Build successful", success},
|
||||
{"Error: file not found", error},
|
||||
{"Warning: low disk space", warning},
|
||||
{"Info: update available", info},
|
||||
};
|
||||
|
||||
for (auto &[text, col] : term_lines)
|
||||
{
|
||||
ImGui::TextColored(col, "%s", text);
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
void color_scheme_editor::apply_palette_to_editor()
|
||||
{
|
||||
const auto ¤t = m_controller.current_palette();
|
||||
if (current.colors().empty())
|
||||
return;
|
||||
|
||||
auto get_color_u32 = [&](const std::string &key, const std::string &fallback = "") -> uint32_t {
|
||||
auto it = current.colors().find(key);
|
||||
if (it == current.colors().end() && !fallback.empty())
|
||||
{
|
||||
it = current.colors().find(fallback);
|
||||
}
|
||||
|
||||
if (it != current.colors().end())
|
||||
{
|
||||
const auto &col = it->second;
|
||||
const uint32_t hex = col.hex();
|
||||
// Convert from RRGGBBAA to AABBGGRR (ImGui format)
|
||||
const uint32_t r = (hex >> 24) & 0xFF;
|
||||
const uint32_t g = (hex >> 16) & 0xFF;
|
||||
const uint32_t b = (hex >> 8) & 0xFF;
|
||||
const uint32_t a = hex & 0xFF;
|
||||
return (a << 24) | (b << 16) | (g << 8) | r;
|
||||
}
|
||||
return 0xFFFFFFFF;
|
||||
};
|
||||
|
||||
auto palette = m_editor.GetPalette();
|
||||
|
||||
palette[int(TextEditor::PaletteIndex::Default)] = get_color_u32("editor_main");
|
||||
palette[int(TextEditor::PaletteIndex::Keyword)] = get_color_u32("editor_command");
|
||||
palette[int(TextEditor::PaletteIndex::Number)] = get_color_u32("editor_warning");
|
||||
palette[int(TextEditor::PaletteIndex::String)] = get_color_u32("editor_string");
|
||||
palette[int(TextEditor::PaletteIndex::CharLiteral)] = get_color_u32("editor_string");
|
||||
palette[int(TextEditor::PaletteIndex::Punctuation)] = get_color_u32("editor_main");
|
||||
palette[int(TextEditor::PaletteIndex::Preprocessor)] = get_color_u32("editor_emphasis");
|
||||
palette[int(TextEditor::PaletteIndex::Identifier)] = get_color_u32("editor_main");
|
||||
palette[int(TextEditor::PaletteIndex::KnownIdentifier)] = get_color_u32("editor_link");
|
||||
palette[int(TextEditor::PaletteIndex::PreprocIdentifier)] = get_color_u32("editor_link");
|
||||
|
||||
palette[int(TextEditor::PaletteIndex::Comment)] = get_color_u32("editor_comment");
|
||||
palette[int(TextEditor::PaletteIndex::MultiLineComment)] = get_color_u32("editor_comment");
|
||||
|
||||
palette[int(TextEditor::PaletteIndex::Background)] = get_color_u32("editor_background");
|
||||
palette[int(TextEditor::PaletteIndex::Cursor)] = get_color_u32("cursor");
|
||||
|
||||
palette[int(TextEditor::PaletteIndex::Selection)] = get_color_u32("editor_selected");
|
||||
palette[int(TextEditor::PaletteIndex::ErrorMarker)] = get_color_u32("editor_error");
|
||||
palette[int(TextEditor::PaletteIndex::Breakpoint)] = get_color_u32("editor_error");
|
||||
|
||||
palette[int(TextEditor::PaletteIndex::LineNumber)] = get_color_u32("editor_line_number");
|
||||
palette[int(TextEditor::PaletteIndex::CurrentLineFill)] = get_color_u32("surface_variant");
|
||||
palette[int(TextEditor::PaletteIndex::CurrentLineFillInactive)] = get_color_u32("surface");
|
||||
|
||||
palette[int(TextEditor::PaletteIndex::CurrentLineEdge)] = get_color_u32("border_focused");
|
||||
|
||||
m_editor.SetPalette(palette);
|
||||
}
|
||||
|
||||
void color_scheme_editor::apply_palette_to_imgui() const
|
||||
{
|
||||
const auto ¤t = m_controller.current_palette();
|
||||
|
||||
if (current.colors().empty())
|
||||
return;
|
||||
|
||||
auto getColor = [&](const std::string &key, const std::string &fallback = "") -> ImVec4 {
|
||||
auto it = current.colors().find(key);
|
||||
if (it == current.colors().end() && !fallback.empty())
|
||||
{
|
||||
it = current.colors().find(fallback);
|
||||
}
|
||||
|
||||
if (it != current.colors().end())
|
||||
{
|
||||
const uint32_t hex = it->second.hex();
|
||||
return {((hex >> 24) & 0xFF) / 255.0f, ((hex >> 16) & 0xFF) / 255.0f,
|
||||
((hex >> 8) & 0xFF) / 255.0f, ((hex) & 0xFF) / 255.0f};
|
||||
}
|
||||
|
||||
std::cout << "WARNING: Color key '" << key << "' not found!\n";
|
||||
return {1, 1, 1, 1};
|
||||
};
|
||||
|
||||
ImGuiStyle &style = ImGui::GetStyle();
|
||||
|
||||
const ImVec4 bg = getColor("background");
|
||||
const ImVec4 surface = getColor("surface");
|
||||
const ImVec4 surfaceVariant = getColor("surface_variant");
|
||||
const ImVec4 fg = getColor("foreground");
|
||||
const ImVec4 fgInactive = getColor("editor_inactive");
|
||||
const ImVec4 accent = getColor("accent");
|
||||
const ImVec4 border = getColor("border");
|
||||
|
||||
style.Colors[ImGuiCol_WindowBg] = bg;
|
||||
style.Colors[ImGuiCol_ChildBg] = surface;
|
||||
style.Colors[ImGuiCol_PopupBg] = surface;
|
||||
|
||||
style.Colors[ImGuiCol_Border] = border;
|
||||
style.Colors[ImGuiCol_BorderShadow] = ImVec4(0, 0, 0, 0);
|
||||
|
||||
style.Colors[ImGuiCol_Text] = fg;
|
||||
style.Colors[ImGuiCol_TextDisabled] = fgInactive;
|
||||
|
||||
style.Colors[ImGuiCol_Header] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(accent.x, accent.y, accent.z, 0.8f);
|
||||
style.Colors[ImGuiCol_HeaderActive] = accent;
|
||||
|
||||
style.Colors[ImGuiCol_Button] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(accent.x, accent.y, accent.z, 0.6f);
|
||||
style.Colors[ImGuiCol_ButtonActive] = accent;
|
||||
|
||||
style.Colors[ImGuiCol_FrameBg] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_FrameBgHovered] =
|
||||
ImVec4(surfaceVariant.x * 1.1f, surfaceVariant.y * 1.1f, surfaceVariant.z * 1.1f, 1.0f);
|
||||
style.Colors[ImGuiCol_FrameBgActive] =
|
||||
ImVec4(surfaceVariant.x * 1.2f, surfaceVariant.y * 1.2f, surfaceVariant.z * 1.2f, 1.0f);
|
||||
|
||||
style.Colors[ImGuiCol_TitleBg] = surface;
|
||||
style.Colors[ImGuiCol_TitleBgActive] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_TitleBgCollapsed] = surface;
|
||||
|
||||
style.Colors[ImGuiCol_ScrollbarBg] = surface;
|
||||
style.Colors[ImGuiCol_ScrollbarGrab] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(accent.x, accent.y, accent.z, 0.6f);
|
||||
style.Colors[ImGuiCol_ScrollbarGrabActive] = accent;
|
||||
|
||||
style.Colors[ImGuiCol_SliderGrab] = accent;
|
||||
style.Colors[ImGuiCol_SliderGrabActive] =
|
||||
ImVec4(accent.x * 1.2f, accent.y * 1.2f, accent.z * 1.2f, 1.0f);
|
||||
|
||||
style.Colors[ImGuiCol_CheckMark] = accent;
|
||||
style.Colors[ImGuiCol_ResizeGrip] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(accent.x, accent.y, accent.z, 0.6f);
|
||||
style.Colors[ImGuiCol_ResizeGripActive] = accent;
|
||||
|
||||
style.Colors[ImGuiCol_Tab] = surface;
|
||||
style.Colors[ImGuiCol_TabHovered] = ImVec4(accent.x, accent.y, accent.z, 0.8f);
|
||||
style.Colors[ImGuiCol_TabActive] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_TabUnfocused] = surface;
|
||||
style.Colors[ImGuiCol_TabUnfocusedActive] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_TabSelectedOverline] = accent;
|
||||
|
||||
style.Colors[ImGuiCol_TableHeaderBg] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_TableBorderStrong] = border;
|
||||
style.Colors[ImGuiCol_TableBorderLight] =
|
||||
ImVec4(border.x * 0.7f, border.y * 0.7f, border.z * 0.7f, border.w);
|
||||
|
||||
style.Colors[ImGuiCol_TableRowBg] = ImVec4(0, 0, 0, 0);
|
||||
style.Colors[ImGuiCol_TableRowBgAlt] = ImVec4(fg.x, fg.y, fg.z, 0.06f);
|
||||
|
||||
style.Colors[ImGuiCol_Separator] = border;
|
||||
style.Colors[ImGuiCol_SeparatorHovered] = accent;
|
||||
style.Colors[ImGuiCol_SeparatorActive] = accent;
|
||||
|
||||
style.Colors[ImGuiCol_MenuBarBg] = surface;
|
||||
|
||||
style.Colors[ImGuiCol_DockingPreview] = ImVec4(accent.x, accent.y, accent.z, 0.7f);
|
||||
style.Colors[ImGuiCol_DockingEmptyBg] = bg;
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
#ifndef CLRSYNC_GUI_COLOR_SCHEME_EDITOR_HPP
|
||||
#define CLRSYNC_GUI_COLOR_SCHEME_EDITOR_HPP
|
||||
|
||||
#include "color_text_edit/TextEditor.h"
|
||||
#include "palette_controller.hpp"
|
||||
#include "color_table_renderer.hpp"
|
||||
#include "preview_renderer.hpp"
|
||||
|
||||
class template_editor;
|
||||
|
||||
@@ -18,15 +19,12 @@ public:
|
||||
|
||||
private:
|
||||
void render_controls();
|
||||
void render_color_table();
|
||||
void render_preview_content();
|
||||
|
||||
void apply_palette_to_editor();
|
||||
void apply_palette_to_imgui() const;
|
||||
void apply_themes();
|
||||
void notify_palette_changed();
|
||||
|
||||
palette_controller m_controller;
|
||||
TextEditor m_editor;
|
||||
color_table_renderer m_color_table;
|
||||
preview_renderer m_preview;
|
||||
template_editor* m_template_editor{nullptr};
|
||||
};
|
||||
|
||||
|
||||
122
src/gui/color_table_renderer.cpp
Normal file
122
src/gui/color_table_renderer.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
#include "color_table_renderer.hpp"
|
||||
#include "imgui.h"
|
||||
#include <vector>
|
||||
|
||||
void color_table_renderer::render_color_row(const std::string &name,
|
||||
const clrsync::core::palette& current,
|
||||
palette_controller& controller,
|
||||
const OnColorChangedCallback& on_changed)
|
||||
{
|
||||
const auto &colors = current.colors();
|
||||
auto it = colors.find(name);
|
||||
if (it == colors.end())
|
||||
return;
|
||||
|
||||
const clrsync::core::color &col = it->second;
|
||||
|
||||
ImGui::TableNextRow();
|
||||
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
ImGui::TextUnformatted(name.c_str());
|
||||
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
{
|
||||
std::string hex_str = col.to_hex_string();
|
||||
char buf[9];
|
||||
strncpy(buf, hex_str.c_str(), sizeof(buf));
|
||||
buf[8] = 0;
|
||||
|
||||
ImGui::SetNextItemWidth(-FLT_MIN);
|
||||
if (ImGui::InputText(("##hex_" + name).c_str(), buf, sizeof(buf),
|
||||
ImGuiInputTextFlags_CharsUppercase))
|
||||
{
|
||||
try
|
||||
{
|
||||
clrsync::core::color new_color;
|
||||
new_color.from_hex_string(buf);
|
||||
controller.set_color(name, new_color);
|
||||
if (on_changed)
|
||||
on_changed();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
ImGui::PushID(name.c_str());
|
||||
float c[4] = {((col.hex() >> 24) & 0xFF) / 255.0f, ((col.hex() >> 16) & 0xFF) / 255.0f,
|
||||
((col.hex() >> 8) & 0xFF) / 255.0f, (col.hex() & 0xFF) / 255.0f};
|
||||
|
||||
ImGui::SetNextItemWidth(-FLT_MIN);
|
||||
if (ImGui::ColorEdit4(("##color_" + name).c_str(), c,
|
||||
ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel |
|
||||
ImGuiColorEditFlags_AlphaBar))
|
||||
{
|
||||
uint32_t r = (uint32_t)(c[0] * 255.0f);
|
||||
uint32_t g = (uint32_t)(c[1] * 255.0f);
|
||||
uint32_t b = (uint32_t)(c[2] * 255.0f);
|
||||
uint32_t a = (uint32_t)(c[3] * 255.0f);
|
||||
uint32_t hex = (r << 24) | (g << 16) | (b << 8) | a;
|
||||
|
||||
controller.set_color(name, clrsync::core::color(hex));
|
||||
if (on_changed)
|
||||
on_changed();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
void color_table_renderer::render(const clrsync::core::palette& current,
|
||||
palette_controller& controller,
|
||||
const OnColorChangedCallback& on_changed)
|
||||
{
|
||||
if (current.colors().empty())
|
||||
{
|
||||
ImGui::Text("No palette loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::Text("Color Variables");
|
||||
ImGui::Separator();
|
||||
|
||||
auto draw_table = [&](const char *title, const std::vector<const char *> &keys) {
|
||||
ImGui::TextUnformatted(title);
|
||||
|
||||
if (ImGui::BeginTable(title, 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
|
||||
{
|
||||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 160.0f);
|
||||
ImGui::TableSetupColumn("HEX", ImGuiTableColumnFlags_WidthFixed, 90.0f);
|
||||
ImGui::TableSetupColumn("Preview", ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (auto *k : keys)
|
||||
render_color_row(k, current, controller, on_changed);
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
};
|
||||
|
||||
draw_table("General UI", {"background", "on_background", "surface", "on_surface",
|
||||
"surface_variant", "on_surface_variant", "foreground",
|
||||
"cursor", "accent"});
|
||||
|
||||
draw_table("Borders", {"border_focused", "border"});
|
||||
|
||||
draw_table("Semantic Colors", {"success", "info", "warning", "error",
|
||||
"on_success", "on_info", "on_warning", "on_error"});
|
||||
|
||||
draw_table("Editor", {"editor_background", "editor_command", "editor_comment",
|
||||
"editor_disabled", "editor_emphasis", "editor_error",
|
||||
"editor_inactive", "editor_line_number", "editor_link",
|
||||
"editor_main", "editor_selected", "editor_selection_inactive",
|
||||
"editor_string", "editor_success", "editor_warning"});
|
||||
|
||||
draw_table("Terminal (Base16)", {"base00", "base01", "base02", "base03",
|
||||
"base04", "base05", "base06", "base07",
|
||||
"base08", "base09", "base0A", "base0B",
|
||||
"base0C", "base0D", "base0E", "base0F"});
|
||||
}
|
||||
24
src/gui/color_table_renderer.hpp
Normal file
24
src/gui/color_table_renderer.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef CLRSYNC_GUI_COLOR_TABLE_RENDERER_HPP
|
||||
#define CLRSYNC_GUI_COLOR_TABLE_RENDERER_HPP
|
||||
|
||||
#include "core/palette/palette.hpp"
|
||||
#include "palette_controller.hpp"
|
||||
#include <functional>
|
||||
|
||||
class color_table_renderer
|
||||
{
|
||||
public:
|
||||
using OnColorChangedCallback = std::function<void()>;
|
||||
|
||||
void render(const clrsync::core::palette& palette,
|
||||
palette_controller& controller,
|
||||
const OnColorChangedCallback& on_changed);
|
||||
|
||||
private:
|
||||
void render_color_row(const std::string& name,
|
||||
const clrsync::core::palette& palette,
|
||||
palette_controller& controller,
|
||||
const OnColorChangedCallback& on_changed);
|
||||
};
|
||||
|
||||
#endif // CLRSYNC_GUI_COLOR_TABLE_RENDERER_HPP
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "GLFW/glfw3.h"
|
||||
@@ -11,14 +12,26 @@
|
||||
|
||||
GLFWwindow * init_glfw()
|
||||
{
|
||||
if (!glfwInit()) return nullptr;
|
||||
glfwSetErrorCallback([](int error, const char* description) {
|
||||
std::cerr << "GLFW Error " << error << ": " << description << std::endl;
|
||||
});
|
||||
|
||||
if (!glfwInit())
|
||||
{
|
||||
std::cerr << "Failed to initialize GLFW\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
|
||||
|
||||
GLFWwindow* w = glfwCreateWindow(1280, 720, "clrsync", nullptr, nullptr);
|
||||
if (!w) return nullptr;
|
||||
if (!w)
|
||||
{
|
||||
std::cerr << "Failed to create GLFW window\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(w);
|
||||
glfwSwapInterval(1);
|
||||
|
||||
@@ -20,7 +20,17 @@ int main(int, char**)
|
||||
{
|
||||
auto config_path = clrsync::core::get_default_config_path();
|
||||
auto conf = std::make_unique<clrsync::core::io::toml_file>(config_path);
|
||||
|
||||
try
|
||||
{
|
||||
clrsync::core::config::instance().initialize(std::move(conf));
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "Fatal error: " << e.what() << std::endl;
|
||||
std::cerr << "Hint: Set CLRSYNC_CONFIG_PATH environment variable or ensure config exists at: " << config_path << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::filesystem::path base = config_path;
|
||||
static std::string ini_path = (base.parent_path() / "layout.ini").string();
|
||||
|
||||
152
src/gui/preview_renderer.cpp
Normal file
152
src/gui/preview_renderer.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
#include "preview_renderer.hpp"
|
||||
#include "theme_applier.hpp"
|
||||
#include "imgui.h"
|
||||
#include <algorithm>
|
||||
|
||||
preview_renderer::preview_renderer()
|
||||
{
|
||||
m_editor.SetLanguageDefinition(TextEditor::LanguageDefinition::CPlusPlus());
|
||||
m_editor.SetText(R"(#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
// Expands ~ to the user's home directory
|
||||
std::string expand_user(const std::string &path)
|
||||
{
|
||||
if (path.empty()) return "";
|
||||
|
||||
std::string result;
|
||||
if (path[0] == '~')
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const char* home = std::getenv("USERPROFILE");
|
||||
#else
|
||||
const char* home = std::getenv("HOME");
|
||||
#endif
|
||||
result = home ? std::string(home) : "~";
|
||||
result += path.substr(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = path;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Lists all files in a directory
|
||||
std::vector<std::string> list_files(const std::string &dir_path)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
try
|
||||
{
|
||||
for (const auto &entry : fs::directory_iterator(dir_path))
|
||||
{
|
||||
if (entry.is_regular_file())
|
||||
files.push_back(entry.path().string());
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::string path = expand_user("~/Documents");
|
||||
std::cout << "Listing files in: " << path << std::endl;
|
||||
|
||||
auto files = list_files(path);
|
||||
for (const auto &f : files)
|
||||
std::cout << " " << f << std::endl;
|
||||
|
||||
return 0;
|
||||
})");
|
||||
|
||||
m_editor.SetShowWhitespaces(false);
|
||||
}
|
||||
|
||||
void preview_renderer::apply_palette(const clrsync::core::palette& palette)
|
||||
{
|
||||
theme_applier::apply_to_editor(m_editor, palette);
|
||||
}
|
||||
|
||||
void preview_renderer::render_code_preview()
|
||||
{
|
||||
const float avail_height = ImGui::GetContentRegionAvail().y;
|
||||
const float code_preview_height = std::max(250.0f, avail_height * 0.55f);
|
||||
|
||||
ImGui::Text("Code Editor:");
|
||||
m_editor.Render("##CodeEditor", ImVec2(0, code_preview_height), true);
|
||||
}
|
||||
|
||||
void preview_renderer::render_terminal_preview(const clrsync::core::palette& current)
|
||||
{
|
||||
auto get_color = [&](const std::string &key) -> ImVec4 {
|
||||
auto it = current.colors().find(key);
|
||||
if (it != current.colors().end())
|
||||
{
|
||||
const auto &col = it->second;
|
||||
const uint32_t hex = col.hex();
|
||||
return {((hex >> 24) & 0xFF) / 255.0f, ((hex >> 16) & 0xFF) / 255.0f,
|
||||
((hex >> 8) & 0xFF) / 255.0f, ((hex) & 0xFF) / 255.0f};
|
||||
}
|
||||
return {1, 1, 1, 1};
|
||||
};
|
||||
|
||||
const ImVec4 editor_bg = get_color("editor_background");
|
||||
const ImVec4 fg = get_color("foreground");
|
||||
const ImVec4 accent = get_color("accent");
|
||||
const ImVec4 border = get_color("border");
|
||||
const ImVec4 error = get_color("error");
|
||||
const ImVec4 warning = get_color("warning");
|
||||
const ImVec4 success = get_color("success");
|
||||
const ImVec4 info = get_color("info");
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Text("Terminal Preview:");
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, editor_bg);
|
||||
ImGui::BeginChild("TerminalPreview", ImVec2(0, 0), true);
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, border);
|
||||
|
||||
struct term_line
|
||||
{
|
||||
const char *text{};
|
||||
ImVec4 col;
|
||||
};
|
||||
term_line term_lines[] = {
|
||||
{"$ ls -la", fg},
|
||||
{"drwxr-xr-x 5 user group 4096 Dec 2 10:30 .", accent},
|
||||
{"Build successful", success},
|
||||
{"Error: file not found", error},
|
||||
{"Warning: low disk space", warning},
|
||||
{"Info: update available", info},
|
||||
};
|
||||
|
||||
for (auto &[text, col] : term_lines)
|
||||
{
|
||||
ImGui::TextColored(col, "%s", text);
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
void preview_renderer::render(const clrsync::core::palette& current)
|
||||
{
|
||||
if (current.colors().empty())
|
||||
{
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f), "Current palette is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
render_code_preview();
|
||||
render_terminal_preview(current);
|
||||
}
|
||||
22
src/gui/preview_renderer.hpp
Normal file
22
src/gui/preview_renderer.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef CLRSYNC_GUI_PREVIEW_RENDERER_HPP
|
||||
#define CLRSYNC_GUI_PREVIEW_RENDERER_HPP
|
||||
|
||||
#include "core/palette/palette.hpp"
|
||||
#include "color_text_edit/TextEditor.h"
|
||||
|
||||
class preview_renderer
|
||||
{
|
||||
public:
|
||||
preview_renderer();
|
||||
|
||||
void render(const clrsync::core::palette& palette);
|
||||
void apply_palette(const clrsync::core::palette& palette);
|
||||
|
||||
private:
|
||||
void render_code_preview();
|
||||
void render_terminal_preview(const clrsync::core::palette& palette);
|
||||
|
||||
TextEditor m_editor;
|
||||
};
|
||||
|
||||
#endif // CLRSYNC_GUI_PREVIEW_RENDERER_HPP
|
||||
@@ -369,11 +369,14 @@ void template_editor::save_template()
|
||||
std::string template_content = m_editor.GetText();
|
||||
|
||||
std::ofstream out(template_file);
|
||||
if (out.is_open())
|
||||
if (!out.is_open())
|
||||
{
|
||||
m_validation_error = "Failed to write template file";
|
||||
return;
|
||||
}
|
||||
|
||||
out << template_content;
|
||||
out.close();
|
||||
}
|
||||
|
||||
clrsync::core::theme_template tmpl(trimmed_name, template_file.string(), trimmed_path);
|
||||
tmpl.set_reload_command(m_reload_command);
|
||||
|
||||
166
src/gui/theme_applier.cpp
Normal file
166
src/gui/theme_applier.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
#include "theme_applier.hpp"
|
||||
#include "imgui.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace theme_applier
|
||||
{
|
||||
|
||||
void apply_to_editor(TextEditor& editor, const clrsync::core::palette& current)
|
||||
{
|
||||
if (current.colors().empty())
|
||||
return;
|
||||
|
||||
auto get_color_u32 = [&](const std::string &key, const std::string &fallback = "") -> uint32_t {
|
||||
auto it = current.colors().find(key);
|
||||
if (it == current.colors().end() && !fallback.empty())
|
||||
{
|
||||
it = current.colors().find(fallback);
|
||||
}
|
||||
|
||||
if (it != current.colors().end())
|
||||
{
|
||||
const auto &col = it->second;
|
||||
const uint32_t hex = col.hex();
|
||||
// Convert from RRGGBBAA to AABBGGRR (ImGui format)
|
||||
const uint32_t r = (hex >> 24) & 0xFF;
|
||||
const uint32_t g = (hex >> 16) & 0xFF;
|
||||
const uint32_t b = (hex >> 8) & 0xFF;
|
||||
const uint32_t a = hex & 0xFF;
|
||||
return (a << 24) | (b << 16) | (g << 8) | r;
|
||||
}
|
||||
return 0xFFFFFFFF;
|
||||
};
|
||||
|
||||
auto palette = editor.GetPalette();
|
||||
|
||||
palette[int(TextEditor::PaletteIndex::Default)] = get_color_u32("editor_main");
|
||||
palette[int(TextEditor::PaletteIndex::Keyword)] = get_color_u32("editor_command");
|
||||
palette[int(TextEditor::PaletteIndex::Number)] = get_color_u32("editor_warning");
|
||||
palette[int(TextEditor::PaletteIndex::String)] = get_color_u32("editor_string");
|
||||
palette[int(TextEditor::PaletteIndex::CharLiteral)] = get_color_u32("editor_string");
|
||||
palette[int(TextEditor::PaletteIndex::Punctuation)] = get_color_u32("editor_main");
|
||||
palette[int(TextEditor::PaletteIndex::Preprocessor)] = get_color_u32("editor_emphasis");
|
||||
palette[int(TextEditor::PaletteIndex::Identifier)] = get_color_u32("editor_main");
|
||||
palette[int(TextEditor::PaletteIndex::KnownIdentifier)] = get_color_u32("editor_link");
|
||||
palette[int(TextEditor::PaletteIndex::PreprocIdentifier)] = get_color_u32("editor_link");
|
||||
|
||||
palette[int(TextEditor::PaletteIndex::Comment)] = get_color_u32("editor_comment");
|
||||
palette[int(TextEditor::PaletteIndex::MultiLineComment)] = get_color_u32("editor_comment");
|
||||
|
||||
palette[int(TextEditor::PaletteIndex::Background)] = get_color_u32("editor_background");
|
||||
palette[int(TextEditor::PaletteIndex::Cursor)] = get_color_u32("cursor");
|
||||
|
||||
palette[int(TextEditor::PaletteIndex::Selection)] = get_color_u32("editor_selected");
|
||||
palette[int(TextEditor::PaletteIndex::ErrorMarker)] = get_color_u32("editor_error");
|
||||
palette[int(TextEditor::PaletteIndex::Breakpoint)] = get_color_u32("editor_error");
|
||||
|
||||
palette[int(TextEditor::PaletteIndex::LineNumber)] = get_color_u32("editor_line_number");
|
||||
palette[int(TextEditor::PaletteIndex::CurrentLineFill)] = get_color_u32("surface_variant");
|
||||
palette[int(TextEditor::PaletteIndex::CurrentLineFillInactive)] = get_color_u32("surface");
|
||||
|
||||
palette[int(TextEditor::PaletteIndex::CurrentLineEdge)] = get_color_u32("border_focused");
|
||||
|
||||
editor.SetPalette(palette);
|
||||
}
|
||||
|
||||
void apply_to_imgui(const clrsync::core::palette& current)
|
||||
{
|
||||
if (current.colors().empty())
|
||||
return;
|
||||
|
||||
auto getColor = [&](const std::string &key, const std::string &fallback = "") -> ImVec4 {
|
||||
auto it = current.colors().find(key);
|
||||
if (it == current.colors().end() && !fallback.empty())
|
||||
{
|
||||
it = current.colors().find(fallback);
|
||||
}
|
||||
|
||||
if (it != current.colors().end())
|
||||
{
|
||||
const uint32_t hex = it->second.hex();
|
||||
return {((hex >> 24) & 0xFF) / 255.0f, ((hex >> 16) & 0xFF) / 255.0f,
|
||||
((hex >> 8) & 0xFF) / 255.0f, ((hex) & 0xFF) / 255.0f};
|
||||
}
|
||||
|
||||
std::cout << "WARNING: Color key '" << key << "' not found!\n";
|
||||
return {1, 1, 1, 1};
|
||||
};
|
||||
|
||||
ImGuiStyle &style = ImGui::GetStyle();
|
||||
|
||||
const ImVec4 bg = getColor("background");
|
||||
const ImVec4 surface = getColor("surface");
|
||||
const ImVec4 surfaceVariant = getColor("surface_variant");
|
||||
const ImVec4 fg = getColor("foreground");
|
||||
const ImVec4 fgInactive = getColor("editor_inactive");
|
||||
const ImVec4 accent = getColor("accent");
|
||||
const ImVec4 border = getColor("border");
|
||||
|
||||
style.Colors[ImGuiCol_WindowBg] = bg;
|
||||
style.Colors[ImGuiCol_ChildBg] = surface;
|
||||
style.Colors[ImGuiCol_PopupBg] = surface;
|
||||
|
||||
style.Colors[ImGuiCol_Border] = border;
|
||||
style.Colors[ImGuiCol_BorderShadow] = ImVec4(0, 0, 0, 0);
|
||||
|
||||
style.Colors[ImGuiCol_Text] = fg;
|
||||
style.Colors[ImGuiCol_TextDisabled] = fgInactive;
|
||||
|
||||
style.Colors[ImGuiCol_Header] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(accent.x, accent.y, accent.z, 0.8f);
|
||||
style.Colors[ImGuiCol_HeaderActive] = accent;
|
||||
|
||||
style.Colors[ImGuiCol_Button] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(accent.x, accent.y, accent.z, 0.6f);
|
||||
style.Colors[ImGuiCol_ButtonActive] = accent;
|
||||
|
||||
style.Colors[ImGuiCol_FrameBg] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_FrameBgHovered] =
|
||||
ImVec4(surfaceVariant.x * 1.1f, surfaceVariant.y * 1.1f, surfaceVariant.z * 1.1f, 1.0f);
|
||||
style.Colors[ImGuiCol_FrameBgActive] =
|
||||
ImVec4(surfaceVariant.x * 1.2f, surfaceVariant.y * 1.2f, surfaceVariant.z * 1.2f, 1.0f);
|
||||
|
||||
style.Colors[ImGuiCol_TitleBg] = surface;
|
||||
style.Colors[ImGuiCol_TitleBgActive] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_TitleBgCollapsed] = surface;
|
||||
|
||||
style.Colors[ImGuiCol_ScrollbarBg] = surface;
|
||||
style.Colors[ImGuiCol_ScrollbarGrab] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(accent.x, accent.y, accent.z, 0.6f);
|
||||
style.Colors[ImGuiCol_ScrollbarGrabActive] = accent;
|
||||
|
||||
style.Colors[ImGuiCol_SliderGrab] = accent;
|
||||
style.Colors[ImGuiCol_SliderGrabActive] =
|
||||
ImVec4(accent.x * 1.2f, accent.y * 1.2f, accent.z * 1.2f, 1.0f);
|
||||
|
||||
style.Colors[ImGuiCol_CheckMark] = accent;
|
||||
style.Colors[ImGuiCol_ResizeGrip] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(accent.x, accent.y, accent.z, 0.6f);
|
||||
style.Colors[ImGuiCol_ResizeGripActive] = accent;
|
||||
|
||||
style.Colors[ImGuiCol_Tab] = surface;
|
||||
style.Colors[ImGuiCol_TabHovered] = ImVec4(accent.x, accent.y, accent.z, 0.8f);
|
||||
style.Colors[ImGuiCol_TabActive] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_TabUnfocused] = surface;
|
||||
style.Colors[ImGuiCol_TabUnfocusedActive] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_TabSelectedOverline] = accent;
|
||||
|
||||
style.Colors[ImGuiCol_TableHeaderBg] = surfaceVariant;
|
||||
style.Colors[ImGuiCol_TableBorderStrong] = border;
|
||||
style.Colors[ImGuiCol_TableBorderLight] =
|
||||
ImVec4(border.x * 0.7f, border.y * 0.7f, border.z * 0.7f, border.w);
|
||||
|
||||
style.Colors[ImGuiCol_TableRowBg] = ImVec4(0, 0, 0, 0);
|
||||
style.Colors[ImGuiCol_TableRowBgAlt] = ImVec4(fg.x, fg.y, fg.z, 0.06f);
|
||||
|
||||
style.Colors[ImGuiCol_Separator] = border;
|
||||
style.Colors[ImGuiCol_SeparatorHovered] = accent;
|
||||
style.Colors[ImGuiCol_SeparatorActive] = accent;
|
||||
|
||||
style.Colors[ImGuiCol_MenuBarBg] = surface;
|
||||
|
||||
style.Colors[ImGuiCol_DockingPreview] = ImVec4(accent.x, accent.y, accent.z, 0.7f);
|
||||
style.Colors[ImGuiCol_DockingEmptyBg] = bg;
|
||||
}
|
||||
|
||||
} // namespace theme_applier
|
||||
13
src/gui/theme_applier.hpp
Normal file
13
src/gui/theme_applier.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef CLRSYNC_GUI_THEME_APPLIER_HPP
|
||||
#define CLRSYNC_GUI_THEME_APPLIER_HPP
|
||||
|
||||
#include "core/palette/palette.hpp"
|
||||
#include "color_text_edit/TextEditor.h"
|
||||
|
||||
namespace theme_applier
|
||||
{
|
||||
void apply_to_imgui(const clrsync::core::palette& pal);
|
||||
void apply_to_editor(TextEditor& editor, const clrsync::core::palette& pal);
|
||||
}
|
||||
|
||||
#endif // CLRSYNC_GUI_THEME_APPLIER_HPP
|
||||
Reference in New Issue
Block a user