2 个版本
使用旧的 Rust 2015
0.1.1 | 2018 年 11 月 2 日 |
---|---|
0.1.0 | 2018 年 11 月 2 日 |
#783 in GUI
71KB
1.5K SLoC
以数据为中心的 Rust 原生 UI 工具包。
Druid 是一个实验性的 Rust 原生 UI 工具包。其主要目标是提供优质的用户体验。实现这一目标有许多因素,包括性能、丰富的交互集(因此有一个支持这些交互的控件库),以及与原生平台良好协作。更多信息请参阅目标部分。
我们已经在 crates.io 上定期发布 Druid,但 API 仍然不稳定。所有更改均记录在变更日志中。
有关一些关键概念的概述,请参阅(工作正在进行中)的Druid 书籍。
项目状态
Druid 项目将由核心开发团队停止。
新的开发工作集中在Xilem上,它进行了许多根本性的改变,以允许创建更多样化的应用程序,并具有更好的性能,但它也大量继承了 Druid。我们将Xilem视为 Druid 的未来。
Druid 对于某些应用程序子集来说是可用的,并且具有丰富的测试历史,这确保了稳定性和正确性。但我们不期望在 Druid 中添加任何主要的新功能。因此,我们不推荐使用 Druid 开发全新的应用程序。如果您坚持使用,请确保您的应用程序不需要 Druid 没有的功能,例如可访问性或 3D 支持。
贡献
由于 Druid 项目正在停止,我们仍将接受所有贡献,但我们更倾向于优先考虑错误修复和文档改进,而不是新功能。
在Zulip 聊天实例的 #druid-help 和 #druid 频道中,询问问题和讨论开发工作是很好的地方。
我们非常欢迎通过 GitHub pull requests 的贡献。有关更多详细信息,请参阅CONTRIBUTING.md。
示例
以下是一个简单的计数器示例应用程序
use druid::widget::{Button, Flex, Label};
use druid::{AppLauncher, LocalizedString, PlatformError, Widget, WidgetExt, WindowDesc};
fn main() -> Result<(), PlatformError> {
let main_window = WindowDesc::new(ui_builder());
let data = 0_u32;
AppLauncher::with_window(main_window)
.log_to_console()
.launch(data)
}
fn ui_builder() -> impl Widget<u32> {
// The label text will be computed dynamically based on the current locale and count
let text =
LocalizedString::new("hello-counter").with_arg("count", |data: &u32, _env| (*data).into());
let label = Label::new(text).padding(5.0).center();
let button = Button::new("increment")
.on_click(|_ctx, data, _env| *data += 1)
.padding(5.0);
Flex::column().with_child(label).with_child(button)
}
查看示例文件夹,以了解Druid现有功能和组件的更全面演示。查看druid_widget_nursery获取更多组件。
屏幕截图
使用Druid
Druid的一个明确目标是易于构建,如果您遇到任何困难,请提出问题。Druid可在crates.io找到,应作为独立依赖项工作(它导出您需要的所有druid-shell、piet和kurbo组件)
druid = "0.8.3"
由于Druid目前处于快速发展阶段,您可能更喜欢直接接触源码
druid = { git = "https://github.com/linebender/druid.git" }
平台说明
Linux
在Linux上,Druid需要gtk+3;请参阅GTK安装页面。(在基于ubuntu的发行版上,从终端运行sudo apt-get install libgtk-3-dev
即可完成任务。)
OpenBSD
在OpenBSD上,Druid需要gtk+3;从软件包中安装
pkg_add gtk+3
另外,还有一个X11后端可用,尽管它目前缺少很多功能。缺少一些功能。您可以使用--features=x11
尝试它。
目标
Druid的目标是使编写和部署高质量桌面应用程序变得容易,在各种常见平台上提供平滑和精致的用户体验。为了实现这一目标,我们努力做到以下几点
- 使所有支持的平台都易于构建和打包。
- 实现抽象以避免特定平台的问题。
- 尊重平台约定和期望。
- 以最小的努力可靠地处理显示分辨率和缩放。
- 实现易于使用且强大的国际化。
- 提供强大的辅助功能支持。
- 生成小型、快速且内存使用低的二进制文件。
- 拥有一个小型依赖项树、高质量的代码库和良好的组织。
- 专注于强大的桌面级应用程序。
- 提供灵活的布局和常用组件。
- 根据需要轻松创建自定义组件和应用逻辑。
非目标
为了实现这些目标,我们无法支持每个用例。幸运的是,Rust社区正在开发各种不同目标的不同库,以下是一些Druid的非目标以及可能的替代方案,它们可以提供这些功能
- 使用平台原生的组件或模仿它们。(Relm,Slint)
- 轻松嵌入到自定义渲染管线。(Conrod)
- 遵循特定的架构风格,例如Elm。(Iced,Relm)
- 支持将渲染输出到HTML,以针对网络。(Iced,Moxie)
Druid只是众多正在进行的Rust原生GUI实验之一。如果它不适合您的用例,也许其他其中之一会适合!
概念
druid-shell
Druid工具包使用druid-shell
来提供一个平台抽象的应用程序外壳。druid-shell
负责启动原生平台运行循环,监听事件,将它们转换为平台无关的表示,并使用它们调用用户提供的处理程序。
在开发时,druid-shell 与 Druid 工具箱一起进行,旨在足够通用,以便其他对 Rust GUI 进行实验的项目可以重用它。druid-shell crate 包含了一些非 druid 的示例。
piet
Druid 依赖于 Piet 库 来进行绘制和文本布局。Piet 是一个具有多个后端的 2D 图形抽象库:目前有 piet-direct2d
、piet-coregraphics
、piet-cairo
、piet-web
和 piet-svg
可用。在 Druid 平台支持方面,macOS 使用 piet-coregraphics
,Linux/OpenBSD/FreeBSD 使用 piet-cairo
,Windows 使用 piet-direct2d
,而网络使用 piet-web
。
use druid::kurbo::{BezPath, Point, Rect};
use druid::piet::Color;
// Create an arbitrary bezier path
// (ctx.size() returns the size of the layout rect we're painting in)
let mut path = BezPath::new();
path.move_to(Point::ORIGIN);
path.quad_to(
(80.0, 90.0),
(ctx.size().width, ctx.size().height),
);
// Create a color
let stroke_color = Color::rgb8(0x00, 0x80, 0x00);
// Stroke the path with thickness 1.0
ctx.stroke(path, &stroke_color, 1.0);
// Rectangles: the path for practical people
let rect = Rect::from_origin_size((10., 10.), (100., 100.));
// Note the Color:rgba8 which includes an alpha channel (7F in this case)
let fill_color = Color::rgba8(0x00, 0x00, 0x00, 0x7F);
ctx.fill(rect, &fill_color);
小部件
Druid 中的小部件(文本框、按钮、布局组件等)是实现 Widget 特质 的对象。该特质由一个类型(T
)用于关联数据。所有特质方法(event
、lifecycle
、update
、paint
和 layout
)都提供了对数据的访问,在 event
的情况下,引用是可变的,以便事件可以直接更新数据。
每次应用程序数据发生变化时,框架都会通过 update
方法遍历小部件层次结构。
所有的小部件特质方法都提供了一个相应的上下文(EventCtx、LifeCycleCtx、UpdateCtx、LayoutCtx、PaintCtx)。小部件可以通过调用该上下文的方法来请求事物并触发动作。
此外,所有特质方法都提供了一个环境 Env
,其中包含当前的主题参数(颜色、尺寸等)。
impl<T: Data> Widget<T> for Button<T> {
fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut T, env: &Env) {
...
}
fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &T, env: &Env) {
...
}
fn update(&mut self, ctx: &mut UpdateCtx, old_data: &T, data: &T, env: &Env) {
...
}
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, data: &T, env: &Env) -> Size {
...
}
fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env) {
...
}
}
Druid 提供了许多 基本实用和布局小部件,并且实现自己的小部件也很容易。您还可以将小部件组合成新的小部件。
fn build_widget() -> impl Widget<u32> {
let mut col = Flex::column();
for i in 0..30 {
let button = Button::new(format!("Button {}", i).padding(5.0);
col.add_child(button);
}
Scroll::new(col)
}
布局
Druid 的布局协议受到 Flutter 的框布局模型 的强烈启发。在 Druid 中,小部件会收到一个 BoxConstraint
,它为布局提供了最小和最大尺寸。如果适用,小部件还负责计算其子小部件的适当约束。
数据
Druid 使用 Data 特质 来表示 值类型。这些类型应该易于比较且易于克隆。
通常,您可以使用 derive
来为您自己的类型生成一个 Data
实现器。
#[derive(Clone, Data)]
struct AppState {
which: bool,
value: f64,
}
透镜
Lens 数据类型 提供了对更大数据结构中某个部分的访问。与 Data
类似,这也可以生成。派生的透镜可以通过与字段同名的关系常量来访问。
#[derive(Clone, Data, Lens)]
struct AppState {
which: bool,
value: f64,
}
要使用透镜,请将您的小部件包装在 LensWrap
中(注意将驼峰式命名法转换为蛇形命名法)
LensWrap::new(WidgetThatExpectsf64::new(), AppState::value);
或者,可以使用 lens
宏按需构建结构体、元组和可索引容器上的透镜
LensWrap::new(WidgetThatExpectsf64::new(), lens!(AppState, value));
这在处理另一个crate中定义的类型时特别有用。
作者
主要作者是Raph Levien和Colin Rofls,得到了一个活跃而友好的社区的很大支持。更多信息请参阅AUTHORS文件。
依赖
~1.4–2MB
~28K SLoC