docs: explain Tessera modules and execution flows in Chinese

This commit is contained in:
2026-11-11 23:36:03 +08:00
parent 4c3fc8b5dd
commit 1fedd21d3c
77 changed files with 1418 additions and 0 deletions
+27
View File
@@ -1,10 +1,15 @@
//! 即时绘制控件的跨帧交互状态:稳定 WidgetId、悬停、按下捕获、键盘焦点和释放激活。
//! 控件用语义 key 标识,而不是屏幕位置或行号。释放时必须仍命中同一个启用目标,拖出控件不能意外触发点击。
//!
use crate::geometry::{Point, Rect};
use std::hash::{Hash, Hasher};
/// Stable across frames, resizing and text changes. Use semantic keys, never row indices.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
/// 由语义 key 生成的稳定控件身份,跨帧移动和文字变化不应改变它。
pub struct WidgetId(u64);
impl WidgetId {
/// 构造本类型并初始化其状态;资源建立和默认字段以函数体为准。
pub fn new(key: impl Hash) -> Self {
let mut hash = std::collections::hash_map::DefaultHasher::new();
key.hash(&mut hash);
@@ -12,11 +17,13 @@ impl WidgetId {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
/// 分隔条和滚动条的操作方向。
pub enum Axis {
Horizontal,
Vertical,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
/// 管理控件角色,决定焦点资格和系统光标。
pub enum Role {
Button,
Tab,
@@ -28,11 +35,13 @@ pub enum Role {
Scrollbar(Axis),
}
impl Role {
/// 判断控件角色是否可以接受键盘焦点。
fn focusable(self) -> bool {
!matches!(self, Self::Splitter(_) | Self::Scrollbar(_) | Self::Row)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
/// 宿主控件请求的系统光标种类。
pub enum Cursor {
Default,
Pointer,
@@ -43,6 +52,7 @@ pub enum Cursor {
Disabled,
}
#[derive(Clone, Debug)]
/// 本帧可命中的管理控件,绑定几何、角色、启用条件与可选 action。
pub struct Target<A> {
pub id: WidgetId,
pub rect: Rect,
@@ -51,6 +61,7 @@ pub struct Target<A> {
pub action: Option<A>,
}
#[derive(Clone, Copy, Debug)]
/// 绘制使用的组合交互状态,避免按钮自己重新推断焦点/捕获。
pub struct VisualState {
pub hovered: bool,
pub pressed: bool,
@@ -62,6 +73,7 @@ pub struct VisualState {
/// Retained input state for an immediate-mode frame. Actions fire on release inside
/// the same enabled control, so dragging away cancels a click.
#[derive(Clone, Debug, Default)]
/// 即时绘制之外保留的输入状态,确保按下与释放跨帧仍匹配同一控件。
pub struct Interaction {
pointer: Option<Point>,
hovered: Option<WidgetId>,
@@ -71,18 +83,22 @@ pub struct Interaction {
keyboard_focus: bool,
}
impl Interaction {
/// 按逆绘制顺序选择指针处的管理控件,避免重叠控件同时激活。
pub fn hit<'a, A>(&self, targets: &'a [Target<A>]) -> Option<&'a Target<A>> {
let p = self.pointer?;
targets.iter().rev().find(|t| t.rect.contains(p))
}
/// 更新指针与悬停目标,但不在移动时直接触发点击。
pub fn pointer_moved<A>(&mut self, p: Point, targets: &[Target<A>]) {
self.pointer = Some(p);
self.hovered = self.hit(targets).map(|t| t.id);
}
/// 清除离开窗口后的指针/悬停状态。
pub fn pointer_left(&mut self) {
self.pointer = None;
self.hovered = None;
}
/// 捕获启用控件的稳定身份,并按角色更新键盘焦点。
pub fn press<A: Clone>(&mut self, targets: &[Target<A>]) -> Option<Target<A>> {
self.key_active = None;
self.keyboard_focus = false;
@@ -91,22 +107,26 @@ impl Interaction {
self.focused = target.as_ref().filter(|t| t.role.focusable()).map(|t| t.id);
target
}
/// 只有释放时仍处于原启用目标内才返回 action,拖出后释放不触发。
pub fn release<A: Clone>(&mut self, targets: &[Target<A>]) -> Option<A> {
let active = self.pointer_active.take()?;
self.hit(targets)
.filter(|t| t.enabled && t.id == active && t.role != Role::TextField)
.and_then(|t| t.action.clone())
}
/// 撤销当前操作的后续交付资格,并执行对应取消清理。
pub fn cancel(&mut self) {
self.pointer_active = None;
self.key_active = None;
}
/// 撤销失焦后的键盘/指针激活状态,防止回到窗口时补发旧操作。
pub fn blur(&mut self) {
self.cancel();
self.focused = None;
self.keyboard_focus = false;
self.pointer_left();
}
/// 用本帧目标集合校正跨帧焦点和捕获,已消失控件不保留可激活身份。
pub fn reconcile<A>(&mut self, targets: &[Target<A>]) -> bool {
let before = (
self.hovered,
@@ -127,11 +147,13 @@ impl Interaction {
self.key_active,
)
}
/// 返回当前仍持有焦点的稳定控件身份。
pub fn focused<'a, A>(&self, targets: &'a [Target<A>]) -> Option<&'a Target<A>> {
targets
.iter()
.find(|t| Some(t.id) == self.focused && t.enabled)
}
/// 沿启用且可聚焦的目标循环导航,支持正向与反向遍历。
pub fn focus_next<A: Clone>(&mut self, targets: &[Target<A>], back: bool) -> Option<Target<A>> {
self.cancel();
self.keyboard_focus = true;
@@ -154,18 +176,21 @@ impl Interaction {
self.focused = Some(target.id);
Some(target.clone())
}
/// 为当前焦点控件记录键盘激活,后续释放仍须匹配目标。
pub fn key_press<A>(&mut self, targets: &[Target<A>]) {
self.key_active = self
.focused(targets)
.filter(|t| t.role != Role::TextField)
.map(|t| t.id);
}
/// 结束键盘激活并按有效控件身份返回操作。
pub fn key_release<A: Clone>(&mut self, targets: &[Target<A>]) -> Option<A> {
let active = self.key_active.take()?;
self.focused(targets)
.filter(|t| t.id == active)
.and_then(|t| t.action.clone())
}
/// 组合悬停、按下、焦点、选中和启用状态,供控件选择正确样式。
pub fn visual(&self, id: WidgetId, selected: bool, enabled: bool) -> VisualState {
let hovered = enabled && self.hovered == Some(id);
VisualState {
@@ -177,9 +202,11 @@ impl Interaction {
enabled,
}
}
/// 返回本次拖动/按压捕获的控件,移动过程中不随悬停目标跳变。
pub fn captured(&self, id: WidgetId) -> bool {
self.pointer_active == Some(id)
}
/// 按命中角色选择系统光标,例如文本、分隔条或可点击按钮。
pub fn cursor<A>(&self, targets: &[Target<A>]) -> Cursor {
let target = self
.pointer_active