In my Iced programs, normally I have 1 state variable "State" which contains the data. I then use "impl State" to assign logic functions such as update and view. I want to attempt to plot some numbers on a canvas so I crated a simple Iced program that created a canvas and allowed the radius of the circle to changed. It worked. Now I am trying to modify this program so that the canvas has 1 structure containing its data and the app has 1 structure containing its data. In addition, I created 2 additional empty structures to hold the logic for the canvas and app. I attempt to pull this all off by creating a program with "impl Program for MyApp" but have hit a wall. There are a couple of issues that I have notated in the code. If someone could help point me in the right direction it will be greatly appreciated.
use iced::alignment::Horizontal;
use iced::widget::{button, canvas, column, text};
use iced::{Color, Element, Length, Rectangle, Renderer, Size, Task, Theme, mouse};
use iced::widget::row;
use iced::Program;
#[derive(Debug, Clone)]
enum ChangeSize {
IncSize,
DecSize,
}
#[derive(Debug, Clone)]
enum CanvasMessage {
IncreaseRadius,
DecreaseRadius,
}
enum Screen {
Main,
Canvas(CanvasState),
}
#[derive(Debug, Clone)]
enum Message {
ShowCanvas,
BackToMain,
Canvas(ChangeSize),
}
struct AppState {
screen: Screen,
canvas_state: CanvasState,
}
struct MyApp {}
#[derive(Default)]
struct CanvasState {
circle_radius: f32,
}
struct MyCanvas {}
impl<Message> canvas::Program<Message> for MyCanvas {
type State = CanvasState;
fn draw(
&self,
state: &CanvasState,
renderer: &Renderer,
_theme: &Theme,
bounds: Rectangle,
_cursor: mouse::Cursor
) -> Vec<canvas::Geometry> {
let mut frame = canvas::Frame::new(renderer, bounds.size());
let circle = canvas::Path::circle(frame.center(), state.circle_radius);
frame.fill(&circle, Color::BLACK);
vec![frame.into_geometry()]
}
}
impl Program for MyApp {
type State = AppState;
type Message = Message;
type Theme = Theme;
type Renderer = Renderer;
type Executor = Default;
// determine default executor
fn window(&self) {
// determine how to indicate default
}
fn settings(&self) -> iced::Settings {
iced::Settings::default()
}
fn name() -> &'static str {
let program_name = "Canvas";
&program_name
}
fn boot(&self) -> (Self::State, iced::Task<Self::Message>) {
let initial_state = Self::State {
screen: Screen::Main,
canvas_state: CanvasState { circle_radius: 25.0 }
};
(initial_state, Task::none())
}
fn update(&self, state: &mut Self::State , message: Message) -> Task<Message> {
match message {
Message::ShowCanvas => {
state.screen = Screen::Canvas(CanvasState { circle_radius: state.canvas_state.circle_radius });
Task::none()
}
Message::BackToMain => {
state.screen = Screen::Main;
Task::none()
}
Message::Canvas(msg) => {
match msg {
ChangeSize::DecSize => {
state.canvas_state.circle_radius -= 10.0;
}
ChangeSize::IncSize => {
state.canvas_state.circle_radius += 10.0;
}
}
state.screen = Screen::Canvas(CanvasState { circle_radius: state.canvas_state.circle_radius });
Task::none()
}
}
}
fn view(&self, state: &'a Self::State, app_id: iced::window::Id) -> Element<'_, Message> {
// 'a appears to be a problem
match &state.screen {
Screen::Main => {
column![
text("Main Screen"),
button("Show Canvas").on_press(Message::ShowCanvas)
]
.into()
}
Screen::Canvas(canvas_program) => {
column![
button("Back").on_press(Message::BackToMain),
canvas(canvas_program.clone())
// the trait iced::widget::canvas::Program not implemented for CanvasState
.width(Length::Fill)
.height(Length::Fill),
row![
button("Decrease").on_press(Message::Canvas(ChangeSize::DecSize)),
button("Increase").on_press(Message::Canvas(ChangeSize::IncSize)),
]
.spacing(100)
]
.align_x(Horizontal::Center)
.spacing(100)
.width(Length::Fill)
.into()
}
}
}
}
fn main() -> iced::Result {
}