From 39aabd77fcf19161ebd9865d413a7ca67f755826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Thu, 13 Aug 2026 14:09:49 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=20UI=20=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=99=A8=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84=E5=92=8C=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改资源模块的类型定义和导入路径,使结构更清晰 - 为数据模型扩展更多元数据字段(如 `NodeStatus`, `NodeSource`, 等)以及类型支持 - 引入命令模块,增加 `UIDesignSuggestion` 实体 - 更新 `SpriteBorder` 和相关组件实现,优化错误校验逻辑 --- .../src-tauri/src/ui_editor/commands/mod.rs | 1 + .../commands/ui_design_suggestion.rs | 9 ++++ .../src/ui_editor/component/image.rs | 15 ++++-- .../src-tauri/src/ui_editor/component/text.rs | 2 +- .../src-tauri/src/ui_editor/layout/node.rs | 22 ++++++++- .../src-tauri/src/ui_editor/mod.rs | 4 +- .../src-tauri/src/ui_editor/resource/font.rs | 2 +- .../src-tauri/src/ui_editor/resource/mod.rs | 1 - .../src/ui_editor/resource/sprite.rs | 46 +++++++++---------- .../src/ui_editor/resource/ui_design_image.rs | 6 ++- .../src-tauri/src/ui_editor/state/mod.rs | 2 +- .../{resource/asset_id.rs => utils.rs} | 10 ++-- .../ui-editor/types/ImageComponent.ts | 4 +- .../features/ui-editor/types/UIDesignImage.ts | 3 +- .../ui-editor/types/UIDesignImageMetadata.ts | 2 +- 15 files changed, 82 insertions(+), 47 deletions(-) create mode 100644 apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/mod.rs create mode 100644 apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/ui_design_suggestion.rs rename apps/ai-game-creator-shell/src-tauri/src/ui_editor/{resource/asset_id.rs => utils.rs} (89%) diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/mod.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/mod.rs new file mode 100644 index 000000000..37757c885 --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/mod.rs @@ -0,0 +1 @@ +mod ui_design_suggestion; diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/ui_design_suggestion.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/ui_design_suggestion.rs new file mode 100644 index 000000000..4f0403cae --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/ui_design_suggestion.rs @@ -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, + role: Option, + slave_to: Option, +} diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/component/image.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/component/image.rs index 962ed75c7..f7db00a63 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/component/image.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/component/image.rs @@ -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, + pub target_graphic: Option, pub image_type: ImageType, } @@ -199,16 +202,20 @@ impl ImageComponent { /// 跨组件把布局重置为 Sprite 的原始尺寸。 pub fn set_native_size( &self, + sprite: &SpriteAsset, control: &mut Transform, ) -> Result, 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) diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/component/text.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/component/text.rs index 85005bc05..b30677037 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/component/text.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/component/text.rs @@ -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/"))] diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/layout/node.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/layout/node.rs index 77bf60d2d..fe5bbabfa 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/layout/node.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/layout/node.rs @@ -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, children: Vec, } +#[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, } diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/mod.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/mod.rs index f7b7b2cec..76ecab07e 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/mod.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/mod.rs @@ -1,6 +1,6 @@ pub mod component; pub mod layout; pub mod resource; - -pub mod agent; pub mod state; +pub mod commands; +mod utils; diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/font.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/font.rs index d3599ab5b..7328c8f4f 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/font.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/font.rs @@ -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)] diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/mod.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/mod.rs index e4072d7cb..3a90efe25 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/mod.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/mod.rs @@ -1,4 +1,3 @@ -pub mod asset_id; pub mod font; pub mod sprite; pub mod ui_design_image; diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/sprite.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/sprite.rs index 097501636..8e07ff69d 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/sprite.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/sprite.rs @@ -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 { - 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 { diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/ui_design_image.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/ui_design_image.rs index 4ebfcc209..5928b1975 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/ui_design_image.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/ui_design_image.rs @@ -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, @@ -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, - slave_to: UIDesignImageId, + slave_to: Option, } diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/state/mod.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/state/mod.rs index 38703c2c5..e33147bf7 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/state/mod.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/state/mod.rs @@ -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/"))] diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/asset_id.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/utils.rs similarity index 89% rename from apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/asset_id.rs rename to apps/ai-game-creator-shell/src-tauri/src/ui_editor/utils.rs index da99dffce..d3882daea 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/resource/asset_id.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/utils.rs @@ -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); diff --git a/apps/ai-game-creator-shell/src/features/ui-editor/types/ImageComponent.ts b/apps/ai-game-creator-shell/src/features/ui-editor/types/ImageComponent.ts index ae11f76e3..61e4de858 100644 --- a/apps/ai-game-creator-shell/src/features/ui-editor/types/ImageComponent.ts +++ b/apps/ai-game-creator-shell/src/features/ui-editor/types/ImageComponent.ts @@ -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, }; diff --git a/apps/ai-game-creator-shell/src/features/ui-editor/types/UIDesignImage.ts b/apps/ai-game-creator-shell/src/features/ui-editor/types/UIDesignImage.ts index c4cf6dbd5..b1f383426 100644 --- a/apps/ai-game-creator-shell/src/features/ui-editor/types/UIDesignImage.ts +++ b/apps/ai-game-creator-shell/src/features/ui-editor/types/UIDesignImage.ts @@ -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, }; diff --git a/apps/ai-game-creator-shell/src/features/ui-editor/types/UIDesignImageMetadata.ts b/apps/ai-game-creator-shell/src/features/ui-editor/types/UIDesignImageMetadata.ts index f4b97fdf7..88a03a79f 100644 --- a/apps/ai-game-creator-shell/src/features/ui-editor/types/UIDesignImageMetadata.ts +++ b/apps/ai-game-creator-shell/src/features/ui-editor/types/UIDesignImageMetadata.ts @@ -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, };