Iced + impl Program for MyApp + canvas::Program: Unable to setup app program

⚓ Rust    📅 2026-05-11    👤 surdeus    👁️ 1      

surdeus

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 {  


}

3 posts - 3 participants

Read full topic

🏷️ Rust_feed