重构 UI 编辑器数据结构和模块设计
- 修改资源模块的类型定义和导入路径,使结构更清晰 - 为数据模型扩展更多元数据字段(如 `NodeStatus`, `NodeSource`, 等)以及类型支持 - 引入命令模块,增加 `UIDesignSuggestion` 实体 - 更新 `SpriteBorder` 和相关组件实现,优化错误校验逻辑
This commit is contained in:
@@ -0,0 +1 @@
|
||||
mod ui_design_suggestion;
|
||||
@@ -0,0 +1,9 @@
|
||||
use crate::ui_editor::resource::ui_design_image::UIDesignImageRole;
|
||||
use crate::ui_editor::utils::UIDesignImageId;
|
||||
|
||||
pub struct UIDesignSuggestion {
|
||||
ui_design_image_id: UIDesignImageId,
|
||||
description: Option<String>,
|
||||
role: Option<UIDesignImageRole>,
|
||||
slave_to: Option<UIDesignImageId>,
|
||||
}
|
||||
@@ -7,6 +7,7 @@ use nalgebra::Vector2;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
use typed_floats::tf32::StrictlyPositiveFinite;
|
||||
use crate::ui_editor::utils::SpriteAssetId;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, TS)]
|
||||
#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/features/ui-editor/types/"))]
|
||||
@@ -165,6 +166,7 @@ impl Default for ImageType {
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum SetNativeSizeError {
|
||||
MissingSprite,
|
||||
MismatchedSprite,
|
||||
UnsupportedImageType,
|
||||
}
|
||||
|
||||
@@ -172,6 +174,7 @@ impl fmt::Display for SetNativeSizeError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let message = match self {
|
||||
Self::MissingSprite => "Image 没有 Target Graphic Sprite",
|
||||
Self::MismatchedSprite => "提供的 Sprite 与 Image Target Graphic 不匹配",
|
||||
Self::UnsupportedImageType => "只有 Simple 或 Filled Image 支持 Set Native Size",
|
||||
};
|
||||
formatter.write_str(message)
|
||||
@@ -184,7 +187,7 @@ impl Error for SetNativeSizeError {}
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, TS)]
|
||||
#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/features/ui-editor/types/"))]
|
||||
pub struct ImageComponent {
|
||||
pub target_graphic: Option<SpriteAsset>,
|
||||
pub target_graphic: Option<SpriteAssetId>,
|
||||
pub image_type: ImageType,
|
||||
}
|
||||
|
||||
@@ -199,16 +202,20 @@ impl ImageComponent {
|
||||
/// 跨组件把布局重置为 Sprite 的原始尺寸。
|
||||
pub fn set_native_size(
|
||||
&self,
|
||||
sprite: &SpriteAsset,
|
||||
control: &mut Transform,
|
||||
) -> Result<Vector2<f32>, SetNativeSizeError> {
|
||||
if !self.image_type.supports_native_size() {
|
||||
return Err(SetNativeSizeError::UnsupportedImageType);
|
||||
}
|
||||
let native_size = self
|
||||
let target_graphic = self
|
||||
.target_graphic
|
||||
.as_ref()
|
||||
.ok_or(SetNativeSizeError::MissingSprite)?
|
||||
.native_size();
|
||||
.ok_or(SetNativeSizeError::MissingSprite)?;
|
||||
if target_graphic != sprite.asset_id() {
|
||||
return Err(SetNativeSizeError::MismatchedSprite);
|
||||
}
|
||||
let native_size = sprite.native_size();
|
||||
control.anchor_max = control.anchor_min;
|
||||
control.offset_max = control.offset_min + native_size;
|
||||
Ok(native_size)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use crate::ui_editor::component::common::error::ComponentValueError;
|
||||
use crate::ui_editor::resource::asset_id::FontAssetId;
|
||||
use crate::ui_editor::resource::sprite::{Color, WHITE};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::num::NonZeroU32;
|
||||
use ts_rs::TS;
|
||||
use typed_floats::tf32::StrictlyPositiveFinite;
|
||||
use crate::ui_editor::utils::FontAssetId;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, TS)]
|
||||
#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/features/ui-editor/types/"))]
|
||||
|
||||
@@ -1,22 +1,40 @@
|
||||
use crate::ui_editor::component::Component;
|
||||
use crate::ui_editor::layout::transform::Transform;
|
||||
use crate::ui_editor::utils::NodeId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, TS)]
|
||||
#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/features/ui-editor/types/"))]
|
||||
pub struct Node {
|
||||
id: NodeId,
|
||||
transform: Transform,
|
||||
metadata: NodeMetadata,
|
||||
components: Vec<Component>,
|
||||
children: Vec<Node>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, TS)]
|
||||
#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/features/ui-editor/types/"))]
|
||||
pub enum NodeSource {
|
||||
Human,
|
||||
Llm,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, TS)]
|
||||
#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/features/ui-editor/types/"))]
|
||||
pub enum NodeStatus {
|
||||
Passed,
|
||||
NeedReview(String), // reason inside
|
||||
Blocked,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, TS)]
|
||||
#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/features/ui-editor/types/"))]
|
||||
pub struct NodeMetadata {
|
||||
name: String,
|
||||
description: String,
|
||||
// TODO
|
||||
from: String,
|
||||
status: NodeStatus,
|
||||
source: NodeSource,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
pub mod component;
|
||||
pub mod layout;
|
||||
pub mod resource;
|
||||
|
||||
pub mod agent;
|
||||
pub mod state;
|
||||
pub mod commands;
|
||||
mod utils;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::ui_editor::resource::asset_id::FontAssetId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
use crate::ui_editor::utils::FontAssetId;
|
||||
|
||||
// TODO
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, TS)]
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
pub mod asset_id;
|
||||
pub mod font;
|
||||
pub mod sprite;
|
||||
pub mod ui_design_image;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::ui_editor::component::common::error::ComponentValueError;
|
||||
use crate::ui_editor::resource::asset_id::SpriteAssetId;
|
||||
use nalgebra::Vector2;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
use typed_floats::tf32::StrictlyPositiveFinite;
|
||||
use crate::ui_editor::utils::SpriteAssetId;
|
||||
|
||||
pub type Color = [u8; 4];
|
||||
|
||||
@@ -12,49 +12,42 @@ pub(in crate::ui_editor) const WHITE: Color = [255, 255, 255, 255];
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, TS)]
|
||||
#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/features/ui-editor/types/"))]
|
||||
pub struct SpriteBorder {
|
||||
left: f32,
|
||||
right: f32,
|
||||
top: f32,
|
||||
bottom: f32,
|
||||
left: u32,
|
||||
right: u32,
|
||||
top: u32,
|
||||
bottom: u32,
|
||||
}
|
||||
|
||||
impl SpriteBorder {
|
||||
pub const NONE: Self = Self {
|
||||
left: 0.0,
|
||||
right: 0.0,
|
||||
top: 0.0,
|
||||
bottom: 0.0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
};
|
||||
|
||||
pub fn new(left: f32, right: f32, top: f32, bottom: f32) -> Result<Self, ComponentValueError> {
|
||||
let values = [left, right, top, bottom];
|
||||
if values.iter().any(|value| !value.is_finite()) {
|
||||
return Err(ComponentValueError::NonFinite);
|
||||
}
|
||||
if values.iter().any(|value| *value < 0.0) {
|
||||
return Err(ComponentValueError::MustBeNonNegative);
|
||||
}
|
||||
Ok(Self {
|
||||
pub const fn new(left: u32, right: u32, top: u32, bottom: u32) -> Self {
|
||||
Self {
|
||||
left,
|
||||
right,
|
||||
top,
|
||||
bottom,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn left(self) -> f32 {
|
||||
pub fn left(self) -> u32 {
|
||||
self.left
|
||||
}
|
||||
|
||||
pub fn right(self) -> f32 {
|
||||
pub fn right(self) -> u32 {
|
||||
self.right
|
||||
}
|
||||
|
||||
pub fn top(self) -> f32 {
|
||||
pub fn top(self) -> u32 {
|
||||
self.top
|
||||
}
|
||||
|
||||
pub fn bottom(self) -> f32 {
|
||||
pub fn bottom(self) -> u32 {
|
||||
self.bottom
|
||||
}
|
||||
|
||||
@@ -103,7 +96,12 @@ impl SpriteAsset {
|
||||
if pixel_size.x <= 0.0 || pixel_size.y <= 0.0 {
|
||||
return Err(ComponentValueError::MustBePositive);
|
||||
}
|
||||
if border.left + border.right > pixel_size.x || border.top + border.bottom > pixel_size.y {
|
||||
let available_width = f64::from(pixel_size.x.floor());
|
||||
let available_height = f64::from(pixel_size.y.floor());
|
||||
if border.has_border()
|
||||
&& (f64::from(border.left) + f64::from(border.right) + 1.0 > available_width
|
||||
|| f64::from(border.top) + f64::from(border.bottom) + 1.0 > available_height)
|
||||
{
|
||||
return Err(ComponentValueError::SpriteBorderExceedsSprite);
|
||||
}
|
||||
Ok(Self {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use nalgebra::Vector2;
|
||||
use crate::ui_editor::resource::asset_id::UIDesignImageId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
use typed_floats::tf32::StrictlyPositiveFinite;
|
||||
use crate::ui_editor::utils::UIDesignImageId;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, TS)]
|
||||
#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/features/ui-editor/types/"))]
|
||||
@@ -20,6 +20,7 @@ pub enum UIDesignImageRole {
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, TS)]
|
||||
#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/features/ui-editor/types/"))]
|
||||
pub struct UIDesignImage {
|
||||
metadata: UIDesignImageMetadata,
|
||||
path: String,
|
||||
#[ts(as = "[f32; 2]")]
|
||||
pixel_size: Vector2<f32>,
|
||||
@@ -30,6 +31,7 @@ pub struct UIDesignImage {
|
||||
#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/features/ui-editor/types/"))]
|
||||
pub struct UIDesignImageMetadata {
|
||||
name: String,
|
||||
description: String,
|
||||
role: Option<UIDesignImageRole>,
|
||||
slave_to: UIDesignImageId,
|
||||
slave_to: Option<UIDesignImageId>,
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use crate::ui_editor::layout::node::Node;
|
||||
use crate::ui_editor::resource::asset_id::{FontAssetId, SpriteAssetId, UIDesignImageId};
|
||||
use crate::ui_editor::resource::font::FontAsset;
|
||||
use crate::ui_editor::resource::sprite::SpriteAsset;
|
||||
use crate::ui_editor::resource::ui_design_image::UIDesignImage;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use ts_rs::TS;
|
||||
use crate::ui_editor::utils::{FontAssetId, SpriteAssetId, UIDesignImageId};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, TS)]
|
||||
#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/features/ui-editor/types/"))]
|
||||
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
use crate::ui_editor::component::common::error::ComponentValueError;
|
||||
|
||||
macro_rules! define_asset_id {
|
||||
macro_rules! define_id {
|
||||
($name:ident) => {
|
||||
#[derive(
|
||||
Clone,
|
||||
@@ -38,7 +38,7 @@ macro_rules! define_asset_id {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
define_asset_id!(FontAssetId);
|
||||
define_asset_id!(SpriteAssetId);
|
||||
define_asset_id!(UIDesignImageId);
|
||||
define_id!(FontAssetId);
|
||||
define_id!(SpriteAssetId);
|
||||
define_id!(UIDesignImageId);
|
||||
define_id!(NodeId);
|
||||
@@ -1,8 +1,8 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ImageType } from "./ImageType";
|
||||
import type { SpriteAsset } from "./SpriteAsset";
|
||||
import type { SpriteAssetId } from "./SpriteAssetId";
|
||||
|
||||
/**
|
||||
* Image 渲染组件;布局由同一 Entity 上独立的 `Control` 提供。
|
||||
*/
|
||||
export type ImageComponent = { target_graphic: SpriteAsset | null, image_type: ImageType, };
|
||||
export type ImageComponent = { target_graphic: SpriteAssetId | null, image_type: ImageType, };
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { UIDesignImageMetadata } from "./UIDesignImageMetadata";
|
||||
|
||||
export type UIDesignImage = { path: string, pixel_size: [number, number], pixels_per_unit: number, };
|
||||
export type UIDesignImage = { metadata: UIDesignImageMetadata, path: string, pixel_size: [number, number], pixels_per_unit: number, };
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
import type { UIDesignImageId } from "./UIDesignImageId";
|
||||
import type { UIDesignImageRole } from "./UIDesignImageRole";
|
||||
|
||||
export type UIDesignImageMetadata = { name: string, role: UIDesignImageRole | null, slave_to: UIDesignImageId, };
|
||||
export type UIDesignImageMetadata = { name: string, role: UIDesignImageRole | null, slave_to: UIDesignImageId | null, };
|
||||
|
||||
Reference in New Issue
Block a user