1 个不稳定版本
0.0.0-alpha.1 | 2023 年 8 月 26 日 |
---|
#386 在 GUI
110KB
2.5K SLoC
Kolibri - 一个设计得与同名的库一样轻量的 GUI 框架
什么是 Kolibri?
Kolibri 是一个非常受 egui 启发的嵌入式即时模式 GUI 微型框架。Kolibri 设计得非常简单。
快速概览
本节中使用的所有示例也可以在
examples
文件夹中找到。目前尚无大量文档,但将在 Kolibri 达到 0.1.0 之前添加。
极其简单,极其高效
快速迭代,像编写文档一样设计 GUI,然后在几分钟内在任何地方运行。
fn main() {
// ... setup code
let mut i = 0;
loop {
// create the UI each frame
let mut ui = Ui::new_fullscreen(&mut display, medsize_rgb565_style());
// ... input code
ui.clear_background();
ui.add(Label::new("Basic Example").with_font(ascii::FONT_10X20));
ui.add(Label::new("Basic Counter (7LOC)"));
if ui.add_horizontal(Button::new("-")).clicked() {
i = i.saturating_sub(1);
}
ui.add_horizontal(Label::new(format!("Clicked {} times", i).as_ref()));
if ui.add_horizontal(Button::new("+")).clicked() {
i = i.saturating_add(1);
}
// ... simulator code
}
}
这 11 行代码将生成此 GUI
是的,就这么简单。没有模板,什么都没有。如果想要查看使用 embedded-graphics-simulator
的完整代码,请查看 examples
文件夹中的 basic-example.rs
文件。(注意,您需要安装 sdl2
才能运行模拟器)
高度优化以提高性能
增量重绘
使用 Kolibri 的智能状态系统,您只需重绘实际需要的内容。这使得即使是超慢的屏幕也能以比人眼能看到的速度更快的速度运行。
那么,这需要多少额外的代码?您需要做两件事
- 使用要使用的智能状态数量初始化一个
SmartstateProvider
- 将一个
smartstate
添加到您希望是智能状态反应的每个小部件
此外,您需要告诉智能状态提供者何时需要强制重绘小部件。
fn main() {
// [...]
// initialize smartstate provider
let smartstates = SmartstateProvider::<10>::new();
// clear the background only once
Ui::new_fullscreen(&mut display, medsize_rgb565_style()).clear_background().unwrap();
loop {
// [...]
// restart the counter at the start (or end) of the loop
smartstates.restart_counter();
// add a smartstate to each widget
ui.add(Label::new("Basic Example").with_font(ascii::FONT_10X20).smartstate(smartstates.next()));
// [...]
if ui.add_horizontal(Button::new("-").smartstate(smartstates.next())).clicked() {
i = i.saturating_sub(1);
smartstates.next().force_redraw()
}
ui.add_horizontal(Label::new(format!("Clicked {} times", i).as_ref()).smartstate(smartstates.next()));
// [...]
}
}
为此麻烦,您在上述示例的 ILI9341 SPI 显示器上可以获得约 15 倍的速度提升,而对于更复杂的 GUI,则超过 100 倍。
注意
这可能在将来自动更改,这将消除对
smartstate
方法的需求,但也将是一个破坏性更改。
智能缓冲
由于内存限制,在嵌入式设备上使用全帧缓冲通常是不可能的。Kolibri 允许您使用一个小缓冲区,其中每个小部件都可以在其中绘制,如果它足够小以至于可以适应。这使得您可以以相同的速度(甚至由于增量重绘而更快)运行,同时只使用一小部分内存。
// Initialize the buffer somehow
fn main() {
// [...]
let mut buffer = [Rgb565::CSS_BLACK; 100 * 60 /* guess your maximum widget size approximately */];
// [...]
loop {
// [...]
// create the UI each frame
let mut ui = Ui::new_fullscreen(&mut display, medsize_rgb565_style());
// set the buffer
ui.set_buffer(&mut buffer);
// [...]
}
}
使用缓冲区可以完全消除重绘时的闪烁,并且可以显著提高绘图速度(在ILI9341 SPI显示屏上可高达3倍)。
主题化
Kolibri内置了主题系统,允许您轻松更改GUI的外观。几乎所有方面都可以自定义,从颜色到字体、图标间距、大小等。
这允许您为任何PixelColor
类型创建主题(例如,黑白用于电子墨水屏幕),甚至可以在运行时切换主题。
(从左到右:深色、蓝色、浅色、复古)
与所有设备兼容
Kolibri基于embedded-graphics
库,这意味着它可以与Rust的几乎所有显示驱动程序一起使用。Kolibri简单直观的输入系统允许您使用任何可以给出屏幕上(x, y)
点的输入设备,例如触摸屏驱动程序或鼠标指针。
还计划支持其他输入设备(例如模拟鼠标光标或基于编码器的输入系统),但目前尚未提供。如果您需要这些功能用于项目,请随时提交问题或拉取请求。
当前状态
Kolibri正在快速发展。目前,它已经具备了小型基本应用所需的一切。它仍然处于alpha版本,但API正在成形。将发生一些破坏性变化,但它们应该都是次要的。
如果您有兴趣贡献,请随时提交问题或拉取请求。
如果您有任何问题,您也可以在嵌入式图形matrix频道找到我。
已实现和计划的功能
基本功能
- 基于embedded-graphics的UI渲染
- 基本小部件(按钮、标签、复选框等)
- 图标
- 增量渲染(仅重绘实际需要的内容)
- 可选基于缓冲区的渲染
- 样式
高级(且细致)
-
布局
- 从右到左,从上到下布局
- 对齐方式(居中、右对齐、底部等)
- 侧面板(右侧)
- 侧面板(所有侧面)
- 模态窗口(例如,在所有其他内容上方绘制警报框)
- 部分完成。仍需要大量手动工作
-
样式
- 样式系统
- 预制的RGB565样式
- 其他颜色类型的预制样式
- 子UI,用于实时编辑样式
-
小部件
- 按钮
- 标签
- 复选框
- 图标
- 间隔
- 图标按钮
- 列表框
- 类似滚动区域的组件
- 进度条
- 切换
- 图表
-
性能
- 必要时无堆栈
- 小缓冲区绘制所有内容
- 增量重绘
-
输入
- 通用输入系统(触摸)
- 智能状态反应基本小部件
- 虚拟鼠标光标(例如,用于非触摸屏的摇杆交互)
- 位置获取器/强制交互器,例如编码器输入
- 自定义手势
- 没有某种手势管理结构的帮助几乎不可能实现。可能更适合作为一个单独的库。
-
测试
- 非小部件代码的单元测试
- 帧缓冲区
- 智能状态
- 小部件的单元测试
- 绘图组件的单元测试
- 定位器
- 绘图器
- 布局的单元测试(目前由不存在的布局阻止)
- Ui结构的单元测试
- 自动集成测试(可能是Wokwi?)
- 非小部件代码的单元测试
-
模拟器(尚未计划,目前只是一个想法)
- 基于e-g web模拟器的示例
- 基于e-g web模拟器的游乐场
- 选择要忽略的行(理由:粘贴嵌入式代码,忽略所有调用软件的行,然后在浏览器中查看和开发GUI,然后将代码复制回嵌入式应用程序,无需删除行)
- 超快实时重新加载
遗漏了什么?添加一个包含您认为有用的功能的问题。
预期的破坏性变化
SmartstateProvider
可能将被集成到 GUI 中,这将消除在部件上使用smartstate
方法的需要。- 子 UI 方法(例如
ui.sub_ui()
或ui.right_panel()
)的回调将更改其签名从(&mut UI) -> GuiResult<()>
到(&mut UI) -> ()
以使 Kolibri 更加易用。预期的 API 变更
// current ui.sub_ui(|ui| { ui.clear_background()?; ui.add(Label::new("Hello World!")); Ok(()) }).unwrap(); // future ui.sub_ui(|ui| { ui.clear_background().ok(); ui.add(Label::new("Hello World!")); });
为什么还需要另一个 GUI 框架?
实际上,它在某种程度上是第一个,至少在其非常、非常具体的细分市场中。嵌入式图形环境很棒,尽管相对底层。这个库的目的是使创建简单的到中等复杂的 GUI 变得非常容易。实际上没有其他东西能做这个,至少在编写这个库的时候是这样。
旁注:什么是 Kolibri?
Kolibri 是德语中蜂鸟的名称,这是一种非常快、非常灵活的小鸟。还有一个同名操作系统(KolibriOS),出于类似的原因:它体积小且速度快。这个库与 KolibriOS 项目没有任何关联,但我鼓励你对它感兴趣的话去了解一下。
这不是什么?
Kolibri 不是一个高端 GUI 框架。它不是用来创建非常复杂或超级漂亮的用户界面的。如果你对此感兴趣,请查看 lvgl 的 rust 绑定 或 slint(商业用途不免费)。
许可证
根据您选择
- Apache 许可证第 2 版 (LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT 许可证 (LICENSE-MIT 或 http://opensource.org/licenses/MIT)
任选其一。
贡献
除非您明确声明,否则任何有意提交以包含在您的工作中的贡献,根据 Apache-2.0 许可证的定义,将按上述方式双重许可,不附加任何额外条款或条件。
依赖项
约 5MB
约 65K SLoC