-
Notifications
You must be signed in to change notification settings - Fork 125
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
43de2cf
commit 564b440
Showing
5 changed files
with
271 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,62 +1,72 @@ | ||
**TODO - This is copy-pasted from ARCHITECTURE.md, needs to be edited.** | ||
(TODO - I'm rewriting this doc, shouldn't mention passes at all) | ||
|
||
### WidgetMut | ||
If you're building your own GUI framework on top of Masonry, or even a GUI app with specific needs, you'll probably want to invent your own widgets. | ||
|
||
In Masonry, widgets can't be mutated directly. All mutations go through a `WidgetMut` wrapper. So, to change a label's text, you might call `WidgetMut<Label>::set_text()`. This helps Masonry make sure that internal metadata is propagated after every widget change. | ||
This documentation explains how. | ||
|
||
Generally speaking, to create a WidgetMut, you need a reference to the parent context that will be updated when the WidgetMut is dropped. That can be the WidgetMut of a parent, an EventCtx / LifecycleCtx, or the WindowRoot. In general, container widgets will have methods such that you can get a WidgetMut of a child from the WidgetMut of a parent. | ||
|
||
WidgetMut gives direct mutable access to the widget tree. This can be used by GUI frameworks in their update method, and it can be used in tests to make specific local modifications and test their result. | ||
|
||
|
||
**TODO - This is copy-pasted from the pass spec RFC, needs to be edited.** | ||
|
||
## Editing the widget tree | ||
|
||
Widgets can be added and removed during event and rewrite passes *except* inside layout and register_children methods. | ||
|
||
Not doing so is a logic error and may trigger debug assertions. | ||
|
||
If you do want to add or remove a child during layout, you can always defer it with the `mutate_later` context method. | ||
|
||
|
||
## Widget methods and context types | ||
## The Widget trait | ||
|
||
Widgets are types which implement the `masonry::Widget` trait. | ||
|
||
This trait includes a set of methods that must be implemented to hook into the different passes listed above: | ||
This trait includes a set of methods that must be implemented to hook into Masonry's internals: | ||
|
||
```rust | ||
// Exact signatures may differ | ||
trait Widget { | ||
fn on_pointer_event(&mut self, ctx: &mut EventCtx, event: &PointerEvent); | ||
fn on_text_event(&mut self, ctx: &mut EventCtx, event: &TextEvent); | ||
fn on_access_event(&mut self, ctx: &mut EventCtx, event: &AccessEvent); | ||
|
||
fn register_children(&mut self, ctx: &mut RegisterCtx); | ||
fn update(&mut self, ctx: &mut UpdateCtx, event: &UpdateEvent); | ||
fn on_anim_frame(&mut self, ctx: &mut UpdateCtx, interval: u64); | ||
fn update(&mut self, ctx: &mut UpdateCtx, event: &Update); | ||
|
||
fn layout(&mut self, ctx: &mut LayoutCtx) -> Size; | ||
fn compose(&mut self, ctx: &mut ComposeCtx); | ||
|
||
fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene); | ||
fn accessibility(&mut self, ctx: &mut AccessCtx); | ||
fn accessibility(&mut self, ctx: &mut AccessCtx, node: &mut NodeBuilder); | ||
|
||
// ... | ||
} | ||
``` | ||
|
||
These methods all take a given context type as a parameter. | ||
Methods aside, `WidgetMut` references can provide a `MutateCtx` context. | ||
`WidgetRef` references can provide a `QueryCtx` context, which is used in some read-only methods. | ||
These methods are called by the framework at various points, with a `FoobarCtx` parameter giving information about the current widget (for example, its size, position, or whether it's currently hovered). | ||
The information accessible from the context type depends on the method. | ||
|
||
In the course of a frame, Masonry will run a series of passes over the widget tree, which will call these methods at different points: | ||
|
||
- `on_pointer_event`, `on_text_event` and `on_access_event` are called once after a user-initiated event (like a mouse click or keyboard input). | ||
- `on_anim_frame` is called once per frame for animated widgets. | ||
- `update` is called many times during a frame, with various events reflecting changes in the widget's state (for instance, it gets or loses focus). | ||
- `layout` is called during Masonry's layout pass. It takes size constraints and returns the widget's desired size. | ||
- `paint`, `accessibility` are called roughly every frame for every widget, to allow them to draw to the screen and describe their structure to assistive technologies. | ||
|
||
Most passes will skip most widgets by default. | ||
For instance, the paint pass will only call a widget's `paint` method once, and then cache the resulting scene. | ||
If your widget's appearance is changed by another method, you need to call `ctx.request_render()` to tell the framework to re-run the paint pass. | ||
|
||
Most context types include these methods for requesting future passes: | ||
|
||
- `request_render()` | ||
- `request_paint_only()` | ||
- `request_accessibility_update()` | ||
- `request_layout()` | ||
- `request_compose()` | ||
- `request_anim_frame()` | ||
|
||
|
||
## Widget mutation | ||
|
||
In Masonry, widgets generally can't be mutated directly. | ||
That is to say, even if you own a window, and even if that window holds a widget tree with a `Label` instance, you can't get a `&mut Label` directly from that window. | ||
|
||
Instead, there are two ways to mutate `Label`: | ||
|
||
- Inside a Widget method. Most methods (`on_pointer_event`, `update`, `layout`, etc) take `&mut self`. | ||
- Through a `WidgetMut` wrapper. So, to change the label's text, you will call `WidgetMut<Label>::set_text()`. This helps Masonry make sure that internal metadata is propagated after every widget change. | ||
|
||
TODO - edit_widget | ||
|
||
Those context types have many methods, some shared, some unique to a given pass. | ||
There are too many to document here, but we can lay out some general principles: | ||
TODO - mutate_later | ||
|
||
- Render passes should be pure and can be skipped occasionally, therefore their context types (`PaintCtx` and `AccessCtx`) can't set invalidation flags or send signals. | ||
- The `layout` and `compose` passes lay out all widgets, which are transiently invalid during the passes, therefore `LayoutCtx`and `ComposeCtx` cannot access the size and position of the `self` widget. | ||
They can access the layout of children if they have already been laid out. | ||
- For the same reason, `LayoutCtx`and `ComposeCtx` cannot create a `WidgetRef` reference to a child. | ||
- `MutateCtx`, `EventCtx` and `UpdateCtx` can let you add and remove children. | ||
- `RegisterCtx` can't do anything except register children. | ||
- `QueryCtx` provides read-only information about the widget. | ||
|
||
## Example widget: ColorRectangle |
Oops, something went wrong.