feat: COSMIC Component System Prototype
This commit is contained in:
parent
08e70faffd
commit
52df3570ec
9 changed files with 597 additions and 0 deletions
109
crates/component-system/examples/basic/components/app.rs
Normal file
109
crates/component-system/examples/basic/components/app.rs
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
// Copyright 2022 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use crate::components::{InfoButton, InfoButtonInput, InfoButtonOutput};
|
||||
use ccs::*;
|
||||
use gtk::prelude::*;
|
||||
|
||||
/// An input event that is used to update the model.
|
||||
pub enum AppEvent {
|
||||
Destroy,
|
||||
Increment,
|
||||
}
|
||||
|
||||
component! {
|
||||
/// The model where component state is stored.
|
||||
#[derive(Default)]
|
||||
pub struct App(gtk::Application) {
|
||||
pub counter: usize,
|
||||
}
|
||||
|
||||
/// Widgets that are initialized in the view.
|
||||
pub struct AppWidgets(gtk::ApplicationWindow) {
|
||||
list: gtk::ListBox,
|
||||
destroyable: Option<Handle<gtk::Box, InfoButtonInput>>,
|
||||
counter: Handle<gtk::Box, InfoButtonInput>,
|
||||
}
|
||||
|
||||
type Input = AppEvent;
|
||||
type Output = ();
|
||||
|
||||
fn init_view(self, app, input, _output) {
|
||||
let button_group = gtk::SizeGroup::new(gtk::SizeGroupMode::Both);
|
||||
|
||||
// Create an `InfoButton` component.
|
||||
let destroyable = InfoButton::default()
|
||||
.register((String::new(), "Destroy".into(), button_group.clone()))
|
||||
.forward(input.clone(), |event| match event {
|
||||
InfoButtonOutput::Clicked => AppEvent::Destroy,
|
||||
});
|
||||
|
||||
// Instruct the component to update its description.
|
||||
let _ = destroyable.emit(InfoButtonInput::SetDescription(
|
||||
"Click this button to destroy me".into(),
|
||||
));
|
||||
|
||||
// Create a counter component, too.
|
||||
let counter = InfoButton::default()
|
||||
.register(("Click me too".into(), "Click".into(), button_group))
|
||||
.forward(input.clone(), |event| match event {
|
||||
InfoButtonOutput::Clicked => AppEvent::Increment,
|
||||
});
|
||||
|
||||
// Construct the view for this component, attaching the component's widget.
|
||||
ccs::view! {
|
||||
window = gtk::ApplicationWindow {
|
||||
set_application: Some(&app),
|
||||
set_child = Some(>k::Box) {
|
||||
set_halign: gtk::Align::Center,
|
||||
set_size_request: args!(400, -1),
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
|
||||
append: list = >k::ListBox {
|
||||
set_selection_mode: gtk::SelectionMode::None,
|
||||
set_hexpand: true,
|
||||
|
||||
append: destroyable.widget(),
|
||||
append: counter.widget(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.show();
|
||||
|
||||
(
|
||||
AppWidgets {
|
||||
list,
|
||||
counter,
|
||||
destroyable: Some(destroyable),
|
||||
},
|
||||
window,
|
||||
)
|
||||
}
|
||||
|
||||
/// Updates the view
|
||||
fn update(self, widgets, event, _input, _output) {
|
||||
match event {
|
||||
AppEvent::Increment => {
|
||||
self.counter += 1;
|
||||
|
||||
widgets
|
||||
.counter
|
||||
.emit(InfoButtonInput::SetDescription(format!(
|
||||
"Clicked {} times",
|
||||
self.counter
|
||||
)));
|
||||
}
|
||||
|
||||
AppEvent::Destroy => {
|
||||
// Components are kept alive by their root GTK widget.
|
||||
if let Some(handle) = widgets.destroyable.take() {
|
||||
if let Some(parent) = handle.widget().parent() {
|
||||
widgets.list.remove(&parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright 2022 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use ccs::*;
|
||||
use gtk::prelude::*;
|
||||
|
||||
pub enum InfoButtonInput {
|
||||
SetDescription(String),
|
||||
}
|
||||
|
||||
pub enum InfoButtonOutput {
|
||||
Clicked,
|
||||
}
|
||||
|
||||
component! {
|
||||
#[derive(Default)]
|
||||
pub struct InfoButton((String, String, gtk::SizeGroup)) {
|
||||
|
||||
}
|
||||
|
||||
pub struct InfoButtonWidgets(gtk::Box) {
|
||||
description: gtk::Label,
|
||||
}
|
||||
|
||||
type Input = InfoButtonInput;
|
||||
type Output = InfoButtonOutput;
|
||||
|
||||
fn init_view(self, args, _input, output) {
|
||||
let (desc, button_label, sg) = args;
|
||||
ccs::view! {
|
||||
root = gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_margin_start: 20,
|
||||
set_margin_end: 20,
|
||||
set_margin_top: 8,
|
||||
set_margin_bottom: 8,
|
||||
set_spacing: 24,
|
||||
|
||||
append: description = >k::Label {
|
||||
set_label: &desc,
|
||||
set_halign: gtk::Align::Start,
|
||||
set_hexpand: true,
|
||||
set_valign: gtk::Align::Center,
|
||||
set_ellipsize: gtk::pango::EllipsizeMode::End,
|
||||
},
|
||||
|
||||
append: button = >k::Button {
|
||||
set_label: &button_label,
|
||||
|
||||
connect_clicked(output) => move |_| {
|
||||
let _ = output.send(InfoButtonOutput::Clicked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sg.add_widget(&button);
|
||||
|
||||
(InfoButtonWidgets { description }, root)
|
||||
}
|
||||
|
||||
fn update(self, widgets, message, _input, _output) {
|
||||
match message {
|
||||
InfoButtonInput::SetDescription(value) => {
|
||||
widgets.description.set_text(&value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
crates/component-system/examples/basic/components/mod.rs
Normal file
8
crates/component-system/examples/basic/components/mod.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// Copyright 2022 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
mod app;
|
||||
mod info_button;
|
||||
|
||||
pub use self::app::*;
|
||||
pub use self::info_button::*;
|
||||
15
crates/component-system/examples/basic/main.rs
Normal file
15
crates/component-system/examples/basic/main.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2022 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
extern crate cosmic_component_system as ccs;
|
||||
|
||||
mod components;
|
||||
|
||||
use self::components::App;
|
||||
use ccs::Component;
|
||||
|
||||
fn main() {
|
||||
ccs::run(|app| {
|
||||
App::default().register(app);
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue