1 个不稳定版本
0.0.5 | 2023年11月10日 |
---|
#371 在 GUI
在 tuig 中使用
250KB
3.5K SLoC
tuig-ui
tuig-ui 是一个针对字符网格的可预测即时模式 UI 系统。
使用方法
请查看 示例 以获取起点。您需要运行一个 'main loop'/'UI thread'。
- 获取下一个用户输入。
- 使用该输入创建一个
Region
和一个Screen
。 - 将某种类型的
Attachment
附加到渲染。通常顶级组件不需要直接实现Attachment
,因为可以直接使用Region
。 - 将
Screen
绘制到实际屏幕。
执行第一步和最后一步的 预期 方法是使用 tuig-iosys
,但没有理由您不能从您方便的任何来源创建 Action
/Screen
。
常见问题解答 (FAQ)
“可预测”是什么意思?
文本模式或字符网格 UI 很奇怪,因为您通常在非常小的“分辨率”下工作,即网格的大小——我写这个窗口大约有 130 列和 60 行——但每个“像素”可以包含相当多的信息。因此,您需要一个您可以确保一致控制的布局的 UI。不要与空白、单个像素、边距或奇怪的内容换行作斗争;东西就放在你放的地方。
缺点是,为了保持可预测性,它必须很简单。然而,考虑到通常在文本模式中看到的 UI 类型,它仍然适用于大多数用例。
即时模式是什么意思?
即时模式 是指一种图形编程中的API风格,其中您调用的API(假装)直接在屏幕上绘制。在UI的情况下,这意味着UI元素的定义(以及相关的输入处理和渲染)在每个帧的过程中同时进行。
例如,即时模式UI可能看起来像这样
struct ChatWindow {
friends: Vec<People>,
current: usize,
histories: Vec<History>,
partial: String,
}
impl<'s> Attachment<'s> for &ChatWindow {
type Output = ();
fn attach(self, root: Region<'s>) {
let (people, right) = root.split(cols!(15 *));
if let Some(sel) = people.attach(FriendsList::new(&self.friends, &self.current)) {
self.current = sel;
}
let (history, entry) = right.split(rows!(* 1));
history.attach(ChatHistory::new(&self.histories[self.current]));
if entry.attach(TextInput::new(&mut self.partial)).is_submitted() {
self.histories[self.current].add(mem::take(self.partial));
}
}
}
注意
- 您没有存储任何UI元素。您对象中保持的状态仅仅是您关心的渲染状态。
- 您的
attach
函数定义了您的UI布局和您对输入的响应。注意例如,当FriendsList
被连接时,它会返回用户刚选中的朋友(如果有的话),而TextInput
返回一个可以描述许多事情复杂的状态对象。
一方面,这种方法往往会导致代码更简单。您不需要担心回调或元素树或任何其他东西;您只需直接编写您想要的UI外观即可。另一方面,您的UI在函数中定义,该函数也是您所有事件处理代码的地方,因此它必须在每次输入时运行,并在没有输入时定期运行以显示外部状态更改。与懒加载输入并仅执行所需的精确回调相比,这可能会消耗更多的CPU。
尽管如此,除非您的UI非常复杂,否则这并不是很多。考虑到 tuig-ui
首要的设计目标是易于使用,性能虽然重要但次之,这种权衡是非常值得的。
依赖项
~0.7–1.2MB
~27K SLoC