TODO 风格系统
This commit is contained in:
parent
3d58348c12
commit
1c3aee5ca1
36
src/mirage_core/misc/name.h
Normal file
36
src/mirage_core/misc/name.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* name_t
|
||||
* @brief 一种用于存储字符串的类,使用哈希值作为唯一标识符
|
||||
* @note 应该尽量少的构造 name_t 对象, 因为每次构造都会在 name_map 中插入一个新的元素并 hash 字符串
|
||||
*/
|
||||
template<typename StringType>
|
||||
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<uint64_t, StringType> name_map;
|
||||
};
|
||||
|
||||
using u8name_t = name_t<std::string>;
|
||||
using u16name_t = name_t<std::u16string>;
|
||||
using u32name_t = name_t<std::u32string>;
|
@ -1,2 +1,110 @@
|
||||
#include "color.h"
|
||||
|
||||
#include <charconv>
|
||||
#include <vector>
|
||||
|
||||
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<float> 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<float>(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 };
|
||||
}
|
||||
|
@ -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] */
|
||||
|
@ -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)
|
||||
|
10
src/mirage_widget/src/style/default_style.toml
Normal file
10
src/mirage_widget/src/style/default_style.toml
Normal file
@ -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)"
|
10
src/mirage_widget/src/style/mirage_style.cpp
Normal file
10
src/mirage_widget/src/style/mirage_style.cpp
Normal file
@ -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());
|
||||
}
|
||||
}
|
19
src/mirage_widget/src/style/mirage_style.h
Normal file
19
src/mirage_widget/src/style/mirage_style.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "misc/name.h"
|
||||
#include <toml++/toml.hpp>
|
||||
#include <filesystem>
|
||||
|
||||
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{};
|
||||
|
||||
};
|
@ -1 +0,0 @@
|
||||
#include "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 };
|
||||
}
|
||||
};
|
||||
|
@ -122,4 +122,5 @@ protected:
|
||||
std::weak_ptr<mwidget> parent_;
|
||||
std::vector<std::shared_ptr<mwidget>> children_;
|
||||
geometry_t geometry_{};
|
||||
std::string tag{}; // 风格标签
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user