5个版本
1.0.0-alpha4 | 2021年8月5日 |
---|---|
1.0.0-alpha3 | 2021年8月4日 |
1.0.0-alpha2 | 2021年7月31日 |
1.0.0-alpha1 | 2021年7月20日 |
0.1.0 | 2018年11月18日 |
#560 in GUI
用于 pangolin
715KB
12K SLoC
Azul - 桌面GUI框架
Azul是一个免费的、函数式、响应式的GUI框架,用于Rust和C++,使用WebRender渲染引擎和类似于CSS/HTML的文档对象模型,快速开发美观的本地桌面应用程序
网站 | 用户指南 | API文档 | 视频演示 | Matrix聊天
关于
Azul是一个用于在Rust和C中创建图形用户界面的库。它结合了函数式、响应式和数据导向编程的范式,并提供了一个适合开发跨平台桌面应用程序的API。Azul的两个核心原则是不渲染不可见的对象,以及通过DOM树组合而不是继承来使用。
Azul通过不允许UI/渲染逻辑以可变方式访问应用程序数据来分离业务逻辑/回调、数据模型和UI渲染/样式的关注点。在Azul中,渲染视图是一个纯函数,它将你的应用程序数据映射到样式化的DOM。"小部件"只是渲染特定状态的函数,更复杂的组件使用函数组合。
由于重新创建DOM对象代价昂贵(注意:"昂贵"= 3毫秒),Azul缓存DOM对象,并且不在每一帧都重新创建它 - 只在回调请求重新创建时才创建。
应用程序和小部件数据使用引用计数的箱式类型(RefAny
)进行管理,如果需要,可以将其向下转换为具体类型。需要在帧之间保留的小部件本地数据存储在DOM节点上,类似于HTML dataset
属性可以用来存储小部件数据。
当前进度
最新的Windows版本可以在这里找到。
目前我正在使用这个框架来构建跨平台的GUI应用程序:虽然这个框架还没有完成,但至少可以构建出适用于Windows的本地、美观的应用程序——例如,这里有一个我正在制作的Excel克隆[点击查看]
创建这个演示大约花费了两小时。正如您所看到的,布局系统已经相当成熟。要运行此XML文件,请下载examples.zip文件夹,将“ui.xml”文件替换为链接文件,并重新启动xml.exe演示。XML本身可以热重载,并且可以后来编译成本地Rust代码——这既给您提供了快速的设计迭代时间,又提供了本地性能。
应用程序目前运行需要大约40MB的内存,当然CPU占用几乎为零。
使用正确的CSS样式,窗口与本地应用程序几乎无法区分。
Azul目前具有以下功能
- 文本输入/文本输入(请参阅“widgets”演示)
- 60+ FPS的动画(使用webrender)
- 支持CSS 查看支持的CSS键列表
- 解码/编码图像和字体(TTF,WOFF,OTF)。
- 跨平台文本形状(通过allsorts)
- 解析和渲染SVG(通过resvg)
- 使用OpenGL纹理渲染/嵌入OpenGL内容
- 将形状拼接到三角形中(通过lyon)
- 异步管理运行中的背景线程以进行文件I/O
- 解析XML(通过xmlparser)
- 稳定的API
当前可用的控件
按钮
TextInput
(问题:尚无光标/文本选择功能)复选框
ColorInput
(打开本地颜色选择器对话框)NumberInput
(与TextInput
相同,但仅接受数字输入)
所有控件都可通过CSS进行样式化。正在进行中的控件
进度条
滑块
下拉列表
单选选择
功能区
此外,Azul还提供了跨平台的MsgBox
和FileDialog
对话框。
注意事项
- 由于X11和Cocoa上的渲染问题,Azul目前只能在Windows上运行
- 非拉丁字体以及回退字体的文本形状非常基础/不存在
- 滚动,尤其是平滑滚动尚未完全实现
- 滚动条不会自动插入
- 富文本布局需要手动计算,而不是自动完成
- C++ API仍在开发中
- 布局引擎可能存在错误(但通常可以解决这些问题)
- 二进制ABI尚不稳定
- 无限滚动/延迟加载DOM内容尚不支持
- 菜单/上下文菜单尚未工作(stub API)
安装
由于相对较大的尺寸(以及提供C/C++互操作),Azul作为动态库构建在azul-dll
包中。您可以从azul.rs/releases下载预构建的二进制文件。
使用预构建的二进制文件
- 从azul.rs/releases下载库
- 设置链接器以链接到库
- Rust:将
AZUL_LINK_PATH
环境变量设置为库的路径 - C/C++:将发布页面上的
azul.h
复制到您的项目头文件,并将azul.dll
复制到您的IDE项目。
- Rust:将
Rust、C++和其他语言的API完全相同,因为API是由build.py
脚本自动生成的。如果您想为您的语言生成语言绑定,可以使用api.json
文件来生成。
在Linux上运行程序时,您可能还需要将libazul.so
复制到/usr/lib
。最终,一旦所有主要错误都得到解决,将通过将库合并到仓库中解决这个问题。
从源代码构建(crates.io)
默认情况下,您应该能够运行
cargo install --version 1.0.0 azul-dll
来从crates.io编译DLL。库将在$AZUL_LINK_PATH
目录中构建和安装,默认为$CARGO_HOME_DIR/lib/azul-dll-0.1.0/target/release/
从源代码构建(git)
从源代码构建库需要clang以及上述所有先决条件。
git clone https://github.com/fschutt/azul
cd azul-dll
cargo build --release
此命令应在/target/release
文件夹中生成一个azul.dll
文件,为了使用它,您还需要将AZUL_LINK_PATH
设置为$BUILD_DIR/target/release/
。
如果您正在开发库,您可能还需要重新生成Rust / C API,在这种情况下,您应该首选使用build.py
脚本
python3 ./build.py
示例
注意:小部件是针对每种编程语言定制的。所有回调都必须使用extern "C"
才能与库兼容。所有API类型的二进制布局在api.json
文件中描述。
Rust
use azul::prelude::*;
use azul_widgets::{button::Button, label::Label};
struct DataModel {
counter: usize,
}
// Model -> View
extern "C" fn render_my_view(data: &RefAny, _: LayoutInfo) -> StyledDom {
let mut result = StyledDom::default();
let data = match data.downcast_ref::<DataModel>() {
Some(s) => s,
None => return result,
};
let label = Label::new(format!("{}", data.counter)).dom();
let button = Button::with_label("Update counter")
.onmouseup(update_counter, data.clone())
.dom();
result
.append(label)
.append(button)
}
// View updates model
extern "C" fn update_counter(data: &mut RefAny, event: CallbackInfo) -> UpdateScreen {
let mut data = match data.downcast_mut::<DataModel>() {
Some(s) => s,
None => return UpdateScreen::DoNothing,
};
data.counter += 1;
UpdateScreen::RegenerateDomForCurrentWindow
}
fn main() {
let app = App::new(RefAny::new(DataModel { counter: 0 }), AppConfig::default());
app.run(WindowCreateOptions::new(render_my_view));
}
C++
#include "azul.h"
#include "azul-widgets.h"
using namespace azul;
using namespace azul.widgets.button;
using namespace azul.widgets.label;
struct DataModel {
counter: uint32_t
}
// Model -> View
StyledDom render_my_view(const RefAny& data, LayoutInfo info) {
auto result = StyledDom::default();
const DataModel* data = data.downcast_ref();
if !(data) {
return result;
}
auto label = Label::new(String::format("{counter}", &[data.counter])).dom();
auto button = Button::with_label("Update counter")
.onmouseup(update_counter, data.clone())
.dom();
result = result
.append(label)
.append(button);
return result;
}
UpdateScreen update_counter(RefAny& data, CallbackInfo event) {
DataModel data = data.downcast_mut().unwrap();
data.counter += 1;
return UpdateScreen::RegenerateDomForCurrentWindow;
}
int main() {
auto app = App::new(RefAny::new(DataModel { .counter = 0 }), AppConfig::default());
app.run(WindowCreateOptions::new(render_my_view));
}
C
#include "azul.h"
typedef struct {
uint32_t counter;
} DataModel;
void DataModel_delete(DataModel* restrict A) { }
AZ_REFLECT(DataModel, DataModel_delete);
AzStyledDom render_my_view(AzRefAny* restrict data, AzLayoutInfo info) {
AzString counter_string;
DataModelRef d = DataModelRef_create(data);
if (DataModel_downcastRef(data, &d)) {
AzFmtArgVec fmt_args = AzFmtArgVec_fromConstArray({{
.key = AzString_fromConstStr("counter"),
.value = AzFmtValue_Uint(d.ptr->counter)
}});
counter_string = AzString_format(AzString_fromConstStr("{counter}"), fmt_args);
} else {
return AzStyledDom_empty();
}
DataModelRef_delete(&d);
AzDom const html = {
.root = AzNodeData_new(AzNodeType_Body),
.children = AzDomVec_fromConstArray({AzDom_new(AzNodeType_Label(counter_string))}),
.total_children = 1, // len(children)
};
AzCss const css = AzCss_fromString(AzString_fromConstStr("body { font-size: 50px; }"));
return AzStyledDom_new(html, css);
}
UpdateScreen update_counter(RefAny& data, CallbackInfo event) {
DataModelRefMut d = DataModelRefMut_create(data);
if !(DataModel_downcastRef(data, &d)) {
return UpdateScreen_DoNothing;
}
d->ptr.counter += 1;
DataModelRefMut_delete(&d);
return UpdateScreen_RegenerateDomForCurrentWindow;
}
int main() {
DataModel model = { .counter = 5 };
AzApp app = AzApp_new(DataModel_upcast(model), AzAppConfig_default());
AzApp_run(app, AzWindowCreateOptions_new(render_my_view));
return 0;
}
文档
使用build.py
脚本构建文档,该脚本将在/target/html
目录中生成整个azul.rs
网站
python3 ./build.py
- 类文档可在azul.rs/api找到
- 教程可在azul.rs/guide找到。
注意:如果需要,类文档也可以打印成PDF格式。
许可证
此库根据LGPL 3.0许可证发布,但静态链接有例外。这意味着与FLTK和wxWidgets许可证类似,您可以在不发布源代码的情况下构建专有应用程序:您只需发布对azul库本身所做的更改即可。静态链接例外允许您在不发布代码的情况下静态链接Azul。
版权 2017 - 当前 Felix Schütt