新增: 添加自定义主题设置相关函数

main
机械师 2025-09-12 19:04:20 +08:00
parent 0a57dae39c
commit 57cac6a451
5 changed files with 587 additions and 125 deletions

View File

@ -5,7 +5,26 @@
#include <string>
#include <map>
#include <vector>
#include <imgui.h>
#include "imgui.h"
struct LogColors {
ImVec4 error_color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f);
ImVec4 warn_color = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
ImVec4 info_color = ImVec4(0.4f, 1.0f, 0.4f, 1.0f);
ImVec4 debug_color = ImVec4(0.6f, 0.6f, 1.0f, 1.0f);
ImVec4 trace_color = ImVec4(0.8f, 0.8f, 0.8f, 1.0f);
void ResetToDefaults() {
error_color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f);
warn_color = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
info_color = ImVec4(0.4f, 1.0f, 0.4f, 1.0f);
debug_color = ImVec4(0.6f, 0.6f, 1.0f, 1.0f);
trace_color = ImVec4(0.8f, 0.8f, 0.8f, 1.0f);
}
};
class AppState {
public:
@ -50,8 +69,12 @@ public:
std::vector<std::string> command_history;
int max_command_history;
LogColors log_colors;
bool use_custom_log_colors = false;
bool use_ansi_colors = true;
bool settings_dirty;
private:
// 环境变量序列化辅助函数
std::string SerializeEnvironmentVariables() const;
@ -60,8 +83,11 @@ private:
// 编码序列化辅助函数
std::string SerializeOutputEncoding() const;
void DeserializeOutputEncoding(const std::string& serialized);
// 日志颜色序列化辅助
std::string SerializeLogColors() const;
void DeserializeLogColors(const std::string &serialized);
// 新增:命令历史记录序列化辅助函数
// 命令历史记录序列化辅助函数
std::string SerializeCommandHistory() const;
void DeserializeCommandHistory(const std::string& serialized);
};

View File

@ -37,6 +37,7 @@
#include "AppState.h"
#include "TrayIcon.h"
class Manager {
public:
// 构造函数和析构函数
@ -45,59 +46,68 @@ public:
~Manager();
// 核心生命周期管理
bool Initialize(); // 初始化应用程序
void Run(); // 运行主循环
void Shutdown(); // 关闭应用程序
bool Initialize(); // 初始化应用程序
void Run(); // 运行主循环
void Shutdown(); // 关闭应用程序
// 托盘事件回调
void OnTrayShowWindow(); // 托盘显示窗口事件
void OnTrayExit(); // 托盘退出事件
void OnTrayExit(); // 托盘退出事件
// 公共成员变量
AppState m_app_state; // 应用程序状态
AppState m_app_state; // 应用程序状态
private:
// 枚举类型定义
enum class LayoutPreset {
Classic, // 经典布局
Development, // 开发布局
Monitoring // 监控布局
Classic, // 经典布局
Development, // 开发布局
Monitoring // 监控布局
};
// UI渲染相关方法
void RenderUI(); // 渲染主UI
void RenderMenuBar(); // 渲染菜单栏
void RenderMainContent(); // 渲染主内容区域
void RenderSettingsMenu(); // 渲染设置菜单
void RenderStopCommandSettings(); // 渲染停止命令设置
void RenderEnvironmentVariablesSettings(); // 渲染环境变量设置
void RenderOutputEncodingSettings(); // 渲染输出编码设置
void RenderControlPanel(float buttonWidth, float buttonHeight, float inputWidth); // 渲染控制面板
void RenderCommandPanel(float buttonWidth, float inputWidth); // 渲染命令面板
void RenderLogPanel(); // 渲染日志面板
void RenderCommandHistory(); // 渲染命令历史
void RenderStatusMessages(); // 渲染状态消息
void RenderUI(); // 渲染主UI
void RenderMenuBar(); // 渲染菜单栏
void RenderMainContent(); // 渲染主内容区域
void RenderSettingsMenu(); // 渲染设置菜单
void RenderStopCommandSettings(); // 渲染停止命令设置
void RenderEnvironmentVariablesSettings(); // 渲染环境变量设置
void RenderOutputEncodingSettings(); // 渲染输出编码设置
void RenderColorThemeSettings();
void RenderControlPanel(float buttonWidth, float buttonHeight, float inputWidth); // 渲染控制面板
void RenderCommandPanel(float buttonWidth, float inputWidth); // 渲染命令面板
void RenderLogPanel(); // 渲染日志面板
void RenderCommandHistory(); // 渲染命令历史
void RenderStatusMessages(); // 渲染状态消息
// 布局管理相关方法
void SetupDefaultDockingLayout(ImGuiID dockspace_id); // 设置默认停靠布局
void RenderLayoutMenu(); // 渲染布局菜单
static void ApplyPresetLayout(LayoutPreset preset); // 应用预设布局
void SaveCurrentLayout(); // 保存当前布局
void LoadSavedLayout(); // 加载已保存布局
void SetupDefaultDockingLayout(ImGuiID dockspace_id); // 设置默认停靠布局
void RenderLayoutMenu(); // 渲染布局菜单
static void ApplyPresetLayout(LayoutPreset preset); // 应用预设布局
void SaveCurrentLayout(); // 保存当前布局
void LoadSavedLayout(); // 加载已保存布局
// 事件处理相关方法
void HandleMessages(); // 处理消息
bool ShouldExit() const; // 检查是否应该退出
static void ContentScaleCallback(GLFWwindow *window, float xscale, float yscale); // 内容缩放回调
void HandleMessages(); // 处理消息
bool ShouldExit() const; // 检查是否应该退出
static void ContentScaleCallback(GLFWwindow *window, float xscale, float yscale); // 内容缩放回调
// 窗口管理相关方法
void ShowMainWindow(); // 显示主窗口
void HideMainWindow(); // 隐藏主窗口
void ShowMainWindow(); // 显示主窗口
void HideMainWindow(); // 隐藏主窗口
// DPI相关方法
void UpdateDPIScale(); // 更新DPI缩放
void ReloadFonts() const; // 重新加载字体
void UpdateDPIScale(); // 更新DPI缩放
void ReloadFonts() const; // 重新加载字体
void SaveCurrentTheme();
void LoadSavedTheme();
ImVec4 GetCustomLogLevelColor(const std::string &log);
// 平台相关初始化方法
#ifdef USE_WIN32_BACKEND
@ -108,17 +118,17 @@ private:
static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // 窗口过程
#else
bool InitializeGLFW(); // 初始化GLFW
void CleanupGLFW(); // 清理GLFW
static void GlfwErrorCallback(int error, const char *description); // GLFW错误回调
bool InitializeGLFW(); // 初始化GLFW
void CleanupGLFW(); // 清理GLFW
static void GlfwErrorCallback(int error, const char *description); // GLFW错误回调
#endif
// 托盘相关方法
bool InitializeTray(); // 初始化托盘
void CleanupTray(); // 清理托盘
bool InitializeTray(); // 初始化托盘
void CleanupTray(); // 清理托盘
#ifdef _WIN32
static HWND CreateHiddenWindow(); // 创建隐藏窗口
static HWND CreateHiddenWindow(); // 创建隐藏窗口
#endif
// 平台相关成员变量
@ -130,41 +140,47 @@ private:
IDXGISwapChain* m_pSwapChain = nullptr; // 交换链
ID3D11RenderTargetView* m_mainRenderTargetView = nullptr; // 主渲染目标视图
#else
GLFWwindow *m_window = nullptr; // GLFW窗口
const char *m_glsl_version = nullptr; // GLSL版本
GLFWwindow *m_window = nullptr; // GLFW窗口
const char *m_glsl_version = nullptr; // GLSL版本
#endif
// 托盘相关成员变量
std::unique_ptr<TrayIcon> m_tray; // 托盘图标
std::unique_ptr<TrayIcon> m_tray; // 托盘图标
#ifdef _WIN32
HWND m_tray_hwnd = nullptr; // 托盘窗口句柄
HWND m_tray_hwnd = nullptr; // 托盘窗口句柄
#endif
// 控制标志
bool m_should_exit = false; // 是否应该退出
bool m_initialized = false; // 是否已初始化
bool m_should_exit = false; // 是否应该退出
bool m_initialized = false; // 是否已初始化
bool m_fullscreen = false;
bool m_padding = false;
// DPI缩放相关
float m_dpi_scale = 1.0f; // 当前DPI缩放
float m_last_dpi_scale = 1.0f; // 上次DPI缩放
float m_dpi_scale = 1.0f; // 当前DPI缩放
float m_last_dpi_scale = 1.0f; // 上次DPI缩放
// 布局相关成员变量
ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_MenuBar;
bool m_apply_preset_layout = false; // 是否需要应用预设布局
LayoutPreset m_pending_preset = LayoutPreset::Classic; // 待应用的预设布局
bool m_reset_layout = false; // 是否重置布局
bool m_show_save_success = false; // 是否显示保存成功消息
bool m_show_load_success = false; // 是否显示加载成功消息
float m_save_success_timer = 0.0f; // 保存成功消息计时器
float m_load_success_timer = 0.0f; // 加载成功消息计时器
bool m_apply_preset_layout = false; // 是否需要应用预设布局
LayoutPreset m_pending_preset = LayoutPreset::Classic; // 待应用的预设布局
bool m_reset_layout = false; // 是否重置布局
bool m_show_save_success = false; // 是否显示保存成功消息
bool m_show_load_success = false; // 是否显示加载成功消息
float m_save_success_timer = 0.0f; // 保存成功消息计时器
float m_load_success_timer = 0.0f; // 加载成功消息计时器
// UI状态相关成员变量
char env_key_input_[256] = {}; // 环境变量键输入缓冲区
char env_value_input_[512] = {}; // 环境变量值输入缓冲区
bool show_env_settings_ = false; // 是否显示环境变量设置
bool show_encoding_settings_ = false; // 是否显示编码设置
bool show_command_history_ = false; // 是否显示命令历史
char env_key_input_[256] = {}; // 环境变量键输入缓冲区
char env_value_input_[512] = {}; // 环境变量值输入缓冲区
bool show_env_settings_ = false; // 是否显示环境变量设置
bool show_encoding_settings_ = false; // 是否显示编码设置
bool show_command_history_ = false; // 是否显示命令历史
bool m_show_theme_save_success = true;
float m_theme_save_success_timer = 3.0f;
float m_theme_load_success_timer = 0.0f;
bool m_show_theme_load_success = false;
};

View File

@ -160,6 +160,82 @@ void AppState::DeserializeOutputEncoding(const std::string& serialized) {
}
}
std::string AppState::SerializeLogColors() const {
std::ostringstream oss;
// 按顺序保存每个颜色的RGBA值
oss << log_colors.error_color.x << ","
<< log_colors.error_color.y << ","
<< log_colors.error_color.z << ","
<< log_colors.error_color.w << "|";
oss << log_colors.warn_color.x << ","
<< log_colors.warn_color.y << ","
<< log_colors.warn_color.z << ","
<< log_colors.warn_color.w << "|";
oss << log_colors.info_color.x << ","
<< log_colors.info_color.y << ","
<< log_colors.info_color.z << ","
<< log_colors.info_color.w << "|";
oss << log_colors.debug_color.x << ","
<< log_colors.debug_color.y << ","
<< log_colors.debug_color.z << ","
<< log_colors.debug_color.w << "|";
oss << log_colors.trace_color.x << ","
<< log_colors.trace_color.y << ","
<< log_colors.trace_color.z << ","
<< log_colors.trace_color.w;
return oss.str();
}
// 新增:反序列化日志颜色
void AppState::DeserializeLogColors(const std::string& serialized) {
if (serialized.empty()) {
log_colors.ResetToDefaults();
return;
}
std::istringstream iss(serialized);
std::string colorStr;
int colorIndex = 0;
while (std::getline(iss, colorStr, '|') && colorIndex < 5) {
std::istringstream colorIss(colorStr);
std::string component;
float rgba[4] = {0.0f, 0.0f, 0.0f, 1.0f};
int i = 0;
while (std::getline(colorIss, component, ',') && i < 4) {
try {
rgba[i++] = std::stof(component);
} catch (const std::exception&) {
// 如果解析失败,使用默认值
}
}
ImVec4 color(rgba[0], rgba[1], rgba[2], rgba[3]);
switch (colorIndex) {
case 0: log_colors.error_color = color; break;
case 1: log_colors.warn_color = color; break;
case 2: log_colors.info_color = color; break;
case 3: log_colors.debug_color = color; break;
case 4: log_colors.trace_color = color; break;
}
colorIndex++;
}
// 如果没有足够的颜色数据,重置为默认值
if (colorIndex < 5) {
log_colors.ResetToDefaults();
}
}
void AppState::LoadSettings() {
std::ifstream file("climanager_settings.ini");
if (!file.is_open()) return;
@ -234,6 +310,14 @@ void AppState::LoadSettings() {
else if (key == "MaxCommandHistory") {
max_command_history = std::stoi(value);
max_command_history = std::max(5, std::min(max_command_history, 100));
}else if (key == "UseCustomLogColors") {
use_custom_log_colors = (value == "1");
}
else if (key == "UseAnsiColors") {
use_ansi_colors = (value == "1");
}
else if (key == "LogColors") {
DeserializeLogColors(value);
}
}
}
@ -271,6 +355,9 @@ void AppState::SaveSettings() {
file << "CommandHistory=" << SerializeCommandHistory() << "\n";
file << "MaxCommandHistory=" << max_command_history << "\n";
file << "UseCustomLogColors=" << (use_custom_log_colors ? "1" : "0") << "\n";
file << "UseAnsiColors=" << (use_ansi_colors ? "1" : "0") << "\n";
file << "LogColors=" << SerializeLogColors() << "\n";
file.close();
settings_dirty = false;

View File

@ -28,10 +28,10 @@ bool Manager::Initialize() {
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO &io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
// io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
// io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
io.ConfigViewportsNoAutoMerge = true;
io.IniFilename = "imgui.ini";
@ -67,10 +67,10 @@ bool Manager::Initialize() {
// 加载字体
#ifdef _WIN32
ImFont *font = io.Fonts->AddFontFromFileTTF(
"C:/Windows/Fonts/msyh.ttc",
16.0f * m_dpi_scale,
nullptr,
io.Fonts->GetGlyphRangesChineseFull()
"C:/Windows/Fonts/msyh.ttc",
16.0f * m_dpi_scale,
nullptr,
io.Fonts->GetGlyphRangesChineseFull()
);
#elif __APPLE__
// macOS 中文字体路径
@ -113,6 +113,7 @@ bool Manager::Initialize() {
m_app_state.ApplySettings();
m_app_state.SaveSettings();
LoadSavedTheme();
#ifdef _WIN32
m_tray->UpdateWebUrl(StringToWide(m_app_state.web_url));
@ -214,7 +215,7 @@ void Manager::RenderUI() {
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoMove;
ImGuiWindowFlags_NoMove;
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
} else {
dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode;
@ -226,7 +227,7 @@ void Manager::RenderUI() {
if (!m_padding)
ImGui::PopStyleVar();
if (m_fullscreen)
ImGui::PopStyleVar(2); // Submit the DockSpace
ImGui::PopStyleVar(2); // Submit the DockSpace
ImGui::Begin("CLI程序管理工具", &m_app_state.show_main_window,
window_flags);
@ -302,9 +303,10 @@ void Manager::RenderMenuBar() {
// 添加主题菜单
if (ImGui::BeginMenu("主题")) {
if (ImGui::MenuItem("暗黑(Dark)")) { ImGui::StyleColorsDark(); }
if (ImGui::MenuItem("明亮(Light)")) { ImGui::StyleColorsLight(); }
if (ImGui::MenuItem("经典(Classic)")) { ImGui::StyleColorsClassic(); }
// if (ImGui::MenuItem("暗黑(Dark)")) { ImGui::StyleColorsDark(); }
// if (ImGui::MenuItem("明亮(Light)")) { ImGui::StyleColorsLight(); }
// if (ImGui::MenuItem("经典(Classic)")) { ImGui::StyleColorsClassic(); }
RenderColorThemeSettings();
ImGui::EndMenu();
}
@ -313,7 +315,7 @@ void Manager::RenderMenuBar() {
ImGui::MenuItem("填充(Padding)", nullptr, &m_padding);
ImGui::Separator();
if (ImGui::MenuItem("标志:不分割(Flag: NoSplit)", "", (dockspace_flags & ImGuiDockNodeFlags_NoSplit) !=
0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoSplit; }
0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoSplit; }
if (ImGui::MenuItem("标志:不调整大小(Flag: NoResize)", "",
(dockspace_flags & ImGuiDockNodeFlags_NoResize) !=
0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoResize; }
@ -510,6 +512,45 @@ void Manager::RenderStatusMessages() {
m_show_load_success = false;
}
}
if (m_show_theme_save_success) {
ImGui::SetNextWindowPos(ImVec2(ImGui::GetMainViewport()->Size.x * 0.5f, 50), ImGuiCond_Always,
ImVec2(0.5f, 0.0f));
ImGui::SetNextWindowBgAlpha(0.8f);
if (ImGui::Begin("ThemeSaveSuccess", nullptr,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "主题已保存");
}
ImGui::End();
m_theme_save_success_timer -= ImGui::GetIO().DeltaTime;
if (m_theme_save_success_timer <= 0.0f) {
m_show_theme_save_success = false;
}
}
// 渲染主题加载成功提示
if (m_show_theme_load_success) {
ImGui::SetNextWindowPos(ImVec2(ImGui::GetMainViewport()->Size.x * 0.5f, 50), ImGuiCond_Always,
ImVec2(0.5f, 0.0f));
ImGui::SetNextWindowBgAlpha(0.8f);
if (ImGui::Begin("ThemeLoadSuccess", nullptr,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "主题已加载");
}
ImGui::End();
m_theme_load_success_timer -= ImGui::GetIO().DeltaTime;
if (m_theme_load_success_timer <= 0.0f) {
m_show_theme_load_success = false;
}
}
}
void Manager::RenderMainContent() {
@ -585,6 +626,7 @@ void Manager::RenderSettingsMenu() {
RenderStopCommandSettings();
RenderEnvironmentVariablesSettings();
RenderOutputEncodingSettings();
}
void Manager::RenderStopCommandSettings() {
@ -690,7 +732,7 @@ void Manager::RenderEnvironmentVariablesSettings() {
ImGui::Spacing();
ImGui::TextWrapped(
"说明启用后CLI程序将使用这些自定义环境变量。这些变量会与系统环境变量合并同名变量会被覆盖。");
"说明启用后CLI程序将使用这些自定义环境变量。这些变量会与系统环境变量合并同名变量会被覆盖。");
ImGui::Unindent();
} else {
@ -773,8 +815,9 @@ void Manager::RenderControlPanel(float buttonWidth, float buttonHeight, float in
m_app_state.AddCommandToHistory(m_app_state.command_input);
if (strlen(m_app_state.working_directory) > 0) {
m_app_state.cli_process.SetWorkingDirectory(m_app_state.working_directory);
}else {
strncpy_s(m_app_state.working_directory,m_app_state.cli_process.GetWorkingDirectory().c_str(),sizeof(m_app_state.working_directory)-1);
} else {
strncpy_s(m_app_state.working_directory, m_app_state.cli_process.GetWorkingDirectory().c_str(),
sizeof(m_app_state.working_directory) - 1);
}
m_tray->UpdateStatus(m_app_state.cli_process.IsRunning() ? L"运行中" : L"已停止",
m_app_state.cli_process.GetPid());
@ -800,9 +843,9 @@ void Manager::RenderControlPanel(float buttonWidth, float buttonHeight, float in
// 状态显示
ImGui::SeparatorText("运行状态");
ImVec4 statusColor = m_app_state.cli_process.IsRunning() ?
ImVec4(0.0f, 1.0f, 0.0f, 1.0f) :
ImVec4(1.0f, 0.0f, 0.0f, 1.0f);
ImVec4 statusColor = m_app_state.cli_process.IsRunning()
? ImVec4(0.0f, 1.0f, 0.0f, 1.0f)
: ImVec4(1.0f, 0.0f, 0.0f, 1.0f);
ImGui::TextColored(statusColor, "状态: %s",
m_app_state.cli_process.IsRunning() ? "运行中" : "已停止");
}
@ -875,11 +918,17 @@ void Manager::RenderLogPanel() {
const std::string &log = logs[i];
if (m_app_state.enable_colored_logs) {
RenderColoredLogLine(log);
if (m_app_state.use_ansi_colors) {
// 使用ANSI颜色转义序列解析
RenderColoredLogLine(log);
} else {
// 仅使用日志级别的颜色区分
ImVec4 textColor = GetCustomLogLevelColor(log);
ImGui::TextColored(textColor, "%s", log.c_str());
}
} else {
// 简单的日志级别颜色区分
ImVec4 textColor = GetLogLevelColor(log);
ImGui::TextColored(textColor, "%s", log.c_str());
// 不启用彩色显示,使用默认白色
ImGui::TextUnformatted(log.c_str());
}
}
}
@ -1087,14 +1136,14 @@ HWND Manager::CreateHiddenWindow() {
}
return CreateWindowEx(
0,
wc.lpszClassName,
L"CLI Manager Tray Window",
0,
0, 0, 0, 0,
NULL, NULL,
wc.hInstance,
NULL
0,
wc.lpszClassName,
L"CLI Manager Tray Window",
0,
0, 0, 0, 0,
NULL, NULL,
wc.hInstance,
NULL
);
}
@ -1303,7 +1352,7 @@ bool Manager::InitializeGLFW() {
int windowWidth = static_cast<int>(screenWidth * 0.8);
int windowHeight = static_cast<int>(screenHeight * 0.8);
// glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);//窗口隐藏
// glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);//窗口隐藏
m_window = glfwCreateWindow(windowWidth, windowHeight, "CLI程序管理工具", nullptr, nullptr);
if (!m_window)
@ -1502,3 +1551,241 @@ extern "C" {
void* GetMacTrayIcon();
}
#endif
void Manager::RenderColorThemeSettings() {
// 预设主题
if (ImGui::MenuItem("暗黑(Dark)")) {
ImGui::StyleColorsDark();
}
if (ImGui::MenuItem("明亮(Light)")) {
ImGui::StyleColorsLight();
}
if (ImGui::MenuItem("经典(Classic)")) {
ImGui::StyleColorsClassic();
}
ImGui::Separator();
ImGui::Text("颜色主题设置");
if (ImGui::Checkbox("自定义日志颜色", &m_app_state.use_custom_log_colors)) {
m_app_state.settings_dirty = true;
}
if (m_app_state.use_custom_log_colors) {
ImGui::Indent();
ImGui::Text("日志级别颜色:");
// 编辑错误日志颜色
ImVec4 errorColor = ImVec4(
m_app_state.log_colors.error_color.x,
m_app_state.log_colors.error_color.y,
m_app_state.log_colors.error_color.z,
1.0f
);
if (ImGui::ColorEdit3("错误日志", (float *) &errorColor)) {
m_app_state.log_colors.error_color = errorColor;
m_app_state.settings_dirty = true;
}
// 编辑警告日志颜色
ImVec4 warnColor = ImVec4(
m_app_state.log_colors.warn_color.x,
m_app_state.log_colors.warn_color.y,
m_app_state.log_colors.warn_color.z,
1.0f
);
if (ImGui::ColorEdit3("警告日志", (float *) &warnColor)) {
m_app_state.log_colors.warn_color = warnColor;
m_app_state.settings_dirty = true;
}
// 编辑信息日志颜色
ImVec4 infoColor = ImVec4(
m_app_state.log_colors.info_color.x,
m_app_state.log_colors.info_color.y,
m_app_state.log_colors.info_color.z,
1.0f
);
if (ImGui::ColorEdit3("信息日志", (float *) &infoColor)) {
m_app_state.log_colors.info_color = infoColor;
m_app_state.settings_dirty = true;
}
// 编辑调试日志颜色
ImVec4 debugColor = ImVec4(
m_app_state.log_colors.debug_color.x,
m_app_state.log_colors.debug_color.y,
m_app_state.log_colors.debug_color.z,
1.0f
);
if (ImGui::ColorEdit3("调试日志", (float *) &debugColor)) {
m_app_state.log_colors.debug_color = debugColor;
m_app_state.settings_dirty = true;
}
// 重置为默认颜色按钮
if (ImGui::Button("重置为默认颜色")) {
m_app_state.log_colors.ResetToDefaults();
m_app_state.settings_dirty = true;
}
ImGui::Unindent();
}
// ANSI颜色设置
ImGui::Separator();
if (ImGui::Checkbox("使用ANSI颜色转义", &m_app_state.use_ansi_colors)) {
m_app_state.settings_dirty = true;
}
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted("启用后日志中的ANSI颜色转义序列将被解析并显示为彩色文本。");
ImGui::TextUnformatted("例如: \\033[31m红色文本\\033[0m");
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
// 颜色样式设置
ImGui::Text("全局颜色样式:");
static int currentTheme = 0; // 默认暗色主题
const char *themes[] = {"暗黑 (Dark)", "明亮 (Light)", "经典 (Classic)", "自定义 (Custom)"};
if (ImGui::Combo("应用主题", &currentTheme, themes, IM_ARRAYSIZE(themes))) {
switch (currentTheme) {
case 0: ImGui::StyleColorsDark();
break;
case 1: ImGui::StyleColorsLight();
break;
case 2: ImGui::StyleColorsClassic();
break;
case 3: /* 应用自定义主题 */ break;
}
}
// 自定义主题编辑器(仅在选择"自定义"主题时显示)
if (currentTheme == 3) {
if (ImGui::TreeNode("自定义主题编辑器")) {
ImGuiStyle &style = ImGui::GetStyle();
// 添加主题颜色编辑器
for (int i = 0; i < ImGuiCol_COUNT; i++) {
const char *name = ImGui::GetStyleColorName(i);
ImGui::ColorEdit4(name, (float *) &style.Colors[i]);
}
// 添加样式参数编辑器
ImGui::SliderFloat("窗口圆角", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("子窗口圆角", &style.ChildRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("框架圆角", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("弹出窗口圆角", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("滚动条圆角", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("抓取圆角", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("标签圆角", &style.TabRounding, 0.0f, 12.0f, "%.0f");
ImGui::Separator();
// 保存/加载主题按钮
if (ImGui::Button("保存当前主题")) {
SaveCurrentTheme();
}
ImGui::SameLine();
if (ImGui::Button("加载保存的主题")) {
LoadSavedTheme();
}
ImGui::TreePop();
}
}
}
// 保存当前主题设置
void Manager::SaveCurrentTheme() {
std::ofstream file("theme.ini", std::ios::binary);
if (file.is_open()) {
ImGuiStyle &style = ImGui::GetStyle();
// 保存主题颜色
for (int i = 0; i < ImGuiCol_COUNT; i++) {
file.write(reinterpret_cast<const char *>(&style.Colors[i]), sizeof(ImVec4));
}
// 保存样式参数
file.write(reinterpret_cast<const char *>(&style.WindowRounding), sizeof(float));
file.write(reinterpret_cast<const char *>(&style.ChildRounding), sizeof(float));
file.write(reinterpret_cast<const char *>(&style.FrameRounding), sizeof(float));
file.write(reinterpret_cast<const char *>(&style.PopupRounding), sizeof(float));
file.write(reinterpret_cast<const char *>(&style.ScrollbarRounding), sizeof(float));
file.write(reinterpret_cast<const char *>(&style.GrabRounding), sizeof(float));
file.write(reinterpret_cast<const char *>(&style.TabRounding), sizeof(float));
file.close();
// 显示保存成功提示
m_show_theme_save_success = true;
m_theme_save_success_timer = 3.0f; // 3秒后消失
}
}
// 加载保存的主题设置
void Manager::LoadSavedTheme() {
std::ifstream file("theme.ini", std::ios::binary);
if (file.is_open()) {
ImGuiStyle &style = ImGui::GetStyle();
// 加载主题颜色
for (int i = 0; i < ImGuiCol_COUNT; i++) {
file.read(reinterpret_cast<char *>(&style.Colors[i]), sizeof(ImVec4));
}
// 加载样式参数
file.read(reinterpret_cast<char *>(&style.WindowRounding), sizeof(float));
file.read(reinterpret_cast<char *>(&style.ChildRounding), sizeof(float));
file.read(reinterpret_cast<char *>(&style.FrameRounding), sizeof(float));
file.read(reinterpret_cast<char *>(&style.PopupRounding), sizeof(float));
file.read(reinterpret_cast<char *>(&style.ScrollbarRounding), sizeof(float));
file.read(reinterpret_cast<char *>(&style.GrabRounding), sizeof(float));
file.read(reinterpret_cast<char *>(&style.TabRounding), sizeof(float));
file.close();
// 显示加载成功提示
m_show_theme_load_success = true;
m_theme_load_success_timer = 3.0f; // 3秒后消失
}
}
ImVec4 Manager::GetCustomLogLevelColor(const std::string &log) {
if (!m_app_state.use_custom_log_colors) {
// 使用默认颜色
return GetLogLevelColor(log);
}
// 使用自定义颜色
if (log.find("错误") != std::string::npos || log.find("[E]") != std::string::npos ||
log.find("[ERROR]") != std::string::npos || log.find("error") != std::string::npos) {
return m_app_state.log_colors.error_color;
} else if (log.find("警告") != std::string::npos || log.find("[W]") != std::string::npos ||
log.find("[WARN]") != std::string::npos || log.find("warning") != std::string::npos) {
return m_app_state.log_colors.warn_color;
} else if (log.find("信息") != std::string::npos || log.find("[I]") != std::string::npos ||
log.find("[INFO]") != std::string::npos || log.find("info") != std::string::npos) {
return m_app_state.log_colors.info_color;
} else if (log.find("调试") != std::string::npos || log.find("[D]") != std::string::npos ||
log.find("[DEBUG]") != std::string::npos || log.find("debug") != std::string::npos) {
return m_app_state.log_colors.debug_color;
} else if (log.find("跟踪") != std::string::npos || log.find("[T]") != std::string::npos ||
log.find("[TRACE]") != std::string::npos || log.find("trace") != std::string::npos) {
return m_app_state.log_colors.trace_color;
}
return ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // 默认白色
}

View File

@ -6,7 +6,7 @@
#include <windows.h>
#include <sstream>
std::wstring StringToWide(const std::string& str) {
std::wstring StringToWide(const std::string &str) {
if (str.empty()) return L"";
int size = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0);
std::wstring wstr(size, 0);
@ -14,7 +14,7 @@ std::wstring StringToWide(const std::string& str) {
return wstr;
}
std::string WideToString(const std::wstring& wstr) {
std::string WideToString(const std::wstring &wstr) {
if (wstr.empty()) return "";
int size = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
std::string str(size, 0);
@ -44,9 +44,8 @@ void SetAutoStart(bool enable) {
if (enable) {
RegSetValueEx(hKey, keyName, 0, REG_SZ,
(BYTE*)exePath, (wcslen(exePath) + 1) * sizeof(WCHAR));
}
else {
(BYTE *) exePath, (wcslen(exePath) + 1) * sizeof(WCHAR));
} else {
RegDeleteValue(hKey, keyName);
}
RegCloseKey(hKey);
@ -79,6 +78,7 @@ bool IsAutoStartEnabled() {
return exists;
}
// 日志颜色处理函数
ImVec4 GetLogLevelColor(const std::string &log) {
// 简单的日志级别颜色区分
if (log.find("错误") != std::string::npos || log.find("[E]") != std::string::npos ||
@ -90,11 +90,17 @@ ImVec4 GetLogLevelColor(const std::string &log) {
} else if (log.find("信息") != std::string::npos || log.find("[I]") != std::string::npos ||
log.find("[INFO]") != std::string::npos || log.find("info") != std::string::npos) {
return ImVec4(0.4f, 1.0f, 0.4f, 1.0f); // 绿色
} else if (log.find("调试") != std::string::npos || log.find("[D]") != std::string::npos ||
log.find("[DEBUG]") != std::string::npos || log.find("debug") != std::string::npos) {
return ImVec4(0.6f, 0.6f, 1.0f, 1.0f); // 蓝色
} else if (log.find("跟踪") != std::string::npos || log.find("[T]") != std::string::npos ||
log.find("[TRACE]") != std::string::npos || log.find("trace") != std::string::npos) {
return ImVec4(0.8f, 0.8f, 0.8f, 1.0f); // 灰色
}
return ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // 默认白色
}
// ANSI颜色处理增强版本
void RenderColoredLogLine(const std::string &log) {
auto segments = ParseAnsiColorCodes(log);
@ -197,18 +203,18 @@ ParseAnsiColorCode(const std::string &code, const ImVec4 &currentColor, bool cur
for (int colorCode: codes) {
switch (colorCode) {
case 0: // 重置
case 0: // 重置
newColor = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
newBold = false;
break;
case 1: // 粗体/亮色
case 1: // 粗体/亮色
newBold = true;
break;
case 22: // 正常强度
newBold = false;
break;
// 前景色 (30-37)
// 前景色 (30-37)
case 30:
newColor = GetAnsiColor(0, newBold);
break; // 黑色
@ -237,13 +243,13 @@ ParseAnsiColorCode(const std::string &code, const ImVec4 &currentColor, bool cur
newColor = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
break; // 默认前景色
// 亮色前景色 (90-97)
// 亮色前景色 (90-97)
case 90:
newColor = GetAnsiColor(8, false);
break; // 亮黑色(灰色)
break; // 亮黑色(灰色)
case 91:
newColor = GetAnsiColor(9, false);
break; // 亮红色
break; // 亮红色
case 92:
newColor = GetAnsiColor(10, false);
break; // 亮绿色
@ -263,10 +269,49 @@ ParseAnsiColorCode(const std::string &code, const ImVec4 &currentColor, bool cur
newColor = GetAnsiColor(15, false);
break; // 亮白色
// 背景色暂时忽略 (40-47, 100-107)
// 增加对背景色的支持 (40-47, 100-107)
case 40:
case 41:
case 42:
case 43:
case 44:
case 45:
case 46:
case 47:
case 100:
case 101:
case 102:
case 103:
case 104:
case 105:
case 106:
case 107:
// 背景色暂时不处理因为ImGui不容易实现背景色
break;
default:
// 处理256色和RGB色彩(38;5;n 和 38;2;r;g;b)
// 这里可以根据需要扩展
if (colorCode == 38 || colorCode == 48) {
// 38=前景48=背景
// 检查是否是256色模式或RGB模式
if (codes.size() > 1) {
if (codes[1] == 5 && codes.size() > 2) {
// 256色模式
// 暂时不实现所有256色仅处理基本的16色
int colorIndex = codes[2];
if (colorIndex >= 0 && colorIndex < 16) {
newColor = GetAnsiColor(colorIndex, newBold);
}
} else if (codes[1] == 2 && codes.size() > 4) {
// RGB模式
// 处理RGB值
float r = static_cast<float>(codes[2]) / 255.0f;
float g = static_cast<float>(codes[3]) / 255.0f;
float b = static_cast<float>(codes[4]) / 255.0f;
newColor = ImVec4(r, g, b, 1.0f);
}
}
}
break;
}
}
@ -277,25 +322,25 @@ ParseAnsiColorCode(const std::string &code, const ImVec4 &currentColor, bool cur
ImVec4 GetAnsiColor(int colorIndex, bool bright) {
// ANSI标准颜色表
static const ImVec4 ansiColors[16] = {
// 标准颜色 (0-7)
ImVec4(0.0f, 0.0f, 0.0f, 1.0f), // 0: 黑色
ImVec4(0.8f, 0.0f, 0.0f, 1.0f), // 1: 红色
ImVec4(0.0f, 0.8f, 0.0f, 1.0f), // 2: 绿色
ImVec4(0.8f, 0.8f, 0.0f, 1.0f), // 3: 黄色
ImVec4(0.0f, 0.0f, 0.8f, 1.0f), // 4: 蓝色
ImVec4(0.8f, 0.0f, 0.8f, 1.0f), // 5: 洋红
ImVec4(0.0f, 0.8f, 0.8f, 1.0f), // 6: 青色
ImVec4(0.8f, 0.8f, 0.8f, 1.0f), // 7: 白色
// 标准颜色 (0-7)
ImVec4(0.0f, 0.0f, 0.0f, 1.0f), // 0: 黑色
ImVec4(0.8f, 0.0f, 0.0f, 1.0f), // 1: 红色
ImVec4(0.0f, 0.8f, 0.0f, 1.0f), // 2: 绿色
ImVec4(0.8f, 0.8f, 0.0f, 1.0f), // 3: 黄色
ImVec4(0.0f, 0.0f, 0.8f, 1.0f), // 4: 蓝色
ImVec4(0.8f, 0.0f, 0.8f, 1.0f), // 5: 洋红
ImVec4(0.0f, 0.8f, 0.8f, 1.0f), // 6: 青色
ImVec4(0.8f, 0.8f, 0.8f, 1.0f), // 7: 白色
// 亮色 (8-15)
ImVec4(0.5f, 0.5f, 0.5f, 1.0f), // 8: 亮黑色(灰色)
ImVec4(1.0f, 0.0f, 0.0f, 1.0f), // 9: 亮红色
ImVec4(0.0f, 1.0f, 0.0f, 1.0f), // 10: 亮绿色
ImVec4(1.0f, 1.0f, 0.0f, 1.0f), // 11: 亮黄色
ImVec4(0.0f, 0.0f, 1.0f, 1.0f), // 12: 亮蓝色
ImVec4(1.0f, 0.0f, 1.0f, 1.0f), // 13: 亮洋红
ImVec4(0.0f, 1.0f, 1.0f, 1.0f), // 14: 亮青色
ImVec4(1.0f, 1.0f, 1.0f, 1.0f), // 15: 亮白色
// 亮色 (8-15)
ImVec4(0.5f, 0.5f, 0.5f, 1.0f), // 8: 亮黑色(灰色)
ImVec4(1.0f, 0.0f, 0.0f, 1.0f), // 9: 亮红色
ImVec4(0.0f, 1.0f, 0.0f, 1.0f), // 10: 亮绿色
ImVec4(1.0f, 1.0f, 0.0f, 1.0f), // 11: 亮黄色
ImVec4(0.0f, 0.0f, 1.0f, 1.0f), // 12: 亮蓝色
ImVec4(1.0f, 0.0f, 1.0f, 1.0f), // 13: 亮洋红
ImVec4(0.0f, 1.0f, 1.0f, 1.0f), // 14: 亮青色
ImVec4(1.0f, 1.0f, 1.0f, 1.0f), // 15: 亮白色
};
if (colorIndex >= 0 && colorIndex < 16) {
@ -313,3 +358,4 @@ ImVec4 GetAnsiColor(int colorIndex, bool bright) {
return ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // 默认白色
}