refactor!(ccs): Improvements to design

This commit is contained in:
Michael Aaron Murphy 2022-01-26 11:30:58 +01:00
parent 148ffc6dae
commit dff9265e35
No known key found for this signature in database
GPG key ID: B2732D4240C9212C
7 changed files with 157 additions and 128 deletions

View file

@ -2,7 +2,7 @@
This library is a GTK4 GUI framework inspired by [Relm](https://github.com/antoyo/relm), which is inspired by [Elm](https://guide.elm-lang.org/architecture/). The philosophy for this framework is to isolate custom widgets into reusable components. You start with a custom `Model` type that implements `Component`, which is used to register a component with an optional argument. On registration, the model is used to construct the view and its widgets in the `init_view()` function. An event-handler is also spawned to handle events from both the component and any component emitting events to it. Those events are received and handled in the `update()` function. Both the `init_view()` and `update()` methods also have access to an outbound sender, which the caller can forward and consume however desired. See the examples directory for a demonstration of how to create a component.
## Defining a Component
## Using a Macro to Define a Component
The simplest way to define a component is to use the `component!()` macro.
@ -13,14 +13,13 @@ pub enum MyCustomInputMessage {
}
component! {
// The `()` is the args parameter accepted by `init_view()`
// and `Component::register()`.
pub struct MyCustomModel(()) {
// The model stores the state of this component.
pub struct MyCustomModel {
pub state: String,
}
// The `gtk::Box` is the root widget returned in `init_view()`.
pub struct MyCustomWidgets(gtk::Box) {
// Widgets managed by the view are stored here.
pub struct MyCustomWidgets {
description: gtk::Label,
}
@ -30,24 +29,35 @@ component! {
// The type of the output sender
type Output = ();
// `self` is `MyCustomModel`, and must return `(MyCustomWidget, RootWidget)`
fn init_view(self, args, input, output) {
// Declares the root widget and how it should be constructed.
type Root = gtk::Box {
ccs::view! {
root = gtk::Box {
set_orientation: gtk::Orientation::Vertical,
append: description = &gtk::Label {
}
}
}
(MyCustomWidgets { description }, root)
root
};
// Constructs the inner component's model and widgets, using the
// initial parameter given by `args`.
fn init(args: (), root, input, output) {
let description = gtk::Label::new();
root.append(&description);
ComponentInner {
model: MyCustomModel { state: String::new() },
widgets: MyCustomWidgets { description },
input,
output
}
}
// Where events are received, with `self` also being `MyCustomModel`, and
// `widgets` is `MyCustomInputMessage`. `event` is `MyCustonInputMessage`.
fn update(self, widgets, event, input, output) {
// Where events are received, with `component` is the `ComponentInner`,
// and `event` is a `MyCustomInputMessage` which was just received.
fn update(component, event) {
match event {
MyCustomInputMessage::Variant1 => {
@ -64,8 +74,7 @@ component! {
Components can be created and have their output events forwarded:
```rs
let counter = InfoButton::default()
.register("Clicked 0 times".into(), "Click".into())
let counter = InfoButton::init("Clicked 0 times".into(), "Click".into())
.forward(input.clone(), |event| match event {
InfoButtonOutput::Clicked => AppEvent::Increment
});