Flatten state in tour example
This commit is contained in:
parent
964ae95827
commit
e0b4ddf7b7
1 changed files with 273 additions and 351 deletions
|
|
@ -21,190 +21,27 @@ pub fn main() -> iced::Result {
|
||||||
.run()
|
.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct Tour {
|
pub struct Tour {
|
||||||
steps: Steps,
|
step: Step,
|
||||||
|
slider: u8,
|
||||||
|
layout: Layout,
|
||||||
|
spacing: u16,
|
||||||
|
text_size: u16,
|
||||||
|
text_color: Color,
|
||||||
|
language: Option<Language>,
|
||||||
|
toggler: bool,
|
||||||
|
image_width: u16,
|
||||||
|
image_filter_method: image::FilterMethod,
|
||||||
|
input_value: String,
|
||||||
|
input_is_secure: bool,
|
||||||
|
input_is_showing_icon: bool,
|
||||||
debug: bool,
|
debug: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tour {
|
|
||||||
fn title(&self) -> String {
|
|
||||||
format!("{} - Iced", self.steps.title())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, event: Message) {
|
|
||||||
match event {
|
|
||||||
Message::BackPressed => {
|
|
||||||
self.steps.go_back();
|
|
||||||
}
|
|
||||||
Message::NextPressed => {
|
|
||||||
self.steps.advance();
|
|
||||||
}
|
|
||||||
Message::StepMessage(step_msg) => {
|
|
||||||
self.steps.update(step_msg, &mut self.debug);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
|
||||||
let Tour { steps, .. } = self;
|
|
||||||
|
|
||||||
let controls =
|
|
||||||
row![]
|
|
||||||
.push_maybe(steps.has_previous().then(|| {
|
|
||||||
padded_button("Back")
|
|
||||||
.on_press(Message::BackPressed)
|
|
||||||
.style(button::secondary)
|
|
||||||
}))
|
|
||||||
.push(horizontal_space())
|
|
||||||
.push_maybe(steps.can_continue().then(|| {
|
|
||||||
padded_button("Next").on_press(Message::NextPressed)
|
|
||||||
}));
|
|
||||||
|
|
||||||
let content: Element<_> = column![
|
|
||||||
steps.view(self.debug).map(Message::StepMessage),
|
|
||||||
controls,
|
|
||||||
]
|
|
||||||
.max_width(540)
|
|
||||||
.spacing(20)
|
|
||||||
.padding(20)
|
|
||||||
.into();
|
|
||||||
|
|
||||||
let scrollable = scrollable(
|
|
||||||
container(if self.debug {
|
|
||||||
content.explain(Color::BLACK)
|
|
||||||
} else {
|
|
||||||
content
|
|
||||||
})
|
|
||||||
.center_x(Length::Fill),
|
|
||||||
);
|
|
||||||
|
|
||||||
container(scrollable).center_y(Length::Fill).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
BackPressed,
|
BackPressed,
|
||||||
NextPressed,
|
NextPressed,
|
||||||
StepMessage(StepMessage),
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Steps {
|
|
||||||
steps: Vec<Step>,
|
|
||||||
current: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Steps {
|
|
||||||
fn new() -> Steps {
|
|
||||||
Steps {
|
|
||||||
steps: vec![
|
|
||||||
Step::Welcome,
|
|
||||||
Step::Slider { value: 50 },
|
|
||||||
Step::RowsAndColumns {
|
|
||||||
layout: Layout::Row,
|
|
||||||
spacing: 20,
|
|
||||||
},
|
|
||||||
Step::Text {
|
|
||||||
size: 30,
|
|
||||||
color: Color::BLACK,
|
|
||||||
},
|
|
||||||
Step::Radio { selection: None },
|
|
||||||
Step::Toggler {
|
|
||||||
can_continue: false,
|
|
||||||
},
|
|
||||||
Step::Image {
|
|
||||||
width: 300,
|
|
||||||
filter_method: image::FilterMethod::Linear,
|
|
||||||
},
|
|
||||||
Step::Scrollable,
|
|
||||||
Step::TextInput {
|
|
||||||
value: String::new(),
|
|
||||||
is_secure: false,
|
|
||||||
is_showing_icon: false,
|
|
||||||
},
|
|
||||||
Step::Debugger,
|
|
||||||
Step::End,
|
|
||||||
],
|
|
||||||
current: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, msg: StepMessage, debug: &mut bool) {
|
|
||||||
self.steps[self.current].update(msg, debug);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self, debug: bool) -> Element<StepMessage> {
|
|
||||||
self.steps[self.current].view(debug)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance(&mut self) {
|
|
||||||
if self.can_continue() {
|
|
||||||
self.current += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn go_back(&mut self) {
|
|
||||||
if self.has_previous() {
|
|
||||||
self.current -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_previous(&self) -> bool {
|
|
||||||
self.current > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn can_continue(&self) -> bool {
|
|
||||||
self.current + 1 < self.steps.len()
|
|
||||||
&& self.steps[self.current].can_continue()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn title(&self) -> &str {
|
|
||||||
self.steps[self.current].title()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Steps {
|
|
||||||
fn default() -> Self {
|
|
||||||
Steps::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Step {
|
|
||||||
Welcome,
|
|
||||||
Slider {
|
|
||||||
value: u8,
|
|
||||||
},
|
|
||||||
RowsAndColumns {
|
|
||||||
layout: Layout,
|
|
||||||
spacing: u16,
|
|
||||||
},
|
|
||||||
Text {
|
|
||||||
size: u16,
|
|
||||||
color: Color,
|
|
||||||
},
|
|
||||||
Radio {
|
|
||||||
selection: Option<Language>,
|
|
||||||
},
|
|
||||||
Toggler {
|
|
||||||
can_continue: bool,
|
|
||||||
},
|
|
||||||
Image {
|
|
||||||
width: u16,
|
|
||||||
filter_method: image::FilterMethod,
|
|
||||||
},
|
|
||||||
Scrollable,
|
|
||||||
TextInput {
|
|
||||||
value: String,
|
|
||||||
is_secure: bool,
|
|
||||||
is_showing_icon: bool,
|
|
||||||
},
|
|
||||||
Debugger,
|
|
||||||
End,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum StepMessage {
|
|
||||||
SliderChanged(u8),
|
SliderChanged(u8),
|
||||||
LayoutChanged(Layout),
|
LayoutChanged(Layout),
|
||||||
SpacingChanged(u16),
|
SpacingChanged(u16),
|
||||||
|
|
@ -220,147 +57,145 @@ pub enum StepMessage {
|
||||||
TogglerChanged(bool),
|
TogglerChanged(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Step {
|
impl Tour {
|
||||||
fn update(&mut self, msg: StepMessage, debug: &mut bool) {
|
fn title(&self) -> String {
|
||||||
match msg {
|
let screen = match self.step {
|
||||||
StepMessage::DebugToggled(value) => {
|
|
||||||
if let Step::Debugger = self {
|
|
||||||
*debug = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StepMessage::LanguageSelected(language) => {
|
|
||||||
if let Step::Radio { selection } = self {
|
|
||||||
*selection = Some(language);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StepMessage::SliderChanged(new_value) => {
|
|
||||||
if let Step::Slider { value, .. } = self {
|
|
||||||
*value = new_value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StepMessage::TextSizeChanged(new_size) => {
|
|
||||||
if let Step::Text { size, .. } = self {
|
|
||||||
*size = new_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StepMessage::TextColorChanged(new_color) => {
|
|
||||||
if let Step::Text { color, .. } = self {
|
|
||||||
*color = new_color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StepMessage::LayoutChanged(new_layout) => {
|
|
||||||
if let Step::RowsAndColumns { layout, .. } = self {
|
|
||||||
*layout = new_layout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StepMessage::SpacingChanged(new_spacing) => {
|
|
||||||
if let Step::RowsAndColumns { spacing, .. } = self {
|
|
||||||
*spacing = new_spacing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StepMessage::ImageWidthChanged(new_width) => {
|
|
||||||
if let Step::Image { width, .. } = self {
|
|
||||||
*width = new_width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StepMessage::ImageUseNearestToggled(use_nearest) => {
|
|
||||||
if let Step::Image { filter_method, .. } = self {
|
|
||||||
*filter_method = if use_nearest {
|
|
||||||
image::FilterMethod::Nearest
|
|
||||||
} else {
|
|
||||||
image::FilterMethod::Linear
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StepMessage::InputChanged(new_value) => {
|
|
||||||
if let Step::TextInput { value, .. } = self {
|
|
||||||
*value = new_value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StepMessage::ToggleSecureInput(toggle) => {
|
|
||||||
if let Step::TextInput { is_secure, .. } = self {
|
|
||||||
*is_secure = toggle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StepMessage::TogglerChanged(value) => {
|
|
||||||
if let Step::Toggler { can_continue, .. } = self {
|
|
||||||
*can_continue = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StepMessage::ToggleTextInputIcon(toggle) => {
|
|
||||||
if let Step::TextInput {
|
|
||||||
is_showing_icon, ..
|
|
||||||
} = self
|
|
||||||
{
|
|
||||||
*is_showing_icon = toggle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn title(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Step::Welcome => "Welcome",
|
Step::Welcome => "Welcome",
|
||||||
Step::Radio { .. } => "Radio button",
|
Step::Radio => "Radio button",
|
||||||
Step::Toggler { .. } => "Toggler",
|
Step::Toggler => "Toggler",
|
||||||
Step::Slider { .. } => "Slider",
|
Step::Slider => "Slider",
|
||||||
Step::Text { .. } => "Text",
|
Step::Text => "Text",
|
||||||
Step::Image { .. } => "Image",
|
Step::Image => "Image",
|
||||||
Step::RowsAndColumns { .. } => "Rows and columns",
|
Step::RowsAndColumns => "Rows and columns",
|
||||||
Step::Scrollable => "Scrollable",
|
Step::Scrollable => "Scrollable",
|
||||||
Step::TextInput { .. } => "Text input",
|
Step::TextInput => "Text input",
|
||||||
Step::Debugger => "Debugger",
|
Step::Debugger => "Debugger",
|
||||||
Step::End => "End",
|
Step::End => "End",
|
||||||
|
};
|
||||||
|
|
||||||
|
format!("{} - Iced", screen)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, event: Message) {
|
||||||
|
match event {
|
||||||
|
Message::BackPressed => {
|
||||||
|
if let Some(step) = self.step.previous() {
|
||||||
|
self.step = step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::NextPressed => {
|
||||||
|
if let Some(step) = self.step.next() {
|
||||||
|
self.step = step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::SliderChanged(value) => {
|
||||||
|
self.slider = value;
|
||||||
|
}
|
||||||
|
Message::LayoutChanged(layout) => {
|
||||||
|
self.layout = layout;
|
||||||
|
}
|
||||||
|
Message::SpacingChanged(spacing) => {
|
||||||
|
self.spacing = spacing;
|
||||||
|
}
|
||||||
|
Message::TextSizeChanged(text_size) => {
|
||||||
|
self.text_size = text_size;
|
||||||
|
}
|
||||||
|
Message::TextColorChanged(text_color) => {
|
||||||
|
self.text_color = text_color;
|
||||||
|
}
|
||||||
|
Message::LanguageSelected(language) => {
|
||||||
|
self.language = Some(language);
|
||||||
|
}
|
||||||
|
Message::ImageWidthChanged(image_width) => {
|
||||||
|
self.image_width = image_width;
|
||||||
|
}
|
||||||
|
Message::ImageUseNearestToggled(use_nearest) => {
|
||||||
|
self.image_filter_method = if use_nearest {
|
||||||
|
image::FilterMethod::Nearest
|
||||||
|
} else {
|
||||||
|
image::FilterMethod::Linear
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Message::InputChanged(input_value) => {
|
||||||
|
self.input_value = input_value;
|
||||||
|
}
|
||||||
|
Message::ToggleSecureInput(is_secure) => {
|
||||||
|
self.input_is_secure = is_secure;
|
||||||
|
}
|
||||||
|
Message::ToggleTextInputIcon(show_icon) => {
|
||||||
|
self.input_is_showing_icon = show_icon;
|
||||||
|
}
|
||||||
|
Message::DebugToggled(debug) => {
|
||||||
|
self.debug = debug;
|
||||||
|
}
|
||||||
|
Message::TogglerChanged(toggler) => {
|
||||||
|
self.toggler = toggler;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn view(&self) -> Element<Message> {
|
||||||
|
let controls =
|
||||||
|
row![]
|
||||||
|
.push_maybe(self.step.previous().is_some().then(|| {
|
||||||
|
padded_button("Back")
|
||||||
|
.on_press(Message::BackPressed)
|
||||||
|
.style(button::secondary)
|
||||||
|
}))
|
||||||
|
.push(horizontal_space())
|
||||||
|
.push_maybe(self.can_continue().then(|| {
|
||||||
|
padded_button("Next").on_press(Message::NextPressed)
|
||||||
|
}));
|
||||||
|
|
||||||
|
let screen = match self.step {
|
||||||
|
Step::Welcome => self.welcome(),
|
||||||
|
Step::Radio => self.radio(),
|
||||||
|
Step::Toggler => self.toggler(),
|
||||||
|
Step::Slider => self.slider(),
|
||||||
|
Step::Text => self.text(),
|
||||||
|
Step::Image => self.image(),
|
||||||
|
Step::RowsAndColumns => self.rows_and_columns(),
|
||||||
|
Step::Scrollable => self.scrollable(),
|
||||||
|
Step::TextInput => self.text_input(),
|
||||||
|
Step::Debugger => self.debugger(),
|
||||||
|
Step::End => self.end(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let content: Element<_> = column![screen, controls,]
|
||||||
|
.max_width(540)
|
||||||
|
.spacing(20)
|
||||||
|
.padding(20)
|
||||||
|
.into();
|
||||||
|
|
||||||
|
let scrollable = scrollable(
|
||||||
|
container(if self.debug {
|
||||||
|
content.explain(Color::BLACK)
|
||||||
|
} else {
|
||||||
|
content
|
||||||
|
})
|
||||||
|
.center_x(Length::Fill),
|
||||||
|
);
|
||||||
|
|
||||||
|
container(scrollable).center_y(Length::Fill).into()
|
||||||
|
}
|
||||||
|
|
||||||
fn can_continue(&self) -> bool {
|
fn can_continue(&self) -> bool {
|
||||||
match self {
|
match self.step {
|
||||||
Step::Welcome => true,
|
Step::Welcome => true,
|
||||||
Step::Radio { selection } => *selection == Some(Language::Rust),
|
Step::Radio => self.language == Some(Language::Rust),
|
||||||
Step::Toggler { can_continue } => *can_continue,
|
Step::Toggler => self.toggler,
|
||||||
Step::Slider { .. } => true,
|
Step::Slider => true,
|
||||||
Step::Text { .. } => true,
|
Step::Text => true,
|
||||||
Step::Image { .. } => true,
|
Step::Image => true,
|
||||||
Step::RowsAndColumns { .. } => true,
|
Step::RowsAndColumns => true,
|
||||||
Step::Scrollable => true,
|
Step::Scrollable => true,
|
||||||
Step::TextInput { value, .. } => !value.is_empty(),
|
Step::TextInput => !self.input_value.is_empty(),
|
||||||
Step::Debugger => true,
|
Step::Debugger => true,
|
||||||
Step::End => false,
|
Step::End => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self, debug: bool) -> Element<StepMessage> {
|
fn welcome(&self) -> Column<Message> {
|
||||||
match self {
|
|
||||||
Step::Welcome => Self::welcome(),
|
|
||||||
Step::Radio { selection } => Self::radio(*selection),
|
|
||||||
Step::Toggler { can_continue } => Self::toggler(*can_continue),
|
|
||||||
Step::Slider { value } => Self::slider(*value),
|
|
||||||
Step::Text { size, color } => Self::text(*size, *color),
|
|
||||||
Step::Image {
|
|
||||||
width,
|
|
||||||
filter_method,
|
|
||||||
} => Self::image(*width, *filter_method),
|
|
||||||
Step::RowsAndColumns { layout, spacing } => {
|
|
||||||
Self::rows_and_columns(*layout, *spacing)
|
|
||||||
}
|
|
||||||
Step::Scrollable => Self::scrollable(),
|
|
||||||
Step::TextInput {
|
|
||||||
value,
|
|
||||||
is_secure,
|
|
||||||
is_showing_icon,
|
|
||||||
} => Self::text_input(value, *is_secure, *is_showing_icon),
|
|
||||||
Step::Debugger => Self::debugger(debug),
|
|
||||||
Step::End => Self::end(),
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn container(title: &str) -> Column<'_, StepMessage> {
|
|
||||||
column![text(title).size(50)].spacing(20)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn welcome() -> Column<'a, StepMessage> {
|
|
||||||
Self::container("Welcome!")
|
Self::container("Welcome!")
|
||||||
.push(
|
.push(
|
||||||
"This is a simple tour meant to showcase a bunch of widgets \
|
"This is a simple tour meant to showcase a bunch of widgets \
|
||||||
|
|
@ -389,7 +224,7 @@ impl<'a> Step {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slider(value: u8) -> Column<'a, StepMessage> {
|
fn slider(&self) -> Column<Message> {
|
||||||
Self::container("Slider")
|
Self::container("Slider")
|
||||||
.push(
|
.push(
|
||||||
"A slider allows you to smoothly select a value from a range \
|
"A slider allows you to smoothly select a value from a range \
|
||||||
|
|
@ -399,47 +234,48 @@ impl<'a> Step {
|
||||||
"The following slider lets you choose an integer from \
|
"The following slider lets you choose an integer from \
|
||||||
0 to 100:",
|
0 to 100:",
|
||||||
)
|
)
|
||||||
.push(slider(0..=100, value, StepMessage::SliderChanged))
|
.push(slider(0..=100, self.slider, Message::SliderChanged))
|
||||||
.push(
|
.push(
|
||||||
text(value.to_string())
|
text(self.slider.to_string())
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.horizontal_alignment(alignment::Horizontal::Center),
|
.horizontal_alignment(alignment::Horizontal::Center),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rows_and_columns(
|
fn rows_and_columns(&self) -> Column<Message> {
|
||||||
layout: Layout,
|
let row_radio = radio(
|
||||||
spacing: u16,
|
"Row",
|
||||||
) -> Column<'a, StepMessage> {
|
Layout::Row,
|
||||||
let row_radio =
|
Some(self.layout),
|
||||||
radio("Row", Layout::Row, Some(layout), StepMessage::LayoutChanged);
|
Message::LayoutChanged,
|
||||||
|
);
|
||||||
|
|
||||||
let column_radio = radio(
|
let column_radio = radio(
|
||||||
"Column",
|
"Column",
|
||||||
Layout::Column,
|
Layout::Column,
|
||||||
Some(layout),
|
Some(self.layout),
|
||||||
StepMessage::LayoutChanged,
|
Message::LayoutChanged,
|
||||||
);
|
);
|
||||||
|
|
||||||
let layout_section: Element<_> = match layout {
|
let layout_section: Element<_> = match self.layout {
|
||||||
Layout::Row => {
|
Layout::Row => {
|
||||||
row![row_radio, column_radio].spacing(spacing).into()
|
row![row_radio, column_radio].spacing(self.spacing).into()
|
||||||
}
|
|
||||||
Layout::Column => {
|
|
||||||
column![row_radio, column_radio].spacing(spacing).into()
|
|
||||||
}
|
}
|
||||||
|
Layout::Column => column![row_radio, column_radio]
|
||||||
|
.spacing(self.spacing)
|
||||||
|
.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let spacing_section = column![
|
let spacing_section = column![
|
||||||
slider(0..=80, spacing, StepMessage::SpacingChanged),
|
slider(0..=80, self.spacing, Message::SpacingChanged),
|
||||||
text!("{spacing} px")
|
text!("{} px", self.spacing)
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.horizontal_alignment(alignment::Horizontal::Center),
|
.horizontal_alignment(alignment::Horizontal::Center),
|
||||||
]
|
]
|
||||||
.spacing(10);
|
.spacing(10);
|
||||||
|
|
||||||
Self::container("Rows and columns")
|
Self::container("Rows and columns")
|
||||||
.spacing(spacing)
|
.spacing(self.spacing)
|
||||||
.push(
|
.push(
|
||||||
"Iced uses a layout model based on flexbox to position UI \
|
"Iced uses a layout model based on flexbox to position UI \
|
||||||
elements.",
|
elements.",
|
||||||
|
|
@ -453,11 +289,14 @@ impl<'a> Step {
|
||||||
.push(spacing_section)
|
.push(spacing_section)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text(size: u16, color: Color) -> Column<'a, StepMessage> {
|
fn text(&self) -> Column<Message> {
|
||||||
|
let size = self.text_size;
|
||||||
|
let color = self.text_color;
|
||||||
|
|
||||||
let size_section = column![
|
let size_section = column![
|
||||||
"You can change its size:",
|
"You can change its size:",
|
||||||
text!("This text is {size} pixels").size(size),
|
text!("This text is {size} pixels").size(size),
|
||||||
slider(10..=70, size, StepMessage::TextSizeChanged),
|
slider(10..=70, size, Message::TextSizeChanged),
|
||||||
]
|
]
|
||||||
.padding(20)
|
.padding(20)
|
||||||
.spacing(20);
|
.spacing(20);
|
||||||
|
|
@ -486,7 +325,7 @@ impl<'a> Step {
|
||||||
.push(color_section)
|
.push(color_section)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn radio(selection: Option<Language>) -> Column<'a, StepMessage> {
|
fn radio(&self) -> Column<Message> {
|
||||||
let question = column![
|
let question = column![
|
||||||
text("Iced is written in...").size(24),
|
text("Iced is written in...").size(24),
|
||||||
column(
|
column(
|
||||||
|
|
@ -497,8 +336,8 @@ impl<'a> Step {
|
||||||
radio(
|
radio(
|
||||||
language,
|
language,
|
||||||
language,
|
language,
|
||||||
selection,
|
self.language,
|
||||||
StepMessage::LanguageSelected,
|
Message::LanguageSelected,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.map(Element::from)
|
.map(Element::from)
|
||||||
|
|
@ -521,27 +360,27 @@ impl<'a> Step {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toggler(can_continue: bool) -> Column<'a, StepMessage> {
|
fn toggler(&self) -> Column<Message> {
|
||||||
Self::container("Toggler")
|
Self::container("Toggler")
|
||||||
.push("A toggler is mostly used to enable or disable something.")
|
.push("A toggler is mostly used to enable or disable something.")
|
||||||
.push(
|
.push(
|
||||||
Container::new(toggler(
|
Container::new(toggler(
|
||||||
"Toggle me to continue...".to_owned(),
|
"Toggle me to continue...".to_owned(),
|
||||||
can_continue,
|
self.toggler,
|
||||||
StepMessage::TogglerChanged,
|
Message::TogglerChanged,
|
||||||
))
|
))
|
||||||
.padding([0, 40]),
|
.padding([0, 40]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn image(
|
fn image(&self) -> Column<Message> {
|
||||||
width: u16,
|
let width = self.image_width;
|
||||||
filter_method: image::FilterMethod,
|
let filter_method = self.image_filter_method;
|
||||||
) -> Column<'a, StepMessage> {
|
|
||||||
Self::container("Image")
|
Self::container("Image")
|
||||||
.push("An image that tries to keep its aspect ratio.")
|
.push("An image that tries to keep its aspect ratio.")
|
||||||
.push(ferris(width, filter_method))
|
.push(ferris(width, filter_method))
|
||||||
.push(slider(100..=500, width, StepMessage::ImageWidthChanged))
|
.push(slider(100..=500, width, Message::ImageWidthChanged))
|
||||||
.push(
|
.push(
|
||||||
text!("Width: {width} px")
|
text!("Width: {width} px")
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
|
|
@ -552,12 +391,12 @@ impl<'a> Step {
|
||||||
"Use nearest interpolation",
|
"Use nearest interpolation",
|
||||||
filter_method == image::FilterMethod::Nearest,
|
filter_method == image::FilterMethod::Nearest,
|
||||||
)
|
)
|
||||||
.on_toggle(StepMessage::ImageUseNearestToggled),
|
.on_toggle(Message::ImageUseNearestToggled),
|
||||||
)
|
)
|
||||||
.align_items(Alignment::Center)
|
.align_items(Alignment::Center)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scrollable() -> Column<'a, StepMessage> {
|
fn scrollable(&self) -> Column<Message> {
|
||||||
Self::container("Scrollable")
|
Self::container("Scrollable")
|
||||||
.push(
|
.push(
|
||||||
"Iced supports scrollable content. Try it out! Find the \
|
"Iced supports scrollable content. Try it out! Find the \
|
||||||
|
|
@ -584,13 +423,13 @@ impl<'a> Step {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text_input(
|
fn text_input(&self) -> Column<Message> {
|
||||||
value: &str,
|
let value = &self.input_value;
|
||||||
is_secure: bool,
|
let is_secure = self.input_is_secure;
|
||||||
is_showing_icon: bool,
|
let is_showing_icon = self.input_is_showing_icon;
|
||||||
) -> Column<'_, StepMessage> {
|
|
||||||
let mut text_input = text_input("Type something to continue...", value)
|
let mut text_input = text_input("Type something to continue...", value)
|
||||||
.on_input(StepMessage::InputChanged)
|
.on_input(Message::InputChanged)
|
||||||
.padding(10)
|
.padding(10)
|
||||||
.size(30);
|
.size(30);
|
||||||
|
|
||||||
|
|
@ -609,11 +448,11 @@ impl<'a> Step {
|
||||||
.push(text_input.secure(is_secure))
|
.push(text_input.secure(is_secure))
|
||||||
.push(
|
.push(
|
||||||
checkbox("Enable password mode", is_secure)
|
checkbox("Enable password mode", is_secure)
|
||||||
.on_toggle(StepMessage::ToggleSecureInput),
|
.on_toggle(Message::ToggleSecureInput),
|
||||||
)
|
)
|
||||||
.push(
|
.push(
|
||||||
checkbox("Show icon", is_showing_icon)
|
checkbox("Show icon", is_showing_icon)
|
||||||
.on_toggle(StepMessage::ToggleTextInputIcon),
|
.on_toggle(Message::ToggleTextInputIcon),
|
||||||
)
|
)
|
||||||
.push(
|
.push(
|
||||||
"A text input produces a message every time it changes. It is \
|
"A text input produces a message every time it changes. It is \
|
||||||
|
|
@ -630,7 +469,7 @@ impl<'a> Step {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn debugger(debug: bool) -> Column<'a, StepMessage> {
|
fn debugger(&self) -> Column<Message> {
|
||||||
Self::container("Debugger")
|
Self::container("Debugger")
|
||||||
.push(
|
.push(
|
||||||
"You can ask Iced to visually explain the layouting of the \
|
"You can ask Iced to visually explain the layouting of the \
|
||||||
|
|
@ -641,23 +480,85 @@ impl<'a> Step {
|
||||||
see element boundaries.",
|
see element boundaries.",
|
||||||
)
|
)
|
||||||
.push(
|
.push(
|
||||||
checkbox("Explain layout", debug)
|
checkbox("Explain layout", self.debug)
|
||||||
.on_toggle(StepMessage::DebugToggled),
|
.on_toggle(Message::DebugToggled),
|
||||||
)
|
)
|
||||||
.push("Feel free to go back and take a look.")
|
.push("Feel free to go back and take a look.")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end() -> Column<'a, StepMessage> {
|
fn end(&self) -> Column<Message> {
|
||||||
Self::container("You reached the end!")
|
Self::container("You reached the end!")
|
||||||
.push("This tour will be updated as more features are added.")
|
.push("This tour will be updated as more features are added.")
|
||||||
.push("Make sure to keep an eye on it!")
|
.push("Make sure to keep an eye on it!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn container(title: &str) -> Column<'_, Message> {
|
||||||
|
column![text(title).size(50)].spacing(20)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum Step {
|
||||||
|
Welcome,
|
||||||
|
Slider,
|
||||||
|
RowsAndColumns,
|
||||||
|
Text,
|
||||||
|
Radio,
|
||||||
|
Toggler,
|
||||||
|
Image,
|
||||||
|
Scrollable,
|
||||||
|
TextInput,
|
||||||
|
Debugger,
|
||||||
|
End,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Step {
|
||||||
|
const ALL: &'static [Self] = &[
|
||||||
|
Self::Welcome,
|
||||||
|
Self::Slider,
|
||||||
|
Self::RowsAndColumns,
|
||||||
|
Self::Text,
|
||||||
|
Self::Radio,
|
||||||
|
Self::Toggler,
|
||||||
|
Self::Image,
|
||||||
|
Self::Scrollable,
|
||||||
|
Self::TextInput,
|
||||||
|
Self::Debugger,
|
||||||
|
Self::End,
|
||||||
|
];
|
||||||
|
|
||||||
|
pub fn next(self) -> Option<Step> {
|
||||||
|
Self::ALL
|
||||||
|
.get(
|
||||||
|
Self::ALL
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.position(|step| step == self)
|
||||||
|
.expect("Step must exist")
|
||||||
|
+ 1,
|
||||||
|
)
|
||||||
|
.copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn previous(self) -> Option<Step> {
|
||||||
|
let position = Self::ALL
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.position(|step| step == self)
|
||||||
|
.expect("Step must exist");
|
||||||
|
|
||||||
|
if position > 0 {
|
||||||
|
Some(Self::ALL[position - 1])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ferris<'a>(
|
fn ferris<'a>(
|
||||||
width: u16,
|
width: u16,
|
||||||
filter_method: image::FilterMethod,
|
filter_method: image::FilterMethod,
|
||||||
) -> Container<'a, StepMessage> {
|
) -> Container<'a, Message> {
|
||||||
container(
|
container(
|
||||||
// This should go away once we unify resource loading on native
|
// This should go away once we unify resource loading on native
|
||||||
// platforms
|
// platforms
|
||||||
|
|
@ -679,9 +580,9 @@ fn padded_button<Message: Clone>(label: &str) -> Button<'_, Message> {
|
||||||
fn color_slider<'a>(
|
fn color_slider<'a>(
|
||||||
component: f32,
|
component: f32,
|
||||||
update: impl Fn(f32) -> Color + 'a,
|
update: impl Fn(f32) -> Color + 'a,
|
||||||
) -> Slider<'a, f64, StepMessage> {
|
) -> Slider<'a, f64, Message> {
|
||||||
slider(0.0..=1.0, f64::from(component), move |c| {
|
slider(0.0..=1.0, f64::from(component), move |c| {
|
||||||
StepMessage::TextColorChanged(update(c as f32))
|
Message::TextColorChanged(update(c as f32))
|
||||||
})
|
})
|
||||||
.step(0.01)
|
.step(0.01)
|
||||||
}
|
}
|
||||||
|
|
@ -727,3 +628,24 @@ pub enum Layout {
|
||||||
Row,
|
Row,
|
||||||
Column,
|
Column,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Tour {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
step: Step::Welcome,
|
||||||
|
slider: 50,
|
||||||
|
layout: Layout::Row,
|
||||||
|
spacing: 20,
|
||||||
|
text_size: 30,
|
||||||
|
text_color: Color::BLACK,
|
||||||
|
language: None,
|
||||||
|
toggler: false,
|
||||||
|
image_width: 300,
|
||||||
|
image_filter_method: image::FilterMethod::Linear,
|
||||||
|
input_value: String::new(),
|
||||||
|
input_is_secure: false,
|
||||||
|
input_is_showing_icon: false,
|
||||||
|
debug: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue