use super::{
boolean_parameter_entry, enumeration_parameter_entry,
numeric_parameter_entry,
};
use gtk::{ListBoxExt, ListBoxRowExt, StyleContextExt, WidgetExt};
use indexmap::IndexMap;
use ommui_data::samplic::{
Parameter, ParameterDescription, ProfileParameterDescription,
};
use relm::{Component, ContainerWidget, Relm, Update, Widget};
use XTr;
#[derive(Debug)]
pub struct Param<TR: XTr + Clone> {
pub values: IndexMap<String, Parameter>,
pub descriptions: IndexMap<String, ParameterDescription>,
pub profile: IndexMap<String, ProfileParameterDescription>,
pub translation: TR,
}
#[derive(Msg, Debug)]
pub enum Msg {
Internal(Internal),
Outgoing(Outgoing),
}
#[derive(Debug)]
pub struct Internal {
msg: InternalMsg,
}
#[derive(Debug)]
enum InternalMsg {
RowActivated(usize),
BooleanMsg {
index: usize,
msg: boolean_parameter_entry::OutgoingMsg,
},
EnumerationMsg {
index: usize,
msg: enumeration_parameter_entry::OutgoingMsg,
},
NumericMsg {
index: usize,
msg: numeric_parameter_entry::OutgoingMsg,
},
}
impl From<InternalMsg> for Msg {
fn from(msg: InternalMsg) -> Msg {
Msg::Internal(Internal { msg })
}
}
#[derive(Debug)]
pub struct Outgoing {
pub msg: OutgoingMsg,
}
#[derive(Debug, Clone)]
pub enum OutgoingMsg {
ValueChanged {
index: usize,
value: Parameter,
},
}
impl From<OutgoingMsg> for Msg {
fn from(msg: OutgoingMsg) -> Msg {
Msg::Outgoing(Outgoing { msg })
}
}
impl<TR: XTr + Clone> Update for W<TR> {
type Model = Param<TR>;
type ModelParam = Param<TR>;
type Msg = Msg;
fn model(_relm: &Relm<Self>, details: Param<TR>) -> Self::Model {
details
}
fn update(&mut self, event: Msg) {
use self::Msg::*;
match event {
Internal(e) => self.update_internal(e.msg),
Outgoing(_) => {}
}
}
}
impl<TR: XTr + Clone> W<TR> {
fn update_internal(&mut self, e: InternalMsg) {
use self::InternalMsg::*;
match e {
RowActivated(index) => {
self.children.get_index(index).unwrap().1.tapped();
}
BooleanMsg { index, msg } => {
use boolean_parameter_entry::OutgoingMsg::*;
match msg {
ValueChanged(value) => {
self.relm.stream().emit(Msg::from(
OutgoingMsg::ValueChanged {
index,
value: Parameter::Boolean(value),
},
));
}
}
}
EnumerationMsg { index, msg } => {
use enumeration_parameter_entry::OutgoingMsg::*;
match msg {
ValueChanged(value) => {
self.relm.stream().emit(Msg::from(
OutgoingMsg::ValueChanged {
index,
value: Parameter::Enumeration(value),
},
));
}
}
}
NumericMsg { index, msg } => {
use numeric_parameter_entry::OutgoingMsg::*;
match msg {
ValueChanged(value) => {
self.relm.stream().emit(Msg::from(
OutgoingMsg::ValueChanged {
index,
value: Parameter::Numeric(value),
},
));
}
}
}
}
}
}
impl<TR: 'static + XTr + Clone> Widget for W<TR> {
type Root = gtk::ListBox;
fn root(&self) -> Self::Root {
self.list_box.clone()
}
fn view(relm: &Relm<Self>, model: Self::Model) -> Self {
let list_box = gtk::ListBox::new();
list_box.set_selection_mode(gtk::SelectionMode::None);
list_box.get_style_context().add_class("parameters");
let mut children = IndexMap::new();
for (i, (k, description)) in model.descriptions.iter().enumerate()
{
let k = k.to_string();
let value = model.values.get(&k).unwrap().clone();
let profile = model.profile.get(&k).unwrap().clone();
match (description, value) {
(
ParameterDescription::Boolean(ref description),
Parameter::Boolean(ref value),
) => {
let component = list_box
.add_widget::<boolean_parameter_entry::W<TR>>(
boolean_parameter_entry::Param {
value: *value,
description: description.clone(),
profile,
translation: model.translation.clone(),
},
);
connect!(
component@boolean_parameter_entry::Msg::Outgoing(ref msg),
relm,
Msg::from(InternalMsg::BooleanMsg{
index: i,
msg: msg.msg.clone()
})
);
children
.insert(k.to_string(), Child::Boolean(component));
}
(
ParameterDescription::Enumeration(ref description),
Parameter::Enumeration(ref value),
) => {
let component = list_box
.add_widget::<enumeration_parameter_entry::W<TR>>(
enumeration_parameter_entry::Param {
value: value.to_string(),
description: description.clone(),
profile: profile.clone(),
translation: model.translation.clone(),
},
);
connect!(
component@enumeration_parameter_entry::Msg::Outgoing(ref msg),
relm,
Msg::from(InternalMsg::EnumerationMsg{
index: i,
msg: msg.msg.clone()
})
);
children.insert(
k.to_string(),
Child::Enumeration(component),
);
}
(
ParameterDescription::Numeric(ref description),
Parameter::Numeric(ref value),
) => {
let component = list_box
.add_widget::<numeric_parameter_entry::W<TR>>(
numeric_parameter_entry::Param {
value: *value,
description: description.clone(),
profile: profile.clone(),
translation: model.translation.clone(),
},
);
connect!(
component@numeric_parameter_entry::Msg::Outgoing(ref msg),
relm,
Msg::from(InternalMsg::NumericMsg{
index: i,
msg: msg.msg.clone()
})
);
children
.insert(k.to_string(), Child::Numeric(component));
}
_ => unimplemented!(),
}
}
connect!(
relm,
list_box,
connect_row_activated(_, row),
Msg::from(InternalMsg::RowActivated(row.get_index() as usize))
);
Self {
list_box,
children,
relm: relm.clone(),
}
}
}
enum Child<TR: XTr> {
Boolean(Component<boolean_parameter_entry::W<TR>>),
Enumeration(Component<enumeration_parameter_entry::W<TR>>),
Numeric(Component<numeric_parameter_entry::W<TR>>),
}
impl<TR: XTr> Child<TR> {
fn tapped(&self) {
match self {
Child::Boolean(component) => component
.emit(boolean_parameter_entry::IncomingMsg::Toggle.into()),
Child::Enumeration(component) => component.emit(
enumeration_parameter_entry::IncomingMsg::Popup.into(),
),
Child::Numeric(component) => component
.emit(numeric_parameter_entry::IncomingMsg::Popup.into()),
}
}
}
pub struct W<TR: 'static + XTr + Clone> {
list_box: gtk::ListBox,
children: IndexMap<String, Child<TR>>,
relm: Relm<W<TR>>,
}