1
0
mirror of synced 2024-11-12 02:00:52 +01:00

feat: Added native custom theme support

This commit is contained in:
WerWolv 2022-12-29 19:26:00 +01:00
parent 696d8d1d54
commit 7859a9bb1f
33 changed files with 911 additions and 161 deletions

View File

@ -188,8 +188,8 @@ public:
void SetLanguageDefinition(const LanguageDefinition& aLanguageDef);
const LanguageDefinition& GetLanguageDefinition() const { return mLanguageDefinition; }
const Palette& GetPalette() const { return mPaletteBase; }
void SetPalette(const Palette& aValue);
static const Palette& GetPalette() { return sPaletteBase; }
static void SetPalette(const Palette& aValue);
void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; }
void SetBreakpoints(const Breakpoints& aMarkers) { mBreakpoints = aMarkers; }
@ -372,7 +372,7 @@ private:
bool mIgnoreImGuiChild;
bool mShowWhitespaces;
Palette mPaletteBase;
static Palette sPaletteBase;
Palette mPalette;
LanguageDefinition mLanguageDefinition;
RegexList mRegexList;

View File

@ -21,9 +21,10 @@ bool equals(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Bi
return first1 == last1 && first2 == last2;
}
TextEditor::Palette TextEditor::sPaletteBase = TextEditor::GetDarkPalette();
TextEditor::TextEditor()
: mLineSpacing(1.0f), mUndoIndex(0), mTabSize(4), mOverwrite(false), mReadOnly(false), mWithinRender(false), mScrollToCursor(false), mScrollToTop(false), mTextChanged(false), mColorizerEnabled(true), mTextStart(20.0f), mLeftMargin(10), mCursorPositionChanged(false), mColorRangeMin(0), mColorRangeMax(0), mSelectionMode(SelectionMode::Normal), mCheckComments(true), mLastClick(-1.0f), mHandleKeyboardInputs(true), mHandleMouseInputs(true), mIgnoreImGuiChild(false), mShowWhitespaces(true), mStartTime(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()) {
SetPalette(GetDarkPalette());
SetLanguageDefinition(LanguageDefinition::HLSL());
mLines.push_back(Line());
}
@ -42,7 +43,7 @@ void TextEditor::SetLanguageDefinition(const LanguageDefinition &aLanguageDef) {
}
void TextEditor::SetPalette(const Palette &aValue) {
mPaletteBase = aValue;
sPaletteBase = aValue;
}
std::string TextEditor::GetText(const Coordinates &aStart, const Coordinates &aEnd) const {
@ -740,7 +741,7 @@ void TextEditor::Render() {
/* Update palette with the current alpha from style */
for (int i = 0; i < (int)PaletteIndex::Max; ++i) {
auto color = ImGui::ColorConvertU32ToFloat4(mPaletteBase[i]);
auto color = ImGui::ColorConvertU32ToFloat4(sPaletteBase[i]);
color.w *= ImGui::GetStyle().Alpha;
mPalette[i] = ImGui::ColorConvertFloat4ToU32(color);
}

View File

@ -116,6 +116,7 @@ set(LIBIMHEX_SOURCES
source/api/plugin_manager.cpp
source/api/localization.cpp
source/api/project_file_manager.cpp
source/api/theme_manager.cpp
source/data_processor/attribute.cpp
source/data_processor/link.cpp

View File

@ -128,7 +128,7 @@ namespace hex {
EVENT_DEF(RequestCloseImHex, bool);
EVENT_DEF(RequestRestartImHex);
EVENT_DEF(RequestOpenFile, std::fs::path);
EVENT_DEF(RequestChangeTheme, u32);
EVENT_DEF(RequestChangeTheme, std::string);
EVENT_DEF(RequestOpenPopup, std::string);
EVENT_DEF(RequestCreateProvider, std::string, bool, hex::prv::Provider **);

View File

@ -191,12 +191,6 @@ namespace hex {
char **envp;
};
enum class Theme {
Dark = 1,
Light = 2,
Classic = 3
};
const ProgramArguments &getProgramArguments();
std::optional<std::u8string> getProgramArgument(int index);
@ -218,9 +212,6 @@ namespace hex {
const std::filesystem::path &getCustomFontPath();
float getFontSize();
void setTheme(Theme theme);
Theme getTheme();
void enableSystemThemeDetection(bool enabled);
bool usesSystemThemeDetection();

View File

@ -0,0 +1,35 @@
#pragma once
#include <hex.hpp>
#include <hex/helpers/fs.hpp>
#include <string>
#include <nlohmann/json_fwd.hpp>
#include <imgui.h>
namespace hex::api {
class ThemeManager {
public:
constexpr static auto NativeTheme = "Native";
static void changeTheme(std::string name);
static void addTheme(const std::string &content);
static void addThemeHandler(const std::string &name, const std::function<void(std::string, std::string)> &handler);
static void addStyleHandler(const std::string &name, const std::function<void(std::string, std::string)> &handler);
static std::vector<std::string> getThemeNames();
static const std::string &getThemeImagePostfix();
static std::optional<ImColor> parseColorString(const std::string &colorString);
private:
ThemeManager() = default;
static std::map<std::string, nlohmann::json> s_themes;
static std::map<std::string, std::function<void(std::string, std::string)>> s_themeHandlers, s_styleHandlers;
static std::string s_imagePostfix;
};
}

View File

@ -101,6 +101,7 @@ namespace hex::fs {
Recent,
Scripts,
Inspectors,
Themes,
END
};

View File

@ -480,19 +480,8 @@ namespace hex {
}
static Theme s_theme;
static bool s_systemThemeDetection;
void setTheme(Theme theme) {
s_theme = theme;
EventManager::post<EventSettingsChanged>();
}
Theme getTheme() {
return s_theme;
}
void enableSystemThemeDetection(bool enabled) {
s_systemThemeDetection = enabled;

View File

@ -0,0 +1,118 @@
#include <hex/api/theme_manager.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/utils.hpp>
#include <nlohmann/json.hpp>
namespace hex::api {
std::map<std::string, nlohmann::json> ThemeManager::s_themes;
std::map<std::string, std::function<void(std::string, std::string)>> ThemeManager::s_themeHandlers, ThemeManager::s_styleHandlers;
std::string ThemeManager::s_imagePostfix;
void ThemeManager::addThemeHandler(const std::string &name, const std::function<void(std::string, std::string)> &handler) {
s_themeHandlers[name] = handler;
}
void ThemeManager::addStyleHandler(const std::string &name, const std::function<void(std::string, std::string)> &handler) {
s_styleHandlers[name] = handler;
}
void ThemeManager::addTheme(const std::string &content) {
auto theme = nlohmann::json::parse(content);
if (theme.contains("name") && theme.contains("colors")) {
s_themes[theme["name"].get<std::string>()] = theme;
} else {
hex::log::error("Invalid theme file");
}
}
std::optional<ImColor> ThemeManager::parseColorString(const std::string &colorString) {
if (colorString.length() != 9 || colorString[0] != '#')
return std::nullopt;
u32 color = 0;
for (u32 i = 1; i < 9; i++) {
color <<= 4;
if (colorString[i] >= '0' && colorString[i] <= '9')
color |= colorString[i] - '0';
else if (colorString[i] >= 'A' && colorString[i] <= 'F')
color |= colorString[i] - 'A' + 10;
else if (colorString[i] >= 'a' && colorString[i] <= 'f')
color |= colorString[i] - 'a' + 10;
else
return std::nullopt;
}
return ImColor(hex::changeEndianess(color, std::endian::big));
}
void ThemeManager::changeTheme(std::string name) {
if (!s_themes.contains(name)) {
if (s_themes.empty()) {
hex::log::error("Theme '{}' does not exist and no other themes are available!", name);
return;
} else {
const std::string &defaultTheme = s_themes.begin()->first;
hex::log::error("Theme '{}' does not exist, using default theme '{}' instead!", name, defaultTheme);
name = defaultTheme;
}
}
const auto &theme = s_themes[name];
if (theme.contains("base")) {
if (theme["base"].is_string()) {
changeTheme(theme["base"].get<std::string>());
} else {
hex::log::error("Theme '{}' has invalid base theme!", name);
}
}
if (theme.contains("colors")) {
for (const auto&[type, content] : theme["colors"].items()) {
if (!s_themeHandlers.contains(type)) {
log::warn("No theme handler found for '{}'", type);
continue;
}
for (const auto &[key, value] : content.items())
s_themeHandlers[type](key, value.get<std::string>());
}
}
if (theme.contains("styles")) {
for (const auto&[key, value] : theme["styles"].items()) {
if (!s_styleHandlers.contains(key)) {
log::warn("No style handler found for '{}'", key);
continue;
}
s_styleHandlers[key](name, value.get<std::string>());
}
}
if (theme.contains("image_postfix")) {
if (theme["image_postfix"].is_string()) {
s_imagePostfix = theme["image_postfix"].get<std::string>();
} else {
hex::log::error("Theme '{}' has invalid image postfix!", name);
}
}
}
const std::string &ThemeManager::getThemeImagePostfix() {
return s_imagePostfix;
}
std::vector<std::string> ThemeManager::getThemeNames() {
std::vector<std::string> themeNames;
for (const auto &[name, theme] : s_themes)
themeNames.push_back(name);
return themeNames;
}
}

View File

@ -253,6 +253,9 @@ namespace hex::fs {
case ImHexPath::Inspectors:
result = appendPath(getDefaultPaths(ImHexPath::Scripts), "inspectors");
break;
case ImHexPath::Themes:
result = appendPath(getDataPaths(), "themes");
break;
}
if (!listNonExisting) {

View File

@ -2,6 +2,7 @@
#include <hex/helpers/utils.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/api/theme_manager.hpp>
#include "window.hpp"

View File

@ -43,7 +43,7 @@ namespace hex {
auto exitCode = WEXITSTATUS(pclose(pipe));
if (exitCode != 0) return;
EventManager::post<RequestChangeTheme>(hex::containsIgnoreCase(result, "light") ? 2 : 1);
EventManager::post<RequestChangeTheme>(hex::containsIgnoreCase(result, "light") ? "Light" : "Dark");
});
if (themeFollowSystem)

View File

@ -30,9 +30,9 @@ namespace hex {
if (!themeFollowSystem) return;
if (!isMacosSystemDarkModeEnabled())
EventManager::post<RequestChangeTheme>(2);
EventManager::post<RequestChangeTheme>("Light");
else
EventManager::post<RequestChangeTheme>(1);
EventManager::post<RequestChangeTheme>("Dark");
});
if (themeFollowSystem)

View File

@ -106,7 +106,7 @@ namespace hex {
this->setupNativeWindow();
// Initialize default theme
EventManager::post<RequestChangeTheme>(1);
EventManager::post<RequestChangeTheme>("Dark");
EventManager::subscribe<RequestCloseImHex>(this, [this](bool noQuestions) {
glfwSetWindowShouldClose(this->m_window, GLFW_TRUE);
@ -688,6 +688,8 @@ namespace hex {
style.Alpha = 1.0F;
style.WindowRounding = 0.0F;
ImNodes::GetStyle().Flags = ImNodesStyleFlags_NodeOutline | ImNodesStyleFlags_GridLines;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigWindowsMoveFromTitleBarOnly = true;
io.FontGlobalScale = 1.0F;

View File

@ -25,6 +25,7 @@ add_library(${PROJECT_NAME} SHARED
source/content/hashes.cpp
source/content/shortcuts.cpp
source/content/global_actions.cpp
source/content/themes.cpp
source/content/providers/file_provider.cpp
source/content/providers/gdb_provider.cpp

View File

@ -372,10 +372,6 @@
"hex.builtin.setting.imhex.recent_files": "Zuletzt geöffnete Dateien",
"hex.builtin.setting.interface": "Aussehen",
"hex.builtin.setting.interface.color": "Farbdesign",
"hex.builtin.setting.interface.color.classic": "Klassisch",
"hex.builtin.setting.interface.color.dark": "Dunkel",
"hex.builtin.setting.interface.color.light": "Hell",
"hex.builtin.setting.interface.color.system": "System",
"hex.builtin.setting.interface.fps": "FPS Limit",
"hex.builtin.setting.interface.fps.unlocked": "Unbegrenzt",
"hex.builtin.setting.interface.language": "Sprache",

View File

@ -373,10 +373,6 @@
"hex.builtin.setting.imhex.recent_files": "Recent Files",
"hex.builtin.setting.interface": "Interface",
"hex.builtin.setting.interface.color": "Color theme",
"hex.builtin.setting.interface.color.classic": "Classic",
"hex.builtin.setting.interface.color.dark": "Dark",
"hex.builtin.setting.interface.color.light": "Light",
"hex.builtin.setting.interface.color.system": "System",
"hex.builtin.setting.interface.fps": "FPS Limit",
"hex.builtin.setting.interface.fps.unlocked": "Unlocked",
"hex.builtin.setting.interface.language": "Language",

View File

@ -371,10 +371,6 @@
"hex.builtin.setting.imhex.recent_files": "File recenti",
"hex.builtin.setting.interface": "Interfaccia",
"hex.builtin.setting.interface.color": "Colore del Tema",
"hex.builtin.setting.interface.color.classic": "Classico",
"hex.builtin.setting.interface.color.dark": "Scuro",
"hex.builtin.setting.interface.color.light": "Chiaro",
"hex.builtin.setting.interface.color.system": "Sistema",
"hex.builtin.setting.interface.fps": "Limite FPS",
"hex.builtin.setting.interface.fps.unlocked": "Unblocca",
"hex.builtin.setting.interface.language": "Lingua",

View File

@ -371,10 +371,6 @@
"hex.builtin.setting.imhex.recent_files": "最近開いたファイル",
"hex.builtin.setting.interface": "UI",
"hex.builtin.setting.interface.color": "カラーテーマ",
"hex.builtin.setting.interface.color.classic": "クラシック",
"hex.builtin.setting.interface.color.dark": "ダーク",
"hex.builtin.setting.interface.color.light": "ライト",
"hex.builtin.setting.interface.color.system": "システム設定に従う",
"hex.builtin.setting.interface.fps": "FPS制限",
"hex.builtin.setting.interface.fps.unlocked": "無制限",
"hex.builtin.setting.interface.language": "言語",

View File

@ -371,10 +371,6 @@
"hex.builtin.setting.imhex.recent_files": "최근 파일",
"hex.builtin.setting.interface": "인터페이스",
"hex.builtin.setting.interface.color": "색상 테마",
"hex.builtin.setting.interface.color.classic": "클래식",
"hex.builtin.setting.interface.color.dark": "다크",
"hex.builtin.setting.interface.color.light": "라이트",
"hex.builtin.setting.interface.color.system": "시스템",
"hex.builtin.setting.interface.fps": "FPS 제한",
"hex.builtin.setting.interface.fps.unlocked": "제한 없음",
"hex.builtin.setting.interface.language": "언어",

View File

@ -371,10 +371,6 @@
"hex.builtin.setting.imhex.recent_files": "Arquivos Recentes",
"hex.builtin.setting.interface": "Interface",
"hex.builtin.setting.interface.color": "Color theme",
"hex.builtin.setting.interface.color.classic": "Classico",
"hex.builtin.setting.interface.color.dark": "Escuro",
"hex.builtin.setting.interface.color.light": "Claro",
"hex.builtin.setting.interface.color.system": "Sistema",
"hex.builtin.setting.interface.fps": "FPS Limit",
"hex.builtin.setting.interface.fps.unlocked": "Destravado",
"hex.builtin.setting.interface.language": "Idioma",

View File

@ -370,11 +370,6 @@
"hex.builtin.setting.imhex": "ImHex",
"hex.builtin.setting.imhex.recent_files": "最近文件",
"hex.builtin.setting.interface": "界面",
"hex.builtin.setting.interface.color": "颜色主题",
"hex.builtin.setting.interface.color.classic": "经典",
"hex.builtin.setting.interface.color.dark": "暗",
"hex.builtin.setting.interface.color.light": "亮",
"hex.builtin.setting.interface.color.system": "跟随系统",
"hex.builtin.setting.interface.fps": "FPS 限制",
"hex.builtin.setting.interface.fps.unlocked": "无限制",
"hex.builtin.setting.interface.language": "语言",

View File

@ -371,10 +371,6 @@
"hex.builtin.setting.imhex.recent_files": "近期檔案",
"hex.builtin.setting.interface": "介面",
"hex.builtin.setting.interface.color": "顏色主題",
"hex.builtin.setting.interface.color.classic": "經典",
"hex.builtin.setting.interface.color.dark": "暗色",
"hex.builtin.setting.interface.color.light": "亮色",
"hex.builtin.setting.interface.color.system": "系統",
"hex.builtin.setting.interface.fps": "FPS 限制",
"hex.builtin.setting.interface.fps.unlocked": "解鎖",
"hex.builtin.setting.interface.language": "語言",

View File

@ -0,0 +1,153 @@
{
"name": "Classic",
"image_postfix": "_dark",
"colors": {
"imgui": {
"border": "#7F7F7F7F",
"border-shadow": "#00000000",
"button": "#59669B9E",
"button-active": "#7589CCFF",
"button-hovered": "#667AB5C9",
"check-mark": "#E5E5E57F",
"child-background": "#00000000",
"docking-empty-background": "#000000D8",
"docking-preview": "#6666E550",
"drag-drop-target": "#FFFF00E5",
"frame-background": "#6D6D6D63",
"frame-background-active": "#6B68A3AF",
"frame-background-hovered": "#7777AF66",
"header": "#6666E572",
"header-active": "#8787DDCC",
"header-hovered": "#7272E5CC",
"menu-bar-background": "#66668CCC",
"modal-window-dim-background": "#33333359",
"nav-highlight": "#7272E5CC",
"nav-windowing-background": "#CCCCCC33",
"nav-windowing-highlight": "#FFFFFFB2",
"plot-histogram": "#E5B200FF",
"plot-histogram-hovered": "#FF9900FF",
"plot-lines": "#FFFFFFFF",
"plot-lines-hovered": "#E5B200FF",
"popup-background": "#1C1C23EA",
"resize-grip": "#FFFFFF19",
"resize-grip-active": "#C6D1FFE5",
"resize-grip-hovered": "#C6D1FF99",
"scrollbar-background": "#333F4C99",
"scrollbar-grab": "#6666CC4C",
"scrollbar-grab-active": "#6863CC99",
"scrollbar-grab-hovered": "#6666CC66",
"separator": "#7F7F7F99",
"separator-active": "#B2B2E5FF",
"separator-hovered": "#9999B2FF",
"slider-grab": "#FFFFFF4C",
"slider-grab-active": "#6863CC99",
"tab": "#5555AEC8",
"tab-active": "#6767B9D6",
"tab-hovered": "#7272E5CC",
"tab-unfocused": "#484891D1",
"tab-unfocused-active": "#5959A6D5",
"table-border-light": "#424247FF",
"table-border-strong": "#4F4F72FF",
"table-header-background": "#444460FF",
"table-row-background": "#00000000",
"table-row-background-alt": "#FFFFFF11",
"text": "#E5E5E5FF",
"text-disabled": "#999999FF",
"text-selected-background": "#0000FF59",
"title-background": "#66668CCC",
"title-background-active": "#66668CCC",
"title-background-collapse": "#66668CCC",
"window-background": "#000000D8"
},
"implot": {
"axis-bg": "#00000001",
"axis-bg-active": "#00000001",
"axis-bg-hovered": "#00000001",
"axis-grid": "#E5E5E53F",
"axis-text": "#E5E5E5FF",
"axis-tick": "#00000001",
"crosshairs": "#7F7F7FBF",
"error-bar": "#E5E5E5FF",
"fill": "#00000001",
"frame-bg": "#6D6D6D63",
"inlay-text": "#E5E5E5FF",
"legend-bg": "#1C1C23EA",
"legend-border": "#7F7F7F7F",
"legend-text": "#E5E5E5FF",
"line": "#00000001",
"marker-fill": "#00000001",
"marker-outline": "#00000001",
"plot-bg": "#00000059",
"plot-border": "#7F7F7F7F",
"selection": "#F7F763FF",
"title-text": "#E5E5E5FF"
},
"imnodes": {
"box-selector": "#00000000",
"box-selector-outline": "#00E50000",
"grid-background": "#00000000",
"grid-line": "#00000000",
"grid-line-primary": "#00000000",
"link": "#06539BFF",
"link-hovered": "#672A78FF",
"link-selected": "#DBB377FF",
"mini-map-background": "#00000000",
"mini-map-background-hovered": "#0000FB90",
"mini-map-canvas": "#00000000",
"mini-map-canvas-outline": "#00000000",
"mini-map-link": "#00000000",
"mini-map-link-selected": "#00000000",
"mini-map-node-background": "#00000000",
"mini-map-node-background-hovered": "#00000000",
"mini-map-node-background-selected": "#00000000",
"mini-map-node-outline": "#00000000",
"mini-map-outline": "#00000000",
"mini-map-outline-hovered": "#00000000",
"node-background": "#282850FF",
"node-background-hovered": "#3C3C64FF",
"node-background-selected": "#505078FF",
"node-outline": "#E6E6E6FF",
"pin": "#4DC69BFF",
"pin-hovered": "#00000000",
"title-bar": "#E74C3CFF",
"title-bar-hovered": "#F1C40FFF",
"title-bar-selected": "#388B42FF"
},
"imhex": {
"desc-button": "#282850FF",
"desc-button-active": "#505078FF",
"desc-button-hovered": "#3C3C64FF",
"highlight": "#4DC69BFF",
"toolbar-blue": "#06539BFF",
"toolbar-brown": "#DBB377FF",
"toolbar-gray": "#E6E6E6FF",
"toolbar-green": "#388B42FF",
"toolbar-purple": "#672A78FF",
"toolbar-red": "#E74C3CFF",
"toolbar-yellow": "#F1C40FFF"
},
"text-editor": {
"background": "#000080FF",
"breakpoint": "#0080FF80",
"char-literal": "#008080FF",
"comment": "#808080FF",
"current-line-edge": "#00000040",
"current-line-fill": "#00000040",
"current-line-fill-inactive": "#80808040",
"cursor": "#FF8000FF",
"default": "#FFFF00FF",
"error-marker": "#FF0000A0",
"identifier": "#FFFF00FF",
"keyword": "#00FFFFFF",
"known-identifier": "#FFFFFFFF",
"line-number": "#008080FF",
"multi-line-comment": "#404040FF",
"number": "#00FF00FF",
"preproc-identifier": "#FF00FFFF",
"preprocessor": "#008000FF",
"punctuation": "#FFFFFFFF",
"selection": "#00FFFF80",
"string": "#008080FF"
}
}
}

View File

@ -0,0 +1,153 @@
{
"name": "Dark",
"image_postfix": "_dark",
"colors": {
"imgui": {
"border": "#6D6D7F7F",
"border-shadow": "#00000000",
"button": "#4296F966",
"button-active": "#0F87F9FF",
"button-hovered": "#4296F9FF",
"check-mark": "#4296F9FF",
"child-background": "#00000000",
"docking-empty-background": "#0F0F0FEF",
"docking-preview": "#4296F9B2",
"drag-drop-target": "#FFFF00E5",
"frame-background": "#28497A89",
"frame-background-active": "#4296F9AA",
"frame-background-hovered": "#4296F966",
"header": "#4296F94F",
"header-active": "#4296F9FF",
"header-hovered": "#4296F9CC",
"menu-bar-background": "#232323FF",
"modal-window-dim-background": "#CCCCCC59",
"nav-highlight": "#4296F9FF",
"nav-windowing-background": "#CCCCCC33",
"nav-windowing-highlight": "#FFFFFFB2",
"plot-histogram": "#E5B200FF",
"plot-histogram-hovered": "#FF9900FF",
"plot-lines": "#9B9B9BFF",
"plot-lines-hovered": "#FF6D59FF",
"popup-background": "#141414EF",
"resize-grip": "#4296F933",
"resize-grip-active": "#4296F9F2",
"resize-grip-hovered": "#4296F9AA",
"scrollbar-background": "#05050587",
"scrollbar-grab": "#4F4F4FFF",
"scrollbar-grab-active": "#828282FF",
"scrollbar-grab-hovered": "#686868FF",
"separator": "#6D6D7F7F",
"separator-active": "#1966BFFF",
"separator-hovered": "#1966BFC6",
"slider-grab": "#3D84E0FF",
"slider-grab-active": "#4296F9FF",
"tab": "#2D5993DB",
"tab-active": "#3268ADFF",
"tab-hovered": "#4296F9CC",
"tab-unfocused": "#111A25F7",
"tab-unfocused-active": "#22426CFF",
"table-border-light": "#3A3A3FFF",
"table-border-strong": "#4F4F59FF",
"table-header-background": "#303033FF",
"table-row-background": "#00000000",
"table-row-background-alt": "#FFFFFF0F",
"text": "#FFFFFFFF",
"text-disabled": "#7F7F7FFF",
"text-selected-background": "#4296F959",
"title-background": "#232323FF",
"title-background-active": "#232323FF",
"title-background-collapse": "#232323FF",
"window-background": "#0F0F0FEF"
},
"implot": {
"axis-bg": "#00000001",
"axis-bg-active": "#00000001",
"axis-bg-hovered": "#00000001",
"axis-grid": "#FFFFFF3F",
"axis-text": "#FFFFFFFF",
"axis-tick": "#00000001",
"crosshairs": "#FFFFFF7F",
"error-bar": "#00000001",
"fill": "#00000001",
"frame-bg": "#FFFFFF11",
"inlay-text": "#FFFFFFFF",
"legend-bg": "#141414EF",
"legend-border": "#6D6D7F7F",
"legend-text": "#FFFFFFFF",
"line": "#00000001",
"marker-fill": "#00000001",
"marker-outline": "#00000001",
"plot-bg": "#0000007F",
"plot-border": "#6D6D7F7F",
"selection": "#FF9900FF",
"title-text": "#FFFFFFFF"
},
"imnodes": {
"box-selector": "#AB000000",
"box-selector-outline": "#00E20000",
"grid-background": "#42009900",
"grid-line": "#63008100",
"grid-line-primary": "#EA005B00",
"link": "#06539BFF",
"link-hovered": "#672A78FF",
"link-selected": "#DBB377FF",
"mini-map-background": "#69001B00",
"mini-map-background-hovered": "#7100B5A6",
"mini-map-canvas": "#00000000",
"mini-map-canvas-outline": "#00000000",
"mini-map-link": "#00000000",
"mini-map-link-selected": "#00000000",
"mini-map-node-background": "#00000000",
"mini-map-node-background-hovered": "#00000000",
"mini-map-node-background-selected": "#00000000",
"mini-map-node-outline": "#00000000",
"mini-map-outline": "#00000000",
"mini-map-outline-hovered": "#00000000",
"node-background": "#282850FF",
"node-background-hovered": "#3C3C64FF",
"node-background-selected": "#505078FF",
"node-outline": "#E6E6E6FF",
"pin": "#4DC69BFF",
"pin-hovered": "#00000000",
"title-bar": "#E74C3CFF",
"title-bar-hovered": "#F1C40FFF",
"title-bar-selected": "#388B42FF"
},
"imhex": {
"desc-button": "#141414FF",
"desc-button-active": "#3C3C3CFF",
"desc-button-hovered": "#282828FF",
"highlight": "#4DC69BFF",
"toolbar-blue": "#06539BFF",
"toolbar-brown": "#DBB377FF",
"toolbar-gray": "#E6E6E6FF",
"toolbar-green": "#388B42FF",
"toolbar-purple": "#672A78FF",
"toolbar-red": "#E74C3CFF",
"toolbar-yellow": "#F1C40FFF"
},
"text-editor": {
"background": "#101010FF",
"breakpoint": "#0080F040",
"char-literal": "#E0A070FF",
"comment": "#206020FF",
"current-line-edge": "#A0A0A040",
"current-line-fill": "#00000040",
"current-line-fill-inactive": "#80808040",
"cursor": "#E0E0E0FF",
"default": "#7F7F7FFF",
"error-marker": "#FF200080",
"identifier": "#AAAAAAFF",
"keyword": "#569CD6FF",
"known-identifier": "#4DC69BFF",
"line-number": "#007070FF",
"multi-line-comment": "#206040FF",
"number": "#00FF00FF",
"preproc-identifier": "#A040C0FF",
"preprocessor": "#808040FF",
"punctuation": "#FFFFFFFF",
"selection": "#2060A080",
"string": "#E07070FF"
}
}
}

View File

@ -0,0 +1,153 @@
{
"name": "Light",
"image_postfix": "_light",
"colors": {
"imgui": {
"border": "#0000004C",
"border-shadow": "#00000000",
"button": "#4296F966",
"button-active": "#0F87F9FF",
"button-hovered": "#4296F9FF",
"check-mark": "#4296F9FF",
"child-background": "#00000000",
"docking-empty-background": "#EFEFEFFF",
"docking-preview": "#4296F937",
"drag-drop-target": "#4296F9F2",
"frame-background": "#FFFFFFFF",
"frame-background-active": "#4296F9AA",
"frame-background-hovered": "#4296F966",
"header": "#4296F94F",
"header-active": "#4296F9FF",
"header-hovered": "#4296F9CC",
"menu-bar-background": "#DBDBDBFF",
"modal-window-dim-background": "#33333359",
"nav-highlight": "#4296F9CC",
"nav-windowing-background": "#33333333",
"nav-windowing-highlight": "#B2B2B2B2",
"plot-histogram": "#E5B200FF",
"plot-histogram-hovered": "#FF7200FF",
"plot-lines": "#636363FF",
"plot-lines-hovered": "#FF6D59FF",
"popup-background": "#FFFFFFF9",
"resize-grip": "#5959592B",
"resize-grip-active": "#4296F9F2",
"resize-grip-hovered": "#4296F9AA",
"scrollbar-background": "#F9F9F987",
"scrollbar-grab": "#AFAFAFCC",
"scrollbar-grab-active": "#7C7C7CFF",
"scrollbar-grab-hovered": "#7C7C7CCC",
"separator": "#6363639E",
"separator-active": "#2370CCFF",
"separator-hovered": "#2370CCC6",
"slider-grab": "#4296F9C6",
"slider-grab-active": "#7589CC99",
"tab": "#C2CBD5ED",
"tab-active": "#97B9E1FF",
"tab-hovered": "#4296F9CC",
"tab-unfocused": "#EAECEEFB",
"tab-unfocused-active": "#BDD1E9FF",
"table-border-light": "#ADADBCFF",
"table-border-strong": "#9191A3FF",
"table-header-background": "#C6DDF9FF",
"table-row-background": "#00000000",
"table-row-background-alt": "#4C4C4C16",
"text": "#000000FF",
"text-disabled": "#999999FF",
"text-selected-background": "#4296F959",
"title-background": "#DBDBDBFF",
"title-background-active": "#DBDBDBFF",
"title-background-collapse": "#DBDBDBFF",
"window-background": "#EFEFEFFF"
},
"implot": {
"axis-bg": "#00000001",
"axis-bg-active": "#00000001",
"axis-bg-hovered": "#00000001",
"axis-grid": "#FFFFFFFF",
"axis-text": "#000000FF",
"axis-tick": "#0000003F",
"crosshairs": "#0000007F",
"error-bar": "#00000001",
"fill": "#00000001",
"frame-bg": "#FFFFFFFF",
"inlay-text": "#000000FF",
"legend-bg": "#FFFFFFF9",
"legend-border": "#D1D1D1CC",
"legend-text": "#000000FF",
"line": "#00000001",
"marker-fill": "#00000001",
"marker-outline": "#00000001",
"plot-bg": "#6B91FF21",
"plot-border": "#00000000",
"selection": "#D1A307FF",
"title-text": "#000000FF"
},
"imnodes": {
"box-selector": "#00000000",
"box-selector-outline": "#00E20000",
"grid-background": "#00000000",
"grid-line": "#00000000",
"grid-line-primary": "#00000000",
"link": "#06539BFF",
"link-hovered": "#672A78FF",
"link-selected": "#DBB377FF",
"mini-map-background": "#00000000",
"mini-map-background-hovered": "#0000B00C",
"mini-map-canvas": "#00000000",
"mini-map-canvas-outline": "#00000000",
"mini-map-link": "#00000000",
"mini-map-link-selected": "#00000000",
"mini-map-node-background": "#00000000",
"mini-map-node-background-hovered": "#00000000",
"mini-map-node-background-selected": "#00000000",
"mini-map-node-outline": "#00000000",
"mini-map-outline": "#00000000",
"mini-map-outline-hovered": "#00000000",
"node-background": "#282850FF",
"node-background-hovered": "#3C3C64FF",
"node-background-selected": "#505078FF",
"node-outline": "#E6E6E6FF",
"pin": "#4DC69BFF",
"pin-hovered": "#00000000",
"title-bar": "#E74C3CFF",
"title-bar-hovered": "#F1C40FFF",
"title-bar-selected": "#388B42FF"
},
"imhex": {
"desc-button": "#E6E6E6FF",
"desc-button-active": "#BEBEBEFF",
"desc-button-hovered": "#D2D2D2FF",
"highlight": "#299770FF",
"toolbar-blue": "#06539BFF",
"toolbar-brown": "#DBB377FF",
"toolbar-gray": "#191919FF",
"toolbar-green": "#388B42FF",
"toolbar-purple": "#672A78FF",
"toolbar-red": "#E74C3CFF",
"toolbar-yellow": "#F1C40FFF"
},
"text-editor": {
"background": "#FFFFFFFF",
"breakpoint": "#0080F080",
"char-literal": "#704030FF",
"comment": "#205020FF",
"current-line-edge": "#00000040",
"current-line-fill": "#00000040",
"current-line-fill-inactive": "#80808040",
"cursor": "#000000FF",
"default": "#7F7F7FFF",
"error-marker": "#FF1000A0",
"identifier": "#404040FF",
"keyword": "#060CFFFF",
"known-identifier": "#106060FF",
"line-number": "#005050FF",
"multi-line-comment": "#205040FF",
"number": "#008000FF",
"preproc-identifier": "#A040C0FF",
"preprocessor": "#606040FF",
"punctuation": "#000000FF",
"selection": "#00006080",
"string": "#A02020FF"
}
}
}

View File

@ -2,6 +2,7 @@
#include <hex/api/content_registry.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/api/localization.hpp>
#include <hex/api/theme_manager.hpp>
#include <hex/helpers/net.hpp>
#include <hex/helpers/utils.hpp>
@ -97,27 +98,34 @@ namespace hex::plugin::builtin {
/* Interface */
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", 0, [](auto name, nlohmann::json &setting) {
static int selection = static_cast<int>(setting);
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", "Dark", [](auto name, nlohmann::json &setting) {
static auto selection = static_cast<std::string>(setting);
const char *themes[] = {
"hex.builtin.setting.interface.color.system"_lang,
"hex.builtin.setting.interface.color.dark"_lang,
"hex.builtin.setting.interface.color.light"_lang,
"hex.builtin.setting.interface.color.classic"_lang
};
const auto themeNames = hex::api::ThemeManager::getThemeNames();
bool changed = false;
if (ImGui::Combo(name.data(), &selection, themes, IM_ARRAYSIZE(themes))) {
setting = selection;
if (ImGui::BeginCombo(name.data(), selection.c_str())) {
if (ImGui::Selectable(api::ThemeManager::NativeTheme, selection == api::ThemeManager::NativeTheme)) {
selection = api::ThemeManager::NativeTheme;
setting = selection;
ImHexApi::System::enableSystemThemeDetection(true);
changed = true;
}
ImHexApi::System::enableSystemThemeDetection(selection == 0);
if (selection != 0)
ImHexApi::System::setTheme(static_cast<ImHexApi::System::Theme>(selection));
for (const auto &themeName : themeNames) {
if (ImGui::Selectable(themeName.c_str(), selection == themeName)) {
selection = themeName;
setting = selection;
ImHexApi::System::enableSystemThemeDetection(false);
api::ThemeManager::changeTheme(selection);
changed = true;
}
}
return true;
ImGui::EndCombo();
}
return false;
return changed;
});
ContentRegistry::Settings::add(
@ -569,10 +577,14 @@ namespace hex::plugin::builtin {
}
static void loadThemeSettings() {
auto theme = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", static_cast<i64>(ImHexApi::System::Theme::Dark));
auto theme = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", api::ThemeManager::NativeTheme);
ImHexApi::System::enableSystemThemeDetection(theme == 0);
ImHexApi::System::setTheme(static_cast<ImHexApi::System::Theme>(theme));
if (theme == api::ThemeManager::NativeTheme)
ImHexApi::System::enableSystemThemeDetection(true);
else {
ImHexApi::System::enableSystemThemeDetection(false);
api::ThemeManager::changeTheme(theme);
}
}
static void loadFoldersSettings() {

View File

@ -0,0 +1,228 @@
#include <hex/api/theme_manager.hpp>
#include <imgui.h>
#include <implot.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <imnodes.h>
#include <TextEditor.h>
#include <romfs/romfs.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/file.hpp>
namespace hex::plugin::builtin {
void registerThemeHandlers() {
api::ThemeManager::addThemeHandler("imgui", [](const std::string &key, const std::string &value) {
const static std::map<std::string, ImGuiCol> ColorMap = {
{ "text", ImGuiCol_Text },
{ "text-disabled", ImGuiCol_TextDisabled },
{ "window-background", ImGuiCol_WindowBg },
{ "child-background", ImGuiCol_ChildBg },
{ "popup-background", ImGuiCol_PopupBg },
{ "border", ImGuiCol_Border },
{ "border-shadow", ImGuiCol_BorderShadow },
{ "frame-background", ImGuiCol_FrameBg },
{ "frame-background-hovered", ImGuiCol_FrameBgHovered },
{ "frame-background-active", ImGuiCol_FrameBgActive },
{ "title-background", ImGuiCol_TitleBg },
{ "title-background-active", ImGuiCol_TitleBgActive },
{ "title-background-collapse", ImGuiCol_TitleBgCollapsed },
{ "menu-bar-background", ImGuiCol_MenuBarBg },
{ "scrollbar-background", ImGuiCol_ScrollbarBg },
{ "scrollbar-grab", ImGuiCol_ScrollbarGrab },
{ "scrollbar-grab-hovered", ImGuiCol_ScrollbarGrabHovered },
{ "scrollbar-grab-active", ImGuiCol_ScrollbarGrabActive },
{ "check-mark", ImGuiCol_CheckMark },
{ "slider-grab", ImGuiCol_SliderGrab },
{ "slider-grab-active", ImGuiCol_SliderGrabActive },
{ "button", ImGuiCol_Button },
{ "button-hovered", ImGuiCol_ButtonHovered },
{ "button-active", ImGuiCol_ButtonActive },
{ "header", ImGuiCol_Header },
{ "header-hovered", ImGuiCol_HeaderHovered },
{ "header-active", ImGuiCol_HeaderActive },
{ "separator", ImGuiCol_Separator },
{ "separator-hovered", ImGuiCol_SeparatorHovered },
{ "separator-active", ImGuiCol_SeparatorActive },
{ "resize-grip", ImGuiCol_ResizeGrip },
{ "resize-grip-hovered", ImGuiCol_ResizeGripHovered },
{ "resize-grip-active", ImGuiCol_ResizeGripActive },
{ "tab", ImGuiCol_Tab },
{ "tab-hovered", ImGuiCol_TabHovered },
{ "tab-active", ImGuiCol_TabActive },
{ "tab-unfocused", ImGuiCol_TabUnfocused },
{ "tab-unfocused-active", ImGuiCol_TabUnfocusedActive },
{ "docking-preview", ImGuiCol_DockingPreview },
{ "docking-empty-background", ImGuiCol_DockingEmptyBg },
{ "plot-lines", ImGuiCol_PlotLines },
{ "plot-lines-hovered", ImGuiCol_PlotLinesHovered },
{ "plot-histogram", ImGuiCol_PlotHistogram },
{ "plot-histogram-hovered", ImGuiCol_PlotHistogramHovered },
{ "table-header-background", ImGuiCol_TableHeaderBg },
{ "table-border-strong", ImGuiCol_TableBorderStrong },
{ "table-border-light", ImGuiCol_TableBorderLight },
{ "table-row-background", ImGuiCol_TableRowBg },
{ "table-row-background-alt", ImGuiCol_TableRowBgAlt },
{ "text-selected-background", ImGuiCol_TextSelectedBg },
{ "drag-drop-target", ImGuiCol_DragDropTarget },
{ "nav-highlight", ImGuiCol_NavHighlight },
{ "nav-windowing-highlight", ImGuiCol_NavWindowingHighlight },
{ "nav-windowing-background", ImGuiCol_NavWindowingDimBg },
{ "modal-window-dim-background", ImGuiCol_ModalWindowDimBg }
};
auto color = api::ThemeManager::parseColorString(value);
auto colors = ImGui::GetStyle().Colors;
if (ColorMap.contains(key) && color.has_value())
colors[ColorMap.at(key)] = color->Value;
});
api::ThemeManager::addThemeHandler("implot", [](const std::string &key, const std::string &value) {
const static std::map<std::string, ImPlotCol> ColorMap = {
{ "line", ImPlotCol_Line },
{ "fill", ImPlotCol_Fill },
{ "marker-outline", ImPlotCol_MarkerOutline },
{ "marker-fill", ImPlotCol_MarkerFill },
{ "error-bar", ImPlotCol_ErrorBar },
{ "frame-bg", ImPlotCol_FrameBg },
{ "plot-bg", ImPlotCol_PlotBg },
{ "plot-border", ImPlotCol_PlotBorder },
{ "legend-bg", ImPlotCol_LegendBg },
{ "legend-border", ImPlotCol_LegendBorder },
{ "legend-text", ImPlotCol_LegendText },
{ "title-text", ImPlotCol_TitleText },
{ "inlay-text", ImPlotCol_InlayText },
{ "axis-text", ImPlotCol_AxisText },
{ "axis-grid", ImPlotCol_AxisGrid },
{ "axis-tick", ImPlotCol_AxisTick },
{ "axis-bg", ImPlotCol_AxisBg },
{ "axis-bg-hovered", ImPlotCol_AxisBgHovered },
{ "axis-bg-active", ImPlotCol_AxisBgActive },
{ "selection", ImPlotCol_Selection },
{ "crosshairs", ImPlotCol_Crosshairs }
};
auto color = api::ThemeManager::parseColorString(value);
auto &colors = ImPlot::GetStyle().Colors;
if (ColorMap.contains(key) && color.has_value())
colors[ColorMap.at(key)] = color->Value;
});
api::ThemeManager::addThemeHandler("imnodes", [](const std::string &key, const std::string &value) {
const static std::map<std::string, ImNodesCol> ColorMap = {
{ "node-background", ImNodesCol_NodeBackground },
{ "node-background-hovered", ImNodesCol_NodeBackgroundHovered },
{ "node-background-selected", ImNodesCol_NodeBackgroundSelected },
{ "node-outline", ImNodesCol_NodeOutline },
{ "title-bar", ImNodesCol_TitleBar },
{ "title-bar-hovered", ImNodesCol_TitleBarHovered },
{ "title-bar-selected", ImNodesCol_TitleBarSelected },
{ "link", ImNodesCol_Link },
{ "link-hovered", ImNodesCol_LinkHovered },
{ "link-selected", ImNodesCol_LinkSelected },
{ "pin", ImNodesCol_Pin },
{ "pin-hovered", ImNodesCol_PinHovered },
{ "box-selector", ImNodesCol_BoxSelector },
{ "box-selector-outline", ImNodesCol_BoxSelectorOutline },
{ "grid-background", ImNodesCol_GridBackground },
{ "grid-line", ImNodesCol_GridLine },
{ "grid-line-primary", ImNodesCol_GridLinePrimary },
{ "mini-map-background", ImNodesCol_MiniMapBackground },
{ "mini-map-background-hovered", ImNodesCol_MiniMapBackgroundHovered },
{ "mini-map-outline", ImNodesCol_MiniMapOutline },
{ "mini-map-outline-hovered", ImNodesCol_MiniMapOutlineHovered },
{ "mini-map-node-background", ImNodesCol_MiniMapNodeBackground },
{ "mini-map-node-background-hovered", ImNodesCol_MiniMapNodeBackgroundHovered },
{ "mini-map-node-background-selected", ImNodesCol_MiniMapNodeBackgroundSelected },
{ "mini-map-node-outline", ImNodesCol_MiniMapNodeOutline },
{ "mini-map-link", ImNodesCol_MiniMapLink },
{ "mini-map-link-selected", ImNodesCol_MiniMapLinkSelected },
{ "mini-map-canvas", ImNodesCol_MiniMapCanvas },
{ "mini-map-canvas-outline", ImNodesCol_MiniMapCanvasOutline },
};
auto color = api::ThemeManager::parseColorString(value);
auto &colors = ImNodes::GetStyle().Colors;
if (ColorMap.contains(key) && color.has_value())
colors[ColorMap.at(key)] = *color;
});
api::ThemeManager::addThemeHandler("imhex", [](const std::string &key, const std::string &value) {
const static std::map<std::string, ImGuiCustomCol> ColorMap = {
{ "desc-button", ImGuiCustomCol_DescButton },
{ "desc-button-hovered", ImGuiCustomCol_DescButtonHovered },
{ "desc-button-active", ImGuiCustomCol_DescButtonActive },
{ "toolbar-gray", ImGuiCustomCol_ToolbarGray },
{ "toolbar-red", ImGuiCustomCol_ToolbarRed },
{ "toolbar-yellow", ImGuiCustomCol_ToolbarYellow },
{ "toolbar-green", ImGuiCustomCol_ToolbarGreen },
{ "toolbar-blue", ImGuiCustomCol_ToolbarBlue },
{ "toolbar-purple", ImGuiCustomCol_ToolbarPurple },
{ "toolbar-brown", ImGuiCustomCol_ToolbarBrown },
{ "highlight", ImGuiCustomCol_Highlight }
};
auto color = api::ThemeManager::parseColorString(value);
auto &colors = static_cast<ImGui::ImHexCustomData *>(GImGui->IO.UserData)->Colors;
if (ColorMap.contains(key) && color.has_value())
colors[ColorMap.at(key)] = color->Value;
});
api::ThemeManager::addThemeHandler("text-editor", [](const std::string &key, const std::string &value) {
using enum TextEditor::PaletteIndex;
const static std::map<std::string, TextEditor::PaletteIndex> ColorMap = {
{ "default", Default },
{ "keyword", Keyword },
{ "number", Number },
{ "string", String },
{ "char-literal", CharLiteral },
{ "punctuation", Punctuation },
{ "preprocessor", Preprocessor },
{ "identifier", Identifier },
{ "known-identifier", KnownIdentifier },
{ "preproc-identifier", PreprocIdentifier },
{ "comment", Comment },
{ "multi-line-comment", MultiLineComment },
{ "background", Background },
{ "cursor", Cursor },
{ "selection", Selection },
{ "error-marker", ErrorMarker },
{ "breakpoint", Breakpoint },
{ "line-number", LineNumber },
{ "current-line-fill", CurrentLineFill },
{ "current-line-fill-inactive", CurrentLineFillInactive },
{ "current-line-edge", CurrentLineEdge }
};
auto color = api::ThemeManager::parseColorString(value);
auto colors = TextEditor::GetPalette();
if (ColorMap.contains(key) && color.has_value())
colors[size_t(ColorMap.at(key))] = ImU32(*color);
TextEditor::SetPalette(colors);
});
}
void registerThemes() {
// Load built-in themes
for (const auto &theme : romfs::list("themes")) {
api::ThemeManager::addTheme(std::string(romfs::get(theme).string()));
}
// Load user themes
for (const auto &themeFolder : fs::getDefaultPaths(fs::ImHexPath::Themes)) {
for (const auto &theme : std::fs::directory_iterator(themeFolder)) {
if (theme.is_regular_file())
api::ThemeManager::addTheme(fs::File(theme.path(), fs::File::Mode::Read).readString());
}
}
}
}

View File

@ -15,23 +15,6 @@
namespace hex::plugin::builtin {
ViewDataProcessor::ViewDataProcessor() : View("hex.builtin.view.data_processor.name") {
EventManager::subscribe<RequestChangeTheme>(this, [](u32 theme) {
switch (theme) {
default:
case 1: /* Dark theme */
ImNodes::StyleColorsDark();
break;
case 2: /* Light theme */
ImNodes::StyleColorsLight();
break;
case 3: /* Classic theme */
ImNodes::StyleColorsClassic();
break;
}
ImNodes::GetStyle().Flags = ImNodesStyleFlags_NodeOutline | ImNodesStyleFlags_GridLines;
});
ProjectFile::registerPerProviderHandler({
.basePath = "data_processor.json",
.required = false,

View File

@ -828,21 +828,6 @@ namespace hex::plugin::builtin {
this->m_textEditor.SetTextLines(lines);
}
});
EventManager::subscribe<RequestChangeTheme>(this, [this](u32 theme) {
switch (theme) {
default:
case 1: /* Dark theme */
this->m_textEditor.SetPalette(TextEditor::GetDarkPalette());
break;
case 2: /* Light theme */
this->m_textEditor.SetPalette(TextEditor::GetLightPalette());
break;
case 3: /* Classic theme */
this->m_textEditor.SetPalette(TextEditor::GetRetroBluePalette());
break;
}
});
}
static void createNestedMenu(const std::vector<std::string> &menus, const std::function<void()> &function) {

View File

@ -3,6 +3,7 @@
#include <hex/api/content_registry.hpp>
#include <hex/api/localization.hpp>
#include <hex/api/plugin_manager.hpp>
#include <hex/api/theme_manager.hpp>
#include <hex/ui/view.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp>
@ -419,12 +420,14 @@ namespace hex::plugin::builtin {
{
auto theme = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color");
if (theme.is_number()) {
static int lastTheme = 0;
if (theme.is_string()) {
if (theme != api::ThemeManager::NativeTheme) {
static std::string lastTheme;
if (const int thisTheme = theme.get<int>(); thisTheme != lastTheme) {
EventManager::post<RequestChangeTheme>(thisTheme);
lastTheme = thisTheme;
if (const auto thisTheme = theme.get<std::string>(); thisTheme != lastTheme) {
EventManager::post<RequestChangeTheme>(thisTheme);
lastTheme = thisTheme;
}
}
}
}
@ -448,51 +451,16 @@ namespace hex::plugin::builtin {
}
});
(void)EventManager::subscribe<RequestChangeTheme>([](u32 theme) {
(void)EventManager::subscribe<RequestChangeTheme>([](const std::string &theme) {
auto changeTexture = [&](const std::string &path) {
auto textureData = romfs::get(path);
return ImGui::Texture(reinterpret_cast<const ImU8*>(textureData.data()), textureData.size());
};
switch (theme) {
default:
case 1: /* Dark theme */
{
ImGui::StyleColorsDark();
ImGui::StyleCustomColorsDark();
ImPlot::StyleColorsDark();
s_bannerTexture = changeTexture("banner_dark.png");
s_backdropTexture = changeTexture("backdrop_dark.png");
break;
}
case 2: /* Light theme */
{
ImGui::StyleColorsLight();
ImGui::StyleCustomColorsLight();
ImPlot::StyleColorsLight();
s_bannerTexture = changeTexture("banner_light.png");
s_backdropTexture = changeTexture("backdrop_light.png");
break;
}
case 3: /* Classic theme */
{
ImGui::StyleColorsClassic();
ImGui::StyleCustomColorsClassic();
ImPlot::StyleColorsClassic();
s_bannerTexture = changeTexture("banner_dark.png");
s_backdropTexture = changeTexture("backdrop_dark.png");
break;
}
}
ImGui::GetStyle().Colors[ImGuiCol_DockingEmptyBg] = ImGui::GetStyle().Colors[ImGuiCol_WindowBg];
ImGui::GetStyle().Colors[ImGuiCol_TitleBg] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg];
ImGui::GetStyle().Colors[ImGuiCol_TitleBgActive] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg];
ImGui::GetStyle().Colors[ImGuiCol_TitleBgCollapsed] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg];
api::ThemeManager::changeTheme(theme);
s_bannerTexture = changeTexture(hex::format("banner{}.png", api::ThemeManager::getThemeImagePostfix()));
s_backdropTexture = changeTexture(hex::format("backdrop{}.png", api::ThemeManager::getThemeImagePostfix()));
if (!s_bannerTexture.isValid()) {
log::error("Failed to load banner texture!");

View File

@ -26,6 +26,8 @@ namespace hex::plugin::builtin {
void createWelcomeScreen();
void registerViews();
void registerShortcuts();
void registerThemeHandlers();
void registerThemes();
void addFooterItems();
void addToolbarItems();
@ -59,6 +61,8 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
createWelcomeScreen();
registerViews();
registerShortcuts();
registerThemeHandlers();
registerThemes();
addFooterItems();
addToolbarItems();

View File

@ -1,6 +1,7 @@
#include <hex/plugin.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/api/theme_manager.hpp>
#include <hex/helpers/logger.hpp>
#include <romfs/romfs.hpp>
@ -20,7 +21,7 @@ namespace hex::plugin::windows {
static void detectSystemTheme() {
// Setup system theme change detector
EventManager::subscribe<EventOSThemeChanged>([] {
bool themeFollowSystem = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color") == 0;
bool themeFollowSystem = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color") == api::ThemeManager::NativeTheme;
if (!themeFollowSystem)
return;
@ -31,7 +32,7 @@ static void detectSystemTheme() {
auto error = RegQueryValueEx(hkey, "AppsUseLightTheme", nullptr, nullptr, reinterpret_cast<LPBYTE>(&value), &size);
if (error == ERROR_SUCCESS) {
EventManager::post<RequestChangeTheme>(value == 0 ? 1 : 2);
EventManager::post<RequestChangeTheme>(value == 0 ? "Dark" : "Light");
} else {
ImHexApi::System::impl::setBorderlessWindowMode(false);
}
@ -41,7 +42,7 @@ static void detectSystemTheme() {
});
EventManager::subscribe<EventWindowInitialized>([=] {
bool themeFollowSystem = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color") == 0;
bool themeFollowSystem = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color") == api::ThemeManager::NativeTheme;
if (themeFollowSystem)
EventManager::post<EventOSThemeChanged>();