diff --git a/src/mirage_core/misc/name.h b/src/mirage_core/misc/name.h new file mode 100644 index 0000000..983045f --- /dev/null +++ b/src/mirage_core/misc/name.h @@ -0,0 +1,36 @@ +#pragma once +#include +#include + +/** + * name_t + * @brief 一种用于存储字符串的类,使用哈希值作为唯一标识符 + * @note 应该尽量少的构造 name_t 对象, 因为每次构造都会在 name_map 中插入一个新的元素并 hash 字符串 + */ +template +struct name_t { +public: + explicit name_t(const StringType& in_str) { + hash_value_ = hash(in_str); + name_map[hash_value_] = in_str; + } + + [[nodiscard]] auto to_string() const { + return name_map[hash_value_]; + } +private: + static uint64_t hash(const StringType& str) { + uint64_t hash = 5381; + for (const auto c : str) { + hash = (hash << 5) + hash + c; // hash * 33 + c + } + return hash; + } +private: + uint64_t hash_value_; + inline static std::unordered_map name_map; +}; + +using u8name_t = name_t; +using u16name_t = name_t; +using u32name_t = name_t; diff --git a/src/mirage_image/color.cpp b/src/mirage_image/color.cpp index 73452be..214f143 100644 --- a/src/mirage_image/color.cpp +++ b/src/mirage_image/color.cpp @@ -1,2 +1,110 @@ #include "color.h" +#include +#include + +linear_color linear_color::from_string(const std::string& in_str) { + // **定义一个表示无效输入的默认返回值 (C++20 designated initializers)** + // Made static constexpr for potential compile-time use if needed elsewhere + static linear_color invalid_color = { 0.0f, 0.0f, 0.0f, 0.0f }; + + std::string str = in_str; + + // **1. 去除前后空格 (No major C++23 change here, std::find_if is efficient)** + auto trim_func = [](unsigned char ch){ return !std::isspace(ch); }; + str.erase(str.begin(), std::ranges::find_if(str, trim_func)); + str.erase(std::find_if(str.rbegin(), str.rend(), trim_func).base(), str.end()); + + // **2. 检查格式前缀和后缀 (C++20 starts_with/ends_with)** + bool is_rgba = false; + std::string_view value_part_sv; + + if (str.starts_with("rgb(") && str.ends_with(')')) { + is_rgba = false; + value_part_sv = std::string_view(str).substr(4, str.length() - 5); // Skip "rgb(" and ")" + } else if (str.starts_with("rgba(") && str.ends_with(')')) { + is_rgba = true; + value_part_sv = std::string_view(str).substr(5, str.length() - 6); // Skip "rgba(" and ")" + } else { + return invalid_color; // **无效格式前缀/后缀** + } + + if (value_part_sv.empty() && (is_rgba ? 4 : 3) > 0) { + // Handle cases like "rgb()" or "rgba()" which are invalid if components are expected + return invalid_color; // **括号内为空** + } + + // **3. 分割数值字符串 (Using stringstream, C++23 views could be an alternative but more complex here)** + std::vector values; + std::stringstream ss; + ss << value_part_sv; + std::string segment; + + while (std::getline(ss, segment, ',')) { + // **4. 处理每个分量** + // 去除分量前后的空格 + segment.erase(segment.begin(), std::ranges::find_if(segment, trim_func)); + segment.erase(std::find_if(segment.rbegin(), segment.rend(), trim_func).base(), segment.end()); + + if (segment.empty()) { + return invalid_color; // **空分量值** + } + + const char* const first = segment.data(); + const char* const last = first + segment.size(); + float component_value = 0.0f; + + // **C++23 std::string::contains to check for decimal point** + if (segment.contains('.')) { + // **处理浮点数 [0, 1]** + float val = 0.0f; + auto [ptr, ec] = std::from_chars(first, last, val); + + // Check for errors: conversion failed OR not the entire segment was parsed + if (ec != std::errc() || ptr != last) { + return invalid_color; // **无效浮点数格式** + } + + // Check range [0, 1] for floats + if (val < 0.0f || val > 1.0f) { + return invalid_color; // **浮点数值超出 [0, 1] 范围** + } + component_value = val; + + } else { + // **处理整数 [0, 255]** + int int_val = 0; + auto [ptr, ec] = std::from_chars(first, last, int_val); + + // Check for errors: conversion failed OR not the entire segment was parsed + if (ec != std::errc() || ptr != last) { + return invalid_color; // **无效整数格式** + } + + // Check range [0, 255] for integers + if (int_val < 0 || int_val > 255) { + return invalid_color; // **整数值超出 [0, 255] 范围** + } + + // **归一化: 将 uint8 范围的值映射到 [0, 1] float** + component_value = static_cast(int_val) / 255.0f; + } + + values.push_back(component_value); + } + + // **5. 检查分量数量是否匹配** + if (is_rgba) { + if (values.size() != 4) { + return invalid_color; // **rgba 分量数量错误** + } + return { values[0], values[1], values[2], values[3] }; + } + + // rgb + if (values.size() != 3) { + return invalid_color; // **rgb 分量数量错误** + } + // **对于 rgb,alpha 默认为 1.0f** + return { values[0], values[1], values[2], 1.f }; +} diff --git a/src/mirage_image/color.h b/src/mirage_image/color.h index 173ff3a..28b10ae 100644 --- a/src/mirage_image/color.h +++ b/src/mirage_image/color.h @@ -135,6 +135,21 @@ public: return r == in_color.r && g == in_color.g && b == in_color.b && a == in_color.a; } + /** + * @brief 从字符串解析颜色值 (C++23 Style adaptation)。 + * 支持格式: "rgb(r, g, b)" 或 "rgba(r, g, b, a)"。 + * - **浮点数值**: 如果分量包含小数点 '.', 它必须在 [0, 1] 范围内。 + * - **整数数值**: 如果分量不包含小数点: + * - 值在 [0, 1] 范围内,直接使用 0.0f 或 1.0f。 (隐式包含在此逻辑中) + * - **值在 (1, 255] 范围内,视为 uint8_t,并归一化为 [0, 1] (value / 255.0f)。** + * - 值 < 0 或 > 255,则视为无效。 + * @param in_str 输入的颜色字符串。 + * @return 解析得到的 linear_color 对象。 + * @note **如果字符串格式无效或颜色分量值无效/超出范围,则返回 linear_color{0.0f, 0.0f, 0.0f, 0.0f}。** + * 使用 [[nodiscard]] 提示调用者应检查返回值。 + */ + [[nodiscard]] static linear_color from_string(const std::string& in_str); + //-------------- 成员变量 -------------- /** 红色分量,范围 [0,1] */ diff --git a/src/mirage_widget/CMakeLists.txt b/src/mirage_widget/CMakeLists.txt index 2c26562..c5f0095 100644 --- a/src/mirage_widget/CMakeLists.txt +++ b/src/mirage_widget/CMakeLists.txt @@ -3,6 +3,8 @@ project(mirage_widget) set(SRC_FILES) retrieve_files(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_FILES) +add_subdirectory(third_party/tomlplusplus) + add_library(${PROJECT_NAME} STATIC ${SRC_FILES}) target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) -target_link_libraries(${PROJECT_NAME} PUBLIC mirage_core mirage_render) +target_link_libraries(${PROJECT_NAME} PUBLIC mirage_core mirage_render tomlplusplus::tomlplusplus) diff --git a/src/mirage_widget/src/style/default_style.toml b/src/mirage_widget/src/style/default_style.toml new file mode 100644 index 0000000..4eb25dd --- /dev/null +++ b/src/mirage_widget/src/style/default_style.toml @@ -0,0 +1,10 @@ +[info] +name = "default_style" +version = "0.0.1" +description = "mirage的默认样式" +author = "奶酪" + +[button] +hover_color = "rgb(31, 31, 31)" +pressed_color = "rgb(31, 31, 31)" +normal_color = "rgb(31, 31, 31)" diff --git a/src/mirage_widget/src/style/mirage_style.cpp b/src/mirage_widget/src/style/mirage_style.cpp new file mode 100644 index 0000000..7d7f67c --- /dev/null +++ b/src/mirage_widget/src/style/mirage_style.cpp @@ -0,0 +1,10 @@ +#include "mirage_style.h" + +bool mirage_style::load_config(const std::filesystem::path& in_filename) { + try { + tbl = toml::parse_file(in_filename.string()); + } + catch (const toml::parse_error& err) { + fprintf(stderr, "%s\n", err.what()); + } +} diff --git a/src/mirage_widget/src/style/mirage_style.h b/src/mirage_widget/src/style/mirage_style.h new file mode 100644 index 0000000..d4af4f2 --- /dev/null +++ b/src/mirage_widget/src/style/mirage_style.h @@ -0,0 +1,19 @@ +#pragma once +#include "misc/name.h" +#include +#include + +class mirage_style { +public: + static auto& get() { + static mirage_style instance; + return instance; + } + + bool load_config(const std::filesystem::path& in_filename); + +private: + mirage_style() = default; + toml::table tbl{}; + +}; diff --git a/src/mirage_widget/src/widget/compound_widget/mborder.cpp b/src/mirage_widget/src/widget/compound_widget/mborder.cpp deleted file mode 100644 index c416044..0000000 --- a/src/mirage_widget/src/widget/compound_widget/mborder.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "mborder.h" diff --git a/src/mirage_widget/src/widget/compound_widget/mborder.h b/src/mirage_widget/src/widget/compound_widget/mborder.h index 9823706..4717746 100644 --- a/src/mirage_widget/src/widget/compound_widget/mborder.h +++ b/src/mirage_widget/src/widget/compound_widget/mborder.h @@ -71,6 +71,6 @@ public: // 或使用现有的 margin.get_total_spacing() 方法 return child_size + margin.get_total_spacing(); } - return Eigen::Vector2f(10, 10); + return { 10, 10 }; } }; diff --git a/src/mirage_widget/src/widget/mwidget.h b/src/mirage_widget/src/widget/mwidget.h index 892226e..492fff0 100644 --- a/src/mirage_widget/src/widget/mwidget.h +++ b/src/mirage_widget/src/widget/mwidget.h @@ -122,4 +122,5 @@ protected: std::weak_ptr parent_; std::vector> children_; geometry_t geometry_{}; + std::string tag{}; // 风格标签 };