lieui 0.2.0-beta.1

A Rust GUI library with C/S architecture and builder-driven UI
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
//! LayerStack — 可扩展的多层 z-index 栈
//!
//! 替换原有的三层硬编码(Base / Overlay / Modal),支持:
//! - 6 种 LayerKind:Content / Popup / Overlay / Tooltip / Modal / System
//! - 每种 Kind 内多实例并存,自动分配 z 值
//! - Anchor 定位(Above / Below / LeftOf / RightOf / Fixed / ScreenCenter)
//! - FocusPolicy(Transparent / Dismissable / BlockBelow)
//! - Modal backdrop 渲染管线级合成
//!
//! 保持向后兼容:`content_handle` / `default_overlay_handle` / `default_modal_handle`
//! 使现有 Runtime / state.rs 的旧 API 调用点零改动。

use crate::core::ElementId;
use crate::event::EventManager;
use crate::geometry::{Point, Rect};
use crate::runtime::element::ElementTree;
use crate::view::node::ViewNode;
use std::cell::{Cell, RefCell};

// ============================================================================
// 层语义分类
// ============================================================================

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum LayerKind {
    /// z-range: 0..=999  主内容(原 Base)
    Content,
    /// z-range: 1000..=1999  弹出菜单 / ComboBox 下拉列表
    Popup,
    /// z-range: 2000..=2999  Toast / 通知(原 Overlay 语义)
    Overlay,
    /// z-range: 3000..=3999  模态弹框(原 Modal,支持叠加 + 阻塞下层)
    Modal,
    /// z-range: 4000..=4999  Tooltip(必须在 Modal 之上)
    Tooltip,
    /// z-range: 5000..=5999  调试面板 / 拖拽中的幽灵节点
    System,
}

impl LayerKind {
    /// 每种 Kind 保留 1000 个 z 档位(同一 Kind 内按插入顺序 ++)
    pub fn z_base(&self) -> i32 {
        match self {
            LayerKind::Content => 0,
            LayerKind::Popup => 1000,
            LayerKind::Overlay => 2000,
            LayerKind::Modal => 3000,
            LayerKind::Tooltip => 4000,
            LayerKind::System => 5000,
        }
    }

    pub fn z_range(&self) -> std::ops::RangeInclusive<i32> {
        self.z_base()..=(self.z_base() + 999)
    }

    /// 事件派发 / 命中测试:高 z 优先
    pub fn dispatch_order() -> [LayerKind; 6] {
        [
            LayerKind::System,
            LayerKind::Tooltip,
            LayerKind::Modal,
            LayerKind::Overlay,
            LayerKind::Popup,
            LayerKind::Content,
        ]
    }
}

// ============================================================================
// LayerHandle
// ============================================================================

/// 条目 ID = u64 generational,用户拿到后可 hide 指定条目
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct LayerHandle(pub u64);

// ============================================================================
// Anchor
// ============================================================================

/// 锚点信息:Tooltip/Popup 需要相对屏幕某个矩形出现在合理位置(上方 / 下方 / 居中对齐)
#[derive(Debug, Clone, Copy)]
pub enum Anchor {
    /// 不锚定,按 FlexStyle 正常布局(Modal / Content)
    None,
    /// 以锚矩形为基准在上方出现,水平居中对齐
    Above { anchor: Rect, gap: f32 },
    /// 以锚矩形为基准在下方出现
    Below { anchor: Rect, gap: f32 },
    /// 以锚矩形为基准在左侧出现
    LeftOf { anchor: Rect, gap: f32 },
    /// 以锚矩形为基准在右侧出现
    RightOf { anchor: Rect, gap: f32 },
    /// 固定屏幕坐标 (x, y) 左上角
    Fixed { x: f32, y: f32 },
    /// 屏幕正中央(Modal 常用)
    ScreenCenter,
}

// ============================================================================
// FocusPolicy
// ============================================================================

/// 焦点/阻塞策略:决定本条目是否吞掉落在其矩形外的事件
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FocusPolicy {
    /// 不阻塞下层:落在本条目外的事件派发给下层条目(Tooltip/Popup/Overlay/Content 适用)
    Transparent,
    /// 本条目外的事件 = 先触发 "auto dismiss"(如果配置了),然后继续派发给下层
    Dismissable,
    /// 阻塞下层:所有下层事件派发跳过(顶层 Modal 适用)
    BlockBelow,
}

// ============================================================================
// LayerOptions
// ============================================================================

#[derive(Debug, Clone, Copy)]
pub struct LayerOptions {
    pub visible: bool,
    pub dismiss_on_outside: bool,
    pub backdrop: Option<crate::geometry::Color>,
}

impl Default for LayerOptions {
    fn default() -> Self {
        Self {
            visible: true,
            dismiss_on_outside: false,
            backdrop: None,
        }
    }
}

// ============================================================================
// LayerEntry
// ============================================================================

/// 栈内单个条目 = 一层视觉 + 交互单元
#[derive(Clone)]
pub struct LayerEntry {
    pub handle: LayerHandle,
    pub kind: LayerKind,
    /// 根 ElementId(ElementTree 中真实存在)
    pub root_id: ElementId,
    /// 锚定:布局阶段按 Anchor + 测量尺寸计算最终 top/left
    pub anchor: Anchor,
    /// 可见性(隐藏时:跳过命中测试 + 跳过渲染,但保留 ElementTree 节点)
    pub visible: Cell<bool>,
    /// 阻塞策略
    pub focus: FocusPolicy,
    /// 条目在其 Kind 内的插入顺序,用于同 Kind 内 z 排序(0 = 最早)
    pub seq: i32,
    /// 点击本条目外是否自动隐藏(Dismissable 专用)
    pub dismiss_on_outside_click: bool,
    /// Modal 专属:在本条目下方绘制半透明遮罩矩形,颜色可配置
    pub backdrop: Option<crate::geometry::Color>,
}

impl LayerEntry {
    /// 实际渲染 z = kind.z_base() + seq
    pub fn z(&self) -> i32 {
        self.kind.z_base() + self.seq
    }
}

impl std::fmt::Debug for LayerEntry {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("LayerEntry")
            .field("handle", &self.handle)
            .field("kind", &self.kind)
            .field("root_id", &self.root_id)
            .field("anchor", &self.anchor)
            .field("visible", &self.visible)
            .field("focus", &self.focus)
            .field("seq", &self.seq)
            .field("dismiss_on_outside_click", &self.dismiss_on_outside_click)
            .field("backdrop", &self.backdrop)
            .finish()
    }
}

// ============================================================================
// LayerStack
// ============================================================================

pub struct LayerStack {
    pub tree: ElementTree,
    pub event_manager: RefCell<EventManager>,
    entries: RefCell<Vec<LayerEntry>>,
    /// 每种 Kind 的下一个 seq 编号(单调递增,删除不回收,保证稳定)
    kind_seq: RefCell<[i32; 6]>, // 下标对应 LayerKind discriminant
    /// handle 生成器
    next_handle: Cell<u64>,

    // ========== 向后兼容 ==========
    /// Content 层固定句柄(LayerHandle(0)),由 Runtime 在首次 submit_view_tree 时创建
    content_handle: Cell<Option<LayerHandle>>,
    /// 默认 Overlay 句柄(单实例语义,兼容旧 show_overlay/hide_overlay)
    default_overlay_handle: Cell<Option<LayerHandle>>,
    /// 默认 Modal 句柄(单实例语义,兼容旧 show_modal/hide_modal)
    default_modal_handle: Cell<Option<LayerHandle>>,
}

impl LayerStack {
    pub fn new() -> Self {
        Self {
            tree: ElementTree::new(),
            event_manager: RefCell::new(EventManager::new()),
            entries: RefCell::new(Vec::new()),
            kind_seq: RefCell::new([0; 6]),
            next_handle: Cell::new(0),
            content_handle: Cell::new(None),
            default_overlay_handle: Cell::new(None),
            default_modal_handle: Cell::new(None),
        }
    }

    // ========== 公开 API ==========

    /// 压入一条目,返回句柄。
    /// 注意:使用 `create_subtree_from_node` 递归构建整棵子树,
    /// 否则浮层只有根节点而无内容(如弹窗背景但有缺标题/按钮)。
    pub fn push(
        &mut self,
        kind: LayerKind,
        view: ViewNode,
        anchor: Anchor,
        focus: FocusPolicy,
        opts: LayerOptions,
    ) -> LayerHandle {
        let id = self.tree.create_subtree_from_node(&view);
        let handle = LayerHandle(self.next_handle.get());
        self.next_handle.set(handle.0 + 1);
        let seq = self.alloc_seq(kind);
        let entry = LayerEntry {
            handle,
            kind,
            root_id: id,
            anchor,
            visible: Cell::new(opts.visible),
            focus,
            seq,
            dismiss_on_outside_click: opts.dismiss_on_outside,
            backdrop: opts.backdrop,
        };
        self.entries.borrow_mut().push(entry);
        handle
    }

    /// 移除一条目(ElementTree.remove + entries 删除)
    pub fn remove(&mut self, handle: LayerHandle) {
        let mut es = self.entries.borrow_mut();
        if let Some(pos) = es.iter().position(|e| e.handle == handle) {
            let e = es.remove(pos);
            self.tree.remove(e.root_id);
        }
    }

    pub fn set_visible(&self, handle: LayerHandle, v: bool) {
        if let Some(entry) = self.by_handle(handle) {
            entry.visible.set(v);
        }
    }

    pub fn update_view(&mut self, handle: LayerHandle, new_view: ViewNode) {
        if let Some(entry) = self.by_handle(handle) {
            self.tree.update_node(entry.root_id, &new_view);
        }
    }

    pub fn reanchor(&self, handle: LayerHandle, new_anchor: Anchor) {
        let mut es = self.entries.borrow_mut();
        if let Some(pos) = es.iter().position(|e| e.handle == handle) {
            es[pos].anchor = new_anchor;
        }
    }

    // ========== 查询 ==========

    /// 按 handle 查找条目(返回克隆)
    pub fn by_handle(&self, handle: LayerHandle) -> Option<LayerEntry> {
        self.entries
            .borrow()
            .iter()
            .find(|e| e.handle == handle)
            .cloned()
    }

    /// 渲染 / 命中测试用:按 z() 升序(同 Kind 内早插入的在下)
    pub fn sorted_entries_for_render(&self) -> Vec<LayerEntry> {
        let mut es = self.entries.borrow().clone();
        es.sort_by_key(|e| e.z());
        es
    }

    /// 事件派发用:按 z() 降序(最顶条目先命中)
    pub fn sorted_entries_for_hit(&self) -> Vec<LayerEntry> {
        let mut es = self.entries.borrow().clone();
        es.sort_by_key(|e| std::cmp::Reverse(e.z()));
        es
    }

    /// 顶层阻塞 Modal:若返回 Some(handle),只对该 handle 及更高 z 的条目派发事件
    pub fn top_blocking_modal(&self) -> Option<LayerHandle> {
        let es = self.entries.borrow();
        es.iter()
            .filter(|e| {
                e.visible.get() && e.focus == FocusPolicy::BlockBelow && e.kind == LayerKind::Modal
            })
            .max_by_key(|e| e.z())
            .map(|e| e.handle)
    }

    // ========== 内部 ==========

    fn alloc_seq(&self, kind: LayerKind) -> i32 {
        let mut arr = self.kind_seq.borrow_mut();
        let idx = kind as usize;
        let s = arr[idx];
        arr[idx] = s + 1;
        s
    }

    // ========== 向后兼容 API ==========

    /// 获取 Content 层 root ElementId
    pub fn content_root_id(&self) -> Option<ElementId> {
        self.content_handle
            .get()
            .and_then(|h| self.by_handle(h))
            .map(|e| e.root_id)
    }

    /// 获取默认 Overlay 层 root ElementId
    pub fn default_overlay_root_id(&self) -> Option<ElementId> {
        self.default_overlay_handle
            .get()
            .and_then(|h| self.by_handle(h))
            .map(|e| e.root_id)
    }

    /// 获取默认 Modal 层 root ElementId
    pub fn default_modal_root_id(&self) -> Option<ElementId> {
        self.default_modal_handle
            .get()
            .and_then(|h| self.by_handle(h))
            .map(|e| e.root_id)
    }

    /// 设置 Content 层 root(兼容旧 set_base_root)
    pub fn set_content_root(&mut self, id: ElementId) {
        let handle = LayerHandle(0);
        // 如果 content_handle 已存在,更新其 root_id;否则新建
        if self.content_handle.get().is_some() {
            if let Some(entry) = self.by_handle(handle) {
                // 如果旧 root 不同,先移除旧的
                if entry.root_id != id {
                    self.tree.remove(entry.root_id);
                    let mut es = self.entries.borrow_mut();
                    if let Some(pos) = es.iter().position(|e| e.handle == handle) {
                        es[pos].root_id = id;
                    }
                }
            }
        } else {
            // 首次创建 Content entry
            let handle = LayerHandle(self.next_handle.get());
            self.next_handle.set(handle.0 + 1);
            let seq = self.alloc_seq(LayerKind::Content);
            let entry = LayerEntry {
                handle,
                kind: LayerKind::Content,
                root_id: id,
                anchor: Anchor::None,
                visible: Cell::new(true),
                focus: FocusPolicy::Transparent,
                seq,
                dismiss_on_outside_click: false,
                backdrop: None,
            };
            self.entries.borrow_mut().push(entry);
            self.content_handle.set(Some(handle));
        }
    }

    /// 设置默认 Overlay(兼容旧 show_overlay)
    pub fn push_default_overlay(&mut self, root_id: ElementId) {
        // 先移除旧的
        if let Some(h) = self.default_overlay_handle.get() {
            self.remove(h);
        }
        let handle = LayerHandle(self.next_handle.get());
        self.next_handle.set(handle.0 + 1);
        let seq = self.alloc_seq(LayerKind::Overlay);
        let entry = LayerEntry {
            handle,
            kind: LayerKind::Overlay,
            root_id,
            anchor: Anchor::None,
            visible: Cell::new(true),
            focus: FocusPolicy::Transparent,
            seq,
            dismiss_on_outside_click: false,
            backdrop: None,
        };
        self.entries.borrow_mut().push(entry);
        self.default_overlay_handle.set(Some(handle));
    }

    /// 移除默认 Overlay(兼容旧 hide_overlay)
    pub fn remove_default_overlay(&mut self) {
        if let Some(h) = self.default_overlay_handle.get() {
            self.remove(h);
            self.default_overlay_handle.set(None);
        }
    }

    /// 设置默认 Modal(兼容旧 show_modal)
    pub fn push_default_modal(&mut self, root_id: ElementId) {
        // 先移除旧的
        if let Some(h) = self.default_modal_handle.get() {
            self.remove(h);
        }
        let handle = LayerHandle(self.next_handle.get());
        self.next_handle.set(handle.0 + 1);
        let seq = self.alloc_seq(LayerKind::Modal);
        let entry = LayerEntry {
            handle,
            kind: LayerKind::Modal,
            root_id,
            anchor: Anchor::ScreenCenter,
            visible: Cell::new(true),
            focus: FocusPolicy::BlockBelow,
            seq,
            dismiss_on_outside_click: false,
            backdrop: Some(crate::geometry::Color::rgba(0, 0, 0, 80)), // 半透明遮罩
        };
        self.entries.borrow_mut().push(entry);
        self.default_modal_handle.set(Some(handle));
    }

    /// 移除默认 Modal(兼容旧 hide_modal)
    pub fn remove_default_modal(&mut self) {
        if let Some(h) = self.default_modal_handle.get() {
            self.remove(h);
            self.default_modal_handle.set(None);
        }
    }

    /// 检查指定 LayerKind 是否有内容(兼容旧 layer_has_content)
    pub fn layer_has_content(&self, kind: LayerKind) -> bool {
        self.entries
            .borrow()
            .iter()
            .any(|e| e.kind == kind && e.visible.get())
    }

    // ========== 命中测试 ==========

    fn hit_test_rec(tree: &ElementTree, id: ElementId, px: f32, py: f32) -> Option<ElementId> {
        let layout = tree.layout(id);
        if !layout.contains(px, py) {
            return None;
        }
        // 优先命中更内层的节点
        for cid in tree.children_ref(id).iter().rev() {
            if let Some(hit) = Self::hit_test_rec(tree, *cid, px, py) {
                return Some(hit);
            }
        }
        Some(id)
    }

    /// 跨所有层做命中测试,返回命中的层与元素(按 dispatch_order 优先高 z)
    pub fn hit_test_top(&mut self, point: Point) -> Option<(LayerKind, ElementId, LayerHandle)> {
        // 获取所有条目按 z 降序排列
        let entries = self.sorted_entries_for_hit();
        let cutoff_z = self
            .top_blocking_modal()
            .and_then(|h| self.by_handle(h))
            .map(|e| e.z())
            .unwrap_or(-1);

        let mut dismissed_handles: Vec<LayerHandle> = Vec::new();

        for entry in &entries {
            if !entry.visible.get() {
                continue;
            }
            if entry.z() < cutoff_z {
                break;
            }

            if let Some(id) = Self::hit_test_rec(&self.tree, entry.root_id, point.x, point.y) {
                return Some((entry.kind, id, entry.handle));
            }

            // 未命中本条目:FocusPolicy::Dismissable + dismiss_on_outside_click = true → 标记待 dismiss
            if entry.focus == FocusPolicy::Dismissable && entry.dismiss_on_outside_click {
                dismissed_handles.push(entry.handle);
            }
        }

        // 末命中任何条目时,对标记的条目执行 dismiss(点击外部关闭 Popup)
        for h in &dismissed_handles {
            self.remove(*h);
        }
        if !dismissed_handles.is_empty() {
            // 通知渲染器需要重绘
            // 通过 set_visible 触发效果
        }

        None
    }

    /// 跨层查找路径
    pub fn path_to(&self, target: ElementId) -> Vec<ElementId> {
        self.tree.path_to(target)
    }
}

impl Default for LayerStack {
    fn default() -> Self {
        Self::new()
    }
}