Add iced cosmic example
This commit is contained in:
parent
167b92f084
commit
699e474427
19 changed files with 532 additions and 121 deletions
173
gtk4/widgets/src/labeled_item/imp.rs
Normal file
173
gtk4/widgets/src/labeled_item/imp.rs
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
use relm4::{
|
||||
component::ComponentSenderInner,
|
||||
gtk::{prelude::*, Align, Box as GtkBox, Label, Orientation, Widget},
|
||||
ComponentParts, ComponentSender, SimpleComponent,
|
||||
};
|
||||
use std::{cell::RefCell, sync::Arc};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum LabeledItemMessage {
|
||||
Title(String),
|
||||
Desc(Option<String>),
|
||||
Align(Align),
|
||||
Child(Widget),
|
||||
}
|
||||
|
||||
#[track]
|
||||
pub(crate) struct LabeledItem {
|
||||
_title: String,
|
||||
_desc: Option<String>,
|
||||
_align: Align,
|
||||
_child: Option<Widget>,
|
||||
#[do_not_track]
|
||||
_remove_child: RefCell<Option<Widget>>,
|
||||
#[do_not_track]
|
||||
_sender: ComponentSender<Self>,
|
||||
}
|
||||
|
||||
impl LabeledItem {
|
||||
pub fn title(&self) -> &str {
|
||||
&self._title
|
||||
}
|
||||
|
||||
pub fn description(&self) -> Option<&String> {
|
||||
self._desc.as_ref()
|
||||
}
|
||||
|
||||
pub fn alignment(&self) -> Align {
|
||||
self._align
|
||||
}
|
||||
|
||||
pub fn child(&self) -> Option<&Widget> {
|
||||
self._child.as_ref()
|
||||
}
|
||||
|
||||
pub fn set_title<S>(&self, title: S)
|
||||
where
|
||||
S: ToString,
|
||||
{
|
||||
self._sender
|
||||
.input(LabeledItemMessage::Title(title.to_string()));
|
||||
}
|
||||
|
||||
pub fn set_description<'a, O>(&self, description: O)
|
||||
where
|
||||
O: Into<Option<&'a str>>,
|
||||
{
|
||||
let description = description.into();
|
||||
self._sender
|
||||
.input(LabeledItemMessage::Desc(description.map(|s| s.to_string())));
|
||||
}
|
||||
|
||||
pub fn set_alignment(&self, align: Align) {
|
||||
self._sender.input(LabeledItemMessage::Align(align));
|
||||
}
|
||||
|
||||
pub fn set_child(&self, child: Widget) {
|
||||
self._sender.input(LabeledItemMessage::Child(child));
|
||||
}
|
||||
}
|
||||
|
||||
#[component(pub(crate))]
|
||||
impl SimpleComponent for LabeledItem {
|
||||
type Widgets = AppWidgets;
|
||||
type InitParams = ();
|
||||
type Input = LabeledItemMessage;
|
||||
type Output = ();
|
||||
|
||||
view! {
|
||||
base_box = GtkBox {
|
||||
add_css_class: "labeled-item",
|
||||
set_orientation: Orientation::Horizontal,
|
||||
set_hexpand: true,
|
||||
set_margin_start: 24,
|
||||
set_margin_end: 24,
|
||||
set_margin_top: 8,
|
||||
set_margin_bottom: 8,
|
||||
set_spacing: 16,
|
||||
append: labeled_item_info = &GtkBox {
|
||||
add_css_class: "labeled-item-info",
|
||||
set_orientation: Orientation::Vertical,
|
||||
set_hexpand: true,
|
||||
set_spacing: 8,
|
||||
set_valign: Align::Center,
|
||||
Label {
|
||||
add_css_class: "labeled-item-title",
|
||||
set_halign: Align::Start,
|
||||
#[watch]
|
||||
set_label: &model._title
|
||||
},
|
||||
Label {
|
||||
add_css_class: "labeled-item-desc",
|
||||
set_halign: Align::Start,
|
||||
#[watch]
|
||||
set_visible: model._desc.is_some(),
|
||||
#[watch]
|
||||
set_label: &model._desc.clone().unwrap_or_default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init(
|
||||
_init_params: Self::InitParams,
|
||||
root: &Self::Root,
|
||||
_sender: Arc<ComponentSenderInner<LabeledItemMessage, (), ()>>,
|
||||
) -> ComponentParts<Self> {
|
||||
let model = LabeledItem {
|
||||
_title: String::default(),
|
||||
_desc: None,
|
||||
_align: Align::Start,
|
||||
_child: None,
|
||||
_remove_child: RefCell::new(None),
|
||||
_sender: _sender.clone(),
|
||||
tracker: 0,
|
||||
};
|
||||
let widgets = view_output!();
|
||||
|
||||
ComponentParts { model, widgets }
|
||||
}
|
||||
|
||||
fn update(
|
||||
&mut self,
|
||||
msg: Self::Input,
|
||||
_sender: Arc<ComponentSenderInner<LabeledItemMessage, (), ()>>,
|
||||
) {
|
||||
self.reset();
|
||||
match msg {
|
||||
LabeledItemMessage::Title(title) => self.set__title(title),
|
||||
LabeledItemMessage::Desc(desc) => self.set__desc(desc),
|
||||
LabeledItemMessage::Align(align) => self.set__align(align),
|
||||
LabeledItemMessage::Child(child) => {
|
||||
*self._remove_child.borrow_mut() = self._child.take();
|
||||
self.set__child(Some(child))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn post_view() {
|
||||
if let Some(child) = self._remove_child.borrow_mut().take() {
|
||||
widgets.base_box.remove(&child);
|
||||
}
|
||||
if self.changed(LabeledItem::_child()) {
|
||||
let child = self._child.as_ref().expect("there's no child??");
|
||||
widgets.base_box.append(child);
|
||||
}
|
||||
if self.changed(LabeledItem::_align()) {
|
||||
let child = self._child.as_ref().expect("set alignment without child");
|
||||
match self._align {
|
||||
Align::Start => {
|
||||
widgets
|
||||
.base_box
|
||||
.reorder_child_after(&widgets.labeled_item_info, Some(child));
|
||||
}
|
||||
Align::End => {
|
||||
widgets
|
||||
.base_box
|
||||
.reorder_child_after(child, Some(&widgets.labeled_item_info));
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
90
gtk4/widgets/src/labeled_item/mod.rs
Normal file
90
gtk4/widgets/src/labeled_item/mod.rs
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
mod imp;
|
||||
|
||||
use relm4::{
|
||||
gtk::{glib::IsA, prelude::*, Align, Box as GtkBox, Orientation, Widget},
|
||||
Component, ComponentController, ComponentParts, Controller,
|
||||
};
|
||||
use std::{cell::Ref, ops::Deref};
|
||||
|
||||
pub struct LabeledItem {
|
||||
root: GtkBox,
|
||||
controller: Controller<imp::LabeledItem>,
|
||||
}
|
||||
|
||||
impl LabeledItem {
|
||||
fn inner(&self) -> Ref<'_, ComponentParts<imp::LabeledItem>> {
|
||||
self.controller.state().get()
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn widget(&self) -> GtkBox {
|
||||
self.root.clone()
|
||||
}
|
||||
|
||||
pub fn title(&self) -> String {
|
||||
self.inner().model.title().to_owned()
|
||||
}
|
||||
|
||||
pub fn description(&self) -> Option<String> {
|
||||
self.inner().model.description().cloned()
|
||||
}
|
||||
|
||||
pub fn alignment(&self) -> Align {
|
||||
self.inner().model.alignment()
|
||||
}
|
||||
|
||||
pub fn child(&self) -> Option<Widget> {
|
||||
self.inner().model.child().cloned()
|
||||
}
|
||||
|
||||
pub fn set_title<S>(&self, title: S)
|
||||
where
|
||||
S: ToString,
|
||||
{
|
||||
self.inner().model.set_title(title)
|
||||
}
|
||||
|
||||
pub fn set_description<'a, O>(&self, description: O)
|
||||
where
|
||||
O: Into<Option<&'a str>>,
|
||||
{
|
||||
self.inner().model.set_description(description)
|
||||
}
|
||||
|
||||
pub fn set_alignment(&self, align: Align) {
|
||||
self.inner().model.set_alignment(align)
|
||||
}
|
||||
|
||||
pub fn set_child(&self, child: &impl IsA<Widget>) {
|
||||
let widget = child.upcast_ref();
|
||||
self.inner().model.set_child(widget.clone());
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LabeledItem {
|
||||
fn default() -> Self {
|
||||
let root = GtkBox::new(Orientation::Horizontal, 0);
|
||||
let controller = imp::LabeledItem::builder()
|
||||
.attach_to(&root)
|
||||
.launch(())
|
||||
.detach();
|
||||
Self { root, controller }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Widget> for LabeledItem {
|
||||
fn as_ref(&self) -> &Widget {
|
||||
self.root.upcast_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for LabeledItem {
|
||||
type Target = GtkBox;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.root
|
||||
}
|
||||
}
|
||||
9
gtk4/widgets/src/lib.rs
Normal file
9
gtk4/widgets/src/lib.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#[macro_use]
|
||||
extern crate relm4_macros;
|
||||
#[macro_use]
|
||||
extern crate tracker;
|
||||
|
||||
pub mod labeled_item;
|
||||
|
||||
pub use labeled_item::LabeledItem;
|
||||
pub use relm4;
|
||||
Loading…
Add table
Add a link
Reference in a new issue