Refactor XCUI editor module layout
This commit is contained in:
@@ -1,109 +0,0 @@
|
|||||||
# CameraRenderer
|
|
||||||
|
|
||||||
**命名空间**: `XCEngine::Rendering`
|
|
||||||
|
|
||||||
**类型**: `class`
|
|
||||||
|
|
||||||
**头文件**: `XCEngine/Rendering/Execution/CameraRenderer.h`
|
|
||||||
|
|
||||||
**描述**: 单个 `CameraRenderRequest` 的执行器,负责在一次提交里串起 scene extraction、shadow/depth 预 pass、主主管线、object-id,以及注入式 pre/post/overlay pass。
|
|
||||||
|
|
||||||
## 概述
|
|
||||||
|
|
||||||
`CameraRenderer` 是当前 Rendering 模块里的“单 request 执行层”。它不负责决定应该渲染哪些相机,也不负责 request 排序;这些职责在 [SceneRenderer](../SceneRenderer/SceneRenderer.md) 与 [SceneRenderRequestPlanner](../SceneRenderRequestPlanner/SceneRenderRequestPlanner.md)。
|
|
||||||
|
|
||||||
它关心的是另一件事:一份已经组装好的 `CameraRenderRequest`,到底按什么顺序跑完。
|
|
||||||
|
|
||||||
## 当前持有的运行时对象
|
|
||||||
|
|
||||||
- `m_sceneExtractor`
|
|
||||||
使用 request surface 的 render-area 尺寸提取当前相机对应的 `RenderSceneData`。
|
|
||||||
- `m_pipelineAsset`
|
|
||||||
当前主管线的创建来源工厂;可能为空。
|
|
||||||
- `m_pipeline`
|
|
||||||
当前实际执行主场景绘制的 runtime [RenderPipeline](../RenderPipeline/RenderPipeline.md)。
|
|
||||||
- `m_objectIdPass`
|
|
||||||
按需消费 `request.objectId` 的 object-id pass;默认是 [Passes::BuiltinObjectIdPass](../Passes/BuiltinObjectIdPass/BuiltinObjectIdPass.md)。
|
|
||||||
- `m_depthOnlyPass`
|
|
||||||
按需消费 `request.depthOnly` 的独立 scene pass;默认是 [Passes::BuiltinDepthOnlyPass](../Passes/BuiltinDepthOnlyPass/BuiltinDepthOnlyPass.md)。
|
|
||||||
- `m_shadowCasterPass`
|
|
||||||
按需消费 `request.shadowCaster` 的独立 scene pass;默认是 [Passes::BuiltinShadowCasterPass](../Passes/BuiltinShadowCasterPass/BuiltinShadowCasterPass.md)。
|
|
||||||
|
|
||||||
这意味着 `CameraRenderer` 不替调用方生成 Scene View 的特殊效果,但会直接消费 request 上已经明确给出的 depth-only / shadow-caster / object-id / post / overlay 槽位。
|
|
||||||
|
|
||||||
## 当前执行顺序
|
|
||||||
|
|
||||||
对一份有效 request,当前 `Render()` 的主顺序是:
|
|
||||||
|
|
||||||
1. 校验 request、自身主管线、render-area,以及 `shadowCaster / depthOnly / objectId` 请求前置条件。
|
|
||||||
2. 用 `m_sceneExtractor.ExtractForCamera(...)` 生成 `RenderSceneData`。
|
|
||||||
3. 用 request 覆盖 `sceneData.cameraData.clearFlags`,必要时再覆盖 `clearColor`。
|
|
||||||
4. 执行 `preScenePasses`。
|
|
||||||
5. 如请求了 shadow-caster,执行 `m_shadowCasterPass`。
|
|
||||||
6. 如请求了 depth-only,执行 `m_depthOnlyPass`。
|
|
||||||
7. 执行 `m_pipeline->Render(...)`。
|
|
||||||
8. 如请求了 object-id,执行 `m_objectIdPass->Render(...)`。
|
|
||||||
9. 执行 `postScenePasses`。
|
|
||||||
10. 执行 `overlayPasses`。
|
|
||||||
11. 按已初始化的 sequence 逆向 `Shutdown()`。
|
|
||||||
|
|
||||||
`tests/Rendering/unit/test_camera_scene_renderer.cpp` 已覆盖这条顺序,包括 shadow-caster / depth-only 位于主主管线之前这一点。
|
|
||||||
|
|
||||||
## 生命周期与回退策略
|
|
||||||
|
|
||||||
- 默认构造会使用静态共享的 [BuiltinForwardPipelineAsset](../Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md),并同时创建 builtin object-id / depth-only / shadow-caster pass。
|
|
||||||
- `SetPipeline()` 走“手动注入 runtime pipeline”路径,并清空当前 `m_pipelineAsset`。
|
|
||||||
- `SetPipelineAsset()` 走“由 asset 创建 runtime pipeline”路径;传空时会回退到默认 asset。
|
|
||||||
- `ResetPipeline()` 会先 `Shutdown()` 旧主管线,再接管新实例;若新实例为空,则再次回退到默认 asset 并创建 builtin forward。
|
|
||||||
- [SetObjectIdPass](SetObjectIdPass.md) 会先关闭旧 pass;传空时回退到 builtin object-id pass。
|
|
||||||
- [SetDepthOnlyPass](SetDepthOnlyPass.md) 会先关闭旧 pass;传空时回退到 builtin depth-only pass。
|
|
||||||
- [SetShadowCasterPass](SetShadowCasterPass.md) 会先关闭旧 pass;传空时回退到 builtin shadow-caster pass。
|
|
||||||
|
|
||||||
## 当前验证规则
|
|
||||||
|
|
||||||
`Render()` 当前会显式拒绝:
|
|
||||||
|
|
||||||
- `request.IsValid()` 为假
|
|
||||||
- 当前 `m_pipeline == nullptr`
|
|
||||||
- `request.surface` 的 render-area 宽或高为 `0`
|
|
||||||
- 请求了 shadow-caster,但 `request.shadowCaster.IsValid()` 为假
|
|
||||||
- 请求了 depth-only,但 `request.depthOnly.IsValid()` 为假
|
|
||||||
- 请求了 object-id,但 `request.objectId.IsValid()` 为假
|
|
||||||
|
|
||||||
## 当前实现边界
|
|
||||||
|
|
||||||
- 这里只执行单个 request;多相机排序、stack 顺序和 clear 规则在 `SceneRenderer` / `SceneRenderRequestPlanner` 层完成。
|
|
||||||
- 这里只消费 request 上已经存在的 scene-pass 与 pass-sequence 槽位,不主动构建 editor 专用 overlay。
|
|
||||||
- post / overlay 阶段仍然只是顺序执行的 `RenderPassSequence`,不是 render graph。
|
|
||||||
|
|
||||||
## 公开方法
|
|
||||||
|
|
||||||
| 方法 | 说明 |
|
|
||||||
|------|------|
|
|
||||||
| [Constructor](Constructor.md) | 构造 `CameraRenderer`,并决定主主管线与 builtin 独立 pass 的初始来源。 |
|
|
||||||
| [Destructor](Destructor.md) | 关闭当前主管线、object-id pass、depth-only pass 与 shadow-caster pass。 |
|
|
||||||
| [SetPipeline](SetPipeline.md) | 手动替换当前 runtime pipeline。 |
|
|
||||||
| [SetPipelineAsset](SetPipelineAsset.md) | 通过 `RenderPipelineAsset` 重建当前 runtime pipeline。 |
|
|
||||||
| [SetObjectIdPass](SetObjectIdPass.md) | 替换当前 object-id pass。 |
|
|
||||||
| [SetDepthOnlyPass](SetDepthOnlyPass.md) | 替换当前 depth-only scene pass。 |
|
|
||||||
| [SetShadowCasterPass](SetShadowCasterPass.md) | 替换当前 shadow-caster scene pass。 |
|
|
||||||
| [GetPipeline](GetPipeline.md) | 读取当前主管线的非拥有指针。 |
|
|
||||||
| [GetPipelineAsset](GetPipelineAsset.md) | 读取当前 pipeline asset 的非拥有指针。 |
|
|
||||||
| [GetObjectIdPass](GetObjectIdPass.md) | 读取当前 object-id pass 的非拥有指针。 |
|
|
||||||
| [GetDepthOnlyPass](GetDepthOnlyPass.md) | 读取当前 depth-only pass 的非拥有指针。 |
|
|
||||||
| [GetShadowCasterPass](GetShadowCasterPass.md) | 读取当前 shadow-caster pass 的非拥有指针。 |
|
|
||||||
| [Render](Render.md) | 执行一次完整的单相机提交。 |
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [Rendering](../Rendering.md)
|
|
||||||
- [SceneRenderer](../SceneRenderer/SceneRenderer.md)
|
|
||||||
- [CameraRenderRequest](../CameraRenderRequest/CameraRenderRequest.md)
|
|
||||||
- [RenderSceneExtractor](../RenderSceneExtractor/RenderSceneExtractor.md)
|
|
||||||
- [RenderPipeline](../RenderPipeline/RenderPipeline.md)
|
|
||||||
- [ObjectIdPass](../ObjectIdPass/ObjectIdPass.md)
|
|
||||||
- [BuiltinDepthOnlyPass](../Passes/BuiltinDepthOnlyPass/BuiltinDepthOnlyPass.md)
|
|
||||||
- [BuiltinShadowCasterPass](../Passes/BuiltinShadowCasterPass/BuiltinShadowCasterPass.md)
|
|
||||||
- [Camera Request Planning And Clear Rules](../../../_guides/Rendering/Camera-Request-Planning-And-Clear-Rules.md)
|
|
||||||
- [Scene Extraction And Builtin Forward Pipeline](../../../_guides/Rendering/Scene-Extraction-And-Builtin-Forward-Pipeline.md)
|
|
||||||
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
# CameraRenderer::Constructor
|
|
||||||
|
|
||||||
**命名空间**: `XCEngine::Rendering`
|
|
||||||
|
|
||||||
**类型**: `constructor-overload group`
|
|
||||||
|
|
||||||
**头文件**: `XCEngine/Rendering/Execution/CameraRenderer.h`
|
|
||||||
|
|
||||||
## 签名
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
CameraRenderer();
|
|
||||||
explicit CameraRenderer(std::unique_ptr<RenderPipeline> pipeline);
|
|
||||||
explicit CameraRenderer(std::shared_ptr<const RenderPipelineAsset> pipelineAsset);
|
|
||||||
CameraRenderer(
|
|
||||||
std::unique_ptr<RenderPipeline> pipeline,
|
|
||||||
std::unique_ptr<ObjectIdPass> objectIdPass,
|
|
||||||
std::unique_ptr<RenderPass> depthOnlyPass = nullptr,
|
|
||||||
std::unique_ptr<RenderPass> shadowCasterPass = nullptr);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 行为说明
|
|
||||||
|
|
||||||
构造函数的核心职责是决定三件事:
|
|
||||||
|
|
||||||
- 当前主管线实例从哪里来
|
|
||||||
- 当前 object-id pass 是否使用默认 builtin 实现
|
|
||||||
- 当前 depth-only / shadow-caster pass 是否使用默认 builtin 实现
|
|
||||||
|
|
||||||
## 当前构造路径
|
|
||||||
|
|
||||||
### 默认构造
|
|
||||||
|
|
||||||
- 通过内部静态 `CreateDefaultPipelineAsset()` 取得共享的默认 asset。
|
|
||||||
- 默认 asset 是 [BuiltinForwardPipelineAsset](../Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md)。
|
|
||||||
- 随后走 asset 构造路径生成 runtime pipeline。
|
|
||||||
|
|
||||||
### `std::unique_ptr<RenderPipeline>` 重载
|
|
||||||
|
|
||||||
- 交由四参重载处理。
|
|
||||||
- 如果未显式提供 object-id / depth-only / shadow-caster pass,会分别补:
|
|
||||||
- [Passes::BuiltinObjectIdPass](../Passes/BuiltinObjectIdPass/BuiltinObjectIdPass.md)
|
|
||||||
- [Passes::BuiltinDepthOnlyPass](../Passes/BuiltinDepthOnlyPass/BuiltinDepthOnlyPass.md)
|
|
||||||
- [Passes::BuiltinShadowCasterPass](../Passes/BuiltinShadowCasterPass/BuiltinShadowCasterPass.md)
|
|
||||||
|
|
||||||
### `std::shared_ptr<const RenderPipelineAsset>` 重载
|
|
||||||
|
|
||||||
- 先保存 asset。
|
|
||||||
- 再调用 [SetPipelineAsset](SetPipelineAsset.md),立即由 asset 创建 runtime pipeline。
|
|
||||||
- 默认同时创建 builtin object-id / depth-only / shadow-caster pass。
|
|
||||||
|
|
||||||
### 四参重载
|
|
||||||
|
|
||||||
- 若 `objectIdPass` 为空,自动回退到 builtin object-id pass。
|
|
||||||
- 若 `depthOnlyPass` 为空,自动回退到 builtin depth-only pass。
|
|
||||||
- 若 `shadowCasterPass` 为空,自动回退到 builtin shadow-caster pass。
|
|
||||||
- 调用内部 `ResetPipeline(std::move(pipeline))`。
|
|
||||||
- 如果传入 `pipeline` 为空,`ResetPipeline()` 会继续回退到默认 pipeline asset,并创建 builtin forward 主管线。
|
|
||||||
|
|
||||||
## 所有权
|
|
||||||
|
|
||||||
- `RenderPipeline`、`ObjectIdPass`、`depthOnlyPass` 和 `shadowCasterPass` 都由 `CameraRenderer` 以 `std::unique_ptr` 独占持有。
|
|
||||||
- `RenderPipelineAsset` 以 `std::shared_ptr<const ...>` 共享持有,只作为 runtime pipeline 的创建来源。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [CameraRenderer](CameraRenderer.md)
|
|
||||||
- [SetPipeline](SetPipeline.md)
|
|
||||||
- [SetPipelineAsset](SetPipelineAsset.md)
|
|
||||||
- [SetObjectIdPass](SetObjectIdPass.md)
|
|
||||||
- [SetDepthOnlyPass](SetDepthOnlyPass.md)
|
|
||||||
- [SetShadowCasterPass](SetShadowCasterPass.md)
|
|
||||||
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
# CameraRenderer::~CameraRenderer
|
|
||||||
|
|
||||||
**命名空间**: `XCEngine::Rendering`
|
|
||||||
|
|
||||||
**类型**: `destructor`
|
|
||||||
|
|
||||||
**头文件**: `XCEngine/Rendering/Execution/CameraRenderer.h`
|
|
||||||
|
|
||||||
## 签名
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
~CameraRenderer();
|
|
||||||
```
|
|
||||||
|
|
||||||
## 作用
|
|
||||||
|
|
||||||
在对象销毁前关闭当前持有的主管线、object-id pass、depth-only pass 和 shadow-caster pass。
|
|
||||||
|
|
||||||
## 当前实现行为
|
|
||||||
|
|
||||||
析构函数当前按以下顺序执行清理:
|
|
||||||
|
|
||||||
1. 如果 `m_pipeline` 非空,调用 `m_pipeline->Shutdown()`。
|
|
||||||
2. 如果 `m_objectIdPass` 非空,调用 `m_objectIdPass->Shutdown()`。
|
|
||||||
3. 如果 `m_depthOnlyPass` 非空,调用 `m_depthOnlyPass->Shutdown()`。
|
|
||||||
4. 如果 `m_shadowCasterPass` 非空,调用 `m_shadowCasterPass->Shutdown()`。
|
|
||||||
|
|
||||||
随后由 `unique_ptr` 和成员对象自身析构负责释放内存。
|
|
||||||
|
|
||||||
## 设计含义
|
|
||||||
|
|
||||||
- 主管线、object-id pass、depth-only pass 和 shadow-caster pass 的 GPU 资源回收路径都是显式 `Shutdown()`,而不是只依赖 C++ 析构。
|
|
||||||
- 调用方注入到 `CameraRenderRequest` 里的 `RenderPassSequence` 并不由这里持有,因此也不在这里做统一回收。
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
- 当前没有内部同步;不应在其它线程仍可能访问这些对象时销毁 `CameraRenderer`。
|
|
||||||
- 如果你只是想切换主管线或这些独立 pass,不要等到析构,应该优先使用 [SetPipeline](SetPipeline.md)、[SetPipelineAsset](SetPipelineAsset.md)、[SetObjectIdPass](SetObjectIdPass.md)、[SetDepthOnlyPass](SetDepthOnlyPass.md) 或 [SetShadowCasterPass](SetShadowCasterPass.md)。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [CameraRenderer](CameraRenderer.md)
|
|
||||||
- [SetPipeline](SetPipeline.md)
|
|
||||||
- [SetObjectIdPass](SetObjectIdPass.md)
|
|
||||||
- [SetDepthOnlyPass](SetDepthOnlyPass.md)
|
|
||||||
- [SetShadowCasterPass](SetShadowCasterPass.md)
|
|
||||||
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# CameraRenderer::GetDepthOnlyPass
|
|
||||||
|
|
||||||
**命名空间**: `XCEngine::Rendering`
|
|
||||||
|
|
||||||
**类型**: `method`
|
|
||||||
|
|
||||||
**头文件**: `XCEngine/Rendering/Execution/CameraRenderer.h`
|
|
||||||
|
|
||||||
## 签名
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
RenderPass* GetDepthOnlyPass() const;
|
|
||||||
```
|
|
||||||
|
|
||||||
## 作用
|
|
||||||
|
|
||||||
返回当前 depth-only scene pass 的裸指针。
|
|
||||||
|
|
||||||
## 当前实现行为
|
|
||||||
|
|
||||||
- 这是头文件内联访问器,直接返回 `m_depthOnlyPass.get()`。
|
|
||||||
- 不转移所有权。
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
- 调用 [SetDepthOnlyPass](SetDepthOnlyPass.md) 之后,之前读取到的裸指针可能立刻失效。
|
|
||||||
- 当前默认返回的通常是 builtin depth-only pass,但调用方不应把这个 API 当成“只会返回某个具体类型”的承诺。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [SetDepthOnlyPass](SetDepthOnlyPass.md)
|
|
||||||
- [Render](Render.md)
|
|
||||||
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# CameraRenderer::GetObjectIdPass
|
|
||||||
|
|
||||||
**命名空间**: `XCEngine::Rendering`
|
|
||||||
|
|
||||||
**类型**: `method`
|
|
||||||
|
|
||||||
**头文件**: `XCEngine/Rendering/Execution/CameraRenderer.h`
|
|
||||||
|
|
||||||
## 签名
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
ObjectIdPass* GetObjectIdPass() const;
|
|
||||||
```
|
|
||||||
|
|
||||||
## 作用
|
|
||||||
|
|
||||||
返回当前 object-id pass 的裸指针。
|
|
||||||
|
|
||||||
## 当前实现行为
|
|
||||||
|
|
||||||
- 这是头文件内联访问器,直接返回 `m_objectIdPass.get()`。
|
|
||||||
- 不转移所有权。
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
- 调用 [SetObjectIdPass](SetObjectIdPass.md) 后,之前读取到的裸指针可能立即失效。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [SetObjectIdPass](SetObjectIdPass.md)
|
|
||||||
- [Render](Render.md)
|
|
||||||
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
# CameraRenderer::GetPipeline
|
|
||||||
|
|
||||||
**命名空间**: `XCEngine::Rendering`
|
|
||||||
|
|
||||||
**类型**: `method`
|
|
||||||
|
|
||||||
**头文件**: `XCEngine/Rendering/Execution/CameraRenderer.h`
|
|
||||||
|
|
||||||
## 签名
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
RenderPipeline* GetPipeline() const;
|
|
||||||
```
|
|
||||||
|
|
||||||
## 作用
|
|
||||||
|
|
||||||
返回当前主管线实例的裸指针。
|
|
||||||
|
|
||||||
## 当前实现行为
|
|
||||||
|
|
||||||
- 这是头文件内联访问器,直接返回 `m_pipeline.get()`。
|
|
||||||
- 不转移所有权,也不提供额外生命周期保证。
|
|
||||||
|
|
||||||
## 返回值
|
|
||||||
|
|
||||||
- 正常路径下通常会返回一个有效指针,因为构造和 `SetPipeline()` / `SetPipelineAsset()` 都会回退到默认管线。
|
|
||||||
- 理论上如果对象正处于构造中的异常路径或未来实现改变,也不能把“永不为空”当成稳定契约。
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
- 不要长期缓存这个裸指针;调用 [SetPipeline](SetPipeline.md) 或 [SetPipelineAsset](SetPipelineAsset.md) 后它可能立即失效。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [SetPipeline](SetPipeline.md)
|
|
||||||
- [SetPipelineAsset](SetPipelineAsset.md)
|
|
||||||
- [GetPipelineAsset](GetPipelineAsset.md)
|
|
||||||
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# CameraRenderer::GetPipelineAsset
|
|
||||||
|
|
||||||
**命名空间**: `XCEngine::Rendering`
|
|
||||||
|
|
||||||
**类型**: `method`
|
|
||||||
|
|
||||||
**头文件**: `XCEngine/Rendering/Execution/CameraRenderer.h`
|
|
||||||
|
|
||||||
## 签名
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
const RenderPipelineAsset* GetPipelineAsset() const;
|
|
||||||
```
|
|
||||||
|
|
||||||
## 作用
|
|
||||||
|
|
||||||
返回当前绑定的 pipeline asset 裸指针。
|
|
||||||
|
|
||||||
## 当前实现行为
|
|
||||||
|
|
||||||
- 这是头文件内联访问器,直接返回 `m_pipelineAsset.get()`。
|
|
||||||
- 如果最近一次切换是通过 [SetPipeline](SetPipeline.md) 手动注入实例完成的,这里可能返回 `nullptr`。
|
|
||||||
|
|
||||||
## 返回值
|
|
||||||
|
|
||||||
- 返回当前 asset 裸指针,或空指针。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [SetPipelineAsset](SetPipelineAsset.md)
|
|
||||||
- [SetPipeline](SetPipeline.md)
|
|
||||||
- [GetPipeline](GetPipeline.md)
|
|
||||||
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# CameraRenderer::GetShadowCasterPass
|
|
||||||
|
|
||||||
**命名空间**: `XCEngine::Rendering`
|
|
||||||
|
|
||||||
**类型**: `method`
|
|
||||||
|
|
||||||
**头文件**: `XCEngine/Rendering/Execution/CameraRenderer.h`
|
|
||||||
|
|
||||||
## 签名
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
RenderPass* GetShadowCasterPass() const;
|
|
||||||
```
|
|
||||||
|
|
||||||
## 作用
|
|
||||||
|
|
||||||
返回当前 shadow-caster scene pass 的裸指针。
|
|
||||||
|
|
||||||
## 当前实现行为
|
|
||||||
|
|
||||||
- 这是头文件内联访问器,直接返回 `m_shadowCasterPass.get()`。
|
|
||||||
- 不转移所有权。
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
- 调用 [SetShadowCasterPass](SetShadowCasterPass.md) 之后,之前读取到的裸指针可能立刻失效。
|
|
||||||
- 当前默认返回的通常是 builtin shadow-caster pass,但调用方不应假定返回值一定来自某个具体实现类。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [SetShadowCasterPass](SetShadowCasterPass.md)
|
|
||||||
- [Render](Render.md)
|
|
||||||
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
# CameraRenderer::Render
|
|
||||||
|
|
||||||
**命名空间**: `XCEngine::Rendering`
|
|
||||||
|
|
||||||
**类型**: `method`
|
|
||||||
|
|
||||||
**头文件**: `XCEngine/Rendering/Execution/CameraRenderer.h`
|
|
||||||
|
|
||||||
## 签名
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
bool Render(const CameraRenderRequest& request);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 行为说明
|
|
||||||
|
|
||||||
执行一次完整的单相机提交。当前实现会把 shadow-caster、depth-only、主场景、object-id,以及调用方注入的 pre / post / overlay pass 串成一条固定顺序的执行链。
|
|
||||||
|
|
||||||
## 当前流程
|
|
||||||
|
|
||||||
1. 校验 `request.IsValid()`,并确认 `m_pipeline` 非空。
|
|
||||||
2. 拒绝 render-area 宽或高为 `0` 的 `surface`。
|
|
||||||
3. 如果请求了 shadow-caster,要让 `request.shadowCaster.IsValid()` 为真。
|
|
||||||
4. 如果请求了 depth-only,要让 `request.depthOnly.IsValid()` 为真。
|
|
||||||
5. 如果请求了 object-id,要让 `request.objectId.IsValid()` 为真。
|
|
||||||
6. 用 `request.surface.GetRenderAreaWidth()` / `GetRenderAreaHeight()` 调用 `m_sceneExtractor.ExtractForCamera(...)`。
|
|
||||||
7. 若 `sceneData.HasCamera()` 为假,则返回 `false`。
|
|
||||||
8. 用 request 覆盖 `sceneData.cameraData.clearFlags`;如果 request 提供了 clear-color override,则继续覆盖 `sceneData.cameraData.clearColor`。
|
|
||||||
9. 依次初始化并执行:
|
|
||||||
- `preScenePasses`
|
|
||||||
- `m_shadowCasterPass->Execute(...)`
|
|
||||||
- `m_depthOnlyPass->Execute(...)`
|
|
||||||
- `m_pipeline->Render(...)`
|
|
||||||
- `m_objectIdPass->Render(...)`
|
|
||||||
- `postScenePasses`
|
|
||||||
- `overlayPasses`
|
|
||||||
10. 按已经成功初始化的 sequence 做逆向 `Shutdown()`。
|
|
||||||
|
|
||||||
## `postScenePasses` / `overlayPasses` 接入点
|
|
||||||
|
|
||||||
`CameraRenderer` 只消费调用方传入的 pass 序列,不额外构建内部后处理层。
|
|
||||||
|
|
||||||
- `postScenePasses` 直接来自调用方提供的 `RenderPassSequence`
|
|
||||||
- `overlayPasses` 也是同样的注入点
|
|
||||||
- 编辑器 Scene View 当前会先通过 [SceneViewportRenderPlan](../../Editor/Viewport/SceneViewportRenderPlan/SceneViewportRenderPlan.md) 组装这些序列,再调用 `ApplySceneViewportRenderPlan(...)` 挂到 request
|
|
||||||
|
|
||||||
这意味着 Scene View 的无限网格、选中轮廓和编辑器 overlay,已经被上移到 request 组装层,不再由 `CameraRenderer` 内部再做一次翻译。与之相对,`shadowCaster` 和 `depthOnly` 当前仍属于 `CameraRenderRequest` 上的专用 scene-pass 槽位,由 `CameraRenderer` 直接在主主管线之前消费。
|
|
||||||
|
|
||||||
## 失败与清理语义
|
|
||||||
|
|
||||||
- 任一验证失败会直接返回 `false`。
|
|
||||||
- `shadowCaster` 或 `depthOnly` 请求校验失败时,不会进入主主管线。
|
|
||||||
- 任一 sequence 初始化失败会立刻执行对应 `Shutdown()` 回滚。
|
|
||||||
- `shadowCaster`、`depthOnly`、主管线、object-id pass、post 或 overlay 任一阶段失败,都会按已经初始化过的 sequence 做清理再返回 `false`。
|
|
||||||
|
|
||||||
## 参数
|
|
||||||
|
|
||||||
- `request` - 本次单相机渲染的完整输入。
|
|
||||||
|
|
||||||
## 返回值
|
|
||||||
|
|
||||||
- 整条提交流成功执行时返回 `true`。
|
|
||||||
- request 校验失败、场景提取失败、主管线失败,或任一附加阶段失败时返回 `false`。
|
|
||||||
|
|
||||||
## 测试覆盖
|
|
||||||
|
|
||||||
`tests/Rendering/unit/test_camera_scene_renderer.cpp` 当前验证了:
|
|
||||||
|
|
||||||
- render-area 会影响提取到的相机 viewport 尺寸
|
|
||||||
- clear-flags 和 clear-color override 会写回 `sceneData.cameraData`
|
|
||||||
- `shadowCaster / depthOnly / pipeline / object-id / post / overlay` 的执行顺序
|
|
||||||
- shadow-caster 请求无效、object-id 失败和 post-pass 初始化失败时的回滚路径
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [CameraRenderer](CameraRenderer.md)
|
|
||||||
- [CameraRenderRequest](../CameraRenderRequest/CameraRenderRequest.md)
|
|
||||||
- [RenderSceneExtractor](../RenderSceneExtractor/RenderSceneExtractor.md)
|
|
||||||
- [RenderPipeline::Render](../RenderPipeline/Render.md)
|
|
||||||
- [SetDepthOnlyPass](SetDepthOnlyPass.md)
|
|
||||||
- [SetShadowCasterPass](SetShadowCasterPass.md)
|
|
||||||
- [Passes](../Passes/Passes.md)
|
|
||||||
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# CameraRenderer::SetDepthOnlyPass
|
|
||||||
|
|
||||||
**命名空间**: `XCEngine::Rendering`
|
|
||||||
|
|
||||||
**类型**: `method`
|
|
||||||
|
|
||||||
**头文件**: `XCEngine/Rendering/Execution/CameraRenderer.h`
|
|
||||||
|
|
||||||
## 签名
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void SetDepthOnlyPass(std::unique_ptr<RenderPass> depthOnlyPass);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 作用
|
|
||||||
|
|
||||||
替换当前用于消费 `request.depthOnly` 的独立 scene pass。
|
|
||||||
|
|
||||||
## 当前实现行为
|
|
||||||
|
|
||||||
1. 如果旧 `m_depthOnlyPass` 非空,先调用它的 `Shutdown()`。
|
|
||||||
2. 接管新的 `depthOnlyPass`。
|
|
||||||
3. 如果新指针为空,则自动回退到 [Passes::BuiltinDepthOnlyPass](../Passes/BuiltinDepthOnlyPass/BuiltinDepthOnlyPass.md)。
|
|
||||||
|
|
||||||
## 关键语义
|
|
||||||
|
|
||||||
- 这里替换的是一个普通 `RenderPass`,并不要求具体类型必须来自 builtin pass 层。
|
|
||||||
- `CameraRenderer::Render()` 只在 `request.depthOnly.IsRequested()` 时才会真正执行这里持有的 pass。
|
|
||||||
- `tests/Rendering/unit/test_camera_scene_renderer.cpp` 通过 mock pass 验证了这条注入链会在主主管线之前执行,并正确消费 `ScenePassRenderRequest` 的 surface / clear-color override。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [GetDepthOnlyPass](GetDepthOnlyPass.md)
|
|
||||||
- [Render](Render.md)
|
|
||||||
- [BuiltinDepthOnlyPass](../Passes/BuiltinDepthOnlyPass/BuiltinDepthOnlyPass.md)
|
|
||||||
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# CameraRenderer::SetObjectIdPass
|
|
||||||
|
|
||||||
**命名空间**: `XCEngine::Rendering`
|
|
||||||
|
|
||||||
**类型**: `method`
|
|
||||||
|
|
||||||
**头文件**: `XCEngine/Rendering/Execution/CameraRenderer.h`
|
|
||||||
|
|
||||||
## 签名
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void SetObjectIdPass(std::unique_ptr<ObjectIdPass> objectIdPass);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 作用
|
|
||||||
|
|
||||||
替换主场景之后使用的 object-id 输出 pass。
|
|
||||||
|
|
||||||
## 当前实现行为
|
|
||||||
|
|
||||||
1. 如果旧 `m_objectIdPass` 非空,先调用它的 `Shutdown()`。
|
|
||||||
2. 接管新的 `objectIdPass`。
|
|
||||||
3. 如果新指针为空,则自动回退到 `Passes::BuiltinObjectIdPass`。
|
|
||||||
|
|
||||||
## 关键语义
|
|
||||||
|
|
||||||
- 这是 object-id 渲染链路的主要注入点,测试里可以通过它替换 mock pass。
|
|
||||||
- `CameraRenderer::Render()` 只在 `request.objectId.IsRequested()` 时才会真正调用这里持有的 pass。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [GetObjectIdPass](GetObjectIdPass.md)
|
|
||||||
- [Render](Render.md)
|
|
||||||
- [Passes](../Passes/Passes.md)
|
|
||||||
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
# CameraRenderer::SetPipeline
|
|
||||||
|
|
||||||
**命名空间**: `XCEngine::Rendering`
|
|
||||||
|
|
||||||
**类型**: `method`
|
|
||||||
|
|
||||||
**头文件**: `XCEngine/Rendering/Execution/CameraRenderer.h`
|
|
||||||
|
|
||||||
## 签名
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void SetPipeline(std::unique_ptr<RenderPipeline> pipeline);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 作用
|
|
||||||
|
|
||||||
手动替换当前主管线实例,并切断与 `RenderPipelineAsset` 的绑定关系。
|
|
||||||
|
|
||||||
## 当前实现行为
|
|
||||||
|
|
||||||
1. 先把 `m_pipelineAsset.reset()`,表示后续不再认为当前管线来自某个 asset。
|
|
||||||
2. 调用内部 `ResetPipeline(std::move(pipeline))`。
|
|
||||||
3. `ResetPipeline()` 会:
|
|
||||||
- 对旧 `m_pipeline` 调用 `Shutdown()`
|
|
||||||
- 接管新的 `pipeline`
|
|
||||||
- 如果新指针为空,则回退到默认 pipeline asset 创建的内建前向管线
|
|
||||||
|
|
||||||
## 参数
|
|
||||||
|
|
||||||
| 参数 | 说明 |
|
|
||||||
|------|------|
|
|
||||||
| `pipeline` | 新的主管线实例所有权。可以为空;为空时会自动回退到默认内建前向管线。 |
|
|
||||||
|
|
||||||
## 关键语义
|
|
||||||
|
|
||||||
- 这是“直接注入实例”的入口,不会保留原来的 pipeline asset。
|
|
||||||
- 替换时走的是显式关停旧管线的路径,而不是简单换指针。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [SetPipelineAsset](SetPipelineAsset.md)
|
|
||||||
- [GetPipeline](GetPipeline.md)
|
|
||||||
- [GetPipelineAsset](GetPipelineAsset.md)
|
|
||||||
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# CameraRenderer::SetPipelineAsset
|
|
||||||
|
|
||||||
**命名空间**: `XCEngine::Rendering`
|
|
||||||
|
|
||||||
**类型**: `method`
|
|
||||||
|
|
||||||
**头文件**: `XCEngine/Rendering/Execution/CameraRenderer.h`
|
|
||||||
|
|
||||||
## 签名
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void SetPipelineAsset(std::shared_ptr<const RenderPipelineAsset> pipelineAsset);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 作用
|
|
||||||
|
|
||||||
通过一份 `RenderPipelineAsset` 重建当前主管线实例。
|
|
||||||
|
|
||||||
## 当前实现行为
|
|
||||||
|
|
||||||
1. 如果传入的 `pipelineAsset` 非空,则保存它。
|
|
||||||
2. 如果传入为空,则回退到内部静态默认 asset。
|
|
||||||
3. 调用 `CreatePipelineFromAsset(m_pipelineAsset)` 创建新的管线实例。
|
|
||||||
4. 再通过 `ResetPipeline(...)` 关停旧管线并接管新实例。
|
|
||||||
|
|
||||||
## 关键语义
|
|
||||||
|
|
||||||
- 这是“从 asset 创建实例”的入口,和 [SetPipeline](SetPipeline.md) 的手动注入路径不同。
|
|
||||||
- 即使 asset 无法返回有效实例,`CreatePipelineFromAsset()` 也会继续回退到内建前向管线。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [SetPipeline](SetPipeline.md)
|
|
||||||
- [GetPipelineAsset](GetPipelineAsset.md)
|
|
||||||
- [Constructor](Constructor.md)
|
|
||||||
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# CameraRenderer::SetShadowCasterPass
|
|
||||||
|
|
||||||
**命名空间**: `XCEngine::Rendering`
|
|
||||||
|
|
||||||
**类型**: `method`
|
|
||||||
|
|
||||||
**头文件**: `XCEngine/Rendering/Execution/CameraRenderer.h`
|
|
||||||
|
|
||||||
## 签名
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void SetShadowCasterPass(std::unique_ptr<RenderPass> shadowCasterPass);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 作用
|
|
||||||
|
|
||||||
替换当前用于消费 `request.shadowCaster` 的独立 scene pass。
|
|
||||||
|
|
||||||
## 当前实现行为
|
|
||||||
|
|
||||||
1. 如果旧 `m_shadowCasterPass` 非空,先调用它的 `Shutdown()`。
|
|
||||||
2. 接管新的 `shadowCasterPass`。
|
|
||||||
3. 如果新指针为空,则自动回退到 [Passes::BuiltinShadowCasterPass](../Passes/BuiltinShadowCasterPass/BuiltinShadowCasterPass.md)。
|
|
||||||
|
|
||||||
## 关键语义
|
|
||||||
|
|
||||||
- 这里替换的是一个普通 `RenderPass`,并不要求必须是 builtin shadow-caster 实现。
|
|
||||||
- `CameraRenderer::Render()` 只在 `request.shadowCaster.IsRequested()` 时才会执行这里持有的 pass。
|
|
||||||
- 当前执行顺序里,shadow-caster pass 位于 depth-only 与主主管线之前。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [GetShadowCasterPass](GetShadowCasterPass.md)
|
|
||||||
- [Render](Render.md)
|
|
||||||
- [BuiltinShadowCasterPass](../Passes/BuiltinShadowCasterPass/BuiltinShadowCasterPass.md)
|
|
||||||
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
# SceneRenderer::BuildRenderRequests
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
std::vector<CameraRenderRequest> BuildRenderRequests(
|
|
||||||
const Components::Scene& scene,
|
|
||||||
Components::CameraComponent* overrideCamera,
|
|
||||||
const RenderContext& context,
|
|
||||||
const RenderSurface& surface) const;
|
|
||||||
```
|
|
||||||
|
|
||||||
## 行为说明
|
|
||||||
|
|
||||||
当前实现直接委托给内部 `SceneRenderRequestPlanner`:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
return m_requestPlanner.BuildRequests(scene, overrideCamera, context, surface);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 当前用途
|
|
||||||
|
|
||||||
这个方法只负责“规划请求”,不负责真正渲染。生成的每个 `CameraRenderRequest` 会携带:
|
|
||||||
|
|
||||||
- 选中的相机
|
|
||||||
- 相机深度和 stack 顺序
|
|
||||||
- 针对该相机解析后的 clear-flags
|
|
||||||
- 继承并裁剪后的 `RenderSurface`
|
|
||||||
- 随后交给 `CameraRenderer` 执行所需的上下文
|
|
||||||
|
|
||||||
## 参数
|
|
||||||
|
|
||||||
- `scene` - 要规划的场景。
|
|
||||||
- `overrideCamera` - 可选的 override 相机;可用时只为它构建请求。
|
|
||||||
- `context` - 当前渲染上下文。
|
|
||||||
- `surface` - 当前输出目标模板,planner 会基于它推导每个相机的 render-area 和 clear 行为。
|
|
||||||
|
|
||||||
## 返回值
|
|
||||||
|
|
||||||
- 按 `SceneRenderRequestPlanner` 规则生成的请求数组。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [SceneRenderer](SceneRenderer.md)
|
|
||||||
- [Render](Render.md)
|
|
||||||
- [SceneRenderRequestPlanner](../SceneRenderRequestPlanner/SceneRenderRequestPlanner.md)
|
|
||||||
- [CameraRenderRequest](../CameraRenderRequest/CameraRenderRequest.md)
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# SceneRenderer::SceneRenderer
|
|
||||||
|
|
||||||
构造一个场景级渲染器。
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
SceneRenderer();
|
|
||||||
explicit SceneRenderer(std::unique_ptr<RenderPipeline> pipeline);
|
|
||||||
explicit SceneRenderer(std::shared_ptr<const RenderPipelineAsset> pipelineAsset);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 当前语义
|
|
||||||
|
|
||||||
- 三个构造路径的差别只在于内部 `m_cameraRenderer` 如何初始化。
|
|
||||||
- 默认构造:使用 `CameraRenderer` 的默认构造路径,最终回退到默认 builtin forward pipeline asset。
|
|
||||||
- `std::unique_ptr<RenderPipeline>` 构造:把调用方提供的 runtime pipeline 直接交给内部 `CameraRenderer` 持有。
|
|
||||||
- `std::shared_ptr<const RenderPipelineAsset>` 构造:让内部 `CameraRenderer` 通过 asset 创建 runtime pipeline。
|
|
||||||
|
|
||||||
## 当前实现细节
|
|
||||||
|
|
||||||
- `SceneRenderer` 自己不在构造阶段创建额外的 GPU 资源;真正的 runtime pipeline 创建和回退逻辑都委托给 `CameraRenderer`。
|
|
||||||
- 如果传入的 `pipeline` 是空指针,`CameraRenderer` 会回退到默认 pipeline asset,而不是保留一个永久空 pipeline。
|
|
||||||
- 如果传入的 `pipelineAsset` 是空指针,也会回退到默认 builtin forward asset。
|
|
||||||
|
|
||||||
## 测试覆盖
|
|
||||||
|
|
||||||
- `tests/Rendering/unit/test_camera_scene_renderer.cpp` 验证了默认构造的 `SceneRenderer` 能创建默认 pipeline 并完成渲染。
|
|
||||||
- 同一测试文件也覆盖了注入 runtime pipeline 和注入 pipeline asset 两条构造路径。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [SceneRenderer](SceneRenderer.md)
|
|
||||||
- [SetPipeline](SetPipeline.md)
|
|
||||||
- [SetPipelineAsset](SetPipelineAsset.md)
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# SceneRenderer::~SceneRenderer
|
|
||||||
|
|
||||||
销毁场景级渲染器对象。
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
~SceneRenderer() = default;
|
|
||||||
```
|
|
||||||
|
|
||||||
## 当前语义
|
|
||||||
|
|
||||||
- `SceneRenderer` 自身没有自定义析构逻辑。
|
|
||||||
- 真正的 teardown 发生在成员对象析构阶段:
|
|
||||||
- `m_cameraRenderer` 会关闭当前 runtime pipeline 和 object-id pass。
|
|
||||||
- `m_requestPlanner` 作为普通值成员按常规方式销毁。
|
|
||||||
- `SceneRenderer` 不拥有外部传入请求上的 `RenderPassSequence`,因此析构时不会回收这些外部序列对象。
|
|
||||||
|
|
||||||
## 调用方影响
|
|
||||||
|
|
||||||
- 即使 `SceneRenderer` 的析构函数是 `= default`,离开作用域时仍会触发内部 `CameraRenderer` 的资源释放路径。
|
|
||||||
- 任何此前通过 [GetPipeline](GetPipeline.md) 或 [GetPipelineAsset](GetPipelineAsset.md) 观察到的非拥有指针,都会在 `SceneRenderer` 销毁后失效。
|
|
||||||
|
|
||||||
## 测试覆盖
|
|
||||||
|
|
||||||
- `tests/Rendering/unit/test_camera_scene_renderer.cpp` 使用作用域退出断言了 `SceneRenderer` 内部持有的 pipeline 会在对象销毁时执行 `Shutdown()`。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [SceneRenderer](SceneRenderer.md)
|
|
||||||
- [GetPipeline](GetPipeline.md)
|
|
||||||
- [Render](Render.md)
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# SceneRenderer::GetPipeline
|
|
||||||
|
|
||||||
返回当前场景渲染器正在使用的 runtime pipeline。
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
RenderPipeline* GetPipeline() const;
|
|
||||||
```
|
|
||||||
|
|
||||||
## 返回值
|
|
||||||
|
|
||||||
- 返回内部 `m_cameraRenderer.GetPipeline()` 的结果。
|
|
||||||
|
|
||||||
## 当前语义
|
|
||||||
|
|
||||||
- 这是一个非拥有裸指针,只用于观察当前绑定的是哪一个 `RenderPipeline` 实例。
|
|
||||||
- 该指针可能指向:
|
|
||||||
- 手动注入的 runtime pipeline。
|
|
||||||
- 由当前 pipeline asset 创建出的 runtime pipeline。
|
|
||||||
- 在空指针回退路径中自动补出的默认 builtin forward pipeline。
|
|
||||||
- 调用 [SetPipeline](SetPipeline.md) 或 [SetPipelineAsset](SetPipelineAsset.md) 后,这个指针都可能变化。
|
|
||||||
|
|
||||||
## 调用方影响
|
|
||||||
|
|
||||||
- 不应跨生命周期长期缓存这个指针;`SceneRenderer` 销毁、替换 pipeline 或回退默认 pipeline 后,它都可能失效。
|
|
||||||
- 它也不是“可由外部 delete 的所有权句柄”;真正的持有者仍是内部 `CameraRenderer`。
|
|
||||||
|
|
||||||
## 测试覆盖
|
|
||||||
|
|
||||||
- `tests/Rendering/unit/test_camera_scene_renderer.cpp` 覆盖了替换 pipeline 前后 `GetPipeline()` 返回值的变化,以及旧 pipeline 被 `Shutdown()` 的行为。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [SceneRenderer](SceneRenderer.md)
|
|
||||||
- [SetPipeline](SetPipeline.md)
|
|
||||||
- [GetPipelineAsset](GetPipelineAsset.md)
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# SceneRenderer::GetPipelineAsset
|
|
||||||
|
|
||||||
返回当前场景渲染器绑定的 pipeline asset。
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
const RenderPipelineAsset* GetPipelineAsset() const;
|
|
||||||
```
|
|
||||||
|
|
||||||
## 返回值
|
|
||||||
|
|
||||||
- 返回内部 `m_cameraRenderer.GetPipelineAsset()` 的结果。
|
|
||||||
|
|
||||||
## 当前语义
|
|
||||||
|
|
||||||
- 这是一个非拥有观察指针,用来回答“当前 runtime pipeline 是由哪个 asset 工厂派生出来的”。
|
|
||||||
- 默认构造的 `SceneRenderer` 通常会返回默认 builtin forward pipeline asset。
|
|
||||||
- 如果最近一次切换是 [SetPipeline](SetPipeline.md) 且传入了非空 runtime pipeline,这里会变成 `nullptr`,因为那条路径会清掉当前 asset 绑定。
|
|
||||||
- 如果 [SetPipelineAsset](SetPipelineAsset.md) 传入空指针,内部不会保留 `nullptr`,而是回退到默认 builtin forward asset。
|
|
||||||
|
|
||||||
## 调用方影响
|
|
||||||
|
|
||||||
- 这不是 `shared_ptr` 的外露别名,不提供所有权,也不保证在 `SceneRenderer` 生命周期之外继续有效。
|
|
||||||
- 对外部来说,它更适合做调试、状态展示或测试断言,而不适合做长期缓存键。
|
|
||||||
|
|
||||||
## 测试覆盖
|
|
||||||
|
|
||||||
- `tests/Rendering/unit/test_camera_scene_renderer.cpp` 覆盖了默认 asset、替换 asset,以及替换 runtime pipeline 后 asset 观察值的变化。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [SceneRenderer](SceneRenderer.md)
|
|
||||||
- [SetPipelineAsset](SetPipelineAsset.md)
|
|
||||||
- [GetPipeline](GetPipeline.md)
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
# SceneRenderer::Render
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
bool Render(const CameraRenderRequest& request);
|
|
||||||
bool Render(const std::vector<CameraRenderRequest>& requests);
|
|
||||||
bool Render(
|
|
||||||
const Components::Scene& scene,
|
|
||||||
Components::CameraComponent* overrideCamera,
|
|
||||||
const RenderContext& context,
|
|
||||||
const RenderSurface& surface);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 行为说明
|
|
||||||
|
|
||||||
`SceneRenderer` 当前提供三种提交入口。
|
|
||||||
|
|
||||||
### `Render(const CameraRenderRequest&)`
|
|
||||||
|
|
||||||
这是最薄的转发层,直接调用:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
m_cameraRenderer.Render(request)
|
|
||||||
```
|
|
||||||
|
|
||||||
### `Render(const std::vector<CameraRenderRequest>&)`
|
|
||||||
|
|
||||||
当前实现会:
|
|
||||||
|
|
||||||
1. 拒绝空数组。
|
|
||||||
2. 检查每个请求都必须 `IsValid()`。
|
|
||||||
3. 复制一份数组并调用 `SceneRenderRequestUtils::SortCameraRenderRequests(...)` 做稳定排序。
|
|
||||||
4. 逐个转发给 `m_cameraRenderer.Render(request)`。
|
|
||||||
5. 任一请求失败即返回 `false`。
|
|
||||||
|
|
||||||
### `Render(const Components::Scene&, ...)`
|
|
||||||
|
|
||||||
这是便捷入口,等价于:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
return Render(BuildRenderRequests(scene, overrideCamera, context, surface));
|
|
||||||
```
|
|
||||||
|
|
||||||
因此它本身不直接做 scene extraction;真正的 `RenderSceneExtractor` 调用发生在 `CameraRenderer::Render(...)` 内部。
|
|
||||||
|
|
||||||
## 返回值
|
|
||||||
|
|
||||||
- 所有需要执行的请求都成功完成时返回 `true`。
|
|
||||||
- 请求数组为空、任一请求无效,或任一请求执行失败时返回 `false`。
|
|
||||||
|
|
||||||
## 测试覆盖
|
|
||||||
|
|
||||||
`tests/Rendering/unit/test_camera_scene_renderer.cpp` 当前覆盖了:
|
|
||||||
|
|
||||||
- 多相机请求的排序与稳定性。
|
|
||||||
- `Render(scene, ...)` 的请求构建与提交链路。
|
|
||||||
- 手工提交请求数组时的排序规则。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [SceneRenderer](SceneRenderer.md)
|
|
||||||
- [BuildRenderRequests](BuildRenderRequests.md)
|
|
||||||
- [CameraRenderer](../CameraRenderer/CameraRenderer.md)
|
|
||||||
- [SceneRenderRequestUtils](../SceneRenderRequestUtils/SceneRenderRequestUtils.md)
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
# SceneRenderer
|
|
||||||
|
|
||||||
**命名空间**: `XCEngine::Rendering`
|
|
||||||
|
|
||||||
**类型**: `class`
|
|
||||||
|
|
||||||
**头文件**: `XCEngine/Rendering/Execution/SceneRenderer.h`
|
|
||||||
|
|
||||||
**描述**: 场景级渲染编排入口。它负责构建和排序 `CameraRenderRequest`,再把每个请求转交给 [CameraRenderer](../CameraRenderer/CameraRenderer.md) 执行。
|
|
||||||
|
|
||||||
## 概览
|
|
||||||
|
|
||||||
`SceneRenderer` 当前不再自己持有 `RenderSceneExtractor` 或直接驱动主管线。它只维护两块运行时对象:
|
|
||||||
|
|
||||||
- `m_requestPlanner`:负责从 `Scene` 和可选 override camera 生成 `CameraRenderRequest` 列表。
|
|
||||||
- `m_cameraRenderer`:负责真正执行单个相机请求,包括场景提取、主管线提交、object-id pass,以及 request 上挂接的 pre/post/overlay pass sequence。
|
|
||||||
|
|
||||||
这意味着当前的主链路已经拆成两层:
|
|
||||||
|
|
||||||
1. `SceneRenderer` 负责“这次要渲染哪些相机、按什么顺序、每个请求的 surface/render-area/clear-flags 是什么”。
|
|
||||||
2. `CameraRenderer` 负责“单个请求如何真正跑完”。
|
|
||||||
|
|
||||||
这条边界是当前 Rendering 模块里最值得保留的设计决定之一。
|
|
||||||
如果把相机规划和 request 执行重新揉回一个类里,Editor 的 Scene View、object-id picking、overlay 注入和离屏渲染很快就会和主管线细节耦合到一起。
|
|
||||||
|
|
||||||
现在的拆法则让 `SceneRenderer` 更像一个稳定的编排入口:
|
|
||||||
|
|
||||||
- 从 `Scene` 直接提交时,它负责生成 request
|
|
||||||
- 从外部手工提交 request 时,它负责复用同一排序规则
|
|
||||||
- 不管 request 来源是什么,真正执行都统一落到 `CameraRenderer`
|
|
||||||
|
|
||||||
## 当前执行路径
|
|
||||||
|
|
||||||
### `BuildRenderRequests(...)`
|
|
||||||
|
|
||||||
直接委托给 [SceneRenderRequestPlanner](../SceneRenderRequestPlanner/SceneRenderRequestPlanner.md):
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
return m_requestPlanner.BuildRequests(scene, overrideCamera, context, surface);
|
|
||||||
```
|
|
||||||
|
|
||||||
### `Render(const Components::Scene&, ...)`
|
|
||||||
|
|
||||||
这是“从场景直接提交”的便捷入口,本质上等价于:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
return Render(BuildRenderRequests(scene, overrideCamera, context, surface));
|
|
||||||
```
|
|
||||||
|
|
||||||
### `Render(const std::vector<CameraRenderRequest>&)`
|
|
||||||
|
|
||||||
当前会:
|
|
||||||
|
|
||||||
1. 拒绝空请求数组。
|
|
||||||
2. 拒绝任何 `IsValid()` 为假的请求。
|
|
||||||
3. 复制一份请求数组,并通过 `SceneRenderRequestUtils::SortCameraRenderRequests(...)` 做稳定排序。
|
|
||||||
4. 依次调用 `m_cameraRenderer.Render(request)`。
|
|
||||||
5. 任一请求失败就立即返回 `false`。
|
|
||||||
|
|
||||||
这里不会额外改写 request 里的 `objectId` 或各类 pass sequence;如果上层已经补好了这些字段,`SceneRenderer` 只负责排序后转交执行。
|
|
||||||
|
|
||||||
这也是为什么手工 request 提交路径仍然会再次排序。当前实现明确认为“stack/depth 规则”属于 `SceneRenderer` 的稳定契约,而不是调用方各自维护的一套隐式约定。
|
|
||||||
|
|
||||||
### `Render(const CameraRenderRequest&)`
|
|
||||||
|
|
||||||
这是最薄的一层,直接转发到 `m_cameraRenderer.Render(request)`。
|
|
||||||
|
|
||||||
## 构造与默认行为
|
|
||||||
|
|
||||||
- 默认构造通过默认构造的 `CameraRenderer` 获得默认主管线与默认 object-id pass。
|
|
||||||
- 传入 `std::unique_ptr<RenderPipeline>` 时,走“手动注入 runtime pipeline”路径。
|
|
||||||
- 传入 `std::shared_ptr<const RenderPipelineAsset>` 时,走“由 asset 创建 runtime pipeline”路径。
|
|
||||||
|
|
||||||
默认主管线的具体创建不在 `SceneRenderer` 内部硬编码,而是由 `CameraRenderer` 通过默认 [BuiltinForwardPipelineAsset](../Pipelines/BuiltinForwardPipelineAsset/BuiltinForwardPipelineAsset.md) 负责。
|
|
||||||
|
|
||||||
## 当前实现边界
|
|
||||||
|
|
||||||
- 不直接做 scene extraction;真正的 `RenderSceneExtractor` 调用发生在 `CameraRenderer` 里。
|
|
||||||
- 不直接操作 `RenderPipeline` 的初始化或渲染细节;它只负责请求规划和排序。
|
|
||||||
- 不负责替 request 自动补 `objectId` 或各类 `RenderPassSequence`;这类附加阶段通常由 Editor 或其他上层调用方在提交前写入。
|
|
||||||
- 对手工提交的请求数组,会再次按相机优先级稳定排序,而不是按调用方原始顺序盲目执行。
|
|
||||||
|
|
||||||
## 测试覆盖
|
|
||||||
|
|
||||||
`tests/Rendering/unit/test_camera_scene_renderer.cpp` 当前验证了:
|
|
||||||
|
|
||||||
- `BuildRenderRequests()` 的多相机排序、override camera、clear-flags 和 viewport/render-area 解析。
|
|
||||||
- 手工提交请求数组时的排序和稳定性。
|
|
||||||
- `SetPipeline()` / `SetPipelineAsset()` 的转发、替换与 shutdown 行为。
|
|
||||||
|
|
||||||
这些测试锚点说明,`SceneRenderer` 当前不是一个“薄到没有语义”的转发器。它真正承担了 request planning 契约本身,包括:
|
|
||||||
|
|
||||||
- override camera 的回退语义
|
|
||||||
- base / overlay 排序
|
|
||||||
- `Auto` clear 的默认策略
|
|
||||||
- 手工 request 重新排序的稳定性
|
|
||||||
|
|
||||||
## 公开方法
|
|
||||||
|
|
||||||
| 方法 | 说明 |
|
|
||||||
|------|------|
|
|
||||||
| [Constructor](Constructor.md) | 构造 `SceneRenderer`,并决定 `CameraRenderer` 的主管线路径。 |
|
|
||||||
| [Destructor](Destructor.md) | 默认析构;真正的运行时清理由成员对象完成。 |
|
|
||||||
| [SetPipeline](SetPipeline.md) | 手动替换当前 runtime `RenderPipeline`。 |
|
|
||||||
| [SetPipelineAsset](SetPipelineAsset.md) | 通过 `RenderPipelineAsset` 重建当前 runtime `RenderPipeline`。 |
|
|
||||||
| [GetPipeline](GetPipeline.md) | 返回当前主管线的非拥有指针。 |
|
|
||||||
| [GetPipelineAsset](GetPipelineAsset.md) | 返回当前 pipeline asset 的非拥有指针。 |
|
|
||||||
| [BuildRenderRequests](BuildRenderRequests.md) | 生成当前场景对应的相机请求列表。 |
|
|
||||||
| [Render](Render.md) | 执行单个请求、请求数组,或从场景直接生成请求并执行。 |
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [Rendering](../Rendering.md)
|
|
||||||
- [CameraRenderer](../CameraRenderer/CameraRenderer.md)
|
|
||||||
- [SceneRenderRequestPlanner](../SceneRenderRequestPlanner/SceneRenderRequestPlanner.md)
|
|
||||||
- [SceneRenderRequestUtils](../SceneRenderRequestUtils/SceneRenderRequestUtils.md)
|
|
||||||
- [RenderSceneExtractor](../RenderSceneExtractor/RenderSceneExtractor.md)
|
|
||||||
- [Camera Request Planning And Clear Rules](../../../_guides/Rendering/Camera-Request-Planning-And-Clear-Rules.md)
|
|
||||||
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# SceneRenderer::SetPipeline
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void SetPipeline(std::unique_ptr<RenderPipeline> pipeline);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 行为说明
|
|
||||||
|
|
||||||
当前实现只是把调用转发给内部 `m_cameraRenderer`:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
m_cameraRenderer.SetPipeline(std::move(pipeline));
|
|
||||||
```
|
|
||||||
|
|
||||||
## 当前语义
|
|
||||||
|
|
||||||
沿用 `CameraRenderer::SetPipeline()` 的规则:
|
|
||||||
|
|
||||||
- 当前绑定的 `RenderPipelineAsset` 会被清空。
|
|
||||||
- 被替换掉的旧 runtime pipeline 会先执行 `Shutdown()`。
|
|
||||||
- 如果新传入的 `pipeline` 为空,内部会回退到默认 pipeline asset,并重新创建默认主管线。
|
|
||||||
|
|
||||||
## 参数
|
|
||||||
|
|
||||||
- `pipeline` - 新的 runtime pipeline 所有权,可为空。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [SceneRenderer](SceneRenderer.md)
|
|
||||||
- [SetPipelineAsset](SetPipelineAsset.md)
|
|
||||||
- [GetPipeline](GetPipeline.md)
|
|
||||||
- [CameraRenderer::SetPipeline](../CameraRenderer/SetPipeline.md)
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
# SceneRenderer::SetPipelineAsset
|
|
||||||
|
|
||||||
切换当前场景渲染器使用的 pipeline asset。
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
void SetPipelineAsset(std::shared_ptr<const RenderPipelineAsset> pipelineAsset);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 参数
|
|
||||||
|
|
||||||
- `pipelineAsset` - 目标 pipeline asset;允许传入空指针。
|
|
||||||
|
|
||||||
## 当前语义
|
|
||||||
|
|
||||||
- 当前实现直接转发到内部 `m_cameraRenderer.SetPipelineAsset(...)`。
|
|
||||||
- 如果传入 asset 非空,后续 runtime pipeline 会由该 asset 创建。
|
|
||||||
- 如果传入 asset 为空,内部会回退到默认 builtin forward pipeline asset,而不是保留空绑定。
|
|
||||||
- 被替换掉的旧 runtime pipeline 会先执行 `Shutdown()`,再由新 asset 创建新实例。
|
|
||||||
|
|
||||||
## 调用方影响
|
|
||||||
|
|
||||||
- 调用之后,[GetPipelineAsset](GetPipelineAsset.md) 和 [GetPipeline](GetPipeline.md) 的返回值都可能变化。
|
|
||||||
- 任何此前缓存的旧 pipeline 指针都应视为潜在失效。
|
|
||||||
- 如果调用方只是想直接接管 runtime pipeline,而不是保留 asset 工厂关系,应改用 [SetPipeline](SetPipeline.md)。
|
|
||||||
|
|
||||||
## 测试覆盖
|
|
||||||
|
|
||||||
- `tests/Rendering/unit/test_camera_scene_renderer.cpp` 验证了替换 asset 时旧 pipeline 会被 `Shutdown()`,并且新 asset 会创建新的 runtime pipeline 实例。
|
|
||||||
|
|
||||||
## 相关文档
|
|
||||||
|
|
||||||
- [SceneRenderer](SceneRenderer.md)
|
|
||||||
- [SetPipeline](SetPipeline.md)
|
|
||||||
- [GetPipelineAsset](GetPipelineAsset.md)
|
|
||||||
@@ -6,64 +6,101 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|||||||
|
|
||||||
file(TO_CMAKE_PATH "${CMAKE_SOURCE_DIR}" XCUIEDITOR_REPO_ROOT_PATH)
|
file(TO_CMAKE_PATH "${CMAKE_SOURCE_DIR}" XCUIEDITOR_REPO_ROOT_PATH)
|
||||||
|
|
||||||
set(XCUI_EDITOR_RESOURCE_FILES
|
function(xcui_editor_apply_common_target_settings target visibility)
|
||||||
ui/views/editor_shell.xcui
|
target_compile_definitions(${target} ${visibility}
|
||||||
ui/themes/editor_shell.xctheme
|
UNICODE
|
||||||
|
_UNICODE
|
||||||
|
)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
target_compile_options(${target} PRIVATE /utf-8 /FS)
|
||||||
|
set_property(TARGET ${target} PROPERTY
|
||||||
|
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
set(XCUI_EDITOR_FOUNDATION_SOURCES
|
||||||
|
src/Foundation/UIEditorCommandDispatcher.cpp
|
||||||
|
src/Foundation/UIEditorCommandRegistry.cpp
|
||||||
|
src/Foundation/UIEditorShortcutManager.cpp
|
||||||
|
src/Foundation/UIEditorTheme.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(XCUI_EDITOR_FIELD_SOURCES
|
||||||
|
src/Fields/UIEditorAssetField.cpp
|
||||||
|
src/Fields/UIEditorAssetFieldInteraction.cpp
|
||||||
|
src/Fields/UIEditorBoolField.cpp
|
||||||
|
src/Fields/UIEditorBoolFieldInteraction.cpp
|
||||||
|
src/Fields/UIEditorColorField.cpp
|
||||||
|
src/Fields/UIEditorColorFieldInteraction.cpp
|
||||||
|
src/Fields/UIEditorEnumField.cpp
|
||||||
|
src/Fields/UIEditorEnumFieldInteraction.cpp
|
||||||
|
src/Fields/UIEditorFieldStyle.cpp
|
||||||
|
src/Fields/UIEditorNumberField.cpp
|
||||||
|
src/Fields/UIEditorNumberFieldInteraction.cpp
|
||||||
|
src/Fields/UIEditorObjectField.cpp
|
||||||
|
src/Fields/UIEditorObjectFieldInteraction.cpp
|
||||||
|
src/Fields/UIEditorPropertyGrid.cpp
|
||||||
|
src/Fields/UIEditorPropertyGridInteraction.cpp
|
||||||
|
src/Fields/UIEditorTextField.cpp
|
||||||
|
src/Fields/UIEditorTextFieldInteraction.cpp
|
||||||
|
src/Fields/UIEditorVector2Field.cpp
|
||||||
|
src/Fields/UIEditorVector2FieldInteraction.cpp
|
||||||
|
src/Fields/UIEditorVector3Field.cpp
|
||||||
|
src/Fields/UIEditorVector3FieldInteraction.cpp
|
||||||
|
src/Fields/UIEditorVector4Field.cpp
|
||||||
|
src/Fields/UIEditorVector4FieldInteraction.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(XCUI_EDITOR_COLLECTION_SOURCES
|
||||||
|
src/Collections/UIEditorInlineRenameSession.cpp
|
||||||
|
src/Collections/UIEditorListView.cpp
|
||||||
|
src/Collections/UIEditorListViewInteraction.cpp
|
||||||
|
src/Collections/UIEditorScrollView.cpp
|
||||||
|
src/Collections/UIEditorScrollViewInteraction.cpp
|
||||||
|
src/Collections/UIEditorTabStrip.cpp
|
||||||
|
src/Collections/UIEditorTabStripInteraction.cpp
|
||||||
|
src/Collections/UIEditorTreeView.cpp
|
||||||
|
src/Collections/UIEditorTreeViewInteraction.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(XCUI_EDITOR_SHELL_SOURCES
|
||||||
|
src/Shell/EditorShellAsset.cpp
|
||||||
|
src/Shell/UIEditorDockHost.cpp
|
||||||
|
src/Shell/UIEditorDockHostInteraction.cpp
|
||||||
|
src/Shell/UIEditorMenuBar.cpp
|
||||||
|
src/Shell/UIEditorMenuModel.cpp
|
||||||
|
src/Shell/UIEditorMenuPopup.cpp
|
||||||
|
src/Shell/UIEditorMenuSession.cpp
|
||||||
|
src/Shell/UIEditorPanelContentHost.cpp
|
||||||
|
src/Shell/UIEditorPanelFrame.cpp
|
||||||
|
src/Shell/UIEditorPanelHostLifecycle.cpp
|
||||||
|
src/Shell/UIEditorPanelRegistry.cpp
|
||||||
|
src/Shell/UIEditorShellCompose.cpp
|
||||||
|
src/Shell/UIEditorShellInteraction.cpp
|
||||||
|
src/Shell/UIEditorStatusBar.cpp
|
||||||
|
src/Shell/UIEditorViewportInputBridge.cpp
|
||||||
|
src/Shell/UIEditorViewportShell.cpp
|
||||||
|
src/Shell/UIEditorViewportSlot.cpp
|
||||||
|
src/Shell/UIEditorWorkspaceCompose.cpp
|
||||||
|
src/Shell/UIEditorWorkspaceController.cpp
|
||||||
|
src/Shell/UIEditorWorkspaceInteraction.cpp
|
||||||
|
src/Shell/UIEditorWorkspaceLayoutPersistence.cpp
|
||||||
|
src/Shell/UIEditorWorkspaceModel.cpp
|
||||||
|
src/Shell/UIEditorWorkspaceSession.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(XCUI_EDITOR_WIDGET_SUPPORT_SOURCES
|
||||||
|
src/Widgets/UIEditorCollectionPrimitives.cpp
|
||||||
|
src/Widgets/UIEditorFieldRowLayout.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(XCUIEditorLib STATIC
|
add_library(XCUIEditorLib STATIC
|
||||||
src/Core/EditorShellAsset.cpp
|
${XCUI_EDITOR_FOUNDATION_SOURCES}
|
||||||
src/Core/UIEditorCommandDispatcher.cpp
|
${XCUI_EDITOR_FIELD_SOURCES}
|
||||||
src/Core/UIEditorCommandRegistry.cpp
|
${XCUI_EDITOR_COLLECTION_SOURCES}
|
||||||
src/Core/UIEditorBoolFieldInteraction.cpp
|
${XCUI_EDITOR_SHELL_SOURCES}
|
||||||
src/Core/UIEditorDockHostInteraction.cpp
|
${XCUI_EDITOR_WIDGET_SUPPORT_SOURCES}
|
||||||
src/Core/UIEditorEnumFieldInteraction.cpp
|
|
||||||
src/Core/UIEditorListViewInteraction.cpp
|
|
||||||
src/Core/UIEditorMenuModel.cpp
|
|
||||||
src/Core/UIEditorMenuSession.cpp
|
|
||||||
src/Core/UIEditorNumberFieldInteraction.cpp
|
|
||||||
src/Core/UIEditorPanelContentHost.cpp
|
|
||||||
src/Core/UIEditorPanelHostLifecycle.cpp
|
|
||||||
src/Core/UIEditorPanelRegistry.cpp
|
|
||||||
src/Core/UIEditorPropertyGridInteraction.cpp
|
|
||||||
src/Core/UIEditorScrollViewInteraction.cpp
|
|
||||||
src/Core/UIEditorShellCompose.cpp
|
|
||||||
src/Core/UIEditorShellInteraction.cpp
|
|
||||||
src/Core/UIEditorShortcutManager.cpp
|
|
||||||
src/Core/UIEditorTextFieldInteraction.cpp
|
|
||||||
src/Core/UIEditorTheme.cpp
|
|
||||||
src/Core/UIEditorTreeViewInteraction.cpp
|
|
||||||
src/Core/UIEditorVector2FieldInteraction.cpp
|
|
||||||
src/Core/UIEditorVector3FieldInteraction.cpp
|
|
||||||
src/Core/UIEditorVector4FieldInteraction.cpp
|
|
||||||
src/Core/UIEditorViewportInputBridge.cpp
|
|
||||||
src/Core/UIEditorViewportShell.cpp
|
|
||||||
src/Core/UIEditorWorkspaceCompose.cpp
|
|
||||||
src/Core/UIEditorWorkspaceInteraction.cpp
|
|
||||||
src/Core/UIEditorWorkspaceLayoutPersistence.cpp
|
|
||||||
src/Core/UIEditorWorkspaceController.cpp
|
|
||||||
src/Core/UIEditorWorkspaceModel.cpp
|
|
||||||
src/Core/UIEditorWorkspaceSession.cpp
|
|
||||||
src/Widgets/UIEditorCollectionPrimitives.cpp
|
|
||||||
src/Widgets/UIEditorFieldRowLayout.cpp
|
|
||||||
src/Widgets/UIEditorBoolField.cpp
|
|
||||||
src/Widgets/UIEditorDockHost.cpp
|
|
||||||
src/Widgets/UIEditorEnumField.cpp
|
|
||||||
src/Widgets/UIEditorListView.cpp
|
|
||||||
src/Widgets/UIEditorMenuBar.cpp
|
|
||||||
src/Widgets/UIEditorMenuPopup.cpp
|
|
||||||
src/Widgets/UIEditorNumberField.cpp
|
|
||||||
src/Widgets/UIEditorPanelFrame.cpp
|
|
||||||
src/Widgets/UIEditorPropertyGrid.cpp
|
|
||||||
src/Widgets/UIEditorScrollView.cpp
|
|
||||||
src/Widgets/UIEditorStatusBar.cpp
|
|
||||||
src/Widgets/UIEditorTabStrip.cpp
|
|
||||||
src/Widgets/UIEditorTextField.cpp
|
|
||||||
src/Widgets/UIEditorTreeView.cpp
|
|
||||||
src/Widgets/UIEditorVector2Field.cpp
|
|
||||||
src/Widgets/UIEditorVector3Field.cpp
|
|
||||||
src/Widgets/UIEditorVector4Field.cpp
|
|
||||||
src/Widgets/UIEditorViewportSlot.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(XCUIEditorLib
|
target_include_directories(XCUIEditorLib
|
||||||
@@ -75,16 +112,10 @@ target_include_directories(XCUIEditorLib
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(XCUIEditorLib PUBLIC
|
target_compile_definitions(XCUIEditorLib PUBLIC
|
||||||
UNICODE
|
|
||||||
_UNICODE
|
|
||||||
XCUIEDITOR_REPO_ROOT="${XCUIEDITOR_REPO_ROOT_PATH}"
|
XCUIEDITOR_REPO_ROOT="${XCUIEDITOR_REPO_ROOT_PATH}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if(MSVC)
|
xcui_editor_apply_common_target_settings(XCUIEditorLib PUBLIC)
|
||||||
target_compile_options(XCUIEditorLib PRIVATE /utf-8 /FS)
|
|
||||||
set_property(TARGET XCUIEditorLib PROPERTY
|
|
||||||
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(XCUIEditorLib PUBLIC
|
target_link_libraries(XCUIEditorLib PUBLIC
|
||||||
XCEngine
|
XCEngine
|
||||||
@@ -99,21 +130,9 @@ target_include_directories(XCUIEditorHost
|
|||||||
PUBLIC
|
PUBLIC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/app
|
${CMAKE_CURRENT_SOURCE_DIR}/app
|
||||||
${CMAKE_SOURCE_DIR}/engine/include
|
${CMAKE_SOURCE_DIR}/engine/include
|
||||||
PRIVATE
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(XCUIEditorHost PUBLIC
|
xcui_editor_apply_common_target_settings(XCUIEditorHost PUBLIC)
|
||||||
UNICODE
|
|
||||||
_UNICODE
|
|
||||||
)
|
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
target_compile_options(XCUIEditorHost PRIVATE /utf-8 /FS)
|
|
||||||
set_property(TARGET XCUIEditorHost PROPERTY
|
|
||||||
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(XCUIEditorHost PUBLIC
|
target_link_libraries(XCUIEditorHost PUBLIC
|
||||||
XCEngine
|
XCEngine
|
||||||
@@ -126,27 +145,18 @@ if(XCENGINE_BUILD_XCUI_EDITOR_APP)
|
|||||||
add_executable(XCUIEditorApp WIN32
|
add_executable(XCUIEditorApp WIN32
|
||||||
app/main.cpp
|
app/main.cpp
|
||||||
app/Application.cpp
|
app/Application.cpp
|
||||||
${XCUI_EDITOR_RESOURCE_FILES}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(XCUIEditorApp PRIVATE
|
target_include_directories(XCUIEditorApp PRIVATE
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/app
|
${CMAKE_CURRENT_SOURCE_DIR}/app
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||||
${CMAKE_SOURCE_DIR}/engine/include
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(XCUIEditorApp PRIVATE
|
target_compile_definitions(XCUIEditorApp PRIVATE
|
||||||
UNICODE
|
|
||||||
_UNICODE
|
|
||||||
XCUIEDITOR_REPO_ROOT="${XCUIEDITOR_REPO_ROOT_PATH}"
|
XCUIEDITOR_REPO_ROOT="${XCUIEDITOR_REPO_ROOT_PATH}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if(MSVC)
|
xcui_editor_apply_common_target_settings(XCUIEditorApp PRIVATE)
|
||||||
target_compile_options(XCUIEditorApp PRIVATE /utf-8 /FS)
|
|
||||||
set_property(TARGET XCUIEditorApp PROPERTY
|
|
||||||
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(XCUIEditorApp PRIVATE
|
target_link_libraries(XCUIEditorApp PRIVATE
|
||||||
XCUIEditorLib
|
XCUIEditorLib
|
||||||
@@ -158,5 +168,3 @@ if(XCENGINE_BUILD_XCUI_EDITOR_APP)
|
|||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin"
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${XCUI_EDITOR_RESOURCE_FILES})
|
|
||||||
|
|||||||
@@ -292,7 +292,8 @@ void Application::RenderFrame() {
|
|||||||
m_pendingInputEvents.clear();
|
m_pendingInputEvents.clear();
|
||||||
|
|
||||||
UIDrawData drawData = {};
|
UIDrawData drawData = {};
|
||||||
if (m_useStructuredScreen && m_screenPlayer.IsLoaded()) {
|
const bool hasAuthoredScreenDocument = !m_screenAsset.documentPath.empty();
|
||||||
|
if (hasAuthoredScreenDocument && m_useStructuredScreen && m_screenPlayer.IsLoaded()) {
|
||||||
UIScreenFrameInput input = {};
|
UIScreenFrameInput input = {};
|
||||||
input.viewportRect = UIRect(0.0f, 0.0f, width, height);
|
input.viewportRect = UIRect(0.0f, 0.0f, width, height);
|
||||||
input.events = std::move(frameEvents);
|
input.events = std::move(frameEvents);
|
||||||
@@ -307,6 +308,10 @@ void Application::RenderFrame() {
|
|||||||
|
|
||||||
m_runtimeStatus = "XCUI Editor Shell";
|
m_runtimeStatus = "XCUI Editor Shell";
|
||||||
m_runtimeError = frame.errorMessage;
|
m_runtimeError = frame.errorMessage;
|
||||||
|
} else if (!hasAuthoredScreenDocument) {
|
||||||
|
++m_frameIndex;
|
||||||
|
m_runtimeStatus = "XCUI Editor Shell | Code-driven";
|
||||||
|
m_runtimeError.clear();
|
||||||
} else {
|
} else {
|
||||||
m_runtimeStatus = "Editor Shell | Load Error";
|
m_runtimeStatus = "Editor Shell | Load Error";
|
||||||
if (m_runtimeError.empty() && !m_screenPlayer.IsLoaded()) {
|
if (m_runtimeError.empty() && !m_screenPlayer.IsLoaded()) {
|
||||||
@@ -401,14 +406,19 @@ void Application::QueueWindowFocusEvent(UIInputEventType type) {
|
|||||||
bool Application::LoadStructuredScreen(const char* triggerReason) {
|
bool Application::LoadStructuredScreen(const char* triggerReason) {
|
||||||
(void)triggerReason;
|
(void)triggerReason;
|
||||||
m_screenAsset = m_structuredShell.screenAsset;
|
m_screenAsset = m_structuredShell.screenAsset;
|
||||||
const bool loaded = m_screenPlayer.Load(m_screenAsset);
|
|
||||||
const EditorShellAssetValidationResult& shellAssetValidation =
|
const EditorShellAssetValidationResult& shellAssetValidation =
|
||||||
m_structuredShell.assetValidation;
|
m_structuredShell.assetValidation;
|
||||||
const auto shortcutValidation = m_structuredShell.shortcutManager.ValidateConfiguration();
|
const auto shortcutValidation = m_structuredShell.shortcutManager.ValidateConfiguration();
|
||||||
m_useStructuredScreen = loaded;
|
const bool hasAuthoredScreenDocument = !m_screenAsset.documentPath.empty();
|
||||||
m_runtimeStatus = loaded ? "XCUI Editor Shell" : "Editor Shell | Load Error";
|
const bool loaded =
|
||||||
|
hasAuthoredScreenDocument ? m_screenPlayer.Load(m_screenAsset) : shellAssetValidation.IsValid();
|
||||||
|
m_useStructuredScreen = hasAuthoredScreenDocument && loaded;
|
||||||
|
m_runtimeStatus =
|
||||||
|
hasAuthoredScreenDocument
|
||||||
|
? (loaded ? "XCUI Editor Shell" : "Editor Shell | Load Error")
|
||||||
|
: "XCUI Editor Shell | Code-driven";
|
||||||
m_runtimeError.clear();
|
m_runtimeError.clear();
|
||||||
if (!loaded) {
|
if (hasAuthoredScreenDocument && !loaded) {
|
||||||
AppendErrorMessage(m_runtimeError, m_screenPlayer.GetLastError());
|
AppendErrorMessage(m_runtimeError, m_screenPlayer.GetLastError());
|
||||||
}
|
}
|
||||||
if (!shellAssetValidation.IsValid()) {
|
if (!shellAssetValidation.IsValid()) {
|
||||||
@@ -468,7 +478,6 @@ void Application::RebuildTrackedFileStates() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
appendTrackedPath(m_screenAsset.documentPath);
|
appendTrackedPath(m_screenAsset.documentPath);
|
||||||
appendTrackedPath(m_screenAsset.themePath);
|
|
||||||
|
|
||||||
if (const auto* document = m_screenPlayer.GetDocument(); document != nullptr) {
|
if (const auto* document = m_screenPlayer.GetDocument(); document != nullptr) {
|
||||||
for (const std::string& dependency : document->dependencies) {
|
for (const std::string& dependency : document->dependencies) {
|
||||||
@@ -503,14 +512,18 @@ bool Application::DetectTrackedFileChange() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Application::AppendRuntimeOverlay(UIDrawData& drawData, float width, float height) const {
|
void Application::AppendRuntimeOverlay(UIDrawData& drawData, float width, float height) const {
|
||||||
const bool authoredMode = m_useStructuredScreen && m_screenPlayer.IsLoaded();
|
const bool authoredMode =
|
||||||
|
!m_screenAsset.documentPath.empty() && m_useStructuredScreen && m_screenPlayer.IsLoaded();
|
||||||
const float panelWidth = authoredMode ? 430.0f : 380.0f;
|
const float panelWidth = authoredMode ? 430.0f : 380.0f;
|
||||||
std::vector<std::string> detailLines = {};
|
std::vector<std::string> detailLines = {};
|
||||||
detailLines.push_back(
|
detailLines.push_back(
|
||||||
authoredMode
|
authoredMode
|
||||||
? "Hot reload watches editor shell resources."
|
? "Hot reload watches editor shell document and dependencies."
|
||||||
: "Authored editor shell failed to load.");
|
: "Editor shell is composed directly from fixed code definitions.");
|
||||||
detailLines.push_back("Document: editor_shell.xcui");
|
detailLines.push_back(
|
||||||
|
authoredMode
|
||||||
|
? "Document: " + std::filesystem::path(m_screenAsset.documentPath).filename().string()
|
||||||
|
: "Document: (none)");
|
||||||
|
|
||||||
if (authoredMode) {
|
if (authoredMode) {
|
||||||
const auto& inputDebug = m_documentHost.GetInputDebugSnapshot();
|
const auto& inputDebug = m_documentHost.GetInputDebugSnapshot();
|
||||||
@@ -560,7 +573,7 @@ void Application::AppendRuntimeOverlay(UIDrawData& drawData, float width, float
|
|||||||
} else if (!m_autoScreenshot.GetLastCaptureError().empty()) {
|
} else if (!m_autoScreenshot.GetLastCaptureError().empty()) {
|
||||||
detailLines.push_back(TruncateText(m_autoScreenshot.GetLastCaptureError(), 78u));
|
detailLines.push_back(TruncateText(m_autoScreenshot.GetLastCaptureError(), 78u));
|
||||||
} else if (!authoredMode) {
|
} else if (!authoredMode) {
|
||||||
detailLines.push_back("No fallback sandbox is rendered in this host.");
|
detailLines.push_back("No authored XCUI document is used by the editor shell host.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const float panelHeight = 38.0f + static_cast<float>(detailLines.size()) * 18.0f;
|
const float panelHeight = 38.0f + static_cast<float>(detailLines.size()) * 18.0f;
|
||||||
|
|||||||
@@ -8,11 +8,11 @@
|
|||||||
#include "Host/InputModifierTracker.h"
|
#include "Host/InputModifierTracker.h"
|
||||||
#include "Host/NativeRenderer.h"
|
#include "Host/NativeRenderer.h"
|
||||||
|
|
||||||
#include "Core/EditorShellAsset.h"
|
#include "Shell/EditorShellAsset.h"
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorShellInteraction.h>
|
#include <XCEditor/Shell/UIEditorShellInteraction.h>
|
||||||
#include <XCEditor/Core/UIEditorShortcutManager.h>
|
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceController.h>
|
#include <XCEditor/Shell/UIEditorWorkspaceController.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Runtime/UIScreenDocumentHost.h>
|
#include <XCEngine/UI/Runtime/UIScreenDocumentHost.h>
|
||||||
#include <XCEngine/UI/Runtime/UIScreenPlayer.h>
|
#include <XCEngine/UI/Runtime/UIScreenPlayer.h>
|
||||||
@@ -50,7 +50,6 @@ inline StructuredEditorShellBinding BuildStructuredEditorShellBinding(
|
|||||||
StructuredEditorShellBinding binding = {};
|
StructuredEditorShellBinding binding = {};
|
||||||
binding.screenAsset.screenId = asset.screenId;
|
binding.screenAsset.screenId = asset.screenId;
|
||||||
binding.screenAsset.documentPath = asset.documentPath.string();
|
binding.screenAsset.documentPath = asset.documentPath.string();
|
||||||
binding.screenAsset.themePath = asset.themePath.string();
|
|
||||||
binding.workspaceController =
|
binding.workspaceController =
|
||||||
UIEditorWorkspaceController(asset.panelRegistry, asset.workspace, asset.workspaceSession);
|
UIEditorWorkspaceController(asset.panelRegistry, asset.workspace, asset.workspaceSession);
|
||||||
binding.shellDefinition = asset.shellDefinition;
|
binding.shellDefinition = asset.shellDefinition;
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
namespace XCEngine::UI::Editor::Host {
|
namespace XCEngine::UI::Editor::Host {
|
||||||
|
|
||||||
@@ -30,16 +33,47 @@ bool IsAutoCaptureOnStartupEnabled() {
|
|||||||
normalized != "no";
|
normalized != "no";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::filesystem::path GetExecutableDirectory() {
|
||||||
|
std::vector<wchar_t> buffer(MAX_PATH);
|
||||||
|
while (true) {
|
||||||
|
const DWORD copied = ::GetModuleFileNameW(
|
||||||
|
nullptr,
|
||||||
|
buffer.data(),
|
||||||
|
static_cast<DWORD>(buffer.size()));
|
||||||
|
if (copied == 0u) {
|
||||||
|
return std::filesystem::current_path().lexically_normal();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copied < buffer.size() - 1u) {
|
||||||
|
return std::filesystem::path(std::wstring(buffer.data(), copied))
|
||||||
|
.parent_path()
|
||||||
|
.lexically_normal();
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.resize(buffer.size() * 2u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path ResolveBuildCaptureRoot(const std::filesystem::path& requestedCaptureRoot) {
|
||||||
|
std::filesystem::path captureRoot = GetExecutableDirectory() / "captures";
|
||||||
|
const std::filesystem::path scenarioPath = requestedCaptureRoot.parent_path().filename();
|
||||||
|
if (!scenarioPath.empty() && scenarioPath != "captures") {
|
||||||
|
captureRoot /= scenarioPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return captureRoot.lexically_normal();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void AutoScreenshotController::Initialize(const std::filesystem::path& captureRoot) {
|
void AutoScreenshotController::Initialize(const std::filesystem::path& captureRoot) {
|
||||||
m_captureRoot = captureRoot.lexically_normal();
|
m_captureRoot = ResolveBuildCaptureRoot(captureRoot);
|
||||||
m_historyRoot = (m_captureRoot / "history").lexically_normal();
|
m_historyRoot = (m_captureRoot / "history").lexically_normal();
|
||||||
m_latestCapturePath = (m_captureRoot / "latest.png").lexically_normal();
|
m_latestCapturePath = (m_captureRoot / "latest.png").lexically_normal();
|
||||||
m_captureCount = 0;
|
m_captureCount = 0;
|
||||||
m_capturePending = false;
|
m_capturePending = false;
|
||||||
m_pendingReason.clear();
|
m_pendingReason.clear();
|
||||||
m_lastCaptureSummary.clear();
|
m_lastCaptureSummary = "Output: " + m_captureRoot.string();
|
||||||
m_lastCaptureError.clear();
|
m_lastCaptureError.clear();
|
||||||
if (IsAutoCaptureOnStartupEnabled()) {
|
if (IsAutoCaptureOnStartupEnabled()) {
|
||||||
RequestCapture("startup");
|
RequestCapture("startup");
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEditor/Fields/UIEditorTextFieldInteraction.h>
|
||||||
|
|
||||||
|
#include <XCEngine/UI/Types.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor {
|
||||||
|
|
||||||
|
struct UIEditorInlineRenameSessionState {
|
||||||
|
bool active = false;
|
||||||
|
std::string itemId = {};
|
||||||
|
Widgets::UIEditorTextFieldSpec textFieldSpec = {};
|
||||||
|
UIEditorTextFieldInteractionState textFieldInteraction = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorInlineRenameSessionRequest {
|
||||||
|
bool beginSession = false;
|
||||||
|
std::string itemId = {};
|
||||||
|
std::string initialText = {};
|
||||||
|
::XCEngine::UI::UIRect bounds = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorInlineRenameSessionResult {
|
||||||
|
bool consumed = false;
|
||||||
|
bool sessionStarted = false;
|
||||||
|
bool sessionCommitted = false;
|
||||||
|
bool sessionCanceled = false;
|
||||||
|
bool valueChanged = false;
|
||||||
|
bool active = false;
|
||||||
|
std::string itemId = {};
|
||||||
|
std::string valueBefore = {};
|
||||||
|
std::string valueAfter = {};
|
||||||
|
UIEditorTextFieldInteractionResult textFieldResult = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorInlineRenameSessionFrame {
|
||||||
|
Widgets::UIEditorTextFieldLayout layout = {};
|
||||||
|
UIEditorInlineRenameSessionResult result = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
Widgets::UIEditorTextFieldMetrics BuildUIEditorInlineRenameTextFieldMetrics(
|
||||||
|
const ::XCEngine::UI::UIRect& bounds,
|
||||||
|
const Widgets::UIEditorTextFieldMetrics& metrics = {});
|
||||||
|
|
||||||
|
UIEditorInlineRenameSessionFrame UpdateUIEditorInlineRenameSession(
|
||||||
|
UIEditorInlineRenameSessionState& state,
|
||||||
|
const UIEditorInlineRenameSessionRequest& request,
|
||||||
|
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
|
||||||
|
const Widgets::UIEditorTextFieldMetrics& metrics = {});
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Widgets/UIEditorListView.h>
|
#include <XCEditor/Collections/UIEditorListView.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Types.h>
|
#include <XCEngine/UI/Types.h>
|
||||||
#include <XCEngine/UI/Widgets/UIKeyboardNavigationModel.h>
|
#include <XCEngine/UI/Widgets/UIKeyboardNavigationModel.h>
|
||||||
@@ -14,6 +14,7 @@ namespace XCEngine::UI::Editor {
|
|||||||
struct UIEditorListViewInteractionState {
|
struct UIEditorListViewInteractionState {
|
||||||
Widgets::UIEditorListViewState listViewState = {};
|
Widgets::UIEditorListViewState listViewState = {};
|
||||||
::XCEngine::UI::Widgets::UIKeyboardNavigationModel keyboardNavigation = {};
|
::XCEngine::UI::Widgets::UIKeyboardNavigationModel keyboardNavigation = {};
|
||||||
|
std::string selectionAnchorId = {};
|
||||||
::XCEngine::UI::UIPoint pointerPosition = {};
|
::XCEngine::UI::UIPoint pointerPosition = {};
|
||||||
bool hasPointerPosition = false;
|
bool hasPointerPosition = false;
|
||||||
};
|
};
|
||||||
@@ -23,8 +24,10 @@ struct UIEditorListViewInteractionResult {
|
|||||||
bool selectionChanged = false;
|
bool selectionChanged = false;
|
||||||
bool keyboardNavigated = false;
|
bool keyboardNavigated = false;
|
||||||
bool secondaryClicked = false;
|
bool secondaryClicked = false;
|
||||||
|
bool renameRequested = false;
|
||||||
Widgets::UIEditorListViewHitTarget hitTarget = {};
|
Widgets::UIEditorListViewHitTarget hitTarget = {};
|
||||||
std::string selectedItemId = {};
|
std::string selectedItemId = {};
|
||||||
|
std::string renameItemId = {};
|
||||||
std::size_t selectedIndex = Widgets::UIEditorListViewInvalidIndex;
|
std::size_t selectedIndex = Widgets::UIEditorListViewInvalidIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ struct UIEditorScrollViewMetrics {
|
|||||||
float scrollbarWidth = 10.0f;
|
float scrollbarWidth = 10.0f;
|
||||||
float scrollbarInset = 4.0f;
|
float scrollbarInset = 4.0f;
|
||||||
float minThumbHeight = 28.0f;
|
float minThumbHeight = 28.0f;
|
||||||
float cornerRounding = 6.0f;
|
float cornerRounding = 8.0f;
|
||||||
float borderThickness = 1.0f;
|
float borderThickness = 1.0f;
|
||||||
float focusedBorderThickness = 2.0f;
|
float focusedBorderThickness = 2.0f;
|
||||||
float wheelStep = 48.0f;
|
float wheelStep = 48.0f;
|
||||||
@@ -33,19 +33,19 @@ struct UIEditorScrollViewMetrics {
|
|||||||
|
|
||||||
struct UIEditorScrollViewPalette {
|
struct UIEditorScrollViewPalette {
|
||||||
::XCEngine::UI::UIColor surfaceColor =
|
::XCEngine::UI::UIColor surfaceColor =
|
||||||
::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f);
|
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.16f, 1.0f);
|
||||||
::XCEngine::UI::UIColor borderColor =
|
::XCEngine::UI::UIColor borderColor =
|
||||||
::XCEngine::UI::UIColor(0.29f, 0.29f, 0.29f, 1.0f);
|
::XCEngine::UI::UIColor(0.30f, 0.32f, 0.34f, 1.0f);
|
||||||
::XCEngine::UI::UIColor focusedBorderColor =
|
::XCEngine::UI::UIColor focusedBorderColor =
|
||||||
::XCEngine::UI::UIColor(0.84f, 0.84f, 0.84f, 1.0f);
|
::XCEngine::UI::UIColor(0.78f, 0.80f, 0.84f, 1.0f);
|
||||||
::XCEngine::UI::UIColor scrollbarTrackColor =
|
::XCEngine::UI::UIColor scrollbarTrackColor =
|
||||||
::XCEngine::UI::UIColor(0.18f, 0.18f, 0.18f, 1.0f);
|
::XCEngine::UI::UIColor(0.19f, 0.19f, 0.21f, 1.0f);
|
||||||
::XCEngine::UI::UIColor scrollbarThumbColor =
|
::XCEngine::UI::UIColor scrollbarThumbColor =
|
||||||
::XCEngine::UI::UIColor(0.31f, 0.31f, 0.31f, 1.0f);
|
::XCEngine::UI::UIColor(0.32f, 0.34f, 0.36f, 1.0f);
|
||||||
::XCEngine::UI::UIColor scrollbarThumbHoverColor =
|
::XCEngine::UI::UIColor scrollbarThumbHoverColor =
|
||||||
::XCEngine::UI::UIColor(0.38f, 0.38f, 0.38f, 1.0f);
|
::XCEngine::UI::UIColor(0.42f, 0.44f, 0.47f, 1.0f);
|
||||||
::XCEngine::UI::UIColor scrollbarThumbActiveColor =
|
::XCEngine::UI::UIColor scrollbarThumbActiveColor =
|
||||||
::XCEngine::UI::UIColor(0.46f, 0.46f, 0.46f, 1.0f);
|
::XCEngine::UI::UIColor(0.50f, 0.52f, 0.56f, 1.0f);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UIEditorScrollViewLayout {
|
struct UIEditorScrollViewLayout {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Widgets/UIEditorScrollView.h>
|
#include <XCEditor/Collections/UIEditorScrollView.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Types.h>
|
#include <XCEngine/UI/Types.h>
|
||||||
|
|
||||||
@@ -46,41 +46,41 @@ struct UIEditorTabStripMetrics {
|
|||||||
|
|
||||||
struct UIEditorTabStripPalette {
|
struct UIEditorTabStripPalette {
|
||||||
::XCEngine::UI::UIColor stripBackgroundColor =
|
::XCEngine::UI::UIColor stripBackgroundColor =
|
||||||
::XCEngine::UI::UIColor(0.17f, 0.17f, 0.17f, 1.0f);
|
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.16f, 1.0f);
|
||||||
::XCEngine::UI::UIColor headerBackgroundColor =
|
::XCEngine::UI::UIColor headerBackgroundColor =
|
||||||
::XCEngine::UI::UIColor(0.20f, 0.20f, 0.20f, 1.0f);
|
::XCEngine::UI::UIColor(0.18f, 0.18f, 0.19f, 1.0f);
|
||||||
::XCEngine::UI::UIColor contentBackgroundColor =
|
::XCEngine::UI::UIColor contentBackgroundColor =
|
||||||
::XCEngine::UI::UIColor(0.21f, 0.21f, 0.21f, 1.0f);
|
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.16f, 1.0f);
|
||||||
::XCEngine::UI::UIColor stripBorderColor =
|
::XCEngine::UI::UIColor stripBorderColor =
|
||||||
::XCEngine::UI::UIColor(0.30f, 0.30f, 0.30f, 1.0f);
|
::XCEngine::UI::UIColor(0.30f, 0.32f, 0.34f, 1.0f);
|
||||||
::XCEngine::UI::UIColor focusedBorderColor =
|
::XCEngine::UI::UIColor focusedBorderColor =
|
||||||
::XCEngine::UI::UIColor(0.86f, 0.86f, 0.86f, 1.0f);
|
::XCEngine::UI::UIColor(0.78f, 0.80f, 0.84f, 1.0f);
|
||||||
::XCEngine::UI::UIColor tabColor =
|
::XCEngine::UI::UIColor tabColor =
|
||||||
::XCEngine::UI::UIColor(0.23f, 0.23f, 0.23f, 1.0f);
|
::XCEngine::UI::UIColor(0.21f, 0.22f, 0.24f, 1.0f);
|
||||||
::XCEngine::UI::UIColor tabHoveredColor =
|
::XCEngine::UI::UIColor tabHoveredColor =
|
||||||
::XCEngine::UI::UIColor(0.27f, 0.27f, 0.27f, 1.0f);
|
::XCEngine::UI::UIColor(0.27f, 0.28f, 0.30f, 1.0f);
|
||||||
::XCEngine::UI::UIColor tabSelectedColor =
|
::XCEngine::UI::UIColor tabSelectedColor =
|
||||||
::XCEngine::UI::UIColor(0.29f, 0.29f, 0.29f, 1.0f);
|
::XCEngine::UI::UIColor(0.33f, 0.35f, 0.38f, 1.0f);
|
||||||
::XCEngine::UI::UIColor tabBorderColor =
|
::XCEngine::UI::UIColor tabBorderColor =
|
||||||
::XCEngine::UI::UIColor(0.32f, 0.32f, 0.32f, 1.0f);
|
::XCEngine::UI::UIColor(0.32f, 0.34f, 0.36f, 1.0f);
|
||||||
::XCEngine::UI::UIColor tabHoveredBorderColor =
|
::XCEngine::UI::UIColor tabHoveredBorderColor =
|
||||||
::XCEngine::UI::UIColor(0.46f, 0.46f, 0.46f, 1.0f);
|
::XCEngine::UI::UIColor(0.42f, 0.44f, 0.47f, 1.0f);
|
||||||
::XCEngine::UI::UIColor tabSelectedBorderColor =
|
::XCEngine::UI::UIColor tabSelectedBorderColor =
|
||||||
::XCEngine::UI::UIColor(0.72f, 0.72f, 0.72f, 1.0f);
|
::XCEngine::UI::UIColor(0.50f, 0.52f, 0.56f, 1.0f);
|
||||||
::XCEngine::UI::UIColor textPrimary =
|
::XCEngine::UI::UIColor textPrimary =
|
||||||
::XCEngine::UI::UIColor(0.94f, 0.94f, 0.94f, 1.0f);
|
::XCEngine::UI::UIColor(0.93f, 0.94f, 0.96f, 1.0f);
|
||||||
::XCEngine::UI::UIColor textSecondary =
|
::XCEngine::UI::UIColor textSecondary =
|
||||||
::XCEngine::UI::UIColor(0.76f, 0.76f, 0.76f, 1.0f);
|
::XCEngine::UI::UIColor(0.70f, 0.72f, 0.74f, 1.0f);
|
||||||
::XCEngine::UI::UIColor textMuted =
|
::XCEngine::UI::UIColor textMuted =
|
||||||
::XCEngine::UI::UIColor(0.60f, 0.60f, 0.60f, 1.0f);
|
::XCEngine::UI::UIColor(0.58f, 0.59f, 0.62f, 1.0f);
|
||||||
::XCEngine::UI::UIColor closeButtonColor =
|
::XCEngine::UI::UIColor closeButtonColor =
|
||||||
::XCEngine::UI::UIColor(0.25f, 0.25f, 0.25f, 1.0f);
|
::XCEngine::UI::UIColor(0.21f, 0.22f, 0.24f, 1.0f);
|
||||||
::XCEngine::UI::UIColor closeButtonHoveredColor =
|
::XCEngine::UI::UIColor closeButtonHoveredColor =
|
||||||
::XCEngine::UI::UIColor(0.36f, 0.36f, 0.36f, 1.0f);
|
::XCEngine::UI::UIColor(0.27f, 0.28f, 0.30f, 1.0f);
|
||||||
::XCEngine::UI::UIColor closeButtonBorderColor =
|
::XCEngine::UI::UIColor closeButtonBorderColor =
|
||||||
::XCEngine::UI::UIColor(0.44f, 0.44f, 0.44f, 1.0f);
|
::XCEngine::UI::UIColor(0.42f, 0.44f, 0.47f, 1.0f);
|
||||||
::XCEngine::UI::UIColor closeGlyphColor =
|
::XCEngine::UI::UIColor closeGlyphColor =
|
||||||
::XCEngine::UI::UIColor(0.92f, 0.92f, 0.92f, 1.0f);
|
::XCEngine::UI::UIColor(0.93f, 0.94f, 0.96f, 1.0f);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UIEditorTabStripLayout {
|
struct UIEditorTabStripLayout {
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEditor/Collections/UIEditorTabStrip.h>
|
||||||
|
|
||||||
|
#include <XCEngine/UI/DrawData.h>
|
||||||
|
#include <XCEngine/UI/Widgets/UITabStripModel.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor {
|
||||||
|
|
||||||
|
struct UIEditorTabStripInteractionState {
|
||||||
|
Widgets::UIEditorTabStripState tabStripState = {};
|
||||||
|
::XCEngine::UI::Widgets::UITabStripModel navigationModel = {};
|
||||||
|
Widgets::UIEditorTabStripHitTarget pressedTarget = {};
|
||||||
|
::XCEngine::UI::UIPoint pointerPosition = {};
|
||||||
|
bool hasPointerPosition = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorTabStripInteractionResult {
|
||||||
|
bool consumed = false;
|
||||||
|
bool selectionChanged = false;
|
||||||
|
bool closeRequested = false;
|
||||||
|
bool keyboardNavigated = false;
|
||||||
|
Widgets::UIEditorTabStripHitTarget hitTarget = {};
|
||||||
|
std::string selectedTabId = {};
|
||||||
|
std::size_t selectedIndex = Widgets::UIEditorTabStripInvalidIndex;
|
||||||
|
std::string closedTabId = {};
|
||||||
|
std::size_t closedIndex = Widgets::UIEditorTabStripInvalidIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorTabStripInteractionFrame {
|
||||||
|
Widgets::UIEditorTabStripLayout layout = {};
|
||||||
|
UIEditorTabStripInteractionResult result = {};
|
||||||
|
bool focused = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEditorTabStripInteractionFrame UpdateUIEditorTabStripInteraction(
|
||||||
|
UIEditorTabStripInteractionState& state,
|
||||||
|
std::string& selectedTabId,
|
||||||
|
const ::XCEngine::UI::UIRect& bounds,
|
||||||
|
const std::vector<Widgets::UIEditorTabStripItem>& items,
|
||||||
|
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
|
||||||
|
const Widgets::UIEditorTabStripMetrics& metrics = {});
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Widgets/UIEditorTreeView.h>
|
#include <XCEditor/Collections/UIEditorTreeView.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Types.h>
|
#include <XCEngine/UI/Types.h>
|
||||||
#include <XCEngine/UI/Widgets/UIExpansionModel.h>
|
#include <XCEngine/UI/Widgets/UIExpansionModel.h>
|
||||||
|
#include <XCEngine/UI/Widgets/UIKeyboardNavigationModel.h>
|
||||||
#include <XCEngine/UI/Widgets/UISelectionModel.h>
|
#include <XCEngine/UI/Widgets/UISelectionModel.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -13,6 +14,8 @@ namespace XCEngine::UI::Editor {
|
|||||||
|
|
||||||
struct UIEditorTreeViewInteractionState {
|
struct UIEditorTreeViewInteractionState {
|
||||||
Widgets::UIEditorTreeViewState treeViewState = {};
|
Widgets::UIEditorTreeViewState treeViewState = {};
|
||||||
|
::XCEngine::UI::Widgets::UIKeyboardNavigationModel keyboardNavigation = {};
|
||||||
|
std::string selectionAnchorId = {};
|
||||||
::XCEngine::UI::UIPoint pointerPosition = {};
|
::XCEngine::UI::UIPoint pointerPosition = {};
|
||||||
bool hasPointerPosition = false;
|
bool hasPointerPosition = false;
|
||||||
};
|
};
|
||||||
@@ -21,10 +24,14 @@ struct UIEditorTreeViewInteractionResult {
|
|||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
bool selectionChanged = false;
|
bool selectionChanged = false;
|
||||||
bool expansionChanged = false;
|
bool expansionChanged = false;
|
||||||
|
bool keyboardNavigated = false;
|
||||||
bool secondaryClicked = false;
|
bool secondaryClicked = false;
|
||||||
|
bool renameRequested = false;
|
||||||
Widgets::UIEditorTreeViewHitTarget hitTarget = {};
|
Widgets::UIEditorTreeViewHitTarget hitTarget = {};
|
||||||
std::string selectedItemId = {};
|
std::string selectedItemId = {};
|
||||||
|
std::string renameItemId = {};
|
||||||
std::string toggledItemId = {};
|
std::string toggledItemId = {};
|
||||||
|
std::size_t selectedVisibleIndex = Widgets::UIEditorTreeViewInvalidIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UIEditorTreeViewInteractionFrame {
|
struct UIEditorTreeViewInteractionFrame {
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <XCEditor/Widgets/UIEditorBoolField.h>
|
|
||||||
#include <XCEditor/Widgets/UIEditorEnumField.h>
|
|
||||||
#include <XCEditor/Widgets/UIEditorMenuPopup.h>
|
|
||||||
#include <XCEditor/Widgets/UIEditorNumberField.h>
|
|
||||||
#include <XCEditor/Widgets/UIEditorPropertyGrid.h>
|
|
||||||
#include <XCEditor/Widgets/UIEditorTextField.h>
|
|
||||||
#include <XCEditor/Widgets/UIEditorVector2Field.h>
|
|
||||||
#include <XCEditor/Widgets/UIEditorVector3Field.h>
|
|
||||||
#include <XCEditor/Widgets/UIEditorVector4Field.h>
|
|
||||||
|
|
||||||
#include <XCEngine/UI/Style/Theme.h>
|
|
||||||
|
|
||||||
#include <string_view>
|
|
||||||
|
|
||||||
namespace XCEngine::UI::Editor {
|
|
||||||
|
|
||||||
float ResolveUIEditorThemeFloat(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
std::string_view tokenName,
|
|
||||||
float fallbackValue);
|
|
||||||
|
|
||||||
::XCEngine::UI::UIColor ResolveUIEditorThemeColor(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
std::string_view tokenName,
|
|
||||||
const ::XCEngine::UI::UIColor& fallbackValue);
|
|
||||||
|
|
||||||
Widgets::UIEditorBoolFieldMetrics ResolveUIEditorBoolFieldMetrics(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorBoolFieldMetrics& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorBoolFieldPalette ResolveUIEditorBoolFieldPalette(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorBoolFieldPalette& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorNumberFieldMetrics ResolveUIEditorNumberFieldMetrics(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorNumberFieldMetrics& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorNumberFieldPalette ResolveUIEditorNumberFieldPalette(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorNumberFieldPalette& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorTextFieldMetrics ResolveUIEditorTextFieldMetrics(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorTextFieldMetrics& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorTextFieldPalette ResolveUIEditorTextFieldPalette(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorTextFieldPalette& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorVector2FieldMetrics ResolveUIEditorVector2FieldMetrics(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorVector2FieldMetrics& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorVector2FieldPalette ResolveUIEditorVector2FieldPalette(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorVector2FieldPalette& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorVector3FieldMetrics ResolveUIEditorVector3FieldMetrics(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorVector3FieldMetrics& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorVector3FieldPalette ResolveUIEditorVector3FieldPalette(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorVector3FieldPalette& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorVector4FieldMetrics ResolveUIEditorVector4FieldMetrics(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorVector4FieldMetrics& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorVector4FieldPalette ResolveUIEditorVector4FieldPalette(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorVector4FieldPalette& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorEnumFieldMetrics ResolveUIEditorEnumFieldMetrics(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorEnumFieldMetrics& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorEnumFieldPalette ResolveUIEditorEnumFieldPalette(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorEnumFieldPalette& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorMenuPopupMetrics ResolveUIEditorMenuPopupMetrics(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorMenuPopupMetrics& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorMenuPopupPalette ResolveUIEditorMenuPopupPalette(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorMenuPopupPalette& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorPropertyGridMetrics ResolveUIEditorPropertyGridMetrics(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorPropertyGridMetrics& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorPropertyGridPalette ResolveUIEditorPropertyGridPalette(
|
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
const Widgets::UIEditorPropertyGridPalette& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorBoolFieldMetrics BuildUIEditorHostedBoolFieldMetrics(
|
|
||||||
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
|
||||||
const Widgets::UIEditorBoolFieldMetrics& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorBoolFieldPalette BuildUIEditorHostedBoolFieldPalette(
|
|
||||||
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
|
||||||
const Widgets::UIEditorBoolFieldPalette& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorNumberFieldMetrics BuildUIEditorHostedNumberFieldMetrics(
|
|
||||||
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
|
||||||
const Widgets::UIEditorNumberFieldMetrics& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorNumberFieldPalette BuildUIEditorHostedNumberFieldPalette(
|
|
||||||
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
|
||||||
const Widgets::UIEditorNumberFieldPalette& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorTextFieldMetrics BuildUIEditorHostedTextFieldMetrics(
|
|
||||||
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
|
||||||
const Widgets::UIEditorTextFieldMetrics& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorTextFieldPalette BuildUIEditorHostedTextFieldPalette(
|
|
||||||
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
|
||||||
const Widgets::UIEditorTextFieldPalette& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorVector2FieldMetrics BuildUIEditorHostedVector2FieldMetrics(
|
|
||||||
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
|
||||||
const Widgets::UIEditorVector2FieldMetrics& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorVector2FieldPalette BuildUIEditorHostedVector2FieldPalette(
|
|
||||||
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
|
||||||
const Widgets::UIEditorVector2FieldPalette& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorVector3FieldMetrics BuildUIEditorHostedVector3FieldMetrics(
|
|
||||||
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
|
||||||
const Widgets::UIEditorVector3FieldMetrics& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorVector3FieldPalette BuildUIEditorHostedVector3FieldPalette(
|
|
||||||
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
|
||||||
const Widgets::UIEditorVector3FieldPalette& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorVector4FieldMetrics BuildUIEditorHostedVector4FieldMetrics(
|
|
||||||
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
|
||||||
const Widgets::UIEditorVector4FieldMetrics& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorVector4FieldPalette BuildUIEditorHostedVector4FieldPalette(
|
|
||||||
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
|
||||||
const Widgets::UIEditorVector4FieldPalette& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorEnumFieldMetrics BuildUIEditorHostedEnumFieldMetrics(
|
|
||||||
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
|
||||||
const Widgets::UIEditorEnumFieldMetrics& fallback = {});
|
|
||||||
|
|
||||||
Widgets::UIEditorEnumFieldPalette BuildUIEditorHostedEnumFieldPalette(
|
|
||||||
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
|
||||||
const Widgets::UIEditorEnumFieldPalette& fallback = {});
|
|
||||||
|
|
||||||
} // namespace XCEngine::UI::Editor
|
|
||||||
188
new_editor/include/XCEditor/Fields/UIEditorAssetField.h
Normal file
188
new_editor/include/XCEditor/Fields/UIEditorAssetField.h
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEngine/UI/DrawData.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor::Widgets {
|
||||||
|
|
||||||
|
enum class UIEditorAssetFieldHitTargetKind : std::uint8_t {
|
||||||
|
None = 0,
|
||||||
|
Row,
|
||||||
|
ValueBox,
|
||||||
|
PickerButton,
|
||||||
|
ClearButton
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorAssetFieldSpec {
|
||||||
|
std::string fieldId = {};
|
||||||
|
std::string label = {};
|
||||||
|
std::string assetId = {};
|
||||||
|
std::string displayName = {};
|
||||||
|
std::string statusText = {};
|
||||||
|
std::string emptyText = "None";
|
||||||
|
::XCEngine::UI::UIColor tint = ::XCEngine::UI::UIColor(0.28f, 0.50f, 0.83f, 1.0f);
|
||||||
|
bool readOnly = false;
|
||||||
|
bool showPickerButton = true;
|
||||||
|
bool allowClear = true;
|
||||||
|
bool showStatusBadge = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorAssetFieldState {
|
||||||
|
UIEditorAssetFieldHitTargetKind hoveredTarget = UIEditorAssetFieldHitTargetKind::None;
|
||||||
|
UIEditorAssetFieldHitTargetKind activeTarget = UIEditorAssetFieldHitTargetKind::None;
|
||||||
|
bool focused = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorAssetFieldMetrics {
|
||||||
|
float rowHeight = 22.0f;
|
||||||
|
float horizontalPadding = 12.0f;
|
||||||
|
float labelControlGap = 20.0f;
|
||||||
|
float controlColumnStart = 236.0f;
|
||||||
|
float controlTrailingInset = 8.0f;
|
||||||
|
float valueBoxMinWidth = 116.0f;
|
||||||
|
float controlInsetY = 1.0f;
|
||||||
|
float labelTextInsetY = 0.0f;
|
||||||
|
float labelFontSize = 11.0f;
|
||||||
|
float valueTextInsetX = 6.0f;
|
||||||
|
float valueTextInsetY = 0.0f;
|
||||||
|
float valueFontSize = 12.0f;
|
||||||
|
float previewSize = 16.0f;
|
||||||
|
float previewInsetX = 4.0f;
|
||||||
|
float previewGap = 6.0f;
|
||||||
|
float previewGlyphFontSize = 10.0f;
|
||||||
|
float statusBadgeGap = 6.0f;
|
||||||
|
float statusBadgeMinWidth = 44.0f;
|
||||||
|
float statusBadgePaddingX = 6.0f;
|
||||||
|
float statusBadgeHeight = 14.0f;
|
||||||
|
float statusBadgeFontSize = 10.0f;
|
||||||
|
float actionButtonGap = 2.0f;
|
||||||
|
float actionButtonWidth = 20.0f;
|
||||||
|
float actionGlyphFontSize = 10.0f;
|
||||||
|
float actionGlyphInsetY = -1.0f;
|
||||||
|
float cornerRounding = 0.0f;
|
||||||
|
float valueBoxRounding = 2.0f;
|
||||||
|
float previewRounding = 2.0f;
|
||||||
|
float badgeRounding = 2.0f;
|
||||||
|
float borderThickness = 1.0f;
|
||||||
|
float focusedBorderThickness = 1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorAssetFieldPalette {
|
||||||
|
::XCEngine::UI::UIColor surfaceColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
::XCEngine::UI::UIColor borderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
::XCEngine::UI::UIColor focusedBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
::XCEngine::UI::UIColor rowHoverColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
::XCEngine::UI::UIColor rowActiveColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
::XCEngine::UI::UIColor valueBoxColor =
|
||||||
|
::XCEngine::UI::UIColor(0.18f, 0.18f, 0.18f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor valueBoxHoverColor =
|
||||||
|
::XCEngine::UI::UIColor(0.22f, 0.22f, 0.22f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor valueBoxActiveColor =
|
||||||
|
::XCEngine::UI::UIColor(0.24f, 0.24f, 0.24f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor readOnlyColor =
|
||||||
|
::XCEngine::UI::UIColor(0.16f, 0.16f, 0.16f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor controlBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.12f, 0.12f, 0.12f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor controlFocusedBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.42f, 0.42f, 0.42f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor labelColor =
|
||||||
|
::XCEngine::UI::UIColor(0.80f, 0.80f, 0.80f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor valueColor =
|
||||||
|
::XCEngine::UI::UIColor(0.92f, 0.92f, 0.92f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor emptyValueColor =
|
||||||
|
::XCEngine::UI::UIColor(0.60f, 0.60f, 0.60f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor previewBaseColor =
|
||||||
|
::XCEngine::UI::UIColor(0.23f, 0.25f, 0.28f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor previewEmptyColor =
|
||||||
|
::XCEngine::UI::UIColor(0.26f, 0.26f, 0.26f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor previewBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.08f, 0.08f, 0.08f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor previewGlyphColor =
|
||||||
|
::XCEngine::UI::UIColor(0.94f, 0.94f, 0.94f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor statusBadgeColor =
|
||||||
|
::XCEngine::UI::UIColor(0.25f, 0.29f, 0.34f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor statusBadgeBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor statusBadgeTextColor =
|
||||||
|
::XCEngine::UI::UIColor(0.82f, 0.87f, 0.96f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor actionButtonHoverColor =
|
||||||
|
::XCEngine::UI::UIColor(0.28f, 0.28f, 0.28f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor actionButtonActiveColor =
|
||||||
|
::XCEngine::UI::UIColor(0.32f, 0.32f, 0.32f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor actionButtonColor =
|
||||||
|
::XCEngine::UI::UIColor(0.16f, 0.16f, 0.16f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor separatorColor =
|
||||||
|
::XCEngine::UI::UIColor(0.24f, 0.24f, 0.24f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor pickerGlyphColor =
|
||||||
|
::XCEngine::UI::UIColor(0.88f, 0.88f, 0.88f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor clearGlyphColor =
|
||||||
|
::XCEngine::UI::UIColor(0.95f, 0.68f, 0.68f, 1.0f);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorAssetFieldLayout {
|
||||||
|
::XCEngine::UI::UIRect bounds = {};
|
||||||
|
::XCEngine::UI::UIRect labelRect = {};
|
||||||
|
::XCEngine::UI::UIRect controlRect = {};
|
||||||
|
::XCEngine::UI::UIRect valueRect = {};
|
||||||
|
::XCEngine::UI::UIRect previewRect = {};
|
||||||
|
::XCEngine::UI::UIRect textRect = {};
|
||||||
|
::XCEngine::UI::UIRect statusBadgeRect = {};
|
||||||
|
::XCEngine::UI::UIRect pickerRect = {};
|
||||||
|
::XCEngine::UI::UIRect clearRect = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorAssetFieldHitTarget {
|
||||||
|
UIEditorAssetFieldHitTargetKind kind = UIEditorAssetFieldHitTargetKind::None;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool HasUIEditorAssetFieldValue(const UIEditorAssetFieldSpec& spec);
|
||||||
|
|
||||||
|
std::string ResolveUIEditorAssetFieldValueText(const UIEditorAssetFieldSpec& spec);
|
||||||
|
|
||||||
|
std::string ResolveUIEditorAssetFieldPreviewGlyph(const UIEditorAssetFieldSpec& spec);
|
||||||
|
|
||||||
|
bool IsUIEditorAssetFieldPointInside(
|
||||||
|
const ::XCEngine::UI::UIRect& rect,
|
||||||
|
const ::XCEngine::UI::UIPoint& point);
|
||||||
|
|
||||||
|
UIEditorAssetFieldLayout BuildUIEditorAssetFieldLayout(
|
||||||
|
const ::XCEngine::UI::UIRect& bounds,
|
||||||
|
const UIEditorAssetFieldSpec& spec,
|
||||||
|
const UIEditorAssetFieldMetrics& metrics = {});
|
||||||
|
|
||||||
|
UIEditorAssetFieldHitTarget HitTestUIEditorAssetField(
|
||||||
|
const UIEditorAssetFieldLayout& layout,
|
||||||
|
const ::XCEngine::UI::UIPoint& point);
|
||||||
|
|
||||||
|
void AppendUIEditorAssetFieldBackground(
|
||||||
|
::XCEngine::UI::UIDrawList& drawList,
|
||||||
|
const UIEditorAssetFieldLayout& layout,
|
||||||
|
const UIEditorAssetFieldSpec& spec,
|
||||||
|
const UIEditorAssetFieldState& state,
|
||||||
|
const UIEditorAssetFieldPalette& palette = {},
|
||||||
|
const UIEditorAssetFieldMetrics& metrics = {});
|
||||||
|
|
||||||
|
void AppendUIEditorAssetFieldForeground(
|
||||||
|
::XCEngine::UI::UIDrawList& drawList,
|
||||||
|
const UIEditorAssetFieldLayout& layout,
|
||||||
|
const UIEditorAssetFieldSpec& spec,
|
||||||
|
const UIEditorAssetFieldState& state,
|
||||||
|
const UIEditorAssetFieldPalette& palette = {},
|
||||||
|
const UIEditorAssetFieldMetrics& metrics = {});
|
||||||
|
|
||||||
|
void AppendUIEditorAssetField(
|
||||||
|
::XCEngine::UI::UIDrawList& drawList,
|
||||||
|
const ::XCEngine::UI::UIRect& bounds,
|
||||||
|
const UIEditorAssetFieldSpec& spec,
|
||||||
|
const UIEditorAssetFieldState& state,
|
||||||
|
const UIEditorAssetFieldPalette& palette = {},
|
||||||
|
const UIEditorAssetFieldMetrics& metrics = {});
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor::Widgets
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEditor/Fields/UIEditorAssetField.h>
|
||||||
|
|
||||||
|
#include <XCEngine/UI/Types.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor {
|
||||||
|
|
||||||
|
struct UIEditorAssetFieldInteractionState {
|
||||||
|
Widgets::UIEditorAssetFieldState fieldState = {};
|
||||||
|
::XCEngine::UI::UIPoint pointerPosition = {};
|
||||||
|
bool hasPointerPosition = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorAssetFieldInteractionResult {
|
||||||
|
bool consumed = false;
|
||||||
|
bool focusChanged = false;
|
||||||
|
bool valueChanged = false;
|
||||||
|
bool activateRequested = false;
|
||||||
|
bool pickerRequested = false;
|
||||||
|
bool clearRequested = false;
|
||||||
|
Widgets::UIEditorAssetFieldHitTarget hitTarget = {};
|
||||||
|
std::string assetIdBefore = {};
|
||||||
|
std::string assetIdAfter = {};
|
||||||
|
std::string displayNameBefore = {};
|
||||||
|
std::string displayNameAfter = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorAssetFieldInteractionFrame {
|
||||||
|
Widgets::UIEditorAssetFieldLayout layout = {};
|
||||||
|
UIEditorAssetFieldInteractionResult result = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEditorAssetFieldInteractionFrame UpdateUIEditorAssetFieldInteraction(
|
||||||
|
UIEditorAssetFieldInteractionState& state,
|
||||||
|
Widgets::UIEditorAssetFieldSpec& spec,
|
||||||
|
const ::XCEngine::UI::UIRect& bounds,
|
||||||
|
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
|
||||||
|
const Widgets::UIEditorAssetFieldMetrics& metrics = {});
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Widgets/UIEditorBoolField.h>
|
#include <XCEditor/Fields/UIEditorBoolField.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Types.h>
|
#include <XCEngine/UI/Types.h>
|
||||||
|
|
||||||
220
new_editor/include/XCEditor/Fields/UIEditorColorField.h
Normal file
220
new_editor/include/XCEditor/Fields/UIEditorColorField.h
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEngine/UI/DrawData.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor::Widgets {
|
||||||
|
|
||||||
|
enum class UIEditorColorFieldHitTargetKind : std::uint8_t {
|
||||||
|
None = 0,
|
||||||
|
Row,
|
||||||
|
Swatch,
|
||||||
|
PopupSurface,
|
||||||
|
PopupCloseButton,
|
||||||
|
HueWheel,
|
||||||
|
SaturationValue,
|
||||||
|
RedChannel,
|
||||||
|
GreenChannel,
|
||||||
|
BlueChannel,
|
||||||
|
AlphaChannel
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorColorFieldSpec {
|
||||||
|
std::string fieldId = {};
|
||||||
|
std::string label = {};
|
||||||
|
::XCEngine::UI::UIColor value = {};
|
||||||
|
bool showAlpha = true;
|
||||||
|
bool readOnly = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorColorFieldState {
|
||||||
|
UIEditorColorFieldHitTargetKind hoveredTarget = UIEditorColorFieldHitTargetKind::None;
|
||||||
|
UIEditorColorFieldHitTargetKind activeTarget = UIEditorColorFieldHitTargetKind::None;
|
||||||
|
bool focused = false;
|
||||||
|
bool popupOpen = false;
|
||||||
|
float hue = 0.0f;
|
||||||
|
bool hueValid = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorColorFieldMetrics {
|
||||||
|
float rowHeight = 22.0f;
|
||||||
|
float horizontalPadding = 12.0f;
|
||||||
|
float labelControlGap = 20.0f;
|
||||||
|
float controlColumnStart = 236.0f;
|
||||||
|
float controlTrailingInset = 8.0f;
|
||||||
|
float swatchWidth = 54.0f;
|
||||||
|
float swatchInsetY = 1.0f;
|
||||||
|
float labelTextInsetY = 0.0f;
|
||||||
|
float labelFontSize = 11.0f;
|
||||||
|
float popupWidth = 292.0f;
|
||||||
|
float popupPadding = 10.0f;
|
||||||
|
float popupGapY = 6.0f;
|
||||||
|
float popupHeaderHeight = 30.0f;
|
||||||
|
float popupTopRowHeight = 34.0f;
|
||||||
|
float popupPreviewWidth = 96.0f;
|
||||||
|
float popupPreviewHeight = 28.0f;
|
||||||
|
float popupCloseButtonSize = 18.0f;
|
||||||
|
float borderThickness = 1.0f;
|
||||||
|
float focusedBorderThickness = 1.0f;
|
||||||
|
float swatchRounding = 2.0f;
|
||||||
|
float popupBorderRounding = 3.0f;
|
||||||
|
float wheelOuterRadius = 110.0f;
|
||||||
|
float wheelRingThickness = 24.0f;
|
||||||
|
float saturationValueSize = 114.0f;
|
||||||
|
float wheelRegionHeight = 220.0f;
|
||||||
|
float channelRowHeight = 20.0f;
|
||||||
|
float numericBoxWidth = 62.0f;
|
||||||
|
float channelLabelWidth = 12.0f;
|
||||||
|
float hexLabelWidth = 84.0f;
|
||||||
|
float controlRowSpacing = 8.0f;
|
||||||
|
float popupFieldInset = 6.0f;
|
||||||
|
float titleFontSize = 12.0f;
|
||||||
|
float valueFontSize = 11.0f;
|
||||||
|
float valueTextInsetX = 6.0f;
|
||||||
|
float valueTextInsetY = 0.0f;
|
||||||
|
float checkerSize = 6.0f;
|
||||||
|
float handleRadius = 8.0f;
|
||||||
|
float ringHandleRadius = 12.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorColorFieldPalette {
|
||||||
|
::XCEngine::UI::UIColor surfaceColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
::XCEngine::UI::UIColor borderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
::XCEngine::UI::UIColor focusedBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
::XCEngine::UI::UIColor rowHoverColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
::XCEngine::UI::UIColor rowActiveColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
::XCEngine::UI::UIColor swatchBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor swatchHoverBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.34f, 0.34f, 0.34f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor swatchReadOnlyOverlayColor =
|
||||||
|
::XCEngine::UI::UIColor(0.08f, 0.08f, 0.08f, 0.18f);
|
||||||
|
::XCEngine::UI::UIColor popupColor =
|
||||||
|
::XCEngine::UI::UIColor(0.24f, 0.24f, 0.24f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor popupBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.15f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor popupHeaderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.43f, 0.24f, 0.05f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor popupTitleColor =
|
||||||
|
::XCEngine::UI::UIColor(0.95f, 0.95f, 0.95f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor closeButtonColor =
|
||||||
|
::XCEngine::UI::UIColor(0.76f, 0.35f, 0.34f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor closeButtonHoverColor =
|
||||||
|
::XCEngine::UI::UIColor(0.82f, 0.40f, 0.39f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor closeGlyphColor =
|
||||||
|
::XCEngine::UI::UIColor(0.95f, 0.95f, 0.95f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor labelColor =
|
||||||
|
::XCEngine::UI::UIColor(0.88f, 0.88f, 0.88f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor popupTextColor =
|
||||||
|
::XCEngine::UI::UIColor(0.86f, 0.86f, 0.86f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor popupTextMutedColor =
|
||||||
|
::XCEngine::UI::UIColor(0.72f, 0.72f, 0.72f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor previewBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.12f, 0.12f, 0.12f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor previewBaseColor =
|
||||||
|
::XCEngine::UI::UIColor(0.19f, 0.19f, 0.19f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor checkerLightColor =
|
||||||
|
::XCEngine::UI::UIColor(0.84f, 0.84f, 0.84f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor checkerDarkColor =
|
||||||
|
::XCEngine::UI::UIColor(0.55f, 0.55f, 0.55f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor sliderBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.12f, 0.12f, 0.12f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor numericBoxColor =
|
||||||
|
::XCEngine::UI::UIColor(0.19f, 0.19f, 0.19f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor numericBoxBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.12f, 0.12f, 0.12f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor numericBoxTextColor =
|
||||||
|
::XCEngine::UI::UIColor(0.90f, 0.90f, 0.90f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor handleFillColor =
|
||||||
|
::XCEngine::UI::UIColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor handleStrokeColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.4f);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorColorFieldLayout {
|
||||||
|
::XCEngine::UI::UIRect bounds = {};
|
||||||
|
::XCEngine::UI::UIRect labelRect = {};
|
||||||
|
::XCEngine::UI::UIRect controlRect = {};
|
||||||
|
::XCEngine::UI::UIRect swatchRect = {};
|
||||||
|
::XCEngine::UI::UIRect popupRect = {};
|
||||||
|
::XCEngine::UI::UIRect popupHeaderRect = {};
|
||||||
|
::XCEngine::UI::UIRect popupTitleRect = {};
|
||||||
|
::XCEngine::UI::UIRect popupCloseButtonRect = {};
|
||||||
|
::XCEngine::UI::UIRect popupBodyRect = {};
|
||||||
|
::XCEngine::UI::UIRect popupTopRowRect = {};
|
||||||
|
::XCEngine::UI::UIRect popupPreviewRect = {};
|
||||||
|
::XCEngine::UI::UIRect popupWheelRect = {};
|
||||||
|
::XCEngine::UI::UIPoint hueWheelCenter = {};
|
||||||
|
float hueWheelOuterRadius = 0.0f;
|
||||||
|
float hueWheelInnerRadius = 0.0f;
|
||||||
|
::XCEngine::UI::UIRect saturationValueRect = {};
|
||||||
|
::XCEngine::UI::UIRect redLabelRect = {};
|
||||||
|
::XCEngine::UI::UIRect redSliderRect = {};
|
||||||
|
::XCEngine::UI::UIRect redValueRect = {};
|
||||||
|
::XCEngine::UI::UIRect greenLabelRect = {};
|
||||||
|
::XCEngine::UI::UIRect greenSliderRect = {};
|
||||||
|
::XCEngine::UI::UIRect greenValueRect = {};
|
||||||
|
::XCEngine::UI::UIRect blueLabelRect = {};
|
||||||
|
::XCEngine::UI::UIRect blueSliderRect = {};
|
||||||
|
::XCEngine::UI::UIRect blueValueRect = {};
|
||||||
|
::XCEngine::UI::UIRect alphaLabelRect = {};
|
||||||
|
::XCEngine::UI::UIRect alphaSliderRect = {};
|
||||||
|
::XCEngine::UI::UIRect alphaValueRect = {};
|
||||||
|
::XCEngine::UI::UIRect hexLabelRect = {};
|
||||||
|
::XCEngine::UI::UIRect hexValueRect = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorColorFieldHitTarget {
|
||||||
|
UIEditorColorFieldHitTargetKind kind = UIEditorColorFieldHitTargetKind::None;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string FormatUIEditorColorFieldRgbaText(
|
||||||
|
const UIEditorColorFieldSpec& spec);
|
||||||
|
|
||||||
|
std::string FormatUIEditorColorFieldHexText(
|
||||||
|
const UIEditorColorFieldSpec& spec);
|
||||||
|
|
||||||
|
UIEditorColorFieldLayout BuildUIEditorColorFieldLayout(
|
||||||
|
const ::XCEngine::UI::UIRect& bounds,
|
||||||
|
const UIEditorColorFieldSpec& spec,
|
||||||
|
const UIEditorColorFieldMetrics& metrics = {},
|
||||||
|
const ::XCEngine::UI::UIRect& viewportRect = {});
|
||||||
|
|
||||||
|
UIEditorColorFieldHitTarget HitTestUIEditorColorField(
|
||||||
|
const UIEditorColorFieldLayout& layout,
|
||||||
|
bool popupOpen,
|
||||||
|
const ::XCEngine::UI::UIPoint& point);
|
||||||
|
|
||||||
|
void AppendUIEditorColorFieldBackground(
|
||||||
|
::XCEngine::UI::UIDrawList& drawList,
|
||||||
|
const UIEditorColorFieldLayout& layout,
|
||||||
|
const UIEditorColorFieldSpec& spec,
|
||||||
|
const UIEditorColorFieldState& state,
|
||||||
|
const UIEditorColorFieldPalette& palette = {},
|
||||||
|
const UIEditorColorFieldMetrics& metrics = {});
|
||||||
|
|
||||||
|
void AppendUIEditorColorFieldForeground(
|
||||||
|
::XCEngine::UI::UIDrawList& drawList,
|
||||||
|
const UIEditorColorFieldLayout& layout,
|
||||||
|
const UIEditorColorFieldSpec& spec,
|
||||||
|
const UIEditorColorFieldState& state,
|
||||||
|
const UIEditorColorFieldPalette& palette = {},
|
||||||
|
const UIEditorColorFieldMetrics& metrics = {});
|
||||||
|
|
||||||
|
void AppendUIEditorColorField(
|
||||||
|
::XCEngine::UI::UIDrawList& drawList,
|
||||||
|
const ::XCEngine::UI::UIRect& bounds,
|
||||||
|
const UIEditorColorFieldSpec& spec,
|
||||||
|
const UIEditorColorFieldState& state,
|
||||||
|
const UIEditorColorFieldPalette& palette = {},
|
||||||
|
const UIEditorColorFieldMetrics& metrics = {},
|
||||||
|
const ::XCEngine::UI::UIRect& viewportRect = {});
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor::Widgets
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEditor/Fields/UIEditorColorField.h>
|
||||||
|
|
||||||
|
#include <XCEngine/UI/Types.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor {
|
||||||
|
|
||||||
|
struct UIEditorColorFieldInteractionState {
|
||||||
|
Widgets::UIEditorColorFieldState colorFieldState = {};
|
||||||
|
::XCEngine::UI::UIPoint pointerPosition = {};
|
||||||
|
bool hasPointerPosition = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorColorFieldInteractionResult {
|
||||||
|
bool consumed = false;
|
||||||
|
bool focusChanged = false;
|
||||||
|
bool popupOpened = false;
|
||||||
|
bool popupClosed = false;
|
||||||
|
bool colorChanged = false;
|
||||||
|
Widgets::UIEditorColorFieldHitTarget hitTarget = {};
|
||||||
|
::XCEngine::UI::UIColor valueBefore = {};
|
||||||
|
::XCEngine::UI::UIColor valueAfter = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorColorFieldInteractionFrame {
|
||||||
|
Widgets::UIEditorColorFieldLayout layout = {};
|
||||||
|
UIEditorColorFieldInteractionResult result = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEditorColorFieldInteractionFrame UpdateUIEditorColorFieldInteraction(
|
||||||
|
UIEditorColorFieldInteractionState& state,
|
||||||
|
Widgets::UIEditorColorFieldSpec& spec,
|
||||||
|
const ::XCEngine::UI::UIRect& bounds,
|
||||||
|
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
|
||||||
|
const Widgets::UIEditorColorFieldMetrics& metrics = {},
|
||||||
|
const ::XCEngine::UI::UIRect& viewportRect = {});
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Widgets/UIEditorMenuPopup.h>
|
#include <XCEditor/Shell/UIEditorMenuPopup.h>
|
||||||
#include <XCEditor/Widgets/UIEditorEnumField.h>
|
#include <XCEditor/Fields/UIEditorEnumField.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Types.h>
|
#include <XCEngine/UI/Types.h>
|
||||||
|
|
||||||
101
new_editor/include/XCEditor/Fields/UIEditorFieldStyle.h
Normal file
101
new_editor/include/XCEditor/Fields/UIEditorFieldStyle.h
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEditor/Fields/UIEditorAssetField.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorBoolField.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorColorField.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorEnumField.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorNumberField.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorObjectField.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorPropertyGrid.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorTextField.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorVector2Field.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorVector3Field.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorVector4Field.h>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor {
|
||||||
|
|
||||||
|
const Widgets::UIEditorPropertyGridMetrics& GetUIEditorFixedPropertyGridMetrics();
|
||||||
|
|
||||||
|
const Widgets::UIEditorPropertyGridPalette& GetUIEditorFixedPropertyGridPalette();
|
||||||
|
|
||||||
|
Widgets::UIEditorBoolFieldMetrics BuildUIEditorPropertyGridBoolFieldMetrics(
|
||||||
|
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
||||||
|
const Widgets::UIEditorBoolFieldMetrics& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorBoolFieldPalette BuildUIEditorPropertyGridBoolFieldPalette(
|
||||||
|
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
||||||
|
const Widgets::UIEditorBoolFieldPalette& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorNumberFieldMetrics BuildUIEditorPropertyGridNumberFieldMetrics(
|
||||||
|
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
||||||
|
const Widgets::UIEditorNumberFieldMetrics& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorNumberFieldPalette BuildUIEditorPropertyGridNumberFieldPalette(
|
||||||
|
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
||||||
|
const Widgets::UIEditorNumberFieldPalette& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorTextFieldMetrics BuildUIEditorPropertyGridTextFieldMetrics(
|
||||||
|
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
||||||
|
const Widgets::UIEditorTextFieldMetrics& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorTextFieldPalette BuildUIEditorPropertyGridTextFieldPalette(
|
||||||
|
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
||||||
|
const Widgets::UIEditorTextFieldPalette& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorVector2FieldMetrics BuildUIEditorPropertyGridVector2FieldMetrics(
|
||||||
|
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
||||||
|
const Widgets::UIEditorVector2FieldMetrics& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorVector2FieldPalette BuildUIEditorPropertyGridVector2FieldPalette(
|
||||||
|
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
||||||
|
const Widgets::UIEditorVector2FieldPalette& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorVector3FieldMetrics BuildUIEditorPropertyGridVector3FieldMetrics(
|
||||||
|
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
||||||
|
const Widgets::UIEditorVector3FieldMetrics& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorVector3FieldPalette BuildUIEditorPropertyGridVector3FieldPalette(
|
||||||
|
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
||||||
|
const Widgets::UIEditorVector3FieldPalette& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorVector4FieldMetrics BuildUIEditorPropertyGridVector4FieldMetrics(
|
||||||
|
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
||||||
|
const Widgets::UIEditorVector4FieldMetrics& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorVector4FieldPalette BuildUIEditorPropertyGridVector4FieldPalette(
|
||||||
|
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
||||||
|
const Widgets::UIEditorVector4FieldPalette& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorEnumFieldMetrics BuildUIEditorPropertyGridEnumFieldMetrics(
|
||||||
|
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
||||||
|
const Widgets::UIEditorEnumFieldMetrics& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorEnumFieldPalette BuildUIEditorPropertyGridEnumFieldPalette(
|
||||||
|
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
||||||
|
const Widgets::UIEditorEnumFieldPalette& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorColorFieldMetrics BuildUIEditorPropertyGridColorFieldMetrics(
|
||||||
|
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
||||||
|
const Widgets::UIEditorColorFieldMetrics& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorColorFieldPalette BuildUIEditorPropertyGridColorFieldPalette(
|
||||||
|
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
||||||
|
const Widgets::UIEditorColorFieldPalette& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorObjectFieldMetrics BuildUIEditorPropertyGridObjectFieldMetrics(
|
||||||
|
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
||||||
|
const Widgets::UIEditorObjectFieldMetrics& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorObjectFieldPalette BuildUIEditorPropertyGridObjectFieldPalette(
|
||||||
|
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
||||||
|
const Widgets::UIEditorObjectFieldPalette& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorAssetFieldMetrics BuildUIEditorPropertyGridAssetFieldMetrics(
|
||||||
|
const Widgets::UIEditorPropertyGridMetrics& propertyGridMetrics,
|
||||||
|
const Widgets::UIEditorAssetFieldMetrics& fallback = {});
|
||||||
|
|
||||||
|
Widgets::UIEditorAssetFieldPalette BuildUIEditorPropertyGridAssetFieldPalette(
|
||||||
|
const Widgets::UIEditorPropertyGridPalette& propertyGridPalette,
|
||||||
|
const Widgets::UIEditorAssetFieldPalette& fallback = {});
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Widgets/UIEditorNumberField.h>
|
#include <XCEditor/Fields/UIEditorNumberField.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Text/UITextInputController.h>
|
#include <XCEngine/UI/Text/UITextInputController.h>
|
||||||
#include <XCEngine/UI/Types.h>
|
#include <XCEngine/UI/Types.h>
|
||||||
153
new_editor/include/XCEditor/Fields/UIEditorObjectField.h
Normal file
153
new_editor/include/XCEditor/Fields/UIEditorObjectField.h
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEngine/UI/DrawData.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor::Widgets {
|
||||||
|
|
||||||
|
enum class UIEditorObjectFieldHitTargetKind : std::uint8_t {
|
||||||
|
None = 0,
|
||||||
|
Row,
|
||||||
|
ValueBox,
|
||||||
|
ClearButton,
|
||||||
|
PickerButton
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorObjectFieldSpec {
|
||||||
|
std::string fieldId = {};
|
||||||
|
std::string label = {};
|
||||||
|
std::string objectName = {};
|
||||||
|
std::string objectTypeName = {};
|
||||||
|
std::string emptyText = "(none)";
|
||||||
|
bool hasValue = false;
|
||||||
|
bool readOnly = false;
|
||||||
|
bool showClearButton = true;
|
||||||
|
bool showPickerButton = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorObjectFieldState {
|
||||||
|
UIEditorObjectFieldHitTargetKind hoveredTarget = UIEditorObjectFieldHitTargetKind::None;
|
||||||
|
UIEditorObjectFieldHitTargetKind activeTarget = UIEditorObjectFieldHitTargetKind::None;
|
||||||
|
bool focused = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorObjectFieldMetrics {
|
||||||
|
float rowHeight = 22.0f;
|
||||||
|
float horizontalPadding = 12.0f;
|
||||||
|
float labelControlGap = 20.0f;
|
||||||
|
float controlColumnStart = 236.0f;
|
||||||
|
float controlTrailingInset = 8.0f;
|
||||||
|
float valueBoxMinWidth = 96.0f;
|
||||||
|
float controlInsetY = 1.0f;
|
||||||
|
float labelTextInsetY = 0.0f;
|
||||||
|
float labelFontSize = 11.0f;
|
||||||
|
float valueTextInsetX = 5.0f;
|
||||||
|
float valueTextInsetY = 0.0f;
|
||||||
|
float valueFontSize = 12.0f;
|
||||||
|
float typeTextInsetX = 5.0f;
|
||||||
|
float typeTextInsetY = 0.0f;
|
||||||
|
float typeFontSize = 10.0f;
|
||||||
|
float typeMaxWidth = 96.0f;
|
||||||
|
float typeMinWidth = 44.0f;
|
||||||
|
float valueTypeGap = 6.0f;
|
||||||
|
float buttonWidth = 20.0f;
|
||||||
|
float buttonGlyphInsetY = -1.0f;
|
||||||
|
float buttonGlyphFontSize = 10.0f;
|
||||||
|
float cornerRounding = 0.0f;
|
||||||
|
float valueBoxRounding = 2.0f;
|
||||||
|
float borderThickness = 1.0f;
|
||||||
|
float focusedBorderThickness = 1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorObjectFieldPalette {
|
||||||
|
::XCEngine::UI::UIColor surfaceColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
::XCEngine::UI::UIColor borderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
::XCEngine::UI::UIColor focusedBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
::XCEngine::UI::UIColor rowHoverColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
::XCEngine::UI::UIColor rowActiveColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
::XCEngine::UI::UIColor valueBoxColor =
|
||||||
|
::XCEngine::UI::UIColor(0.18f, 0.18f, 0.18f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor valueBoxHoverColor =
|
||||||
|
::XCEngine::UI::UIColor(0.21f, 0.21f, 0.21f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor readOnlyColor =
|
||||||
|
::XCEngine::UI::UIColor(0.17f, 0.17f, 0.17f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor controlBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor controlFocusedBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.46f, 0.46f, 0.46f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor buttonColor =
|
||||||
|
::XCEngine::UI::UIColor(0.16f, 0.16f, 0.16f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor buttonHoverColor =
|
||||||
|
::XCEngine::UI::UIColor(0.22f, 0.22f, 0.22f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor buttonActiveColor =
|
||||||
|
::XCEngine::UI::UIColor(0.26f, 0.26f, 0.26f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor buttonGlyphColor =
|
||||||
|
::XCEngine::UI::UIColor(0.86f, 0.86f, 0.86f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor separatorColor =
|
||||||
|
::XCEngine::UI::UIColor(0.24f, 0.24f, 0.24f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor labelColor =
|
||||||
|
::XCEngine::UI::UIColor(0.80f, 0.80f, 0.80f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor valueColor =
|
||||||
|
::XCEngine::UI::UIColor(0.92f, 0.92f, 0.92f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor emptyValueColor =
|
||||||
|
::XCEngine::UI::UIColor(0.62f, 0.62f, 0.62f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor typeColor =
|
||||||
|
::XCEngine::UI::UIColor(0.68f, 0.68f, 0.68f, 1.0f);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorObjectFieldLayout {
|
||||||
|
::XCEngine::UI::UIRect bounds = {};
|
||||||
|
::XCEngine::UI::UIRect labelRect = {};
|
||||||
|
::XCEngine::UI::UIRect controlRect = {};
|
||||||
|
::XCEngine::UI::UIRect valueRect = {};
|
||||||
|
::XCEngine::UI::UIRect typeRect = {};
|
||||||
|
::XCEngine::UI::UIRect clearButtonRect = {};
|
||||||
|
::XCEngine::UI::UIRect pickerButtonRect = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorObjectFieldHitTarget {
|
||||||
|
UIEditorObjectFieldHitTargetKind kind = UIEditorObjectFieldHitTargetKind::None;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string ResolveUIEditorObjectFieldDisplayText(const UIEditorObjectFieldSpec& spec);
|
||||||
|
|
||||||
|
UIEditorObjectFieldLayout BuildUIEditorObjectFieldLayout(
|
||||||
|
const ::XCEngine::UI::UIRect& bounds,
|
||||||
|
const UIEditorObjectFieldSpec& spec,
|
||||||
|
const UIEditorObjectFieldMetrics& metrics = {});
|
||||||
|
|
||||||
|
UIEditorObjectFieldHitTarget HitTestUIEditorObjectField(
|
||||||
|
const UIEditorObjectFieldLayout& layout,
|
||||||
|
const ::XCEngine::UI::UIPoint& point);
|
||||||
|
|
||||||
|
void AppendUIEditorObjectFieldBackground(
|
||||||
|
::XCEngine::UI::UIDrawList& drawList,
|
||||||
|
const UIEditorObjectFieldLayout& layout,
|
||||||
|
const UIEditorObjectFieldSpec& spec,
|
||||||
|
const UIEditorObjectFieldState& state,
|
||||||
|
const UIEditorObjectFieldPalette& palette = {},
|
||||||
|
const UIEditorObjectFieldMetrics& metrics = {});
|
||||||
|
|
||||||
|
void AppendUIEditorObjectFieldForeground(
|
||||||
|
::XCEngine::UI::UIDrawList& drawList,
|
||||||
|
const UIEditorObjectFieldLayout& layout,
|
||||||
|
const UIEditorObjectFieldSpec& spec,
|
||||||
|
const UIEditorObjectFieldPalette& palette = {},
|
||||||
|
const UIEditorObjectFieldMetrics& metrics = {});
|
||||||
|
|
||||||
|
void AppendUIEditorObjectField(
|
||||||
|
::XCEngine::UI::UIDrawList& drawList,
|
||||||
|
const ::XCEngine::UI::UIRect& bounds,
|
||||||
|
const UIEditorObjectFieldSpec& spec,
|
||||||
|
const UIEditorObjectFieldState& state,
|
||||||
|
const UIEditorObjectFieldPalette& palette = {},
|
||||||
|
const UIEditorObjectFieldMetrics& metrics = {});
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor::Widgets
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEditor/Fields/UIEditorObjectField.h>
|
||||||
|
|
||||||
|
#include <XCEngine/UI/Types.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor {
|
||||||
|
|
||||||
|
struct UIEditorObjectFieldInteractionState {
|
||||||
|
Widgets::UIEditorObjectFieldState fieldState = {};
|
||||||
|
::XCEngine::UI::UIPoint pointerPosition = {};
|
||||||
|
bool hasPointerPosition = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorObjectFieldInteractionResult {
|
||||||
|
bool consumed = false;
|
||||||
|
bool focusChanged = false;
|
||||||
|
bool activateRequested = false;
|
||||||
|
bool clearRequested = false;
|
||||||
|
Widgets::UIEditorObjectFieldHitTarget hitTarget = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIEditorObjectFieldInteractionFrame {
|
||||||
|
Widgets::UIEditorObjectFieldLayout layout = {};
|
||||||
|
UIEditorObjectFieldInteractionResult result = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
UIEditorObjectFieldInteractionFrame UpdateUIEditorObjectFieldInteraction(
|
||||||
|
UIEditorObjectFieldInteractionState& state,
|
||||||
|
const Widgets::UIEditorObjectFieldSpec& spec,
|
||||||
|
const ::XCEngine::UI::UIRect& bounds,
|
||||||
|
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
|
||||||
|
const Widgets::UIEditorObjectFieldMetrics& metrics = {});
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor
|
||||||
@@ -5,7 +5,8 @@
|
|||||||
#include <XCEngine/UI/Widgets/UIPropertyEditModel.h>
|
#include <XCEngine/UI/Widgets/UIPropertyEditModel.h>
|
||||||
#include <XCEngine/UI/Widgets/UISelectionModel.h>
|
#include <XCEngine/UI/Widgets/UISelectionModel.h>
|
||||||
|
|
||||||
#include <XCEditor/Widgets/UIEditorMenuPopup.h>
|
#include <XCEditor/Fields/UIEditorColorField.h>
|
||||||
|
#include <XCEditor/Shell/UIEditorMenuPopup.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
@@ -23,6 +24,7 @@ enum class UIEditorPropertyGridFieldKind : std::uint8_t {
|
|||||||
Bool,
|
Bool,
|
||||||
Number,
|
Number,
|
||||||
Enum,
|
Enum,
|
||||||
|
Color,
|
||||||
Vector2,
|
Vector2,
|
||||||
Vector3,
|
Vector3,
|
||||||
Vector4
|
Vector4
|
||||||
@@ -58,6 +60,11 @@ struct UIEditorPropertyGridEnumFieldValue {
|
|||||||
std::size_t selectedIndex = 0u;
|
std::size_t selectedIndex = 0u;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct UIEditorPropertyGridColorFieldValue {
|
||||||
|
::XCEngine::UI::UIColor value = {};
|
||||||
|
bool showAlpha = true;
|
||||||
|
};
|
||||||
|
|
||||||
struct UIEditorPropertyGridVector2FieldValue {
|
struct UIEditorPropertyGridVector2FieldValue {
|
||||||
std::array<double, 2u> values = { 0.0, 0.0 };
|
std::array<double, 2u> values = { 0.0, 0.0 };
|
||||||
std::array<std::string, 2u> componentLabels = { std::string("X"), std::string("Y") };
|
std::array<std::string, 2u> componentLabels = { std::string("X"), std::string("Y") };
|
||||||
@@ -104,6 +111,7 @@ struct UIEditorPropertyGridField {
|
|||||||
bool boolValue = false;
|
bool boolValue = false;
|
||||||
UIEditorPropertyGridNumberFieldValue numberValue = {};
|
UIEditorPropertyGridNumberFieldValue numberValue = {};
|
||||||
UIEditorPropertyGridEnumFieldValue enumValue = {};
|
UIEditorPropertyGridEnumFieldValue enumValue = {};
|
||||||
|
UIEditorPropertyGridColorFieldValue colorValue = {};
|
||||||
UIEditorPropertyGridVector2FieldValue vector2Value = {};
|
UIEditorPropertyGridVector2FieldValue vector2Value = {};
|
||||||
UIEditorPropertyGridVector3FieldValue vector3Value = {};
|
UIEditorPropertyGridVector3FieldValue vector3Value = {};
|
||||||
UIEditorPropertyGridVector4FieldValue vector4Value = {};
|
UIEditorPropertyGridVector4FieldValue vector4Value = {};
|
||||||
@@ -116,6 +124,11 @@ struct UIEditorPropertyGridSection {
|
|||||||
float desiredHeaderHeight = 0.0f;
|
float desiredHeaderHeight = 0.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct UIEditorPropertyGridColorFieldVisualState {
|
||||||
|
std::string fieldId = {};
|
||||||
|
UIEditorColorFieldState state = {};
|
||||||
|
};
|
||||||
|
|
||||||
struct UIEditorPropertyGridState {
|
struct UIEditorPropertyGridState {
|
||||||
std::string hoveredSectionId = {};
|
std::string hoveredSectionId = {};
|
||||||
std::string hoveredFieldId = {};
|
std::string hoveredFieldId = {};
|
||||||
@@ -124,6 +137,7 @@ struct UIEditorPropertyGridState {
|
|||||||
std::string pressedFieldId = {};
|
std::string pressedFieldId = {};
|
||||||
std::string popupFieldId = {};
|
std::string popupFieldId = {};
|
||||||
std::size_t popupHighlightedIndex = UIEditorPropertyGridInvalidIndex;
|
std::size_t popupHighlightedIndex = UIEditorPropertyGridInvalidIndex;
|
||||||
|
std::vector<UIEditorPropertyGridColorFieldVisualState> colorFieldStates = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UIEditorPropertyGridMetrics {
|
struct UIEditorPropertyGridMetrics {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Widgets/UIEditorPropertyGrid.h>
|
#include <XCEditor/Fields/UIEditorPropertyGrid.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Text/UITextInputController.h>
|
#include <XCEngine/UI/Text/UITextInputController.h>
|
||||||
#include <XCEngine/UI/Types.h>
|
#include <XCEngine/UI/Types.h>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Widgets/UIEditorTextField.h>
|
#include <XCEditor/Fields/UIEditorTextField.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Text/UITextInputController.h>
|
#include <XCEngine/UI/Text/UITextInputController.h>
|
||||||
#include <XCEngine/UI/Types.h>
|
#include <XCEngine/UI/Types.h>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Widgets/UIEditorVector2Field.h>
|
#include <XCEditor/Fields/UIEditorVector2Field.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Text/UITextInputController.h>
|
#include <XCEngine/UI/Text/UITextInputController.h>
|
||||||
#include <XCEngine/UI/Types.h>
|
#include <XCEngine/UI/Types.h>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Widgets/UIEditorVector3Field.h>
|
#include <XCEditor/Fields/UIEditorVector3Field.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Text/UITextInputController.h>
|
#include <XCEngine/UI/Text/UITextInputController.h>
|
||||||
#include <XCEngine/UI/Types.h>
|
#include <XCEngine/UI/Types.h>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Widgets/UIEditorVector4Field.h>
|
#include <XCEditor/Fields/UIEditorVector4Field.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Text/UITextInputController.h>
|
#include <XCEngine/UI/Text/UITextInputController.h>
|
||||||
#include <XCEngine/UI/Types.h>
|
#include <XCEngine/UI/Types.h>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorCommandRegistry.h>
|
#include <XCEditor/Foundation/UIEditorCommandRegistry.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceController.h>
|
#include <XCEditor/Shell/UIEditorWorkspaceController.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorCommandDispatcher.h>
|
#include <XCEditor/Foundation/UIEditorCommandDispatcher.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Input/UIShortcutRegistry.h>
|
#include <XCEngine/UI/Input/UIShortcutRegistry.h>
|
||||||
|
|
||||||
76
new_editor/include/XCEditor/Foundation/UIEditorTheme.h
Normal file
76
new_editor/include/XCEditor/Foundation/UIEditorTheme.h
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEditor/Collections/UIEditorListView.h>
|
||||||
|
#include <XCEditor/Collections/UIEditorScrollView.h>
|
||||||
|
#include <XCEditor/Collections/UIEditorTabStrip.h>
|
||||||
|
#include <XCEditor/Collections/UIEditorTreeView.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorAssetField.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorBoolField.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorColorField.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorEnumField.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorNumberField.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorObjectField.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorPropertyGrid.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorTextField.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorVector2Field.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorVector3Field.h>
|
||||||
|
#include <XCEditor/Fields/UIEditorVector4Field.h>
|
||||||
|
#include <XCEditor/Shell/UIEditorDockHost.h>
|
||||||
|
#include <XCEditor/Shell/UIEditorMenuBar.h>
|
||||||
|
#include <XCEditor/Shell/UIEditorMenuPopup.h>
|
||||||
|
#include <XCEditor/Shell/UIEditorPanelFrame.h>
|
||||||
|
#include <XCEditor/Shell/UIEditorShellCompose.h>
|
||||||
|
#include <XCEditor/Shell/UIEditorShellInteraction.h>
|
||||||
|
#include <XCEditor/Shell/UIEditorStatusBar.h>
|
||||||
|
#include <XCEditor/Shell/UIEditorViewportSlot.h>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor {
|
||||||
|
|
||||||
|
const Widgets::UIEditorBoolFieldMetrics& ResolveUIEditorBoolFieldMetrics();
|
||||||
|
const Widgets::UIEditorBoolFieldPalette& ResolveUIEditorBoolFieldPalette();
|
||||||
|
const Widgets::UIEditorNumberFieldMetrics& ResolveUIEditorNumberFieldMetrics();
|
||||||
|
const Widgets::UIEditorNumberFieldPalette& ResolveUIEditorNumberFieldPalette();
|
||||||
|
const Widgets::UIEditorTextFieldMetrics& ResolveUIEditorTextFieldMetrics();
|
||||||
|
const Widgets::UIEditorTextFieldPalette& ResolveUIEditorTextFieldPalette();
|
||||||
|
const Widgets::UIEditorVector2FieldMetrics& ResolveUIEditorVector2FieldMetrics();
|
||||||
|
const Widgets::UIEditorVector2FieldPalette& ResolveUIEditorVector2FieldPalette();
|
||||||
|
const Widgets::UIEditorVector3FieldMetrics& ResolveUIEditorVector3FieldMetrics();
|
||||||
|
const Widgets::UIEditorVector3FieldPalette& ResolveUIEditorVector3FieldPalette();
|
||||||
|
const Widgets::UIEditorVector4FieldMetrics& ResolveUIEditorVector4FieldMetrics();
|
||||||
|
const Widgets::UIEditorVector4FieldPalette& ResolveUIEditorVector4FieldPalette();
|
||||||
|
const Widgets::UIEditorEnumFieldMetrics& ResolveUIEditorEnumFieldMetrics();
|
||||||
|
const Widgets::UIEditorEnumFieldPalette& ResolveUIEditorEnumFieldPalette();
|
||||||
|
const Widgets::UIEditorColorFieldMetrics& ResolveUIEditorColorFieldMetrics();
|
||||||
|
const Widgets::UIEditorColorFieldPalette& ResolveUIEditorColorFieldPalette();
|
||||||
|
const Widgets::UIEditorObjectFieldMetrics& ResolveUIEditorObjectFieldMetrics();
|
||||||
|
const Widgets::UIEditorObjectFieldPalette& ResolveUIEditorObjectFieldPalette();
|
||||||
|
const Widgets::UIEditorAssetFieldMetrics& ResolveUIEditorAssetFieldMetrics();
|
||||||
|
const Widgets::UIEditorAssetFieldPalette& ResolveUIEditorAssetFieldPalette();
|
||||||
|
const Widgets::UIEditorMenuPopupMetrics& ResolveUIEditorMenuPopupMetrics();
|
||||||
|
const Widgets::UIEditorMenuPopupPalette& ResolveUIEditorMenuPopupPalette();
|
||||||
|
const Widgets::UIEditorListViewMetrics& ResolveUIEditorListViewMetrics();
|
||||||
|
const Widgets::UIEditorListViewPalette& ResolveUIEditorListViewPalette();
|
||||||
|
const Widgets::UIEditorTreeViewMetrics& ResolveUIEditorTreeViewMetrics();
|
||||||
|
const Widgets::UIEditorTreeViewPalette& ResolveUIEditorTreeViewPalette();
|
||||||
|
const Widgets::UIEditorScrollViewMetrics& ResolveUIEditorScrollViewMetrics();
|
||||||
|
const Widgets::UIEditorScrollViewPalette& ResolveUIEditorScrollViewPalette();
|
||||||
|
const Widgets::UIEditorTabStripMetrics& ResolveUIEditorTabStripMetrics();
|
||||||
|
const Widgets::UIEditorTabStripPalette& ResolveUIEditorTabStripPalette();
|
||||||
|
const Widgets::UIEditorMenuBarMetrics& ResolveUIEditorMenuBarMetrics();
|
||||||
|
const Widgets::UIEditorMenuBarPalette& ResolveUIEditorMenuBarPalette();
|
||||||
|
const Widgets::UIEditorStatusBarMetrics& ResolveUIEditorStatusBarMetrics();
|
||||||
|
const Widgets::UIEditorStatusBarPalette& ResolveUIEditorStatusBarPalette();
|
||||||
|
const Widgets::UIEditorPanelFrameMetrics& ResolveUIEditorPanelFrameMetrics();
|
||||||
|
const Widgets::UIEditorPanelFramePalette& ResolveUIEditorPanelFramePalette();
|
||||||
|
const Widgets::UIEditorDockHostMetrics& ResolveUIEditorDockHostMetrics();
|
||||||
|
const Widgets::UIEditorDockHostPalette& ResolveUIEditorDockHostPalette();
|
||||||
|
const Widgets::UIEditorViewportSlotMetrics& ResolveUIEditorViewportSlotMetrics();
|
||||||
|
const Widgets::UIEditorViewportSlotPalette& ResolveUIEditorViewportSlotPalette();
|
||||||
|
const UIEditorShellComposeMetrics& ResolveUIEditorShellComposeMetrics();
|
||||||
|
const UIEditorShellComposePalette& ResolveUIEditorShellComposePalette();
|
||||||
|
const UIEditorShellInteractionMetrics& ResolveUIEditorShellInteractionMetrics();
|
||||||
|
const UIEditorShellInteractionPalette& ResolveUIEditorShellInteractionPalette();
|
||||||
|
const Widgets::UIEditorPropertyGridMetrics& ResolveUIEditorPropertyGridMetrics();
|
||||||
|
const Widgets::UIEditorPropertyGridPalette& ResolveUIEditorPropertyGridPalette();
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorPanelRegistry.h>
|
#include <XCEditor/Shell/UIEditorPanelRegistry.h>
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceModel.h>
|
#include <XCEditor/Shell/UIEditorWorkspaceModel.h>
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceSession.h>
|
#include <XCEditor/Shell/UIEditorWorkspaceSession.h>
|
||||||
#include <XCEditor/Widgets/UIEditorPanelFrame.h>
|
#include <XCEditor/Shell/UIEditorPanelFrame.h>
|
||||||
#include <XCEditor/Widgets/UIEditorTabStrip.h>
|
#include <XCEditor/Collections/UIEditorTabStrip.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Layout/UISplitterLayout.h>
|
#include <XCEngine/UI/Layout/UISplitterLayout.h>
|
||||||
|
|
||||||
@@ -35,10 +35,16 @@ struct UIEditorDockHostHitTarget {
|
|||||||
std::size_t index = UIEditorTabStripInvalidIndex;
|
std::size_t index = UIEditorTabStripInvalidIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct UIEditorDockHostTabStripVisualState {
|
||||||
|
std::string nodeId = {};
|
||||||
|
UIEditorTabStripState state = {};
|
||||||
|
};
|
||||||
|
|
||||||
struct UIEditorDockHostState {
|
struct UIEditorDockHostState {
|
||||||
bool focused = false;
|
bool focused = false;
|
||||||
UIEditorDockHostHitTarget hoveredTarget = {};
|
UIEditorDockHostHitTarget hoveredTarget = {};
|
||||||
std::string activeSplitterNodeId = {};
|
std::string activeSplitterNodeId = {};
|
||||||
|
std::vector<UIEditorDockHostTabStripVisualState> tabStripStates = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UIEditorDockHostMetrics {
|
struct UIEditorDockHostMetrics {
|
||||||
@@ -58,17 +64,17 @@ struct UIEditorDockHostPalette {
|
|||||||
UIEditorTabStripPalette tabStripPalette = {};
|
UIEditorTabStripPalette tabStripPalette = {};
|
||||||
UIEditorPanelFramePalette panelFramePalette = {};
|
UIEditorPanelFramePalette panelFramePalette = {};
|
||||||
::XCEngine::UI::UIColor splitterColor =
|
::XCEngine::UI::UIColor splitterColor =
|
||||||
::XCEngine::UI::UIColor(0.26f, 0.26f, 0.26f, 1.0f);
|
::XCEngine::UI::UIColor(0.22f, 0.23f, 0.25f, 1.0f);
|
||||||
::XCEngine::UI::UIColor splitterHoveredColor =
|
::XCEngine::UI::UIColor splitterHoveredColor =
|
||||||
::XCEngine::UI::UIColor(0.36f, 0.36f, 0.36f, 1.0f);
|
::XCEngine::UI::UIColor(0.32f, 0.34f, 0.36f, 1.0f);
|
||||||
::XCEngine::UI::UIColor splitterActiveColor =
|
::XCEngine::UI::UIColor splitterActiveColor =
|
||||||
::XCEngine::UI::UIColor(0.86f, 0.86f, 0.86f, 1.0f);
|
::XCEngine::UI::UIColor(0.50f, 0.52f, 0.56f, 1.0f);
|
||||||
::XCEngine::UI::UIColor placeholderTitleColor =
|
::XCEngine::UI::UIColor placeholderTitleColor =
|
||||||
::XCEngine::UI::UIColor(0.94f, 0.94f, 0.94f, 1.0f);
|
::XCEngine::UI::UIColor(0.93f, 0.94f, 0.96f, 1.0f);
|
||||||
::XCEngine::UI::UIColor placeholderTextColor =
|
::XCEngine::UI::UIColor placeholderTextColor =
|
||||||
::XCEngine::UI::UIColor(0.72f, 0.72f, 0.72f, 1.0f);
|
::XCEngine::UI::UIColor(0.70f, 0.72f, 0.74f, 1.0f);
|
||||||
::XCEngine::UI::UIColor placeholderMutedColor =
|
::XCEngine::UI::UIColor placeholderMutedColor =
|
||||||
::XCEngine::UI::UIColor(0.58f, 0.58f, 0.58f, 1.0f);
|
::XCEngine::UI::UIColor(0.58f, 0.59f, 0.62f, 1.0f);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UIEditorDockHostTabItemLayout {
|
struct UIEditorDockHostTabItemLayout {
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceController.h>
|
#include <XCEditor/Collections/UIEditorTabStripInteraction.h>
|
||||||
#include <XCEditor/Widgets/UIEditorDockHost.h>
|
#include <XCEditor/Shell/UIEditorWorkspaceController.h>
|
||||||
|
#include <XCEditor/Shell/UIEditorDockHost.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/DrawData.h>
|
#include <XCEngine/UI/DrawData.h>
|
||||||
#include <XCEngine/UI/Widgets/UISplitterInteraction.h>
|
#include <XCEngine/UI/Widgets/UISplitterInteraction.h>
|
||||||
@@ -11,9 +12,15 @@
|
|||||||
|
|
||||||
namespace XCEngine::UI::Editor {
|
namespace XCEngine::UI::Editor {
|
||||||
|
|
||||||
|
struct UIEditorDockHostTabStripInteractionEntry {
|
||||||
|
std::string nodeId = {};
|
||||||
|
UIEditorTabStripInteractionState state = {};
|
||||||
|
};
|
||||||
|
|
||||||
struct UIEditorDockHostInteractionState {
|
struct UIEditorDockHostInteractionState {
|
||||||
Widgets::UIEditorDockHostState dockHostState = {};
|
Widgets::UIEditorDockHostState dockHostState = {};
|
||||||
::XCEngine::UI::Widgets::UISplitterDragState splitterDragState = {};
|
::XCEngine::UI::Widgets::UISplitterDragState splitterDragState = {};
|
||||||
|
std::vector<UIEditorDockHostTabStripInteractionEntry> tabStripInteractions = {};
|
||||||
::XCEngine::UI::UIPoint pointerPosition = {};
|
::XCEngine::UI::UIPoint pointerPosition = {};
|
||||||
bool hasPointerPosition = false;
|
bool hasPointerPosition = false;
|
||||||
};
|
};
|
||||||
@@ -34,7 +34,7 @@ struct UIEditorMenuBarMetrics {
|
|||||||
float estimatedGlyphWidth = 7.0f;
|
float estimatedGlyphWidth = 7.0f;
|
||||||
float labelInsetY = -1.0f;
|
float labelInsetY = -1.0f;
|
||||||
float barCornerRounding = 8.0f;
|
float barCornerRounding = 8.0f;
|
||||||
float buttonCornerRounding = 7.0f;
|
float buttonCornerRounding = 6.0f;
|
||||||
float baseBorderThickness = 1.0f;
|
float baseBorderThickness = 1.0f;
|
||||||
float focusedBorderThickness = 2.0f;
|
float focusedBorderThickness = 2.0f;
|
||||||
float openBorderThickness = 1.5f;
|
float openBorderThickness = 1.5f;
|
||||||
@@ -42,25 +42,25 @@ struct UIEditorMenuBarMetrics {
|
|||||||
|
|
||||||
struct UIEditorMenuBarPalette {
|
struct UIEditorMenuBarPalette {
|
||||||
::XCEngine::UI::UIColor barColor =
|
::XCEngine::UI::UIColor barColor =
|
||||||
::XCEngine::UI::UIColor(0.16f, 0.16f, 0.16f, 1.0f);
|
::XCEngine::UI::UIColor(0.18f, 0.18f, 0.19f, 1.0f);
|
||||||
::XCEngine::UI::UIColor buttonColor =
|
::XCEngine::UI::UIColor buttonColor =
|
||||||
::XCEngine::UI::UIColor(0.23f, 0.23f, 0.23f, 1.0f);
|
::XCEngine::UI::UIColor(0.21f, 0.22f, 0.24f, 1.0f);
|
||||||
::XCEngine::UI::UIColor buttonHoveredColor =
|
::XCEngine::UI::UIColor buttonHoveredColor =
|
||||||
::XCEngine::UI::UIColor(0.29f, 0.29f, 0.29f, 1.0f);
|
::XCEngine::UI::UIColor(0.27f, 0.28f, 0.30f, 1.0f);
|
||||||
::XCEngine::UI::UIColor buttonOpenColor =
|
::XCEngine::UI::UIColor buttonOpenColor =
|
||||||
::XCEngine::UI::UIColor(0.35f, 0.35f, 0.35f, 1.0f);
|
::XCEngine::UI::UIColor(0.33f, 0.35f, 0.38f, 1.0f);
|
||||||
::XCEngine::UI::UIColor borderColor =
|
::XCEngine::UI::UIColor borderColor =
|
||||||
::XCEngine::UI::UIColor(0.30f, 0.30f, 0.30f, 1.0f);
|
::XCEngine::UI::UIColor(0.30f, 0.32f, 0.34f, 1.0f);
|
||||||
::XCEngine::UI::UIColor focusedBorderColor =
|
::XCEngine::UI::UIColor focusedBorderColor =
|
||||||
::XCEngine::UI::UIColor(0.84f, 0.84f, 0.84f, 1.0f);
|
::XCEngine::UI::UIColor(0.78f, 0.80f, 0.84f, 1.0f);
|
||||||
::XCEngine::UI::UIColor openBorderColor =
|
::XCEngine::UI::UIColor openBorderColor =
|
||||||
::XCEngine::UI::UIColor(0.68f, 0.68f, 0.68f, 1.0f);
|
::XCEngine::UI::UIColor(0.50f, 0.52f, 0.56f, 1.0f);
|
||||||
::XCEngine::UI::UIColor textPrimary =
|
::XCEngine::UI::UIColor textPrimary =
|
||||||
::XCEngine::UI::UIColor(0.94f, 0.94f, 0.94f, 1.0f);
|
::XCEngine::UI::UIColor(0.93f, 0.94f, 0.96f, 1.0f);
|
||||||
::XCEngine::UI::UIColor textMuted =
|
::XCEngine::UI::UIColor textMuted =
|
||||||
::XCEngine::UI::UIColor(0.74f, 0.74f, 0.74f, 1.0f);
|
::XCEngine::UI::UIColor(0.70f, 0.72f, 0.74f, 1.0f);
|
||||||
::XCEngine::UI::UIColor textDisabled =
|
::XCEngine::UI::UIColor textDisabled =
|
||||||
::XCEngine::UI::UIColor(0.52f, 0.52f, 0.52f, 1.0f);
|
::XCEngine::UI::UIColor(0.54f, 0.55f, 0.58f, 1.0f);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UIEditorMenuBarLayout {
|
struct UIEditorMenuBarLayout {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorCommandDispatcher.h>
|
#include <XCEditor/Foundation/UIEditorCommandDispatcher.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorMenuModel.h>
|
#include <XCEditor/Shell/UIEditorMenuModel.h>
|
||||||
#include <XCEngine/UI/DrawData.h>
|
#include <XCEngine/UI/DrawData.h>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
@@ -24,8 +24,8 @@ struct UIEditorMenuSessionMutationResult {
|
|||||||
std::string openRootMenuId = {};
|
std::string openRootMenuId = {};
|
||||||
std::string openedPopupId = {};
|
std::string openedPopupId = {};
|
||||||
std::vector<std::string> closedPopupIds = {};
|
std::vector<std::string> closedPopupIds = {};
|
||||||
Widgets::UIPopupDismissReason dismissReason =
|
::XCEngine::UI::Widgets::UIPopupDismissReason dismissReason =
|
||||||
Widgets::UIPopupDismissReason::None;
|
::XCEngine::UI::Widgets::UIPopupDismissReason::None;
|
||||||
|
|
||||||
[[nodiscard]] bool HasOpenMenu() const {
|
[[nodiscard]] bool HasOpenMenu() const {
|
||||||
return !openRootMenuId.empty();
|
return !openRootMenuId.empty();
|
||||||
@@ -34,7 +34,7 @@ struct UIEditorMenuSessionMutationResult {
|
|||||||
|
|
||||||
class UIEditorMenuSession {
|
class UIEditorMenuSession {
|
||||||
public:
|
public:
|
||||||
const Widgets::UIPopupOverlayModel& GetPopupOverlayModel() const {
|
const ::XCEngine::UI::Widgets::UIPopupOverlayModel& GetPopupOverlayModel() const {
|
||||||
return m_popupOverlayModel;
|
return m_popupOverlayModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,23 +66,23 @@ public:
|
|||||||
|
|
||||||
UIEditorMenuSessionMutationResult OpenRootMenu(
|
UIEditorMenuSessionMutationResult OpenRootMenu(
|
||||||
std::string_view menuId,
|
std::string_view menuId,
|
||||||
Widgets::UIPopupOverlayEntry entry);
|
::XCEngine::UI::Widgets::UIPopupOverlayEntry entry);
|
||||||
|
|
||||||
UIEditorMenuSessionMutationResult OpenMenuBarRoot(
|
UIEditorMenuSessionMutationResult OpenMenuBarRoot(
|
||||||
std::string_view menuId,
|
std::string_view menuId,
|
||||||
Widgets::UIPopupOverlayEntry entry);
|
::XCEngine::UI::Widgets::UIPopupOverlayEntry entry);
|
||||||
|
|
||||||
UIEditorMenuSessionMutationResult HoverMenuBarRoot(
|
UIEditorMenuSessionMutationResult HoverMenuBarRoot(
|
||||||
std::string_view menuId,
|
std::string_view menuId,
|
||||||
Widgets::UIPopupOverlayEntry entry);
|
::XCEngine::UI::Widgets::UIPopupOverlayEntry entry);
|
||||||
|
|
||||||
UIEditorMenuSessionMutationResult HoverSubmenu(
|
UIEditorMenuSessionMutationResult HoverSubmenu(
|
||||||
std::string_view itemId,
|
std::string_view itemId,
|
||||||
Widgets::UIPopupOverlayEntry entry);
|
::XCEngine::UI::Widgets::UIPopupOverlayEntry entry);
|
||||||
|
|
||||||
UIEditorMenuSessionMutationResult CloseAll(
|
UIEditorMenuSessionMutationResult CloseAll(
|
||||||
Widgets::UIPopupDismissReason dismissReason =
|
::XCEngine::UI::Widgets::UIPopupDismissReason dismissReason =
|
||||||
Widgets::UIPopupDismissReason::Programmatic);
|
::XCEngine::UI::Widgets::UIPopupDismissReason::Programmatic);
|
||||||
|
|
||||||
UIEditorMenuSessionMutationResult DismissFromEscape();
|
UIEditorMenuSessionMutationResult DismissFromEscape();
|
||||||
UIEditorMenuSessionMutationResult DismissFromPointerDown(
|
UIEditorMenuSessionMutationResult DismissFromPointerDown(
|
||||||
@@ -92,13 +92,13 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
UIEditorMenuSessionMutationResult BuildResult(
|
UIEditorMenuSessionMutationResult BuildResult(
|
||||||
const Widgets::UIPopupOverlayMutationResult& mutation) const;
|
const ::XCEngine::UI::Widgets::UIPopupOverlayMutationResult& mutation) const;
|
||||||
|
|
||||||
void RemoveClosedPopupStates(const std::vector<std::string>& closedPopupIds);
|
void RemoveClosedPopupStates(const std::vector<std::string>& closedPopupIds);
|
||||||
void RebuildDerivedState();
|
void RebuildDerivedState();
|
||||||
|
|
||||||
std::string m_openRootMenuId = {};
|
std::string m_openRootMenuId = {};
|
||||||
Widgets::UIPopupOverlayModel m_popupOverlayModel = {};
|
::XCEngine::UI::Widgets::UIPopupOverlayModel m_popupOverlayModel = {};
|
||||||
std::vector<UIEditorMenuPopupState> m_popupStates = {};
|
std::vector<UIEditorMenuPopupState> m_popupStates = {};
|
||||||
std::vector<std::string> m_openSubmenuItemIds = {};
|
std::vector<std::string> m_openSubmenuItemIds = {};
|
||||||
};
|
};
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorPanelRegistry.h>
|
#include <XCEditor/Shell/UIEditorPanelRegistry.h>
|
||||||
#include <XCEditor/Widgets/UIEditorDockHost.h>
|
#include <XCEditor/Shell/UIEditorDockHost.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -41,7 +41,7 @@ struct UIEditorPanelFrameText {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct UIEditorPanelFrameMetrics {
|
struct UIEditorPanelFrameMetrics {
|
||||||
float cornerRounding = 10.0f;
|
float cornerRounding = 8.0f;
|
||||||
float headerHeight = 36.0f;
|
float headerHeight = 36.0f;
|
||||||
float footerHeight = 24.0f;
|
float footerHeight = 24.0f;
|
||||||
float contentPadding = 12.0f;
|
float contentPadding = 12.0f;
|
||||||
@@ -61,35 +61,35 @@ struct UIEditorPanelFrameMetrics {
|
|||||||
|
|
||||||
struct UIEditorPanelFramePalette {
|
struct UIEditorPanelFramePalette {
|
||||||
::XCEngine::UI::UIColor surfaceColor =
|
::XCEngine::UI::UIColor surfaceColor =
|
||||||
::XCEngine::UI::UIColor(0.16f, 0.16f, 0.16f, 1.0f);
|
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.16f, 1.0f);
|
||||||
::XCEngine::UI::UIColor headerColor =
|
::XCEngine::UI::UIColor headerColor =
|
||||||
::XCEngine::UI::UIColor(0.20f, 0.20f, 0.20f, 1.0f);
|
::XCEngine::UI::UIColor(0.18f, 0.18f, 0.19f, 1.0f);
|
||||||
::XCEngine::UI::UIColor footerColor =
|
::XCEngine::UI::UIColor footerColor =
|
||||||
::XCEngine::UI::UIColor(0.19f, 0.19f, 0.19f, 1.0f);
|
::XCEngine::UI::UIColor(0.17f, 0.17f, 0.18f, 1.0f);
|
||||||
::XCEngine::UI::UIColor borderColor =
|
::XCEngine::UI::UIColor borderColor =
|
||||||
::XCEngine::UI::UIColor(0.30f, 0.30f, 0.30f, 1.0f);
|
::XCEngine::UI::UIColor(0.30f, 0.32f, 0.34f, 1.0f);
|
||||||
::XCEngine::UI::UIColor hoveredBorderColor =
|
::XCEngine::UI::UIColor hoveredBorderColor =
|
||||||
::XCEngine::UI::UIColor(0.42f, 0.42f, 0.42f, 1.0f);
|
::XCEngine::UI::UIColor(0.39f, 0.41f, 0.43f, 1.0f);
|
||||||
::XCEngine::UI::UIColor activeBorderColor =
|
::XCEngine::UI::UIColor activeBorderColor =
|
||||||
::XCEngine::UI::UIColor(0.58f, 0.58f, 0.58f, 1.0f);
|
::XCEngine::UI::UIColor(0.50f, 0.52f, 0.56f, 1.0f);
|
||||||
::XCEngine::UI::UIColor focusedBorderColor =
|
::XCEngine::UI::UIColor focusedBorderColor =
|
||||||
::XCEngine::UI::UIColor(0.84f, 0.84f, 0.84f, 1.0f);
|
::XCEngine::UI::UIColor(0.78f, 0.80f, 0.84f, 1.0f);
|
||||||
::XCEngine::UI::UIColor textPrimary =
|
::XCEngine::UI::UIColor textPrimary =
|
||||||
::XCEngine::UI::UIColor(0.94f, 0.94f, 0.94f, 1.0f);
|
::XCEngine::UI::UIColor(0.93f, 0.94f, 0.96f, 1.0f);
|
||||||
::XCEngine::UI::UIColor textSecondary =
|
::XCEngine::UI::UIColor textSecondary =
|
||||||
::XCEngine::UI::UIColor(0.71f, 0.71f, 0.71f, 1.0f);
|
::XCEngine::UI::UIColor(0.70f, 0.72f, 0.74f, 1.0f);
|
||||||
::XCEngine::UI::UIColor textMuted =
|
::XCEngine::UI::UIColor textMuted =
|
||||||
::XCEngine::UI::UIColor(0.60f, 0.60f, 0.60f, 1.0f);
|
::XCEngine::UI::UIColor(0.58f, 0.59f, 0.62f, 1.0f);
|
||||||
::XCEngine::UI::UIColor actionButtonColor =
|
::XCEngine::UI::UIColor actionButtonColor =
|
||||||
::XCEngine::UI::UIColor(0.24f, 0.24f, 0.24f, 1.0f);
|
::XCEngine::UI::UIColor(0.21f, 0.22f, 0.24f, 1.0f);
|
||||||
::XCEngine::UI::UIColor actionButtonHoveredColor =
|
::XCEngine::UI::UIColor actionButtonHoveredColor =
|
||||||
::XCEngine::UI::UIColor(0.34f, 0.34f, 0.34f, 1.0f);
|
::XCEngine::UI::UIColor(0.27f, 0.28f, 0.30f, 1.0f);
|
||||||
::XCEngine::UI::UIColor actionButtonSelectedColor =
|
::XCEngine::UI::UIColor actionButtonSelectedColor =
|
||||||
::XCEngine::UI::UIColor(0.48f, 0.48f, 0.48f, 1.0f);
|
::XCEngine::UI::UIColor(0.33f, 0.35f, 0.38f, 1.0f);
|
||||||
::XCEngine::UI::UIColor actionButtonBorderColor =
|
::XCEngine::UI::UIColor actionButtonBorderColor =
|
||||||
::XCEngine::UI::UIColor(0.52f, 0.52f, 0.52f, 1.0f);
|
::XCEngine::UI::UIColor(0.42f, 0.44f, 0.47f, 1.0f);
|
||||||
::XCEngine::UI::UIColor actionGlyphColor =
|
::XCEngine::UI::UIColor actionGlyphColor =
|
||||||
::XCEngine::UI::UIColor(0.92f, 0.92f, 0.92f, 1.0f);
|
::XCEngine::UI::UIColor(0.93f, 0.94f, 0.96f, 1.0f);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UIEditorPanelFrameLayout {
|
struct UIEditorPanelFrameLayout {
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorPanelRegistry.h>
|
#include <XCEditor/Shell/UIEditorPanelRegistry.h>
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceSession.h>
|
#include <XCEditor/Shell/UIEditorWorkspaceSession.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceCompose.h>
|
#include <XCEditor/Shell/UIEditorWorkspaceCompose.h>
|
||||||
#include <XCEditor/Widgets/UIEditorMenuBar.h>
|
#include <XCEditor/Shell/UIEditorMenuBar.h>
|
||||||
#include <XCEditor/Widgets/UIEditorStatusBar.h>
|
#include <XCEditor/Shell/UIEditorStatusBar.h>
|
||||||
|
|
||||||
namespace XCEngine::UI::Editor {
|
namespace XCEngine::UI::Editor {
|
||||||
|
|
||||||
@@ -24,6 +24,7 @@ struct UIEditorShellComposeMetrics {
|
|||||||
float surfaceCornerRounding = 10.0f;
|
float surfaceCornerRounding = 10.0f;
|
||||||
Widgets::UIEditorMenuBarMetrics menuBarMetrics = {};
|
Widgets::UIEditorMenuBarMetrics menuBarMetrics = {};
|
||||||
Widgets::UIEditorDockHostMetrics dockHostMetrics = {};
|
Widgets::UIEditorDockHostMetrics dockHostMetrics = {};
|
||||||
|
Widgets::UIEditorViewportSlotMetrics viewportMetrics = {};
|
||||||
Widgets::UIEditorStatusBarMetrics statusBarMetrics = {};
|
Widgets::UIEditorStatusBarMetrics statusBarMetrics = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ struct UIEditorShellComposePalette {
|
|||||||
::XCEngine::UI::UIColor(0.27f, 0.27f, 0.27f, 1.0f);
|
::XCEngine::UI::UIColor(0.27f, 0.27f, 0.27f, 1.0f);
|
||||||
Widgets::UIEditorMenuBarPalette menuBarPalette = {};
|
Widgets::UIEditorMenuBarPalette menuBarPalette = {};
|
||||||
Widgets::UIEditorDockHostPalette dockHostPalette = {};
|
Widgets::UIEditorDockHostPalette dockHostPalette = {};
|
||||||
|
Widgets::UIEditorViewportSlotPalette viewportPalette = {};
|
||||||
Widgets::UIEditorStatusBarPalette statusBarPalette = {};
|
Widgets::UIEditorStatusBarPalette statusBarPalette = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorMenuModel.h>
|
#include <XCEditor/Shell/UIEditorMenuModel.h>
|
||||||
#include <XCEditor/Core/UIEditorMenuSession.h>
|
#include <XCEditor/Shell/UIEditorMenuSession.h>
|
||||||
#include <XCEditor/Core/UIEditorShellCompose.h>
|
#include <XCEditor/Shell/UIEditorShellCompose.h>
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceController.h>
|
#include <XCEditor/Shell/UIEditorWorkspaceController.h>
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceInteraction.h>
|
#include <XCEditor/Shell/UIEditorWorkspaceInteraction.h>
|
||||||
#include <XCEditor/Widgets/UIEditorMenuPopup.h>
|
#include <XCEditor/Shell/UIEditorMenuPopup.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/DrawData.h>
|
#include <XCEngine/UI/DrawData.h>
|
||||||
|
|
||||||
@@ -59,32 +59,32 @@ struct UIEditorStatusBarMetrics {
|
|||||||
float cornerRounding = 8.0f;
|
float cornerRounding = 8.0f;
|
||||||
float estimatedGlyphWidth = 7.0f;
|
float estimatedGlyphWidth = 7.0f;
|
||||||
float borderThickness = 1.0f;
|
float borderThickness = 1.0f;
|
||||||
float focusedBorderThickness = 1.5f;
|
float focusedBorderThickness = 2.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UIEditorStatusBarPalette {
|
struct UIEditorStatusBarPalette {
|
||||||
::XCEngine::UI::UIColor surfaceColor =
|
::XCEngine::UI::UIColor surfaceColor =
|
||||||
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.15f, 1.0f);
|
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.16f, 1.0f);
|
||||||
::XCEngine::UI::UIColor borderColor =
|
::XCEngine::UI::UIColor borderColor =
|
||||||
::XCEngine::UI::UIColor(0.28f, 0.28f, 0.28f, 1.0f);
|
::XCEngine::UI::UIColor(0.30f, 0.32f, 0.34f, 1.0f);
|
||||||
::XCEngine::UI::UIColor focusedBorderColor =
|
::XCEngine::UI::UIColor focusedBorderColor =
|
||||||
::XCEngine::UI::UIColor(0.78f, 0.78f, 0.78f, 1.0f);
|
::XCEngine::UI::UIColor(0.78f, 0.80f, 0.84f, 1.0f);
|
||||||
::XCEngine::UI::UIColor segmentColor =
|
::XCEngine::UI::UIColor segmentColor =
|
||||||
::XCEngine::UI::UIColor(0.17f, 0.17f, 0.17f, 1.0f);
|
::XCEngine::UI::UIColor(0.19f, 0.19f, 0.21f, 1.0f);
|
||||||
::XCEngine::UI::UIColor segmentHoveredColor =
|
::XCEngine::UI::UIColor segmentHoveredColor =
|
||||||
::XCEngine::UI::UIColor(0.23f, 0.23f, 0.23f, 1.0f);
|
::XCEngine::UI::UIColor(0.24f, 0.26f, 0.28f, 1.0f);
|
||||||
::XCEngine::UI::UIColor segmentActiveColor =
|
::XCEngine::UI::UIColor segmentActiveColor =
|
||||||
::XCEngine::UI::UIColor(0.29f, 0.29f, 0.29f, 1.0f);
|
::XCEngine::UI::UIColor(0.30f, 0.32f, 0.35f, 1.0f);
|
||||||
::XCEngine::UI::UIColor segmentBorderColor =
|
::XCEngine::UI::UIColor segmentBorderColor =
|
||||||
::XCEngine::UI::UIColor(0.35f, 0.35f, 0.35f, 1.0f);
|
::XCEngine::UI::UIColor(0.42f, 0.44f, 0.47f, 1.0f);
|
||||||
::XCEngine::UI::UIColor separatorColor =
|
::XCEngine::UI::UIColor separatorColor =
|
||||||
::XCEngine::UI::UIColor(0.32f, 0.32f, 0.32f, 1.0f);
|
::XCEngine::UI::UIColor(0.32f, 0.34f, 0.36f, 1.0f);
|
||||||
::XCEngine::UI::UIColor textPrimary =
|
::XCEngine::UI::UIColor textPrimary =
|
||||||
::XCEngine::UI::UIColor(0.92f, 0.92f, 0.92f, 1.0f);
|
::XCEngine::UI::UIColor(0.93f, 0.94f, 0.96f, 1.0f);
|
||||||
::XCEngine::UI::UIColor textMuted =
|
::XCEngine::UI::UIColor textMuted =
|
||||||
::XCEngine::UI::UIColor(0.66f, 0.66f, 0.66f, 1.0f);
|
::XCEngine::UI::UIColor(0.58f, 0.59f, 0.62f, 1.0f);
|
||||||
::XCEngine::UI::UIColor textAccent =
|
::XCEngine::UI::UIColor textAccent =
|
||||||
::XCEngine::UI::UIColor(0.94f, 0.94f, 0.94f, 1.0f);
|
::XCEngine::UI::UIColor(0.82f, 0.86f, 0.93f, 1.0f);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UIEditorStatusBarLayout {
|
struct UIEditorStatusBarLayout {
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorViewportInputBridge.h>
|
#include <XCEditor/Shell/UIEditorViewportInputBridge.h>
|
||||||
#include <XCEditor/Widgets/UIEditorViewportSlot.h>
|
#include <XCEditor/Shell/UIEditorViewportSlot.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEngine/UI/DrawData.h>
|
#include <XCEngine/UI/DrawData.h>
|
||||||
#include <XCEditor/Widgets/UIEditorStatusBar.h>
|
#include <XCEditor/Shell/UIEditorStatusBar.h>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorPanelContentHost.h>
|
#include <XCEditor/Shell/UIEditorPanelContentHost.h>
|
||||||
#include <XCEditor/Core/UIEditorPanelRegistry.h>
|
#include <XCEditor/Shell/UIEditorPanelRegistry.h>
|
||||||
#include <XCEditor/Core/UIEditorViewportShell.h>
|
#include <XCEditor/Shell/UIEditorViewportShell.h>
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceSession.h>
|
#include <XCEditor/Shell/UIEditorWorkspaceSession.h>
|
||||||
#include <XCEditor/Widgets/UIEditorDockHost.h>
|
#include <XCEditor/Shell/UIEditorDockHost.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/DrawData.h>
|
#include <XCEngine/UI/DrawData.h>
|
||||||
|
|
||||||
@@ -78,7 +78,8 @@ UIEditorWorkspaceComposeRequest ResolveUIEditorWorkspaceComposeRequest(
|
|||||||
const UIEditorWorkspaceSession& session,
|
const UIEditorWorkspaceSession& session,
|
||||||
const std::vector<UIEditorWorkspacePanelPresentationModel>& presentations,
|
const std::vector<UIEditorWorkspacePanelPresentationModel>& presentations,
|
||||||
const Widgets::UIEditorDockHostState& dockHostState = {},
|
const Widgets::UIEditorDockHostState& dockHostState = {},
|
||||||
const Widgets::UIEditorDockHostMetrics& dockHostMetrics = {});
|
const Widgets::UIEditorDockHostMetrics& dockHostMetrics = {},
|
||||||
|
const Widgets::UIEditorViewportSlotMetrics& viewportMetrics = {});
|
||||||
|
|
||||||
UIEditorWorkspaceComposeFrame UpdateUIEditorWorkspaceCompose(
|
UIEditorWorkspaceComposeFrame UpdateUIEditorWorkspaceCompose(
|
||||||
UIEditorWorkspaceComposeState& state,
|
UIEditorWorkspaceComposeState& state,
|
||||||
@@ -89,7 +90,8 @@ UIEditorWorkspaceComposeFrame UpdateUIEditorWorkspaceCompose(
|
|||||||
const std::vector<UIEditorWorkspacePanelPresentationModel>& presentations,
|
const std::vector<UIEditorWorkspacePanelPresentationModel>& presentations,
|
||||||
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
|
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
|
||||||
const Widgets::UIEditorDockHostState& dockHostState = {},
|
const Widgets::UIEditorDockHostState& dockHostState = {},
|
||||||
const Widgets::UIEditorDockHostMetrics& dockHostMetrics = {});
|
const Widgets::UIEditorDockHostMetrics& dockHostMetrics = {},
|
||||||
|
const Widgets::UIEditorViewportSlotMetrics& viewportMetrics = {});
|
||||||
|
|
||||||
std::vector<std::string> CollectUIEditorWorkspaceComposeExternalBodyPanelIds(
|
std::vector<std::string> CollectUIEditorWorkspaceComposeExternalBodyPanelIds(
|
||||||
const UIEditorWorkspaceComposeFrame& frame);
|
const UIEditorWorkspaceComposeFrame& frame);
|
||||||
@@ -98,6 +100,8 @@ void AppendUIEditorWorkspaceCompose(
|
|||||||
::XCEngine::UI::UIDrawList& drawList,
|
::XCEngine::UI::UIDrawList& drawList,
|
||||||
const UIEditorWorkspaceComposeFrame& frame,
|
const UIEditorWorkspaceComposeFrame& frame,
|
||||||
const Widgets::UIEditorDockHostPalette& dockHostPalette = {},
|
const Widgets::UIEditorDockHostPalette& dockHostPalette = {},
|
||||||
const Widgets::UIEditorDockHostMetrics& dockHostMetrics = {});
|
const Widgets::UIEditorDockHostMetrics& dockHostMetrics = {},
|
||||||
|
const Widgets::UIEditorViewportSlotPalette& viewportPalette = {},
|
||||||
|
const Widgets::UIEditorViewportSlotMetrics& viewportMetrics = {});
|
||||||
|
|
||||||
} // namespace XCEngine::UI::Editor
|
} // namespace XCEngine::UI::Editor
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceLayoutPersistence.h>
|
#include <XCEditor/Shell/UIEditorWorkspaceLayoutPersistence.h>
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceSession.h>
|
#include <XCEditor/Shell/UIEditorWorkspaceSession.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorDockHostInteraction.h>
|
#include <XCEditor/Shell/UIEditorDockHostInteraction.h>
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceCompose.h>
|
#include <XCEditor/Shell/UIEditorWorkspaceCompose.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Types.h>
|
#include <XCEngine/UI/Types.h>
|
||||||
|
|
||||||
@@ -41,6 +41,7 @@ UIEditorWorkspaceInteractionFrame UpdateUIEditorWorkspaceInteraction(
|
|||||||
const ::XCEngine::UI::UIRect& bounds,
|
const ::XCEngine::UI::UIRect& bounds,
|
||||||
const UIEditorWorkspaceInteractionModel& model,
|
const UIEditorWorkspaceInteractionModel& model,
|
||||||
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
|
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
|
||||||
const Widgets::UIEditorDockHostMetrics& dockHostMetrics = {});
|
const Widgets::UIEditorDockHostMetrics& dockHostMetrics = {},
|
||||||
|
const Widgets::UIEditorViewportSlotMetrics& viewportMetrics = {});
|
||||||
|
|
||||||
} // namespace XCEngine::UI::Editor
|
} // namespace XCEngine::UI::Editor
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceSession.h>
|
#include <XCEditor/Shell/UIEditorWorkspaceSession.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEditor/Core/UIEditorPanelRegistry.h>
|
#include <XCEditor/Shell/UIEditorPanelRegistry.h>
|
||||||
#include <XCEditor/Core/UIEditorWorkspaceModel.h>
|
#include <XCEditor/Shell/UIEditorWorkspaceModel.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <XCEngine/UI/Style/Theme.h>
|
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
@@ -24,14 +22,11 @@ bool UsesUIEditorCollectionPrimitiveColumnLayout(UIEditorCollectionPrimitiveKind
|
|||||||
bool IsUIEditorCollectionPrimitiveHoverable(UIEditorCollectionPrimitiveKind kind);
|
bool IsUIEditorCollectionPrimitiveHoverable(UIEditorCollectionPrimitiveKind kind);
|
||||||
bool DoesUIEditorCollectionPrimitiveClipChildren(UIEditorCollectionPrimitiveKind kind);
|
bool DoesUIEditorCollectionPrimitiveClipChildren(UIEditorCollectionPrimitiveKind kind);
|
||||||
float ResolveUIEditorCollectionPrimitivePadding(
|
float ResolveUIEditorCollectionPrimitivePadding(
|
||||||
UIEditorCollectionPrimitiveKind kind,
|
UIEditorCollectionPrimitiveKind kind);
|
||||||
const ::XCEngine::UI::Style::UITheme& theme);
|
|
||||||
float ResolveUIEditorCollectionPrimitiveDefaultHeight(
|
float ResolveUIEditorCollectionPrimitiveDefaultHeight(
|
||||||
UIEditorCollectionPrimitiveKind kind,
|
UIEditorCollectionPrimitiveKind kind);
|
||||||
const ::XCEngine::UI::Style::UITheme& theme);
|
|
||||||
float ResolveUIEditorCollectionPrimitiveIndent(
|
float ResolveUIEditorCollectionPrimitiveIndent(
|
||||||
UIEditorCollectionPrimitiveKind kind,
|
UIEditorCollectionPrimitiveKind kind,
|
||||||
const ::XCEngine::UI::Style::UITheme& theme,
|
|
||||||
float indentLevel);
|
float indentLevel);
|
||||||
|
|
||||||
} // namespace XCEngine::UI::Editor::Widgets
|
} // namespace XCEngine::UI::Editor::Widgets
|
||||||
|
|||||||
178
new_editor/include/XCEditor/Widgets/UIEditorColorUtils.h
Normal file
178
new_editor/include/XCEditor/Widgets/UIEditorColorUtils.h
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEngine/UI/DrawData.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor::Widgets {
|
||||||
|
|
||||||
|
struct UIEditorHsvColor {
|
||||||
|
float hue = 0.0f;
|
||||||
|
float saturation = 0.0f;
|
||||||
|
float value = 0.0f;
|
||||||
|
float alpha = 1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline float ClampUIEditorColorUnit(float value) {
|
||||||
|
return (std::clamp)(value, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int ToUIEditorColorByte(float value) {
|
||||||
|
return static_cast<int>(std::lround(ClampUIEditorColorUnit(value) * 255.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline UIEditorHsvColor ConvertUIEditorColorToHsv(
|
||||||
|
const ::XCEngine::UI::UIColor& color,
|
||||||
|
float fallbackHue = 0.0f) {
|
||||||
|
const float red = ClampUIEditorColorUnit(color.r);
|
||||||
|
const float green = ClampUIEditorColorUnit(color.g);
|
||||||
|
const float blue = ClampUIEditorColorUnit(color.b);
|
||||||
|
const float maxChannel = (std::max)({ red, green, blue });
|
||||||
|
const float minChannel = (std::min)({ red, green, blue });
|
||||||
|
const float delta = maxChannel - minChannel;
|
||||||
|
|
||||||
|
UIEditorHsvColor hsv = {};
|
||||||
|
hsv.hue = ClampUIEditorColorUnit(fallbackHue);
|
||||||
|
hsv.saturation = maxChannel <= 0.0f ? 0.0f : delta / maxChannel;
|
||||||
|
hsv.value = maxChannel;
|
||||||
|
hsv.alpha = ClampUIEditorColorUnit(color.a);
|
||||||
|
|
||||||
|
if (delta <= 0.00001f) {
|
||||||
|
return hsv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxChannel == red) {
|
||||||
|
hsv.hue = std::fmod(((green - blue) / delta), 6.0f) / 6.0f;
|
||||||
|
} else if (maxChannel == green) {
|
||||||
|
hsv.hue = (((blue - red) / delta) + 2.0f) / 6.0f;
|
||||||
|
} else {
|
||||||
|
hsv.hue = (((red - green) / delta) + 4.0f) / 6.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hsv.hue < 0.0f) {
|
||||||
|
hsv.hue += 1.0f;
|
||||||
|
}
|
||||||
|
return hsv;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ::XCEngine::UI::UIColor ConvertUIEditorHsvToColor(const UIEditorHsvColor& hsv) {
|
||||||
|
const float hue = ClampUIEditorColorUnit(hsv.hue);
|
||||||
|
const float saturation = ClampUIEditorColorUnit(hsv.saturation);
|
||||||
|
const float value = ClampUIEditorColorUnit(hsv.value);
|
||||||
|
|
||||||
|
if (saturation <= 0.00001f) {
|
||||||
|
return ::XCEngine::UI::UIColor(value, value, value, ClampUIEditorColorUnit(hsv.alpha));
|
||||||
|
}
|
||||||
|
|
||||||
|
const float sector = hue * 6.0f;
|
||||||
|
const int sectorIndex = static_cast<int>(std::floor(sector)) % 6;
|
||||||
|
const float fraction = sector - std::floor(sector);
|
||||||
|
const float p = value * (1.0f - saturation);
|
||||||
|
const float q = value * (1.0f - saturation * fraction);
|
||||||
|
const float t = value * (1.0f - saturation * (1.0f - fraction));
|
||||||
|
|
||||||
|
float red = value;
|
||||||
|
float green = t;
|
||||||
|
float blue = p;
|
||||||
|
switch (sectorIndex) {
|
||||||
|
case 0:
|
||||||
|
red = value;
|
||||||
|
green = t;
|
||||||
|
blue = p;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
red = q;
|
||||||
|
green = value;
|
||||||
|
blue = p;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
red = p;
|
||||||
|
green = value;
|
||||||
|
blue = t;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
red = p;
|
||||||
|
green = q;
|
||||||
|
blue = value;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
red = t;
|
||||||
|
green = p;
|
||||||
|
blue = value;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
default:
|
||||||
|
red = value;
|
||||||
|
green = p;
|
||||||
|
blue = q;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ::XCEngine::UI::UIColor(red, green, blue, ClampUIEditorColorUnit(hsv.alpha));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline UIEditorHsvColor ResolveUIEditorDisplayHsv(
|
||||||
|
const ::XCEngine::UI::UIColor& color,
|
||||||
|
float rememberedHue,
|
||||||
|
bool hueValid) {
|
||||||
|
UIEditorHsvColor hsv = ConvertUIEditorColorToHsv(color, hueValid ? rememberedHue : 0.0f);
|
||||||
|
if (hsv.saturation <= 0.00001f && hueValid) {
|
||||||
|
hsv.hue = ClampUIEditorColorUnit(rememberedHue);
|
||||||
|
}
|
||||||
|
return hsv;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string FormatUIEditorColorHex(
|
||||||
|
const ::XCEngine::UI::UIColor& color,
|
||||||
|
bool includeAlpha = true) {
|
||||||
|
char buffer[16] = {};
|
||||||
|
if (includeAlpha) {
|
||||||
|
std::snprintf(
|
||||||
|
buffer,
|
||||||
|
sizeof(buffer),
|
||||||
|
"#%02X%02X%02X%02X",
|
||||||
|
ToUIEditorColorByte(color.r),
|
||||||
|
ToUIEditorColorByte(color.g),
|
||||||
|
ToUIEditorColorByte(color.b),
|
||||||
|
ToUIEditorColorByte(color.a));
|
||||||
|
} else {
|
||||||
|
std::snprintf(
|
||||||
|
buffer,
|
||||||
|
sizeof(buffer),
|
||||||
|
"#%02X%02X%02X",
|
||||||
|
ToUIEditorColorByte(color.r),
|
||||||
|
ToUIEditorColorByte(color.g),
|
||||||
|
ToUIEditorColorByte(color.b));
|
||||||
|
}
|
||||||
|
return std::string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string FormatUIEditorColorChannelsText(
|
||||||
|
const ::XCEngine::UI::UIColor& color,
|
||||||
|
bool includeAlpha = true) {
|
||||||
|
char buffer[64] = {};
|
||||||
|
if (includeAlpha) {
|
||||||
|
std::snprintf(
|
||||||
|
buffer,
|
||||||
|
sizeof(buffer),
|
||||||
|
"RGBA %d, %d, %d, %d",
|
||||||
|
ToUIEditorColorByte(color.r),
|
||||||
|
ToUIEditorColorByte(color.g),
|
||||||
|
ToUIEditorColorByte(color.b),
|
||||||
|
ToUIEditorColorByte(color.a));
|
||||||
|
} else {
|
||||||
|
std::snprintf(
|
||||||
|
buffer,
|
||||||
|
sizeof(buffer),
|
||||||
|
"RGB %d, %d, %d",
|
||||||
|
ToUIEditorColorByte(color.r),
|
||||||
|
ToUIEditorColorByte(color.g),
|
||||||
|
ToUIEditorColorByte(color.b));
|
||||||
|
}
|
||||||
|
return std::string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor::Widgets
|
||||||
@@ -4,6 +4,95 @@
|
|||||||
|
|
||||||
namespace XCEngine::UI::Editor::Widgets {
|
namespace XCEngine::UI::Editor::Widgets {
|
||||||
|
|
||||||
|
struct UIEditorInspectorFieldStyleTokens {
|
||||||
|
::XCEngine::UI::UIColor rowHoverColor =
|
||||||
|
::XCEngine::UI::UIColor(0.20f, 0.20f, 0.20f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor rowActiveColor =
|
||||||
|
::XCEngine::UI::UIColor(0.24f, 0.24f, 0.24f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor labelColor =
|
||||||
|
::XCEngine::UI::UIColor(0.80f, 0.80f, 0.80f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor valueColor =
|
||||||
|
::XCEngine::UI::UIColor(0.92f, 0.92f, 0.92f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor readOnlyValueColor =
|
||||||
|
::XCEngine::UI::UIColor(0.60f, 0.60f, 0.60f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor controlColor =
|
||||||
|
::XCEngine::UI::UIColor(0.18f, 0.18f, 0.18f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor controlHoverColor =
|
||||||
|
::XCEngine::UI::UIColor(0.21f, 0.21f, 0.21f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor controlEditingColor =
|
||||||
|
::XCEngine::UI::UIColor(0.24f, 0.24f, 0.24f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor controlReadOnlyColor =
|
||||||
|
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.15f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor controlBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.30f, 0.30f, 0.30f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor controlFocusedBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.64f, 0.64f, 0.64f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor prefixColor =
|
||||||
|
::XCEngine::UI::UIColor(0.20f, 0.20f, 0.20f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor prefixBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.31f, 0.31f, 0.31f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor axisXColor =
|
||||||
|
::XCEngine::UI::UIColor(0.78f, 0.42f, 0.42f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor axisYColor =
|
||||||
|
::XCEngine::UI::UIColor(0.56f, 0.72f, 0.46f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor axisZColor =
|
||||||
|
::XCEngine::UI::UIColor(0.45f, 0.62f, 0.82f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor axisWColor =
|
||||||
|
::XCEngine::UI::UIColor(0.76f, 0.66f, 0.42f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor arrowColor =
|
||||||
|
::XCEngine::UI::UIColor(0.88f, 0.88f, 0.88f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor swatchBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.30f, 0.30f, 0.30f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor swatchHoverBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.64f, 0.64f, 0.64f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor swatchReadOnlyOverlayColor =
|
||||||
|
::XCEngine::UI::UIColor(0.08f, 0.08f, 0.08f, 0.18f);
|
||||||
|
::XCEngine::UI::UIColor popupColor =
|
||||||
|
::XCEngine::UI::UIColor(0.20f, 0.20f, 0.20f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor popupBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.12f, 0.12f, 0.12f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor popupHeaderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.17f, 0.17f, 0.17f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor popupTitleColor =
|
||||||
|
::XCEngine::UI::UIColor(0.93f, 0.93f, 0.93f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor popupTextColor =
|
||||||
|
::XCEngine::UI::UIColor(0.86f, 0.86f, 0.86f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor popupTextMutedColor =
|
||||||
|
::XCEngine::UI::UIColor(0.72f, 0.72f, 0.72f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor previewBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.11f, 0.11f, 0.11f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor previewBaseColor =
|
||||||
|
::XCEngine::UI::UIColor(0.19f, 0.19f, 0.19f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor checkerLightColor =
|
||||||
|
::XCEngine::UI::UIColor(0.84f, 0.84f, 0.84f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor checkerDarkColor =
|
||||||
|
::XCEngine::UI::UIColor(0.55f, 0.55f, 0.55f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor sliderBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.11f, 0.11f, 0.11f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor numericBoxColor =
|
||||||
|
::XCEngine::UI::UIColor(0.17f, 0.17f, 0.17f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor numericBoxBorderColor =
|
||||||
|
::XCEngine::UI::UIColor(0.11f, 0.11f, 0.11f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor numericBoxTextColor =
|
||||||
|
::XCEngine::UI::UIColor(0.93f, 0.93f, 0.93f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor closeButtonColor =
|
||||||
|
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
::XCEngine::UI::UIColor closeButtonHoverColor =
|
||||||
|
::XCEngine::UI::UIColor(0.25f, 0.25f, 0.25f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor closeGlyphColor =
|
||||||
|
::XCEngine::UI::UIColor(0.85f, 0.85f, 0.85f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor handleFillColor =
|
||||||
|
::XCEngine::UI::UIColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
::XCEngine::UI::UIColor handleStrokeColor =
|
||||||
|
::XCEngine::UI::UIColor(0.10f, 0.10f, 0.10f, 0.5f);
|
||||||
|
float controlTrailingInset = 9.0f;
|
||||||
|
float controlMinWidth = 88.0f;
|
||||||
|
float dropdownArrowWidth = 14.0f;
|
||||||
|
float vectorComponentMinWidth = 74.0f;
|
||||||
|
float vectorPrefixWidth = 18.0f;
|
||||||
|
float vectorPrefixGap = 5.0f;
|
||||||
|
};
|
||||||
|
|
||||||
struct UIEditorFieldRowLayoutMetrics {
|
struct UIEditorFieldRowLayoutMetrics {
|
||||||
float rowHeight = 22.0f;
|
float rowHeight = 22.0f;
|
||||||
float horizontalPadding = 12.0f;
|
float horizontalPadding = 12.0f;
|
||||||
@@ -19,6 +108,14 @@ struct UIEditorFieldRowLayout {
|
|||||||
::XCEngine::UI::UIRect controlRect = {};
|
::XCEngine::UI::UIRect controlRect = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const UIEditorInspectorFieldStyleTokens& GetUIEditorInspectorFieldStyleTokens();
|
||||||
|
|
||||||
|
bool AreUIEditorFieldMetricsEqual(float lhs, float rhs);
|
||||||
|
|
||||||
|
bool AreUIEditorFieldColorsEqual(
|
||||||
|
const ::XCEngine::UI::UIColor& lhs,
|
||||||
|
const ::XCEngine::UI::UIColor& rhs);
|
||||||
|
|
||||||
UIEditorFieldRowLayout BuildUIEditorFieldRowLayout(
|
UIEditorFieldRowLayout BuildUIEditorFieldRowLayout(
|
||||||
const ::XCEngine::UI::UIRect& bounds,
|
const ::XCEngine::UI::UIRect& bounds,
|
||||||
float minimumControlWidth,
|
float minimumControlWidth,
|
||||||
|
|||||||
@@ -1,132 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <XCEngine/UI/DrawData.h>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
|
||||||
|
|
||||||
namespace XCEngine::UI::Editor::Widgets {
|
|
||||||
|
|
||||||
struct UIEditorPanelChromeState {
|
|
||||||
bool active = false;
|
|
||||||
bool hovered = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct UIEditorPanelChromeText {
|
|
||||||
std::string_view title = {};
|
|
||||||
std::string_view subtitle = {};
|
|
||||||
std::string_view footer = {};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct UIEditorPanelChromeMetrics {
|
|
||||||
float cornerRounding = 18.0f;
|
|
||||||
float headerHeight = 42.0f;
|
|
||||||
float titleInsetX = 16.0f;
|
|
||||||
float titleInsetY = 12.0f;
|
|
||||||
float subtitleInsetY = 28.0f;
|
|
||||||
float footerInsetX = 16.0f;
|
|
||||||
float footerInsetBottom = 18.0f;
|
|
||||||
float activeBorderThickness = 2.0f;
|
|
||||||
float inactiveBorderThickness = 1.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct UIEditorPanelChromePalette {
|
|
||||||
::XCEngine::UI::UIColor surfaceColor =
|
|
||||||
::XCEngine::UI::UIColor(9.0f / 255.0f, 13.0f / 255.0f, 18.0f / 255.0f, 212.0f / 255.0f);
|
|
||||||
::XCEngine::UI::UIColor borderColor =
|
|
||||||
::XCEngine::UI::UIColor(53.0f / 255.0f, 72.0f / 255.0f, 96.0f / 255.0f, 1.0f);
|
|
||||||
::XCEngine::UI::UIColor accentColor =
|
|
||||||
::XCEngine::UI::UIColor(84.0f / 255.0f, 176.0f / 255.0f, 244.0f / 255.0f, 1.0f);
|
|
||||||
::XCEngine::UI::UIColor hoveredAccentColor =
|
|
||||||
::XCEngine::UI::UIColor(1.0f, 206.0f / 255.0f, 112.0f / 255.0f, 1.0f);
|
|
||||||
::XCEngine::UI::UIColor headerColor =
|
|
||||||
::XCEngine::UI::UIColor(13.0f / 255.0f, 20.0f / 255.0f, 28.0f / 255.0f, 242.0f / 255.0f);
|
|
||||||
::XCEngine::UI::UIColor textPrimary =
|
|
||||||
::XCEngine::UI::UIColor(232.0f / 255.0f, 238.0f / 255.0f, 246.0f / 255.0f, 1.0f);
|
|
||||||
::XCEngine::UI::UIColor textSecondary =
|
|
||||||
::XCEngine::UI::UIColor(150.0f / 255.0f, 164.0f / 255.0f, 184.0f / 255.0f, 1.0f);
|
|
||||||
::XCEngine::UI::UIColor textMuted =
|
|
||||||
::XCEngine::UI::UIColor(108.0f / 255.0f, 123.0f / 255.0f, 145.0f / 255.0f, 1.0f);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline ::XCEngine::UI::UIRect BuildUIEditorPanelChromeHeaderRect(
|
|
||||||
const ::XCEngine::UI::UIRect& panelRect,
|
|
||||||
const UIEditorPanelChromeMetrics& metrics = {}) {
|
|
||||||
return ::XCEngine::UI::UIRect(
|
|
||||||
panelRect.x,
|
|
||||||
panelRect.y,
|
|
||||||
panelRect.width,
|
|
||||||
metrics.headerHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ::XCEngine::UI::UIColor ResolveUIEditorPanelChromeBorderColor(
|
|
||||||
const UIEditorPanelChromeState& state,
|
|
||||||
const UIEditorPanelChromePalette& palette = {}) {
|
|
||||||
if (state.active) {
|
|
||||||
return palette.accentColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.hovered) {
|
|
||||||
return palette.hoveredAccentColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
return palette.borderColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float ResolveUIEditorPanelChromeBorderThickness(
|
|
||||||
const UIEditorPanelChromeState& state,
|
|
||||||
const UIEditorPanelChromeMetrics& metrics = {}) {
|
|
||||||
return state.active
|
|
||||||
? metrics.activeBorderThickness
|
|
||||||
: metrics.inactiveBorderThickness;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void AppendUIEditorPanelChromeBackground(
|
|
||||||
::XCEngine::UI::UIDrawList& drawList,
|
|
||||||
const ::XCEngine::UI::UIRect& panelRect,
|
|
||||||
const UIEditorPanelChromeState& state,
|
|
||||||
const UIEditorPanelChromePalette& palette = {},
|
|
||||||
const UIEditorPanelChromeMetrics& metrics = {}) {
|
|
||||||
drawList.AddFilledRect(panelRect, palette.surfaceColor, metrics.cornerRounding);
|
|
||||||
drawList.AddRectOutline(
|
|
||||||
panelRect,
|
|
||||||
ResolveUIEditorPanelChromeBorderColor(state, palette),
|
|
||||||
ResolveUIEditorPanelChromeBorderThickness(state, metrics),
|
|
||||||
metrics.cornerRounding);
|
|
||||||
drawList.AddFilledRect(
|
|
||||||
BuildUIEditorPanelChromeHeaderRect(panelRect, metrics),
|
|
||||||
palette.headerColor,
|
|
||||||
metrics.cornerRounding);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void AppendUIEditorPanelChromeForeground(
|
|
||||||
::XCEngine::UI::UIDrawList& drawList,
|
|
||||||
const ::XCEngine::UI::UIRect& panelRect,
|
|
||||||
const UIEditorPanelChromeText& text,
|
|
||||||
const UIEditorPanelChromePalette& palette = {},
|
|
||||||
const UIEditorPanelChromeMetrics& metrics = {}) {
|
|
||||||
if (!text.title.empty()) {
|
|
||||||
drawList.AddText(
|
|
||||||
::XCEngine::UI::UIPoint(panelRect.x + metrics.titleInsetX, panelRect.y + metrics.titleInsetY),
|
|
||||||
std::string(text.title),
|
|
||||||
palette.textPrimary);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!text.subtitle.empty()) {
|
|
||||||
drawList.AddText(
|
|
||||||
::XCEngine::UI::UIPoint(panelRect.x + metrics.titleInsetX, panelRect.y + metrics.subtitleInsetY),
|
|
||||||
std::string(text.subtitle),
|
|
||||||
palette.textSecondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!text.footer.empty()) {
|
|
||||||
drawList.AddText(
|
|
||||||
::XCEngine::UI::UIPoint(
|
|
||||||
panelRect.x + metrics.footerInsetX,
|
|
||||||
panelRect.y + panelRect.height - metrics.footerInsetBottom),
|
|
||||||
std::string(text.footer),
|
|
||||||
palette.textMuted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace XCEngine::UI::Editor::Widgets
|
|
||||||
114
new_editor/src/Collections/UIEditorInlineRenameSession.cpp
Normal file
114
new_editor/src/Collections/UIEditorInlineRenameSession.cpp
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
#include <XCEditor/Collections/UIEditorInlineRenameSession.h>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor {
|
||||||
|
|
||||||
|
Widgets::UIEditorTextFieldMetrics BuildUIEditorInlineRenameTextFieldMetrics(
|
||||||
|
const ::XCEngine::UI::UIRect& bounds,
|
||||||
|
const Widgets::UIEditorTextFieldMetrics& metrics) {
|
||||||
|
Widgets::UIEditorTextFieldMetrics resolved = metrics;
|
||||||
|
resolved.rowHeight = bounds.height > 0.0f ? bounds.height : metrics.rowHeight;
|
||||||
|
resolved.horizontalPadding = 0.0f;
|
||||||
|
resolved.labelControlGap = 0.0f;
|
||||||
|
resolved.controlColumnStart = 0.0f;
|
||||||
|
resolved.controlTrailingInset = 0.0f;
|
||||||
|
resolved.valueBoxMinWidth = bounds.width;
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void ResetSession(UIEditorInlineRenameSessionState& state) {
|
||||||
|
state = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeginSession(
|
||||||
|
UIEditorInlineRenameSessionState& state,
|
||||||
|
const UIEditorInlineRenameSessionRequest& request,
|
||||||
|
UIEditorInlineRenameSessionResult& result) {
|
||||||
|
ResetSession(state);
|
||||||
|
state.active = true;
|
||||||
|
state.itemId = request.itemId;
|
||||||
|
state.textFieldSpec.fieldId = request.itemId;
|
||||||
|
state.textFieldSpec.label.clear();
|
||||||
|
state.textFieldSpec.value = request.initialText;
|
||||||
|
state.textFieldSpec.readOnly = false;
|
||||||
|
state.textFieldInteraction.textFieldState.focused = true;
|
||||||
|
state.textFieldInteraction.textFieldState.editing = true;
|
||||||
|
state.textFieldInteraction.textFieldState.displayText = request.initialText;
|
||||||
|
state.textFieldInteraction.textInputState.value = request.initialText;
|
||||||
|
state.textFieldInteraction.textInputState.caret = request.initialText.size();
|
||||||
|
state.textFieldInteraction.editModel.BeginEdit(request.itemId, request.initialText);
|
||||||
|
|
||||||
|
result.sessionStarted = true;
|
||||||
|
result.active = true;
|
||||||
|
result.itemId = request.itemId;
|
||||||
|
result.valueBefore = request.initialText;
|
||||||
|
result.valueAfter = request.initialText;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
UIEditorInlineRenameSessionFrame UpdateUIEditorInlineRenameSession(
|
||||||
|
UIEditorInlineRenameSessionState& state,
|
||||||
|
const UIEditorInlineRenameSessionRequest& request,
|
||||||
|
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
|
||||||
|
const Widgets::UIEditorTextFieldMetrics& metrics) {
|
||||||
|
UIEditorInlineRenameSessionResult result = {};
|
||||||
|
|
||||||
|
if (request.beginSession &&
|
||||||
|
!request.itemId.empty() &&
|
||||||
|
(!state.active || state.itemId != request.itemId)) {
|
||||||
|
BeginSession(state, request, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets::UIEditorTextFieldLayout layout = {};
|
||||||
|
if (!state.active) {
|
||||||
|
return {
|
||||||
|
std::move(layout),
|
||||||
|
std::move(result)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const Widgets::UIEditorTextFieldMetrics inlineMetrics =
|
||||||
|
BuildUIEditorInlineRenameTextFieldMetrics(request.bounds, metrics);
|
||||||
|
const std::string valueBefore = state.textFieldSpec.value;
|
||||||
|
UIEditorTextFieldInteractionFrame textFieldFrame =
|
||||||
|
UpdateUIEditorTextFieldInteraction(
|
||||||
|
state.textFieldInteraction,
|
||||||
|
state.textFieldSpec,
|
||||||
|
request.bounds,
|
||||||
|
inputEvents,
|
||||||
|
inlineMetrics);
|
||||||
|
|
||||||
|
layout = textFieldFrame.layout;
|
||||||
|
result.textFieldResult = textFieldFrame.result;
|
||||||
|
result.itemId = state.itemId;
|
||||||
|
result.active = state.active;
|
||||||
|
result.consumed = textFieldFrame.result.consumed;
|
||||||
|
result.valueBefore = textFieldFrame.result.valueBefore.empty()
|
||||||
|
? valueBefore
|
||||||
|
: textFieldFrame.result.valueBefore;
|
||||||
|
result.valueAfter = state.textFieldSpec.value;
|
||||||
|
|
||||||
|
if (textFieldFrame.result.editCommitted) {
|
||||||
|
result.sessionCommitted = true;
|
||||||
|
result.valueChanged = textFieldFrame.result.valueChanged;
|
||||||
|
result.valueAfter = state.textFieldSpec.value;
|
||||||
|
ResetSession(state);
|
||||||
|
result.active = false;
|
||||||
|
} else if (textFieldFrame.result.editCanceled) {
|
||||||
|
result.sessionCanceled = true;
|
||||||
|
result.valueAfter = result.valueBefore;
|
||||||
|
ResetSession(state);
|
||||||
|
result.active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
std::move(layout),
|
||||||
|
std::move(result)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include <XCEditor/Widgets/UIEditorListView.h>
|
#include <XCEditor/Collections/UIEditorListView.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
#include <XCEditor/Core/UIEditorListViewInteraction.h>
|
#include <XCEditor/Collections/UIEditorListViewInteraction.h>
|
||||||
|
|
||||||
#include <XCEngine/Input/InputTypes.h>
|
#include <XCEngine/Input/InputTypes.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace XCEngine::UI::Editor {
|
namespace XCEngine::UI::Editor {
|
||||||
@@ -33,10 +34,6 @@ bool ShouldUsePointerPosition(const UIInputEvent& event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasNavigationModifiers(const ::XCEngine::UI::UIInputModifiers& modifiers) {
|
|
||||||
return modifiers.shift || modifiers.control || modifiers.alt || modifiers.super;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SyncHoverTarget(
|
void SyncHoverTarget(
|
||||||
UIEditorListViewInteractionState& state,
|
UIEditorListViewInteractionState& state,
|
||||||
const Widgets::UIEditorListViewLayout& layout,
|
const Widgets::UIEditorListViewLayout& layout,
|
||||||
@@ -76,21 +73,156 @@ void SyncKeyboardNavigation(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SyncSelectionAnchor(
|
||||||
|
UIEditorListViewInteractionState& state,
|
||||||
|
const ::XCEngine::UI::Widgets::UISelectionModel& selectionModel) {
|
||||||
|
if (!selectionModel.HasSelection()) {
|
||||||
|
state.selectionAnchorId.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.selectionAnchorId.empty() ||
|
||||||
|
!selectionModel.IsSelected(state.selectionAnchorId)) {
|
||||||
|
state.selectionAnchorId = selectionModel.GetSelectedId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectItem(
|
||||||
|
UIEditorListViewInteractionState& state,
|
||||||
|
::XCEngine::UI::Widgets::UISelectionModel& selectionModel,
|
||||||
|
const std::vector<Widgets::UIEditorListViewItem>& items,
|
||||||
|
std::size_t itemIndex,
|
||||||
|
UIEditorListViewInteractionResult& result,
|
||||||
|
bool markKeyboardNavigation) {
|
||||||
|
if (itemIndex >= items.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Widgets::UIEditorListViewItem& item = items[itemIndex];
|
||||||
|
result.selectionChanged = selectionModel.SetSelection(item.itemId);
|
||||||
|
result.selectedItemId = item.itemId;
|
||||||
|
result.selectedIndex = itemIndex;
|
||||||
|
result.keyboardNavigated = markKeyboardNavigation;
|
||||||
|
result.consumed = true;
|
||||||
|
state.keyboardNavigation.SetCurrentIndex(itemIndex);
|
||||||
|
state.selectionAnchorId = item.itemId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ToggleItemSelection(
|
||||||
|
UIEditorListViewInteractionState& state,
|
||||||
|
::XCEngine::UI::Widgets::UISelectionModel& selectionModel,
|
||||||
|
const std::vector<Widgets::UIEditorListViewItem>& items,
|
||||||
|
std::size_t itemIndex,
|
||||||
|
UIEditorListViewInteractionResult& result) {
|
||||||
|
if (itemIndex >= items.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Widgets::UIEditorListViewItem& item = items[itemIndex];
|
||||||
|
result.selectionChanged = selectionModel.ToggleSelectionMembership(item.itemId, true);
|
||||||
|
result.selectedItemId = item.itemId;
|
||||||
|
result.selectedIndex = itemIndex;
|
||||||
|
result.consumed = true;
|
||||||
|
state.keyboardNavigation.SetCurrentIndex(itemIndex);
|
||||||
|
state.selectionAnchorId = item.itemId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectItemRange(
|
||||||
|
UIEditorListViewInteractionState& state,
|
||||||
|
::XCEngine::UI::Widgets::UISelectionModel& selectionModel,
|
||||||
|
const std::vector<Widgets::UIEditorListViewItem>& items,
|
||||||
|
std::size_t itemIndex,
|
||||||
|
UIEditorListViewInteractionResult& result,
|
||||||
|
bool markKeyboardNavigation) {
|
||||||
|
if (itemIndex >= items.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t anchorIndex = UIEditorListViewInvalidIndex;
|
||||||
|
if (!state.selectionAnchorId.empty()) {
|
||||||
|
anchorIndex = FindUIEditorListViewItemIndex(items, state.selectionAnchorId);
|
||||||
|
}
|
||||||
|
if (anchorIndex == UIEditorListViewInvalidIndex) {
|
||||||
|
return SelectItem(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
items,
|
||||||
|
itemIndex,
|
||||||
|
result,
|
||||||
|
markKeyboardNavigation);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t rangeBegin = (std::min)(anchorIndex, itemIndex);
|
||||||
|
const std::size_t rangeEnd = (std::max)(anchorIndex, itemIndex);
|
||||||
|
std::vector<std::string> selectedIds = {};
|
||||||
|
selectedIds.reserve(rangeEnd - rangeBegin + 1u);
|
||||||
|
for (std::size_t index = rangeBegin; index <= rangeEnd; ++index) {
|
||||||
|
selectedIds.push_back(items[index].itemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Widgets::UIEditorListViewItem& item = items[itemIndex];
|
||||||
|
result.selectionChanged = selectionModel.SetSelections(std::move(selectedIds), item.itemId);
|
||||||
|
result.selectedItemId = item.itemId;
|
||||||
|
result.selectedIndex = itemIndex;
|
||||||
|
result.keyboardNavigated = markKeyboardNavigation;
|
||||||
|
result.consumed = true;
|
||||||
|
state.keyboardNavigation.SetCurrentIndex(itemIndex, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ApplyKeyboardNavigation(
|
bool ApplyKeyboardNavigation(
|
||||||
UIEditorListViewInteractionState& state,
|
UIEditorListViewInteractionState& state,
|
||||||
std::int32_t keyCode) {
|
::XCEngine::UI::Widgets::UISelectionModel& selectionModel,
|
||||||
|
const std::vector<Widgets::UIEditorListViewItem>& items,
|
||||||
|
std::int32_t keyCode,
|
||||||
|
UIEditorListViewInteractionResult& result,
|
||||||
|
bool extendSelectionRange) {
|
||||||
switch (static_cast<KeyCode>(keyCode)) {
|
switch (static_cast<KeyCode>(keyCode)) {
|
||||||
case KeyCode::Up:
|
case KeyCode::Up:
|
||||||
return state.keyboardNavigation.MovePrevious();
|
if (!state.keyboardNavigation.MovePrevious()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case KeyCode::Down:
|
case KeyCode::Down:
|
||||||
return state.keyboardNavigation.MoveNext();
|
if (!state.keyboardNavigation.MoveNext()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case KeyCode::Home:
|
case KeyCode::Home:
|
||||||
return state.keyboardNavigation.MoveHome();
|
if (!state.keyboardNavigation.MoveHome()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case KeyCode::End:
|
case KeyCode::End:
|
||||||
return state.keyboardNavigation.MoveEnd();
|
if (!state.keyboardNavigation.MoveEnd()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!state.keyboardNavigation.HasCurrentIndex()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return extendSelectionRange
|
||||||
|
? SelectItemRange(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
items,
|
||||||
|
state.keyboardNavigation.GetCurrentIndex(),
|
||||||
|
result,
|
||||||
|
true)
|
||||||
|
: SelectItem(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
items,
|
||||||
|
state.keyboardNavigation.GetCurrentIndex(),
|
||||||
|
result,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -105,6 +237,7 @@ UIEditorListViewInteractionFrame UpdateUIEditorListViewInteraction(
|
|||||||
Widgets::UIEditorListViewLayout layout =
|
Widgets::UIEditorListViewLayout layout =
|
||||||
BuildUIEditorListViewLayout(bounds, items, metrics);
|
BuildUIEditorListViewLayout(bounds, items, metrics);
|
||||||
SyncKeyboardNavigation(state, selectionModel, items);
|
SyncKeyboardNavigation(state, selectionModel, items);
|
||||||
|
SyncSelectionAnchor(state, selectionModel);
|
||||||
SyncHoverTarget(state, layout, items);
|
SyncHoverTarget(state, layout, items);
|
||||||
|
|
||||||
UIEditorListViewInteractionResult interactionResult = {};
|
UIEditorListViewInteractionResult interactionResult = {};
|
||||||
@@ -180,38 +313,79 @@ UIEditorListViewInteractionFrame UpdateUIEditorListViewInteraction(
|
|||||||
const Widgets::UIEditorListViewItem& item = items[hitTarget.itemIndex];
|
const Widgets::UIEditorListViewItem& item = items[hitTarget.itemIndex];
|
||||||
if (event.pointerButton == UIPointerButton::Left &&
|
if (event.pointerButton == UIPointerButton::Left &&
|
||||||
hitTarget.kind == UIEditorListViewHitTargetKind::Row) {
|
hitTarget.kind == UIEditorListViewHitTargetKind::Row) {
|
||||||
eventResult.selectionChanged = selectionModel.SetSelection(item.itemId);
|
if (event.modifiers.shift) {
|
||||||
|
SelectItemRange(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
items,
|
||||||
|
hitTarget.itemIndex,
|
||||||
|
eventResult,
|
||||||
|
false);
|
||||||
|
} else if (event.modifiers.control) {
|
||||||
|
ToggleItemSelection(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
items,
|
||||||
|
hitTarget.itemIndex,
|
||||||
|
eventResult);
|
||||||
|
} else {
|
||||||
|
SelectItem(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
items,
|
||||||
|
hitTarget.itemIndex,
|
||||||
|
eventResult,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
state.listViewState.focused = true;
|
||||||
|
} else if (event.pointerButton == UIPointerButton::Right &&
|
||||||
|
hitTarget.kind == UIEditorListViewHitTargetKind::Row) {
|
||||||
|
if (selectionModel.IsSelected(item.itemId)) {
|
||||||
|
selectionModel.SetPrimarySelection(item.itemId);
|
||||||
|
eventResult.selectionChanged = false;
|
||||||
eventResult.selectedItemId = item.itemId;
|
eventResult.selectedItemId = item.itemId;
|
||||||
eventResult.selectedIndex = hitTarget.itemIndex;
|
eventResult.selectedIndex = hitTarget.itemIndex;
|
||||||
eventResult.consumed = true;
|
eventResult.consumed = true;
|
||||||
state.listViewState.focused = true;
|
|
||||||
state.keyboardNavigation.SetCurrentIndex(hitTarget.itemIndex);
|
state.keyboardNavigation.SetCurrentIndex(hitTarget.itemIndex);
|
||||||
} else if (event.pointerButton == UIPointerButton::Right &&
|
state.selectionAnchorId = item.itemId;
|
||||||
hitTarget.kind == UIEditorListViewHitTargetKind::Row) {
|
} else {
|
||||||
eventResult.selectionChanged = selectionModel.SetSelection(item.itemId);
|
SelectItem(
|
||||||
eventResult.selectedItemId = item.itemId;
|
state,
|
||||||
eventResult.selectedIndex = hitTarget.itemIndex;
|
selectionModel,
|
||||||
|
items,
|
||||||
|
hitTarget.itemIndex,
|
||||||
|
eventResult,
|
||||||
|
false);
|
||||||
|
}
|
||||||
eventResult.secondaryClicked = true;
|
eventResult.secondaryClicked = true;
|
||||||
eventResult.consumed = true;
|
eventResult.consumed = true;
|
||||||
state.listViewState.focused = true;
|
state.listViewState.focused = true;
|
||||||
state.keyboardNavigation.SetCurrentIndex(hitTarget.itemIndex);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case UIInputEventType::KeyDown:
|
case UIInputEventType::KeyDown:
|
||||||
if (state.listViewState.focused && !HasNavigationModifiers(event.modifiers)) {
|
if (state.listViewState.focused &&
|
||||||
if (ApplyKeyboardNavigation(state, event.keyCode) &&
|
!event.modifiers.control &&
|
||||||
state.keyboardNavigation.HasCurrentIndex()) {
|
!event.modifiers.alt &&
|
||||||
const std::size_t currentIndex = state.keyboardNavigation.GetCurrentIndex();
|
!event.modifiers.super) {
|
||||||
if (currentIndex < items.size()) {
|
if (event.keyCode == static_cast<std::int32_t>(KeyCode::F2) &&
|
||||||
eventResult.selectionChanged =
|
selectionModel.HasSelection()) {
|
||||||
selectionModel.SetSelection(items[currentIndex].itemId);
|
const std::string& selectedItemId = selectionModel.GetSelectedId();
|
||||||
eventResult.keyboardNavigated = true;
|
eventResult.renameRequested = true;
|
||||||
eventResult.selectedItemId = items[currentIndex].itemId;
|
eventResult.renameItemId = selectedItemId;
|
||||||
eventResult.selectedIndex = currentIndex;
|
eventResult.selectedItemId = selectedItemId;
|
||||||
|
eventResult.selectedIndex =
|
||||||
|
FindUIEditorListViewItemIndex(items, selectedItemId);
|
||||||
|
eventResult.consumed = true;
|
||||||
|
} else if (ApplyKeyboardNavigation(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
items,
|
||||||
|
event.keyCode,
|
||||||
|
eventResult,
|
||||||
|
event.modifiers.shift)) {
|
||||||
eventResult.consumed = true;
|
eventResult.consumed = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -222,6 +396,7 @@ UIEditorListViewInteractionFrame UpdateUIEditorListViewInteraction(
|
|||||||
|
|
||||||
layout = BuildUIEditorListViewLayout(bounds, items, metrics);
|
layout = BuildUIEditorListViewLayout(bounds, items, metrics);
|
||||||
SyncKeyboardNavigation(state, selectionModel, items);
|
SyncKeyboardNavigation(state, selectionModel, items);
|
||||||
|
SyncSelectionAnchor(state, selectionModel);
|
||||||
SyncHoverTarget(state, layout, items);
|
SyncHoverTarget(state, layout, items);
|
||||||
if (eventResult.hitTarget.kind == UIEditorListViewHitTargetKind::None &&
|
if (eventResult.hitTarget.kind == UIEditorListViewHitTargetKind::None &&
|
||||||
state.hasPointerPosition) {
|
state.hasPointerPosition) {
|
||||||
@@ -232,14 +407,17 @@ UIEditorListViewInteractionFrame UpdateUIEditorListViewInteraction(
|
|||||||
eventResult.selectionChanged ||
|
eventResult.selectionChanged ||
|
||||||
eventResult.keyboardNavigated ||
|
eventResult.keyboardNavigated ||
|
||||||
eventResult.secondaryClicked ||
|
eventResult.secondaryClicked ||
|
||||||
|
eventResult.renameRequested ||
|
||||||
eventResult.hitTarget.kind != UIEditorListViewHitTargetKind::None ||
|
eventResult.hitTarget.kind != UIEditorListViewHitTargetKind::None ||
|
||||||
!eventResult.selectedItemId.empty()) {
|
!eventResult.selectedItemId.empty() ||
|
||||||
|
!eventResult.renameItemId.empty()) {
|
||||||
interactionResult = std::move(eventResult);
|
interactionResult = std::move(eventResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
layout = BuildUIEditorListViewLayout(bounds, items, metrics);
|
layout = BuildUIEditorListViewLayout(bounds, items, metrics);
|
||||||
SyncKeyboardNavigation(state, selectionModel, items);
|
SyncKeyboardNavigation(state, selectionModel, items);
|
||||||
|
SyncSelectionAnchor(state, selectionModel);
|
||||||
SyncHoverTarget(state, layout, items);
|
SyncHoverTarget(state, layout, items);
|
||||||
if (interactionResult.hitTarget.kind == UIEditorListViewHitTargetKind::None &&
|
if (interactionResult.hitTarget.kind == UIEditorListViewHitTargetKind::None &&
|
||||||
state.hasPointerPosition) {
|
state.hasPointerPosition) {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include <XCEditor/Widgets/UIEditorScrollView.h>
|
#include <XCEditor/Collections/UIEditorScrollView.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@@ -14,6 +14,47 @@ float ClampRange(float value, float minValue, float maxValue) {
|
|||||||
return (std::min)((std::max)(value, minValue), maxValue);
|
return (std::min)((std::max)(value, minValue), maxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::XCEngine::UI::UIColor LerpColor(
|
||||||
|
const ::XCEngine::UI::UIColor& from,
|
||||||
|
const ::XCEngine::UI::UIColor& to,
|
||||||
|
float factor) {
|
||||||
|
const float t = ClampRange(factor, 0.0f, 1.0f);
|
||||||
|
return ::XCEngine::UI::UIColor(
|
||||||
|
from.r + (to.r - from.r) * t,
|
||||||
|
from.g + (to.g - from.g) * t,
|
||||||
|
from.b + (to.b - from.b) * t,
|
||||||
|
from.a + (to.a - from.a) * t);
|
||||||
|
}
|
||||||
|
|
||||||
|
::XCEngine::UI::UIColor ResolveBorderColor(
|
||||||
|
const UIEditorScrollViewState& state,
|
||||||
|
const UIEditorScrollViewPalette& palette) {
|
||||||
|
if (state.focused) {
|
||||||
|
return palette.focusedBorderColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.hovered || state.scrollbarHovered) {
|
||||||
|
return LerpColor(palette.borderColor, palette.focusedBorderColor, 0.45f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return palette.borderColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ResolveBorderThickness(
|
||||||
|
const UIEditorScrollViewState& state,
|
||||||
|
const UIEditorScrollViewMetrics& metrics) {
|
||||||
|
if (state.focused) {
|
||||||
|
return metrics.focusedBorderThickness;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.hovered || state.scrollbarHovered) {
|
||||||
|
return metrics.borderThickness +
|
||||||
|
(metrics.focusedBorderThickness - metrics.borderThickness) * 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return metrics.borderThickness;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool IsUIEditorScrollViewPointInside(
|
bool IsUIEditorScrollViewPointInside(
|
||||||
@@ -124,8 +165,8 @@ void AppendUIEditorScrollViewBackground(
|
|||||||
drawList.AddFilledRect(layout.bounds, palette.surfaceColor, metrics.cornerRounding);
|
drawList.AddFilledRect(layout.bounds, palette.surfaceColor, metrics.cornerRounding);
|
||||||
drawList.AddRectOutline(
|
drawList.AddRectOutline(
|
||||||
layout.bounds,
|
layout.bounds,
|
||||||
state.focused ? palette.focusedBorderColor : palette.borderColor,
|
ResolveBorderColor(state, palette),
|
||||||
state.focused ? metrics.focusedBorderThickness : metrics.borderThickness,
|
ResolveBorderThickness(state, metrics),
|
||||||
metrics.cornerRounding);
|
metrics.cornerRounding);
|
||||||
|
|
||||||
if (!layout.hasScrollbar) {
|
if (!layout.hasScrollbar) {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include <XCEditor/Core/UIEditorScrollViewInteraction.h>
|
#include <XCEditor/Collections/UIEditorScrollViewInteraction.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include <XCEditor/Widgets/UIEditorTabStrip.h>
|
#include <XCEditor/Collections/UIEditorTabStrip.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -34,6 +34,20 @@ bool IsPointInsideRect(
|
|||||||
point.y <= rect.y + rect.height;
|
point.y <= rect.y + rect.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float ResolveStripRounding(const UIEditorTabStripMetrics& metrics) {
|
||||||
|
return (std::max)(
|
||||||
|
(std::min)(ClampNonNegative(metrics.layoutMetrics.headerHeight) * 0.25f, kStripRounding),
|
||||||
|
0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float ResolveTabRounding(const UIEditorTabStripMetrics& metrics) {
|
||||||
|
return (std::max)(ResolveStripRounding(metrics) - 1.0f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float ResolveCloseButtonRounding(const UIEditorTabStripMetrics& metrics) {
|
||||||
|
return (std::min)(ClampNonNegative(metrics.closeButtonExtent) * 0.35f, 5.0f);
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t ResolveSelectedIndex(
|
std::size_t ResolveSelectedIndex(
|
||||||
std::size_t itemCount,
|
std::size_t itemCount,
|
||||||
std::size_t selectedIndex) {
|
std::size_t selectedIndex) {
|
||||||
@@ -291,18 +305,20 @@ void AppendUIEditorTabStripBackground(
|
|||||||
const UIEditorTabStripState& state,
|
const UIEditorTabStripState& state,
|
||||||
const UIEditorTabStripPalette& palette,
|
const UIEditorTabStripPalette& palette,
|
||||||
const UIEditorTabStripMetrics& metrics) {
|
const UIEditorTabStripMetrics& metrics) {
|
||||||
drawList.AddFilledRect(layout.bounds, palette.stripBackgroundColor, kStripRounding);
|
const float stripRounding = ResolveStripRounding(metrics);
|
||||||
|
const float tabRounding = ResolveTabRounding(metrics);
|
||||||
|
drawList.AddFilledRect(layout.bounds, palette.stripBackgroundColor, stripRounding);
|
||||||
if (layout.contentRect.height > 0.0f) {
|
if (layout.contentRect.height > 0.0f) {
|
||||||
drawList.AddFilledRect(layout.contentRect, palette.contentBackgroundColor, kStripRounding);
|
drawList.AddFilledRect(layout.contentRect, palette.contentBackgroundColor, stripRounding);
|
||||||
}
|
}
|
||||||
if (layout.headerRect.height > 0.0f) {
|
if (layout.headerRect.height > 0.0f) {
|
||||||
drawList.AddFilledRect(layout.headerRect, palette.headerBackgroundColor, kStripRounding);
|
drawList.AddFilledRect(layout.headerRect, palette.headerBackgroundColor, stripRounding);
|
||||||
}
|
}
|
||||||
drawList.AddRectOutline(
|
drawList.AddRectOutline(
|
||||||
layout.bounds,
|
layout.bounds,
|
||||||
ResolveStripBorderColor(state, palette),
|
ResolveStripBorderColor(state, palette),
|
||||||
ResolveStripBorderThickness(state, metrics),
|
ResolveStripBorderThickness(state, metrics),
|
||||||
kStripRounding);
|
stripRounding);
|
||||||
|
|
||||||
for (std::size_t index = 0; index < layout.tabHeaderRects.size(); ++index) {
|
for (std::size_t index = 0; index < layout.tabHeaderRects.size(); ++index) {
|
||||||
const bool selected = layout.selectedIndex == index;
|
const bool selected = layout.selectedIndex == index;
|
||||||
@@ -310,12 +326,12 @@ void AppendUIEditorTabStripBackground(
|
|||||||
drawList.AddFilledRect(
|
drawList.AddFilledRect(
|
||||||
layout.tabHeaderRects[index],
|
layout.tabHeaderRects[index],
|
||||||
ResolveTabFillColor(selected, hovered, palette),
|
ResolveTabFillColor(selected, hovered, palette),
|
||||||
kTabRounding);
|
tabRounding);
|
||||||
drawList.AddRectOutline(
|
drawList.AddRectOutline(
|
||||||
layout.tabHeaderRects[index],
|
layout.tabHeaderRects[index],
|
||||||
ResolveTabBorderColor(selected, hovered, state.focused, palette),
|
ResolveTabBorderColor(selected, hovered, state.focused, palette),
|
||||||
ResolveTabBorderThickness(selected, state.focused, metrics),
|
ResolveTabBorderThickness(selected, state.focused, metrics),
|
||||||
kTabRounding);
|
tabRounding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,15 +377,16 @@ void AppendUIEditorTabStripForeground(
|
|||||||
|
|
||||||
const bool closeHovered = state.closeHoveredIndex == index;
|
const bool closeHovered = state.closeHoveredIndex == index;
|
||||||
const UIRect& closeRect = layout.closeButtonRects[index];
|
const UIRect& closeRect = layout.closeButtonRects[index];
|
||||||
|
const float closeRounding = ResolveCloseButtonRounding(metrics);
|
||||||
drawList.AddFilledRect(
|
drawList.AddFilledRect(
|
||||||
closeRect,
|
closeRect,
|
||||||
closeHovered ? palette.closeButtonHoveredColor : palette.closeButtonColor,
|
closeHovered ? palette.closeButtonHoveredColor : palette.closeButtonColor,
|
||||||
4.0f);
|
closeRounding);
|
||||||
drawList.AddRectOutline(
|
drawList.AddRectOutline(
|
||||||
closeRect,
|
closeRect,
|
||||||
palette.closeButtonBorderColor,
|
palette.closeButtonBorderColor,
|
||||||
1.0f,
|
1.0f,
|
||||||
4.0f);
|
closeRounding);
|
||||||
drawList.AddText(
|
drawList.AddText(
|
||||||
UIPoint(
|
UIPoint(
|
||||||
closeRect.x + (std::max)(0.0f, (closeRect.width - 7.0f) * 0.5f),
|
closeRect.x + (std::max)(0.0f, (closeRect.width - 7.0f) * 0.5f),
|
||||||
329
new_editor/src/Collections/UIEditorTabStripInteraction.cpp
Normal file
329
new_editor/src/Collections/UIEditorTabStripInteraction.cpp
Normal file
@@ -0,0 +1,329 @@
|
|||||||
|
#include <XCEditor/Collections/UIEditorTabStripInteraction.h>
|
||||||
|
|
||||||
|
#include <XCEngine/Input/InputTypes.h>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using ::XCEngine::Input::KeyCode;
|
||||||
|
using ::XCEngine::UI::UIInputEvent;
|
||||||
|
using ::XCEngine::UI::UIInputEventType;
|
||||||
|
using ::XCEngine::UI::UIPointerButton;
|
||||||
|
using Widgets::BuildUIEditorTabStripLayout;
|
||||||
|
using Widgets::HitTestUIEditorTabStrip;
|
||||||
|
using Widgets::ResolveUIEditorTabStripSelectedIndex;
|
||||||
|
using Widgets::UIEditorTabStripHitTarget;
|
||||||
|
using Widgets::UIEditorTabStripHitTargetKind;
|
||||||
|
using Widgets::UIEditorTabStripInvalidIndex;
|
||||||
|
|
||||||
|
bool ShouldUsePointerPosition(const UIInputEvent& event) {
|
||||||
|
switch (event.type) {
|
||||||
|
case UIInputEventType::PointerMove:
|
||||||
|
case UIInputEventType::PointerEnter:
|
||||||
|
case UIInputEventType::PointerButtonDown:
|
||||||
|
case UIInputEventType::PointerButtonUp:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasNavigationModifiers(const ::XCEngine::UI::UIInputModifiers& modifiers) {
|
||||||
|
return modifiers.shift || modifiers.control || modifiers.alt || modifiers.super;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsPointInside(const ::XCEngine::UI::UIRect& rect, const ::XCEngine::UI::UIPoint& point) {
|
||||||
|
return point.x >= rect.x &&
|
||||||
|
point.x <= rect.x + rect.width &&
|
||||||
|
point.y >= rect.y &&
|
||||||
|
point.y <= rect.y + rect.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AreEquivalentTargets(
|
||||||
|
const UIEditorTabStripHitTarget& lhs,
|
||||||
|
const UIEditorTabStripHitTarget& rhs) {
|
||||||
|
return lhs.kind == rhs.kind && lhs.index == rhs.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearHoverState(UIEditorTabStripInteractionState& state) {
|
||||||
|
state.tabStripState.hoveredIndex = UIEditorTabStripInvalidIndex;
|
||||||
|
state.tabStripState.closeHoveredIndex = UIEditorTabStripInvalidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SyncHoverTarget(
|
||||||
|
UIEditorTabStripInteractionState& state,
|
||||||
|
const Widgets::UIEditorTabStripLayout& layout) {
|
||||||
|
ClearHoverState(state);
|
||||||
|
if (!state.hasPointerPosition) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UIEditorTabStripHitTarget hitTarget =
|
||||||
|
HitTestUIEditorTabStrip(layout, state.tabStripState, state.pointerPosition);
|
||||||
|
if (hitTarget.index == UIEditorTabStripInvalidIndex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (hitTarget.kind) {
|
||||||
|
case UIEditorTabStripHitTargetKind::CloseButton:
|
||||||
|
state.tabStripState.hoveredIndex = hitTarget.index;
|
||||||
|
state.tabStripState.closeHoveredIndex = hitTarget.index;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UIEditorTabStripHitTargetKind::Tab:
|
||||||
|
state.tabStripState.hoveredIndex = hitTarget.index;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SyncSelectionState(
|
||||||
|
UIEditorTabStripInteractionState& state,
|
||||||
|
std::string_view selectedTabId,
|
||||||
|
const std::vector<Widgets::UIEditorTabStripItem>& items) {
|
||||||
|
state.navigationModel.SetItemCount(items.size());
|
||||||
|
|
||||||
|
const std::size_t fallbackIndex =
|
||||||
|
state.navigationModel.HasSelection()
|
||||||
|
? state.navigationModel.GetSelectedIndex()
|
||||||
|
: UIEditorTabStripInvalidIndex;
|
||||||
|
const std::size_t resolvedSelectedIndex =
|
||||||
|
ResolveUIEditorTabStripSelectedIndex(items, selectedTabId, fallbackIndex);
|
||||||
|
if (resolvedSelectedIndex != UIEditorTabStripInvalidIndex) {
|
||||||
|
state.navigationModel.SetSelectedIndex(resolvedSelectedIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.tabStripState.selectedIndex =
|
||||||
|
state.navigationModel.HasSelection()
|
||||||
|
? state.navigationModel.GetSelectedIndex()
|
||||||
|
: UIEditorTabStripInvalidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectTab(
|
||||||
|
UIEditorTabStripInteractionState& state,
|
||||||
|
std::string& selectedTabId,
|
||||||
|
const std::vector<Widgets::UIEditorTabStripItem>& items,
|
||||||
|
std::size_t selectedIndex,
|
||||||
|
UIEditorTabStripInteractionResult& result,
|
||||||
|
bool keyboardNavigated) {
|
||||||
|
if (selectedIndex >= items.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.navigationModel.SetSelectedIndex(selectedIndex);
|
||||||
|
state.tabStripState.selectedIndex = selectedIndex;
|
||||||
|
|
||||||
|
const std::string& tabId = items[selectedIndex].tabId;
|
||||||
|
result.selectionChanged = selectedTabId != tabId;
|
||||||
|
selectedTabId = tabId;
|
||||||
|
result.keyboardNavigated = keyboardNavigated;
|
||||||
|
result.selectedTabId = tabId;
|
||||||
|
result.selectedIndex = selectedIndex;
|
||||||
|
result.consumed = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ApplyKeyboardNavigation(
|
||||||
|
UIEditorTabStripInteractionState& state,
|
||||||
|
std::int32_t keyCode) {
|
||||||
|
switch (static_cast<KeyCode>(keyCode)) {
|
||||||
|
case KeyCode::Left:
|
||||||
|
return state.navigationModel.SelectPrevious();
|
||||||
|
case KeyCode::Right:
|
||||||
|
return state.navigationModel.SelectNext();
|
||||||
|
case KeyCode::Home:
|
||||||
|
return state.navigationModel.SelectFirst();
|
||||||
|
case KeyCode::End:
|
||||||
|
return state.navigationModel.SelectLast();
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
UIEditorTabStripInteractionFrame UpdateUIEditorTabStripInteraction(
|
||||||
|
UIEditorTabStripInteractionState& state,
|
||||||
|
std::string& selectedTabId,
|
||||||
|
const ::XCEngine::UI::UIRect& bounds,
|
||||||
|
const std::vector<Widgets::UIEditorTabStripItem>& items,
|
||||||
|
const std::vector<UIInputEvent>& inputEvents,
|
||||||
|
const Widgets::UIEditorTabStripMetrics& metrics) {
|
||||||
|
SyncSelectionState(state, selectedTabId, items);
|
||||||
|
Widgets::UIEditorTabStripLayout layout =
|
||||||
|
BuildUIEditorTabStripLayout(bounds, items, state.tabStripState, metrics);
|
||||||
|
SyncHoverTarget(state, layout);
|
||||||
|
|
||||||
|
UIEditorTabStripInteractionResult interactionResult = {};
|
||||||
|
for (const UIInputEvent& event : inputEvents) {
|
||||||
|
if (ShouldUsePointerPosition(event)) {
|
||||||
|
state.pointerPosition = event.position;
|
||||||
|
state.hasPointerPosition = true;
|
||||||
|
} else if (event.type == UIInputEventType::PointerLeave) {
|
||||||
|
state.hasPointerPosition = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIEditorTabStripInteractionResult eventResult = {};
|
||||||
|
eventResult.hitTarget =
|
||||||
|
state.hasPointerPosition
|
||||||
|
? HitTestUIEditorTabStrip(layout, state.tabStripState, state.pointerPosition)
|
||||||
|
: UIEditorTabStripHitTarget {};
|
||||||
|
|
||||||
|
switch (event.type) {
|
||||||
|
case UIInputEventType::FocusGained:
|
||||||
|
state.tabStripState.focused = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UIInputEventType::FocusLost:
|
||||||
|
state.tabStripState.focused = false;
|
||||||
|
state.hasPointerPosition = false;
|
||||||
|
state.pressedTarget = {};
|
||||||
|
ClearHoverState(state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UIInputEventType::PointerMove:
|
||||||
|
case UIInputEventType::PointerEnter:
|
||||||
|
case UIInputEventType::PointerLeave:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UIInputEventType::PointerButtonDown: {
|
||||||
|
if (event.pointerButton != UIPointerButton::Left) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.pressedTarget = eventResult.hitTarget;
|
||||||
|
if (eventResult.hitTarget.kind != UIEditorTabStripHitTargetKind::None ||
|
||||||
|
(state.hasPointerPosition && IsPointInside(layout.bounds, state.pointerPosition))) {
|
||||||
|
state.tabStripState.focused = true;
|
||||||
|
eventResult.consumed = true;
|
||||||
|
} else {
|
||||||
|
state.tabStripState.focused = false;
|
||||||
|
state.pressedTarget = {};
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case UIInputEventType::PointerButtonUp: {
|
||||||
|
if (event.pointerButton != UIPointerButton::Left) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool insideStrip =
|
||||||
|
state.hasPointerPosition && IsPointInside(layout.bounds, state.pointerPosition);
|
||||||
|
const bool matchedPressedTarget =
|
||||||
|
AreEquivalentTargets(state.pressedTarget, eventResult.hitTarget);
|
||||||
|
|
||||||
|
if (matchedPressedTarget) {
|
||||||
|
switch (eventResult.hitTarget.kind) {
|
||||||
|
case UIEditorTabStripHitTargetKind::CloseButton:
|
||||||
|
if (eventResult.hitTarget.index < items.size() &&
|
||||||
|
items[eventResult.hitTarget.index].closable) {
|
||||||
|
eventResult.closeRequested = true;
|
||||||
|
eventResult.closedTabId = items[eventResult.hitTarget.index].tabId;
|
||||||
|
eventResult.closedIndex = eventResult.hitTarget.index;
|
||||||
|
eventResult.consumed = true;
|
||||||
|
state.tabStripState.focused = true;
|
||||||
|
} else if (insideStrip) {
|
||||||
|
state.tabStripState.focused = true;
|
||||||
|
eventResult.consumed = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UIEditorTabStripHitTargetKind::Tab:
|
||||||
|
SelectTab(
|
||||||
|
state,
|
||||||
|
selectedTabId,
|
||||||
|
items,
|
||||||
|
eventResult.hitTarget.index,
|
||||||
|
eventResult,
|
||||||
|
false);
|
||||||
|
state.tabStripState.focused = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UIEditorTabStripHitTargetKind::HeaderBackground:
|
||||||
|
case UIEditorTabStripHitTargetKind::Content:
|
||||||
|
state.tabStripState.focused = true;
|
||||||
|
eventResult.consumed = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UIEditorTabStripHitTargetKind::None:
|
||||||
|
default:
|
||||||
|
if (!insideStrip) {
|
||||||
|
state.tabStripState.focused = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (!insideStrip) {
|
||||||
|
state.tabStripState.focused = false;
|
||||||
|
} else if (eventResult.hitTarget.kind == UIEditorTabStripHitTargetKind::HeaderBackground ||
|
||||||
|
eventResult.hitTarget.kind == UIEditorTabStripHitTargetKind::Content) {
|
||||||
|
state.tabStripState.focused = true;
|
||||||
|
eventResult.consumed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.pressedTarget = {};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case UIInputEventType::KeyDown:
|
||||||
|
if (state.tabStripState.focused &&
|
||||||
|
!HasNavigationModifiers(event.modifiers) &&
|
||||||
|
ApplyKeyboardNavigation(state, event.keyCode) &&
|
||||||
|
state.navigationModel.HasSelection()) {
|
||||||
|
const std::size_t selectedIndex = state.navigationModel.GetSelectedIndex();
|
||||||
|
SelectTab(
|
||||||
|
state,
|
||||||
|
selectedTabId,
|
||||||
|
items,
|
||||||
|
selectedIndex,
|
||||||
|
eventResult,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SyncSelectionState(state, selectedTabId, items);
|
||||||
|
layout = BuildUIEditorTabStripLayout(bounds, items, state.tabStripState, metrics);
|
||||||
|
SyncHoverTarget(state, layout);
|
||||||
|
if (eventResult.hitTarget.kind == UIEditorTabStripHitTargetKind::None &&
|
||||||
|
state.hasPointerPosition) {
|
||||||
|
eventResult.hitTarget =
|
||||||
|
HitTestUIEditorTabStrip(layout, state.tabStripState, state.pointerPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventResult.consumed ||
|
||||||
|
eventResult.selectionChanged ||
|
||||||
|
eventResult.closeRequested ||
|
||||||
|
eventResult.keyboardNavigated ||
|
||||||
|
eventResult.hitTarget.kind != UIEditorTabStripHitTargetKind::None ||
|
||||||
|
!eventResult.selectedTabId.empty() ||
|
||||||
|
!eventResult.closedTabId.empty()) {
|
||||||
|
interactionResult = std::move(eventResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SyncSelectionState(state, selectedTabId, items);
|
||||||
|
layout = BuildUIEditorTabStripLayout(bounds, items, state.tabStripState, metrics);
|
||||||
|
SyncHoverTarget(state, layout);
|
||||||
|
if (interactionResult.hitTarget.kind == UIEditorTabStripHitTargetKind::None &&
|
||||||
|
state.hasPointerPosition) {
|
||||||
|
interactionResult.hitTarget =
|
||||||
|
HitTestUIEditorTabStrip(layout, state.tabStripState, state.pointerPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
std::move(layout),
|
||||||
|
std::move(interactionResult),
|
||||||
|
state.tabStripState.focused
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include <XCEditor/Widgets/UIEditorTreeView.h>
|
#include <XCEditor/Collections/UIEditorTreeView.h>
|
||||||
|
|
||||||
#include <XCEngine/UI/Widgets/UIFlatHierarchyHelpers.h>
|
#include <XCEngine/UI/Widgets/UIFlatHierarchyHelpers.h>
|
||||||
|
|
||||||
677
new_editor/src/Collections/UIEditorTreeViewInteraction.cpp
Normal file
677
new_editor/src/Collections/UIEditorTreeViewInteraction.cpp
Normal file
@@ -0,0 +1,677 @@
|
|||||||
|
#include <XCEditor/Collections/UIEditorTreeViewInteraction.h>
|
||||||
|
|
||||||
|
#include <XCEngine/Input/InputTypes.h>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace XCEngine::UI::Editor {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using ::XCEngine::Input::KeyCode;
|
||||||
|
using ::XCEngine::UI::UIInputEvent;
|
||||||
|
using ::XCEngine::UI::UIInputEventType;
|
||||||
|
using ::XCEngine::UI::UIPointerButton;
|
||||||
|
using Widgets::BuildUIEditorTreeViewLayout;
|
||||||
|
using Widgets::DoesUIEditorTreeViewItemHaveChildren;
|
||||||
|
using Widgets::FindUIEditorTreeViewFirstVisibleChildItemIndex;
|
||||||
|
using Widgets::FindUIEditorTreeViewItemIndex;
|
||||||
|
using Widgets::FindUIEditorTreeViewParentItemIndex;
|
||||||
|
using Widgets::HitTestUIEditorTreeView;
|
||||||
|
using Widgets::IsUIEditorTreeViewPointInside;
|
||||||
|
using Widgets::UIEditorTreeViewHitTarget;
|
||||||
|
using Widgets::UIEditorTreeViewHitTargetKind;
|
||||||
|
using Widgets::UIEditorTreeViewInvalidIndex;
|
||||||
|
|
||||||
|
bool ShouldUsePointerPosition(const UIInputEvent& event) {
|
||||||
|
switch (event.type) {
|
||||||
|
case UIInputEventType::PointerMove:
|
||||||
|
case UIInputEventType::PointerEnter:
|
||||||
|
case UIInputEventType::PointerButtonDown:
|
||||||
|
case UIInputEventType::PointerButtonUp:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasNavigationModifiers(const ::XCEngine::UI::UIInputModifiers& modifiers) {
|
||||||
|
return modifiers.shift || modifiers.control || modifiers.alt || modifiers.super;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SyncHoverTarget(
|
||||||
|
UIEditorTreeViewInteractionState& state,
|
||||||
|
const Widgets::UIEditorTreeViewLayout& layout,
|
||||||
|
const std::vector<Widgets::UIEditorTreeViewItem>& items) {
|
||||||
|
state.treeViewState.hoveredItemId.clear();
|
||||||
|
if (!state.hasPointerPosition) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UIEditorTreeViewHitTarget hitTarget =
|
||||||
|
HitTestUIEditorTreeView(layout, state.pointerPosition);
|
||||||
|
if (hitTarget.itemIndex < items.size()) {
|
||||||
|
state.treeViewState.hoveredItemId = items[hitTarget.itemIndex].itemId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t FindVisibleIndexForItemIndex(
|
||||||
|
const Widgets::UIEditorTreeViewLayout& layout,
|
||||||
|
std::size_t itemIndex) {
|
||||||
|
for (std::size_t visibleIndex = 0u; visibleIndex < layout.visibleItemIndices.size(); ++visibleIndex) {
|
||||||
|
if (layout.visibleItemIndices[visibleIndex] == itemIndex) {
|
||||||
|
return visibleIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UIEditorTreeViewInvalidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t FindVisibleIndexForItemId(
|
||||||
|
const Widgets::UIEditorTreeViewLayout& layout,
|
||||||
|
const std::vector<Widgets::UIEditorTreeViewItem>& items,
|
||||||
|
std::string_view itemId) {
|
||||||
|
const std::size_t itemIndex = FindUIEditorTreeViewItemIndex(items, itemId);
|
||||||
|
if (itemIndex == UIEditorTreeViewInvalidIndex) {
|
||||||
|
return UIEditorTreeViewInvalidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FindVisibleIndexForItemIndex(layout, itemIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SyncKeyboardNavigation(
|
||||||
|
UIEditorTreeViewInteractionState& state,
|
||||||
|
const ::XCEngine::UI::Widgets::UISelectionModel& selectionModel,
|
||||||
|
const Widgets::UIEditorTreeViewLayout& layout,
|
||||||
|
const std::vector<Widgets::UIEditorTreeViewItem>& items) {
|
||||||
|
state.keyboardNavigation.SetItemCount(layout.visibleItemIndices.size());
|
||||||
|
state.keyboardNavigation.ClampToItemCount();
|
||||||
|
|
||||||
|
if (!selectionModel.HasSelection()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t selectedVisibleIndex =
|
||||||
|
FindVisibleIndexForItemId(layout, items, selectionModel.GetSelectedId());
|
||||||
|
if (selectedVisibleIndex == UIEditorTreeViewInvalidIndex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state.keyboardNavigation.HasCurrentIndex() ||
|
||||||
|
state.keyboardNavigation.GetCurrentIndex() != selectedVisibleIndex) {
|
||||||
|
state.keyboardNavigation.SetCurrentIndex(selectedVisibleIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SyncSelectionAnchor(
|
||||||
|
UIEditorTreeViewInteractionState& state,
|
||||||
|
const ::XCEngine::UI::Widgets::UISelectionModel& selectionModel) {
|
||||||
|
if (!selectionModel.HasSelection()) {
|
||||||
|
state.selectionAnchorId.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.selectionAnchorId.empty() ||
|
||||||
|
!selectionModel.IsSelected(state.selectionAnchorId)) {
|
||||||
|
state.selectionAnchorId = selectionModel.GetSelectedId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDescendantItem(
|
||||||
|
const std::vector<Widgets::UIEditorTreeViewItem>& items,
|
||||||
|
std::size_t ancestorIndex,
|
||||||
|
std::size_t candidateIndex) {
|
||||||
|
if (ancestorIndex >= items.size() || candidateIndex >= items.size() || candidateIndex <= ancestorIndex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::uint32_t ancestorDepth = items[ancestorIndex].depth;
|
||||||
|
for (std::size_t index = ancestorIndex + 1u; index <= candidateIndex; ++index) {
|
||||||
|
if (items[index].depth <= ancestorDepth) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectVisibleItem(
|
||||||
|
UIEditorTreeViewInteractionState& state,
|
||||||
|
::XCEngine::UI::Widgets::UISelectionModel& selectionModel,
|
||||||
|
const Widgets::UIEditorTreeViewLayout& layout,
|
||||||
|
const std::vector<Widgets::UIEditorTreeViewItem>& items,
|
||||||
|
std::size_t visibleIndex,
|
||||||
|
UIEditorTreeViewInteractionResult& result,
|
||||||
|
bool markKeyboardNavigation) {
|
||||||
|
if (visibleIndex >= layout.visibleItemIndices.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t itemIndex = layout.visibleItemIndices[visibleIndex];
|
||||||
|
if (itemIndex >= items.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Widgets::UIEditorTreeViewItem& item = items[itemIndex];
|
||||||
|
result.selectionChanged = selectionModel.SetSelection(item.itemId);
|
||||||
|
result.selectedItemId = item.itemId;
|
||||||
|
result.selectedVisibleIndex = visibleIndex;
|
||||||
|
result.keyboardNavigated = markKeyboardNavigation;
|
||||||
|
result.consumed = true;
|
||||||
|
state.keyboardNavigation.SetCurrentIndex(visibleIndex);
|
||||||
|
state.selectionAnchorId = item.itemId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ToggleVisibleItemSelection(
|
||||||
|
UIEditorTreeViewInteractionState& state,
|
||||||
|
::XCEngine::UI::Widgets::UISelectionModel& selectionModel,
|
||||||
|
const Widgets::UIEditorTreeViewLayout& layout,
|
||||||
|
const std::vector<Widgets::UIEditorTreeViewItem>& items,
|
||||||
|
std::size_t visibleIndex,
|
||||||
|
UIEditorTreeViewInteractionResult& result) {
|
||||||
|
if (visibleIndex >= layout.visibleItemIndices.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t itemIndex = layout.visibleItemIndices[visibleIndex];
|
||||||
|
if (itemIndex >= items.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Widgets::UIEditorTreeViewItem& item = items[itemIndex];
|
||||||
|
result.selectionChanged = selectionModel.ToggleSelectionMembership(item.itemId, true);
|
||||||
|
result.selectedItemId = item.itemId;
|
||||||
|
result.selectedVisibleIndex = visibleIndex;
|
||||||
|
result.consumed = true;
|
||||||
|
state.keyboardNavigation.SetCurrentIndex(visibleIndex);
|
||||||
|
state.selectionAnchorId = item.itemId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectVisibleItemRange(
|
||||||
|
UIEditorTreeViewInteractionState& state,
|
||||||
|
::XCEngine::UI::Widgets::UISelectionModel& selectionModel,
|
||||||
|
const Widgets::UIEditorTreeViewLayout& layout,
|
||||||
|
const std::vector<Widgets::UIEditorTreeViewItem>& items,
|
||||||
|
std::size_t visibleIndex,
|
||||||
|
UIEditorTreeViewInteractionResult& result,
|
||||||
|
bool markKeyboardNavigation) {
|
||||||
|
if (visibleIndex >= layout.visibleItemIndices.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t anchorVisibleIndex = UIEditorTreeViewInvalidIndex;
|
||||||
|
if (!state.selectionAnchorId.empty()) {
|
||||||
|
anchorVisibleIndex = FindVisibleIndexForItemId(layout, items, state.selectionAnchorId);
|
||||||
|
}
|
||||||
|
if (anchorVisibleIndex == UIEditorTreeViewInvalidIndex) {
|
||||||
|
return SelectVisibleItem(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
layout,
|
||||||
|
items,
|
||||||
|
visibleIndex,
|
||||||
|
result,
|
||||||
|
markKeyboardNavigation);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t rangeBegin = (std::min)(anchorVisibleIndex, visibleIndex);
|
||||||
|
const std::size_t rangeEnd = (std::max)(anchorVisibleIndex, visibleIndex);
|
||||||
|
std::vector<std::string> selectedIds = {};
|
||||||
|
selectedIds.reserve(rangeEnd - rangeBegin + 1u);
|
||||||
|
for (std::size_t index = rangeBegin; index <= rangeEnd; ++index) {
|
||||||
|
const std::size_t itemIndex = layout.visibleItemIndices[index];
|
||||||
|
if (itemIndex < items.size()) {
|
||||||
|
selectedIds.push_back(items[itemIndex].itemId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t itemIndex = layout.visibleItemIndices[visibleIndex];
|
||||||
|
if (itemIndex >= items.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Widgets::UIEditorTreeViewItem& item = items[itemIndex];
|
||||||
|
result.selectionChanged = selectionModel.SetSelections(std::move(selectedIds), item.itemId);
|
||||||
|
result.selectedItemId = item.itemId;
|
||||||
|
result.selectedVisibleIndex = visibleIndex;
|
||||||
|
result.keyboardNavigated = markKeyboardNavigation;
|
||||||
|
result.consumed = true;
|
||||||
|
state.keyboardNavigation.SetCurrentIndex(visibleIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopulateCurrentVisibleItemResult(
|
||||||
|
const Widgets::UIEditorTreeViewLayout& layout,
|
||||||
|
const std::vector<Widgets::UIEditorTreeViewItem>& items,
|
||||||
|
std::size_t visibleIndex,
|
||||||
|
UIEditorTreeViewInteractionResult& result) {
|
||||||
|
if (visibleIndex >= layout.visibleItemIndices.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t itemIndex = layout.visibleItemIndices[visibleIndex];
|
||||||
|
if (itemIndex >= items.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.selectedItemId = items[itemIndex].itemId;
|
||||||
|
result.selectedVisibleIndex = visibleIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ApplyVerticalNavigation(
|
||||||
|
UIEditorTreeViewInteractionState& state,
|
||||||
|
::XCEngine::UI::Widgets::UISelectionModel& selectionModel,
|
||||||
|
const Widgets::UIEditorTreeViewLayout& layout,
|
||||||
|
const std::vector<Widgets::UIEditorTreeViewItem>& items,
|
||||||
|
std::int32_t keyCode,
|
||||||
|
UIEditorTreeViewInteractionResult& result,
|
||||||
|
bool extendSelectionRange) {
|
||||||
|
bool moved = false;
|
||||||
|
switch (static_cast<KeyCode>(keyCode)) {
|
||||||
|
case KeyCode::Up:
|
||||||
|
moved = state.keyboardNavigation.MovePrevious();
|
||||||
|
break;
|
||||||
|
case KeyCode::Down:
|
||||||
|
moved = state.keyboardNavigation.MoveNext();
|
||||||
|
break;
|
||||||
|
case KeyCode::Home:
|
||||||
|
moved = state.keyboardNavigation.MoveHome();
|
||||||
|
break;
|
||||||
|
case KeyCode::End:
|
||||||
|
moved = state.keyboardNavigation.MoveEnd();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!moved || !state.keyboardNavigation.HasCurrentIndex()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return extendSelectionRange
|
||||||
|
? SelectVisibleItemRange(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
layout,
|
||||||
|
items,
|
||||||
|
state.keyboardNavigation.GetCurrentIndex(),
|
||||||
|
result,
|
||||||
|
true)
|
||||||
|
: SelectVisibleItem(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
layout,
|
||||||
|
items,
|
||||||
|
state.keyboardNavigation.GetCurrentIndex(),
|
||||||
|
result,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ApplyHorizontalNavigation(
|
||||||
|
UIEditorTreeViewInteractionState& state,
|
||||||
|
::XCEngine::UI::Widgets::UISelectionModel& selectionModel,
|
||||||
|
::XCEngine::UI::Widgets::UIExpansionModel& expansionModel,
|
||||||
|
const Widgets::UIEditorTreeViewLayout& layout,
|
||||||
|
const std::vector<Widgets::UIEditorTreeViewItem>& items,
|
||||||
|
std::int32_t keyCode,
|
||||||
|
UIEditorTreeViewInteractionResult& result) {
|
||||||
|
if (!state.keyboardNavigation.HasCurrentIndex()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t visibleIndex = state.keyboardNavigation.GetCurrentIndex();
|
||||||
|
if (visibleIndex >= layout.visibleItemIndices.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t itemIndex = layout.visibleItemIndices[visibleIndex];
|
||||||
|
if (itemIndex >= items.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Widgets::UIEditorTreeViewItem& item = items[itemIndex];
|
||||||
|
const bool hasChildren = DoesUIEditorTreeViewItemHaveChildren(items, itemIndex);
|
||||||
|
const bool expanded = expansionModel.IsExpanded(item.itemId);
|
||||||
|
|
||||||
|
switch (static_cast<KeyCode>(keyCode)) {
|
||||||
|
case KeyCode::Right:
|
||||||
|
if (hasChildren && !expanded) {
|
||||||
|
result.expansionChanged = expansionModel.Expand(item.itemId);
|
||||||
|
result.toggledItemId = item.itemId;
|
||||||
|
result.keyboardNavigated = true;
|
||||||
|
PopulateCurrentVisibleItemResult(layout, items, visibleIndex, result);
|
||||||
|
result.consumed = true;
|
||||||
|
return result.expansionChanged;
|
||||||
|
}
|
||||||
|
if (hasChildren && expanded) {
|
||||||
|
const std::size_t childItemIndex =
|
||||||
|
FindUIEditorTreeViewFirstVisibleChildItemIndex(items, expansionModel, itemIndex);
|
||||||
|
const std::size_t childVisibleIndex =
|
||||||
|
FindVisibleIndexForItemIndex(layout, childItemIndex);
|
||||||
|
if (childVisibleIndex != UIEditorTreeViewInvalidIndex) {
|
||||||
|
return SelectVisibleItem(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
layout,
|
||||||
|
items,
|
||||||
|
childVisibleIndex,
|
||||||
|
result,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case KeyCode::Left:
|
||||||
|
if (hasChildren && expanded) {
|
||||||
|
result.expansionChanged = expansionModel.Collapse(item.itemId);
|
||||||
|
result.toggledItemId = item.itemId;
|
||||||
|
result.keyboardNavigated = true;
|
||||||
|
PopulateCurrentVisibleItemResult(layout, items, visibleIndex, result);
|
||||||
|
result.consumed = true;
|
||||||
|
return result.expansionChanged;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::size_t parentItemIndex = FindUIEditorTreeViewParentItemIndex(items, itemIndex);
|
||||||
|
const std::size_t parentVisibleIndex =
|
||||||
|
FindVisibleIndexForItemIndex(layout, parentItemIndex);
|
||||||
|
if (parentVisibleIndex != UIEditorTreeViewInvalidIndex) {
|
||||||
|
return SelectVisibleItem(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
layout,
|
||||||
|
items,
|
||||||
|
parentVisibleIndex,
|
||||||
|
result,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NormalizeSelectionAfterCollapse(
|
||||||
|
UIEditorTreeViewInteractionState& state,
|
||||||
|
::XCEngine::UI::Widgets::UISelectionModel& selectionModel,
|
||||||
|
const Widgets::UIEditorTreeViewLayout& layout,
|
||||||
|
const std::vector<Widgets::UIEditorTreeViewItem>& items,
|
||||||
|
std::string_view collapsedItemId,
|
||||||
|
UIEditorTreeViewInteractionResult& result) {
|
||||||
|
if (!selectionModel.HasSelection()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t collapsedItemIndex = FindUIEditorTreeViewItemIndex(items, collapsedItemId);
|
||||||
|
const std::size_t selectedItemIndex = FindUIEditorTreeViewItemIndex(items, selectionModel.GetSelectedId());
|
||||||
|
if (collapsedItemIndex == UIEditorTreeViewInvalidIndex ||
|
||||||
|
selectedItemIndex == UIEditorTreeViewInvalidIndex ||
|
||||||
|
!IsDescendantItem(items, collapsedItemIndex, selectedItemIndex)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t collapsedVisibleIndex =
|
||||||
|
FindVisibleIndexForItemIndex(layout, collapsedItemIndex);
|
||||||
|
if (collapsedVisibleIndex == UIEditorTreeViewInvalidIndex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectVisibleItem(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
layout,
|
||||||
|
items,
|
||||||
|
collapsedVisibleIndex,
|
||||||
|
result,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
UIEditorTreeViewInteractionFrame UpdateUIEditorTreeViewInteraction(
|
||||||
|
UIEditorTreeViewInteractionState& state,
|
||||||
|
::XCEngine::UI::Widgets::UISelectionModel& selectionModel,
|
||||||
|
::XCEngine::UI::Widgets::UIExpansionModel& expansionModel,
|
||||||
|
const ::XCEngine::UI::UIRect& bounds,
|
||||||
|
const std::vector<Widgets::UIEditorTreeViewItem>& items,
|
||||||
|
const std::vector<UIInputEvent>& inputEvents,
|
||||||
|
const Widgets::UIEditorTreeViewMetrics& metrics) {
|
||||||
|
Widgets::UIEditorTreeViewLayout layout =
|
||||||
|
BuildUIEditorTreeViewLayout(bounds, items, expansionModel, metrics);
|
||||||
|
SyncKeyboardNavigation(state, selectionModel, layout, items);
|
||||||
|
SyncSelectionAnchor(state, selectionModel);
|
||||||
|
SyncHoverTarget(state, layout, items);
|
||||||
|
|
||||||
|
UIEditorTreeViewInteractionResult interactionResult = {};
|
||||||
|
for (const UIInputEvent& event : inputEvents) {
|
||||||
|
if (ShouldUsePointerPosition(event)) {
|
||||||
|
state.pointerPosition = event.position;
|
||||||
|
state.hasPointerPosition = true;
|
||||||
|
} else if (event.type == UIInputEventType::PointerLeave) {
|
||||||
|
state.hasPointerPosition = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIEditorTreeViewInteractionResult eventResult = {};
|
||||||
|
switch (event.type) {
|
||||||
|
case UIInputEventType::FocusGained:
|
||||||
|
state.treeViewState.focused = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UIInputEventType::FocusLost:
|
||||||
|
state.treeViewState.focused = false;
|
||||||
|
state.hasPointerPosition = false;
|
||||||
|
state.treeViewState.hoveredItemId.clear();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UIInputEventType::PointerMove:
|
||||||
|
case UIInputEventType::PointerEnter:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UIInputEventType::PointerLeave:
|
||||||
|
state.treeViewState.hoveredItemId.clear();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UIInputEventType::PointerButtonDown: {
|
||||||
|
const UIEditorTreeViewHitTarget hitTarget =
|
||||||
|
state.hasPointerPosition
|
||||||
|
? HitTestUIEditorTreeView(layout, state.pointerPosition)
|
||||||
|
: UIEditorTreeViewHitTarget {};
|
||||||
|
eventResult.hitTarget = hitTarget;
|
||||||
|
if ((event.pointerButton == UIPointerButton::Left ||
|
||||||
|
event.pointerButton == UIPointerButton::Right) &&
|
||||||
|
hitTarget.kind != UIEditorTreeViewHitTargetKind::None) {
|
||||||
|
state.treeViewState.focused = true;
|
||||||
|
eventResult.consumed = true;
|
||||||
|
} else if (event.pointerButton == UIPointerButton::Left &&
|
||||||
|
(!state.hasPointerPosition ||
|
||||||
|
!IsUIEditorTreeViewPointInside(layout.bounds, state.pointerPosition))) {
|
||||||
|
state.treeViewState.focused = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case UIInputEventType::PointerButtonUp: {
|
||||||
|
const UIEditorTreeViewHitTarget hitTarget =
|
||||||
|
state.hasPointerPosition
|
||||||
|
? HitTestUIEditorTreeView(layout, state.pointerPosition)
|
||||||
|
: UIEditorTreeViewHitTarget {};
|
||||||
|
eventResult.hitTarget = hitTarget;
|
||||||
|
|
||||||
|
const bool insideTree =
|
||||||
|
state.hasPointerPosition &&
|
||||||
|
IsUIEditorTreeViewPointInside(layout.bounds, state.pointerPosition);
|
||||||
|
|
||||||
|
if (hitTarget.itemIndex >= items.size()) {
|
||||||
|
if (event.pointerButton == UIPointerButton::Left && insideTree) {
|
||||||
|
eventResult.consumed = true;
|
||||||
|
state.treeViewState.focused = true;
|
||||||
|
} else if (event.pointerButton == UIPointerButton::Left) {
|
||||||
|
state.treeViewState.focused = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Widgets::UIEditorTreeViewItem& item = items[hitTarget.itemIndex];
|
||||||
|
if (event.pointerButton == UIPointerButton::Left) {
|
||||||
|
if (hitTarget.kind == UIEditorTreeViewHitTargetKind::Disclosure &&
|
||||||
|
DoesUIEditorTreeViewItemHaveChildren(items, hitTarget.itemIndex)) {
|
||||||
|
eventResult.expansionChanged =
|
||||||
|
expansionModel.ToggleExpanded(item.itemId);
|
||||||
|
eventResult.toggledItemId = item.itemId;
|
||||||
|
eventResult.consumed = true;
|
||||||
|
state.treeViewState.focused = true;
|
||||||
|
} else if (hitTarget.kind == UIEditorTreeViewHitTargetKind::Row) {
|
||||||
|
if (event.modifiers.shift) {
|
||||||
|
SelectVisibleItemRange(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
layout,
|
||||||
|
items,
|
||||||
|
hitTarget.visibleIndex,
|
||||||
|
eventResult,
|
||||||
|
false);
|
||||||
|
} else if (event.modifiers.control) {
|
||||||
|
ToggleVisibleItemSelection(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
layout,
|
||||||
|
items,
|
||||||
|
hitTarget.visibleIndex,
|
||||||
|
eventResult);
|
||||||
|
} else {
|
||||||
|
SelectVisibleItem(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
layout,
|
||||||
|
items,
|
||||||
|
hitTarget.visibleIndex,
|
||||||
|
eventResult,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
state.treeViewState.focused = true;
|
||||||
|
}
|
||||||
|
} else if (event.pointerButton == UIPointerButton::Right &&
|
||||||
|
(hitTarget.kind == UIEditorTreeViewHitTargetKind::Row ||
|
||||||
|
hitTarget.kind == UIEditorTreeViewHitTargetKind::Disclosure)) {
|
||||||
|
if (hitTarget.visibleIndex != UIEditorTreeViewInvalidIndex &&
|
||||||
|
hitTarget.itemIndex < items.size()) {
|
||||||
|
const Widgets::UIEditorTreeViewItem& hitItem = items[hitTarget.itemIndex];
|
||||||
|
if (selectionModel.IsSelected(hitItem.itemId)) {
|
||||||
|
selectionModel.SetPrimarySelection(hitItem.itemId);
|
||||||
|
eventResult.selectedItemId = hitItem.itemId;
|
||||||
|
eventResult.selectedVisibleIndex = hitTarget.visibleIndex;
|
||||||
|
eventResult.consumed = true;
|
||||||
|
state.keyboardNavigation.SetCurrentIndex(hitTarget.visibleIndex);
|
||||||
|
state.selectionAnchorId = hitItem.itemId;
|
||||||
|
} else {
|
||||||
|
SelectVisibleItem(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
layout,
|
||||||
|
items,
|
||||||
|
hitTarget.visibleIndex,
|
||||||
|
eventResult,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eventResult.secondaryClicked = true;
|
||||||
|
eventResult.consumed = true;
|
||||||
|
state.treeViewState.focused = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case UIInputEventType::KeyDown:
|
||||||
|
if (state.treeViewState.focused &&
|
||||||
|
!event.modifiers.control &&
|
||||||
|
!event.modifiers.alt &&
|
||||||
|
!event.modifiers.super) {
|
||||||
|
if (event.keyCode == static_cast<std::int32_t>(KeyCode::F2) &&
|
||||||
|
selectionModel.HasSelection()) {
|
||||||
|
eventResult.renameRequested = true;
|
||||||
|
eventResult.renameItemId = selectionModel.GetSelectedId();
|
||||||
|
eventResult.selectedItemId = selectionModel.GetSelectedId();
|
||||||
|
eventResult.selectedVisibleIndex =
|
||||||
|
FindVisibleIndexForItemId(layout, items, selectionModel.GetSelectedId());
|
||||||
|
eventResult.consumed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ApplyVerticalNavigation(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
layout,
|
||||||
|
items,
|
||||||
|
event.keyCode,
|
||||||
|
eventResult,
|
||||||
|
event.modifiers.shift) ||
|
||||||
|
ApplyHorizontalNavigation(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
expansionModel,
|
||||||
|
layout,
|
||||||
|
items,
|
||||||
|
event.keyCode,
|
||||||
|
eventResult)) {
|
||||||
|
eventResult.consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
layout = BuildUIEditorTreeViewLayout(bounds, items, expansionModel, metrics);
|
||||||
|
if (eventResult.expansionChanged &&
|
||||||
|
!eventResult.toggledItemId.empty() &&
|
||||||
|
!expansionModel.IsExpanded(eventResult.toggledItemId)) {
|
||||||
|
NormalizeSelectionAfterCollapse(
|
||||||
|
state,
|
||||||
|
selectionModel,
|
||||||
|
layout,
|
||||||
|
items,
|
||||||
|
eventResult.toggledItemId,
|
||||||
|
eventResult);
|
||||||
|
}
|
||||||
|
SyncKeyboardNavigation(state, selectionModel, layout, items);
|
||||||
|
SyncSelectionAnchor(state, selectionModel);
|
||||||
|
SyncHoverTarget(state, layout, items);
|
||||||
|
if (eventResult.hitTarget.kind == UIEditorTreeViewHitTargetKind::None &&
|
||||||
|
state.hasPointerPosition) {
|
||||||
|
eventResult.hitTarget = HitTestUIEditorTreeView(layout, state.pointerPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventResult.consumed ||
|
||||||
|
eventResult.selectionChanged ||
|
||||||
|
eventResult.expansionChanged ||
|
||||||
|
eventResult.keyboardNavigated ||
|
||||||
|
eventResult.secondaryClicked ||
|
||||||
|
eventResult.renameRequested ||
|
||||||
|
eventResult.hitTarget.kind != UIEditorTreeViewHitTargetKind::None ||
|
||||||
|
!eventResult.selectedItemId.empty() ||
|
||||||
|
!eventResult.renameItemId.empty() ||
|
||||||
|
!eventResult.toggledItemId.empty()) {
|
||||||
|
interactionResult = std::move(eventResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layout = BuildUIEditorTreeViewLayout(bounds, items, expansionModel, metrics);
|
||||||
|
SyncKeyboardNavigation(state, selectionModel, layout, items);
|
||||||
|
SyncSelectionAnchor(state, selectionModel);
|
||||||
|
SyncHoverTarget(state, layout, items);
|
||||||
|
if (interactionResult.hitTarget.kind == UIEditorTreeViewHitTargetKind::None &&
|
||||||
|
state.hasPointerPosition) {
|
||||||
|
interactionResult.hitTarget = HitTestUIEditorTreeView(layout, state.pointerPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
std::move(layout),
|
||||||
|
std::move(interactionResult)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace XCEngine::UI::Editor
|
||||||
@@ -1,304 +0,0 @@
|
|||||||
#include <XCEditor/Core/UIEditorDockHostInteraction.h>
|
|
||||||
|
|
||||||
#include <XCEngine/UI/Widgets/UISplitterInteraction.h>
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace XCEngine::UI::Editor {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
using ::XCEngine::UI::UIInputEvent;
|
|
||||||
using ::XCEngine::UI::UIInputEventType;
|
|
||||||
using ::XCEngine::UI::UIRect;
|
|
||||||
using ::XCEngine::UI::Widgets::BeginUISplitterDrag;
|
|
||||||
using ::XCEngine::UI::Widgets::EndUISplitterDrag;
|
|
||||||
using ::XCEngine::UI::Widgets::UpdateUISplitterDrag;
|
|
||||||
using Widgets::BuildUIEditorDockHostLayout;
|
|
||||||
using Widgets::FindUIEditorDockHostSplitterLayout;
|
|
||||||
using Widgets::HitTestUIEditorDockHost;
|
|
||||||
using Widgets::UIEditorDockHostHitTarget;
|
|
||||||
using Widgets::UIEditorDockHostHitTargetKind;
|
|
||||||
|
|
||||||
bool ShouldUsePointerPosition(const UIInputEvent& event) {
|
|
||||||
switch (event.type) {
|
|
||||||
case UIInputEventType::PointerMove:
|
|
||||||
case UIInputEventType::PointerEnter:
|
|
||||||
case UIInputEventType::PointerButtonDown:
|
|
||||||
case UIInputEventType::PointerButtonUp:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UIEditorWorkspaceLayoutOperationResult ApplySplitRatio(
|
|
||||||
UIEditorWorkspaceController& controller,
|
|
||||||
std::string_view nodeId,
|
|
||||||
float splitRatio) {
|
|
||||||
return controller.SetSplitRatio(nodeId, splitRatio);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SyncHoverTarget(
|
|
||||||
UIEditorDockHostInteractionState& state,
|
|
||||||
const Widgets::UIEditorDockHostLayout& layout) {
|
|
||||||
if (state.splitterDragState.active) {
|
|
||||||
state.dockHostState.hoveredTarget = {
|
|
||||||
UIEditorDockHostHitTargetKind::SplitterHandle,
|
|
||||||
state.dockHostState.activeSplitterNodeId,
|
|
||||||
{},
|
|
||||||
Widgets::UIEditorTabStripInvalidIndex
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!state.hasPointerPosition) {
|
|
||||||
state.dockHostState.hoveredTarget = {};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.dockHostState.hoveredTarget =
|
|
||||||
HitTestUIEditorDockHost(layout, state.pointerPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
UIEditorWorkspaceCommandResult DispatchPanelCommand(
|
|
||||||
UIEditorWorkspaceController& controller,
|
|
||||||
UIEditorWorkspaceCommandKind kind,
|
|
||||||
std::string panelId) {
|
|
||||||
UIEditorWorkspaceCommand command = {};
|
|
||||||
command.kind = kind;
|
|
||||||
command.panelId = std::move(panelId);
|
|
||||||
return controller.Dispatch(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
UIEditorDockHostInteractionFrame UpdateUIEditorDockHostInteraction(
|
|
||||||
UIEditorDockHostInteractionState& state,
|
|
||||||
UIEditorWorkspaceController& controller,
|
|
||||||
const UIRect& bounds,
|
|
||||||
const std::vector<UIInputEvent>& inputEvents,
|
|
||||||
const Widgets::UIEditorDockHostMetrics& metrics) {
|
|
||||||
UIEditorDockHostInteractionResult interactionResult = {};
|
|
||||||
Widgets::UIEditorDockHostLayout layout = BuildUIEditorDockHostLayout(
|
|
||||||
bounds,
|
|
||||||
controller.GetPanelRegistry(),
|
|
||||||
controller.GetWorkspace(),
|
|
||||||
controller.GetSession(),
|
|
||||||
state.dockHostState,
|
|
||||||
metrics);
|
|
||||||
SyncHoverTarget(state, layout);
|
|
||||||
|
|
||||||
for (const UIInputEvent& event : inputEvents) {
|
|
||||||
if (ShouldUsePointerPosition(event)) {
|
|
||||||
state.pointerPosition = event.position;
|
|
||||||
state.hasPointerPosition = true;
|
|
||||||
} else if (event.type == UIInputEventType::PointerLeave) {
|
|
||||||
state.hasPointerPosition = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UIEditorDockHostInteractionResult eventResult = {};
|
|
||||||
|
|
||||||
switch (event.type) {
|
|
||||||
case UIInputEventType::FocusGained:
|
|
||||||
state.dockHostState.focused = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UIInputEventType::FocusLost:
|
|
||||||
state.dockHostState.focused = false;
|
|
||||||
state.dockHostState.hoveredTarget = {};
|
|
||||||
if (state.splitterDragState.active) {
|
|
||||||
EndUISplitterDrag(state.splitterDragState);
|
|
||||||
state.dockHostState.activeSplitterNodeId.clear();
|
|
||||||
eventResult.consumed = true;
|
|
||||||
eventResult.releasePointerCapture = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UIInputEventType::PointerMove:
|
|
||||||
case UIInputEventType::PointerEnter:
|
|
||||||
if (state.splitterDragState.active) {
|
|
||||||
const auto* splitter = FindUIEditorDockHostSplitterLayout(
|
|
||||||
layout,
|
|
||||||
state.dockHostState.activeSplitterNodeId);
|
|
||||||
if (splitter != nullptr) {
|
|
||||||
::XCEngine::UI::Layout::UISplitterLayoutResult draggedLayout = {};
|
|
||||||
if (UpdateUISplitterDrag(
|
|
||||||
state.splitterDragState,
|
|
||||||
state.pointerPosition,
|
|
||||||
draggedLayout)) {
|
|
||||||
eventResult.layoutResult = ApplySplitRatio(
|
|
||||||
controller,
|
|
||||||
state.dockHostState.activeSplitterNodeId,
|
|
||||||
draggedLayout.splitRatio);
|
|
||||||
eventResult.layoutChanged =
|
|
||||||
eventResult.layoutResult.status ==
|
|
||||||
UIEditorWorkspaceLayoutOperationStatus::Changed;
|
|
||||||
}
|
|
||||||
eventResult.consumed = true;
|
|
||||||
eventResult.hitTarget.kind = UIEditorDockHostHitTargetKind::SplitterHandle;
|
|
||||||
eventResult.hitTarget.nodeId = state.dockHostState.activeSplitterNodeId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UIInputEventType::PointerLeave:
|
|
||||||
if (!state.splitterDragState.active) {
|
|
||||||
state.dockHostState.hoveredTarget = {};
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UIInputEventType::PointerButtonDown:
|
|
||||||
if (event.pointerButton != ::XCEngine::UI::UIPointerButton::Left) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.dockHostState.hoveredTarget.kind ==
|
|
||||||
UIEditorDockHostHitTargetKind::SplitterHandle) {
|
|
||||||
const auto* splitter = FindUIEditorDockHostSplitterLayout(
|
|
||||||
layout,
|
|
||||||
state.dockHostState.hoveredTarget.nodeId);
|
|
||||||
if (splitter != nullptr &&
|
|
||||||
BeginUISplitterDrag(
|
|
||||||
1u,
|
|
||||||
splitter->axis == UIEditorWorkspaceSplitAxis::Horizontal
|
|
||||||
? ::XCEngine::UI::Layout::UILayoutAxis::Horizontal
|
|
||||||
: ::XCEngine::UI::Layout::UILayoutAxis::Vertical,
|
|
||||||
splitter->bounds,
|
|
||||||
splitter->splitterLayout,
|
|
||||||
splitter->constraints,
|
|
||||||
splitter->metrics,
|
|
||||||
state.pointerPosition,
|
|
||||||
state.splitterDragState)) {
|
|
||||||
state.dockHostState.activeSplitterNodeId = splitter->nodeId;
|
|
||||||
state.dockHostState.focused = true;
|
|
||||||
eventResult.consumed = true;
|
|
||||||
eventResult.requestPointerCapture = true;
|
|
||||||
eventResult.hitTarget = state.dockHostState.hoveredTarget;
|
|
||||||
eventResult.activeSplitterNodeId = splitter->nodeId;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
state.dockHostState.focused =
|
|
||||||
state.dockHostState.hoveredTarget.kind !=
|
|
||||||
UIEditorDockHostHitTargetKind::None;
|
|
||||||
eventResult.consumed = state.dockHostState.focused;
|
|
||||||
eventResult.hitTarget = state.dockHostState.hoveredTarget;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UIInputEventType::PointerButtonUp:
|
|
||||||
if (event.pointerButton != ::XCEngine::UI::UIPointerButton::Left) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.splitterDragState.active) {
|
|
||||||
::XCEngine::UI::Layout::UISplitterLayoutResult draggedLayout = {};
|
|
||||||
if (UpdateUISplitterDrag(
|
|
||||||
state.splitterDragState,
|
|
||||||
state.pointerPosition,
|
|
||||||
draggedLayout)) {
|
|
||||||
eventResult.layoutResult = ApplySplitRatio(
|
|
||||||
controller,
|
|
||||||
state.dockHostState.activeSplitterNodeId,
|
|
||||||
draggedLayout.splitRatio);
|
|
||||||
eventResult.layoutChanged =
|
|
||||||
eventResult.layoutResult.status ==
|
|
||||||
UIEditorWorkspaceLayoutOperationStatus::Changed;
|
|
||||||
}
|
|
||||||
EndUISplitterDrag(state.splitterDragState);
|
|
||||||
eventResult.consumed = true;
|
|
||||||
eventResult.releasePointerCapture = true;
|
|
||||||
eventResult.activeSplitterNodeId = state.dockHostState.activeSplitterNodeId;
|
|
||||||
state.dockHostState.activeSplitterNodeId.clear();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
eventResult.hitTarget = state.dockHostState.hoveredTarget;
|
|
||||||
switch (state.dockHostState.hoveredTarget.kind) {
|
|
||||||
case UIEditorDockHostHitTargetKind::Tab:
|
|
||||||
case UIEditorDockHostHitTargetKind::PanelHeader:
|
|
||||||
case UIEditorDockHostHitTargetKind::PanelBody:
|
|
||||||
case UIEditorDockHostHitTargetKind::PanelFooter:
|
|
||||||
eventResult.commandResult = DispatchPanelCommand(
|
|
||||||
controller,
|
|
||||||
UIEditorWorkspaceCommandKind::ActivatePanel,
|
|
||||||
state.dockHostState.hoveredTarget.panelId);
|
|
||||||
eventResult.commandExecuted =
|
|
||||||
eventResult.commandResult.status !=
|
|
||||||
UIEditorWorkspaceCommandStatus::Rejected;
|
|
||||||
eventResult.consumed = true;
|
|
||||||
state.dockHostState.focused = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UIEditorDockHostHitTargetKind::TabCloseButton:
|
|
||||||
case UIEditorDockHostHitTargetKind::PanelCloseButton:
|
|
||||||
eventResult.commandResult = DispatchPanelCommand(
|
|
||||||
controller,
|
|
||||||
UIEditorWorkspaceCommandKind::ClosePanel,
|
|
||||||
state.dockHostState.hoveredTarget.panelId);
|
|
||||||
eventResult.commandExecuted =
|
|
||||||
eventResult.commandResult.status !=
|
|
||||||
UIEditorWorkspaceCommandStatus::Rejected;
|
|
||||||
eventResult.consumed = true;
|
|
||||||
state.dockHostState.focused = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UIEditorDockHostHitTargetKind::TabStripBackground:
|
|
||||||
state.dockHostState.focused = true;
|
|
||||||
eventResult.consumed = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UIEditorDockHostHitTargetKind::None:
|
|
||||||
default:
|
|
||||||
state.dockHostState.focused = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
layout = BuildUIEditorDockHostLayout(
|
|
||||||
bounds,
|
|
||||||
controller.GetPanelRegistry(),
|
|
||||||
controller.GetWorkspace(),
|
|
||||||
controller.GetSession(),
|
|
||||||
state.dockHostState,
|
|
||||||
metrics);
|
|
||||||
SyncHoverTarget(state, layout);
|
|
||||||
if (eventResult.hitTarget.kind == UIEditorDockHostHitTargetKind::None) {
|
|
||||||
eventResult.hitTarget = state.dockHostState.hoveredTarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventResult.consumed ||
|
|
||||||
eventResult.commandExecuted ||
|
|
||||||
eventResult.layoutChanged ||
|
|
||||||
eventResult.requestPointerCapture ||
|
|
||||||
eventResult.releasePointerCapture ||
|
|
||||||
eventResult.layoutResult.status != UIEditorWorkspaceLayoutOperationStatus::Rejected ||
|
|
||||||
eventResult.hitTarget.kind != UIEditorDockHostHitTargetKind::None ||
|
|
||||||
!eventResult.activeSplitterNodeId.empty()) {
|
|
||||||
interactionResult = std::move(eventResult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
layout = BuildUIEditorDockHostLayout(
|
|
||||||
bounds,
|
|
||||||
controller.GetPanelRegistry(),
|
|
||||||
controller.GetWorkspace(),
|
|
||||||
controller.GetSession(),
|
|
||||||
state.dockHostState,
|
|
||||||
metrics);
|
|
||||||
SyncHoverTarget(state, layout);
|
|
||||||
if (interactionResult.hitTarget.kind == UIEditorDockHostHitTargetKind::None) {
|
|
||||||
interactionResult.hitTarget = state.dockHostState.hoveredTarget;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
std::move(layout),
|
|
||||||
std::move(interactionResult),
|
|
||||||
state.dockHostState.focused
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace XCEngine::UI::Editor
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user