druid-shell
Druid 工具包使用 Druid-shell 作為平臺(tái)抽象應(yīng)用程序 shell。Druid-shell 負(fù)責(zé)啟動(dòng)本機(jī)平臺(tái)運(yùn)行循環(huán),監(jiān)聽(tīng)事件,將它們轉(zhuǎn)換為與平臺(tái)無(wú)關(guān)的表示,并用它們調(diào)用用戶提供的處理程序。
piet
Druid依賴(lài) Piet 庫(kù)進(jìn)行繪圖和文本布局。Piet 是一個(gè)具有多個(gè)后端的2D 圖形抽象: Piet-direct2d、 Piet-coregraphy、 Piet-cairo、 Piet-web 和 Piet-svg 目前可用,并且計(jì)劃使用 GPU 后端。在通過(guò) Piet 對(duì) Druid 平臺(tái)的支持方面,macOS 使用 Piet-coregraph,Linux 和 OpenBSD 使用 Piet-cairo,Windows 使用 Piet-direct2d,web 使用 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 colorlet stroke_color = Color::rgb8(0x00, 0x80, 0x00);// Stroke the path with thickness 1.0ctx.stroke(path, &stroke_color, 1.0);// Rectangles: the path for practical peoplelet 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);
widgets
Druid 中的 Widget (文本框、按鈕、布局組件等)是實(shí)現(xiàn) Widget 特性的對(duì)象。Trait 由關(guān)聯(lián)數(shù)據(jù)的類(lèi)型(T)參數(shù)化。所有 trait 方法(事件、生命周期、更新、繪制和布局)都提供了對(duì)這些數(shù)據(jù)的訪問(wèn),并且在事件的情況下,引用是可變的,因此事件可以直接更新數(shù)據(jù)。
只要應(yīng)用程序數(shù)據(jù)發(fā)生變化,框架就會(huì)使用 update 方法遍歷小部件層次結(jié)構(gòu)。
所有小部件 trait 方法都提供了相應(yīng)的上下文(EventCtx、 LifeCycleCtx、 UpdateCtx、 LayoutCtx、 PaintCtx)。小部件可以通過(guò)調(diào)用上下文中的方法來(lái)請(qǐng)求事物并導(dǎo)致操作。
此外,所有 trait 方法都提供了一個(gè)環(huán)境 Env,其中包括當(dāng)前主題參數(shù)(顏色、尺寸等)。
impl Widget for Button { 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 提供了許多基本的實(shí)用工具和布局小部件,并且很容易實(shí)現(xiàn)自己的小部件。您還可以將小部件組裝成新的小部件:
fn build_widget() -> impl Widget { 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)}
layout
Druid的布局協(xié)議是強(qiáng)烈的靈感來(lái)自撲動(dòng)的盒子布局模型。在 Druid 中,小部件被傳遞一個(gè) BoxConstraint,它為它們提供了布局的最小和最大大小。如果適用,小部件還負(fù)責(zé)為其子級(jí)計(jì)算適當(dāng)?shù)募s束。
data
Druid 使用數(shù)據(jù)特征來(lái)表示值類(lèi)型。這些值類(lèi)型應(yīng)該比較便宜,克隆起來(lái)也便宜。通常,可以使用派生為類(lèi)型生成 Data impl。
#[derive(Clone, Data)]struct AppState { which: bool, value: f64,}
Lens
Lens 數(shù)據(jù)類(lèi)型提供了對(duì)更大數(shù)據(jù)結(jié)構(gòu)的一部分的訪問(wèn)。和 Data 一樣,這也可以派生出來(lái)。Derive lens 作為與字段同名的關(guān)聯(lián)常數(shù)訪問(wèn)。
#[derive(Clone, Data, Lens)]struct AppState { which: bool, value: f64,}
要使用Lens,用 LensWrap (注意 CamelCase 到 Snake _ case 的轉(zhuǎn)換)包裝你的小部件:
LensWrap::new(WidgetThatExpectsf64::new(), AppState::value);
或者,用于結(jié)構(gòu)、元組和可轉(zhuǎn)位容器的Lens可以根據(jù)需要用Lens宏來(lái)構(gòu)造:
LensWrap::new(WidgetThatExpectsf64::new(), lens!(AppState, value));