|
/// |
|
/// Solution I came up with |
|
/// |
|
/// |
|
/// |
|
|
|
use std::marker::PhantomData; |
|
|
|
use gtk::prelude::ButtonExt; |
|
use gtk::prelude::BoxExt; |
|
use gtk::prelude::OrientableExt; |
|
use gtk::prelude::GtkWindowExt; |
|
|
|
use relm4::*; |
|
|
|
// Provides interface for button initialization strategy |
|
// |
|
// Extra trait with only static methods |
|
trait ButtonInitiator<Parent> |
|
where |
|
Parent: ButtonParentModel |
|
{ |
|
fn get_label(parent_model: &Parent) -> String; |
|
} |
|
|
|
// Allows to initialize left button |
|
struct LeftButtonInitiator{} |
|
impl<Parent> ButtonInitiator<Parent> for LeftButtonInitiator |
|
where |
|
Parent: ButtonParentModel |
|
{ |
|
fn get_label(parent_model: &Parent) -> String { |
|
parent_model.get_left() |
|
} |
|
} |
|
|
|
// Allows to initialize right button |
|
struct RightButtonInitiator{} |
|
impl<Parent> ButtonInitiator<Parent> for RightButtonInitiator |
|
where |
|
Parent: ButtonParentModel |
|
{ |
|
fn get_label(parent_model: &Parent) -> String { |
|
parent_model.get_right() |
|
} |
|
} |
|
|
|
struct ButtonModel<Initiator, Parent> |
|
where |
|
Parent: ButtonParentModel, |
|
Initiator: ButtonInitiator<Parent>, |
|
{ |
|
label: String, |
|
|
|
parent: PhantomData<*const Parent>, |
|
initiator: PhantomData<*const Initiator>, |
|
} |
|
|
|
enum ButtonMsg{} |
|
|
|
impl<Initiator, Parent> Model for ButtonModel<Initiator, Parent> |
|
where |
|
Parent: ButtonParentModel, |
|
Initiator: ButtonInitiator<Parent>, |
|
{ |
|
type Msg = ButtonMsg; |
|
type Widgets = ButtonWidgets; |
|
type Components = (); |
|
} |
|
|
|
trait ButtonParentModel: Model { |
|
fn get_left(&self) -> String; |
|
fn get_right(&self) -> String; |
|
} |
|
|
|
impl<Initiator, Parent> ComponentUpdate<Parent> for ButtonModel<Initiator, Parent> |
|
where |
|
Parent: ButtonParentModel, |
|
Initiator: ButtonInitiator<Parent> |
|
{ |
|
fn init_model(parent_model: &Parent) -> Self { |
|
Self { |
|
label: Initiator::get_label(parent_model), //Use initiator to select proper value from the model |
|
|
|
parent: PhantomData, |
|
initiator: PhantomData |
|
} |
|
} |
|
|
|
fn update( |
|
&mut self, |
|
_msg: ButtonMsg, |
|
_components: &(), |
|
_sender: Sender<ButtonMsg>, |
|
_parent_sender: Sender<Parent::Msg> |
|
) {} |
|
} |
|
|
|
#[relm4_macros::widget] |
|
impl<Initiator, Parent> Widgets<ButtonModel<Initiator,Parent>, Parent> for ButtonWidgets |
|
where |
|
Parent: ButtonParentModel, |
|
Initiator: ButtonInitiator<Parent> |
|
{ |
|
view! { |
|
gtk::Button{ |
|
set_label: &model.label |
|
} |
|
} |
|
} |
|
|
|
enum AppMsg {} |
|
|
|
struct AppModel { |
|
left: String, |
|
right: String, |
|
} |
|
|
|
impl AppModel { |
|
fn new() -> Self { |
|
AppModel{ |
|
left: String::from("Left"), |
|
right: String::from("Right"), |
|
} |
|
} |
|
} |
|
|
|
impl Model for AppModel { |
|
type Msg = AppMsg; |
|
type Widgets = AppWidgets; |
|
type Components = AppComponents; |
|
} |
|
|
|
impl ButtonParentModel for AppModel { |
|
fn get_left(&self) -> String { |
|
self.left.clone() |
|
} |
|
|
|
fn get_right(&self) -> String { |
|
self.right.clone() |
|
} |
|
} |
|
|
|
struct AppComponents { |
|
left: RelmComponent<ButtonModel<LeftButtonInitiator, AppModel>, AppModel>, |
|
right: RelmComponent<ButtonModel<RightButtonInitiator, AppModel>, AppModel>, |
|
} |
|
|
|
impl Components<AppModel> for AppComponents { |
|
fn init_components( |
|
parent_model: &AppModel, |
|
parent_widgets: &AppWidgets, |
|
parent_sender: Sender<AppMsg>, |
|
) -> Self { |
|
AppComponents { |
|
left: RelmComponent::new(parent_model, parent_widgets, parent_sender.clone()), |
|
right: RelmComponent::new(parent_model, parent_widgets, parent_sender) |
|
} |
|
} |
|
} |
|
|
|
impl AppUpdate for AppModel { |
|
fn update(&mut self, _msg: AppMsg, _components: &AppComponents, _sender: Sender<AppMsg>) -> bool { |
|
true |
|
} |
|
} |
|
|
|
#[relm4_macros::widget] |
|
impl Widgets<AppModel, ()> for AppWidgets { |
|
view! { |
|
main_window = gtk::ApplicationWindow { |
|
set_child = Some(>k::Box) { |
|
set_orientation: gtk::Orientation::Horizontal, |
|
|
|
append: component!(components.left.root_widget()), |
|
append: component!(components.right.root_widget()), |
|
} |
|
} |
|
} |
|
} |
|
|
|
fn main() { |
|
let model = AppModel::new(); |
|
let relm = RelmApp::new(model); |
|
relm.run(); |
|
} |