1mod fill;
2
3use wasm_bindgen::prelude::*;
4
5pub use logo_runtime;
6
7use raqote::*;
8use logo_runtime::colors::LogoColor;
9use logo_runtime::common::Pos;
10use logo_runtime::drawinglib::add_drawinglib;
11use logo_runtime::logo_interp::executor::execute_str;
12use logo_runtime::logo_interp::executor_state::EState;
13use logo_runtime::logo_interp::stdlib::add_stdlib;
14use logo_runtime::state::{Delegate, State};
15use crate::fill::flood_fill;
16
17pub struct DrawingDelegate {
18 pub dt: DrawTarget,
19 pub show_fn: Option<Box<dyn Fn(&str)>>,
20}
21
22impl DrawingDelegate {
23 fn transform_coords(&self, pos: Pos) -> (f32, f32) {
24 let width = self.dt.width() as f64;
25 let height = self.dt.height() as f64;
26 ((pos.x + width / 2f64 + 0.5) as f32, (-pos.y + height / 2f64 + 0.5) as f32)
27 }
28}
29
30impl Delegate for DrawingDelegate {
31 fn clear_graphics(&mut self) {
32 self.dt.clear(SolidSource{
33 r: 255,
34 g: 255,
35 b: 255,
36 a: 255,
37 });
38 }
39
40 fn draw_line(&mut self, from: Pos, to: Pos, pen_size: f64, color: LogoColor) {
41 let upd_from = self.transform_coords(from);
42 let upd_to = self.transform_coords(to);
43 let mut pb = PathBuilder::new();
44 pb.move_to(upd_from.0, upd_from.1);
45 pb.line_to(upd_to.0, upd_to.1);
46 let path = pb.finish();
47 self.dt.stroke(&path, &Source::Solid(SolidSource {
48 r: color.r,
49 g: color.g,
50 b: color.b,
51 a: 255
52 }),
53 &StrokeStyle {
54 width: pen_size as f32,
55 cap: LineCap::Square,
56 ..StrokeStyle::default()
57 },
58 &DrawOptions::new()
59 );
60 }
61
62 fn fill(&mut self, pos: Pos, color: LogoColor) {
63 let upd_pos = self.transform_coords(pos);
64 flood_fill(self.dt.width(), self.dt.height(), self.dt.get_data_u8_mut(),
65 upd_pos.0 as i32, upd_pos.1 as i32, color);
66 }
67
68 fn show(&mut self, message: &str) {
69 if let Some(show_fn) = &self.show_fn {
70 (show_fn)(message);
71 }
72 }
73}
74
75#[wasm_bindgen]
76pub struct Context {
77 #[wasm_bindgen(skip)]
78 pub state: EState<State<DrawingDelegate>>,
79}
80
81impl Context {
82 pub fn new(width: i32, height: i32) -> Self {
83 let dt = DrawTarget::new(width, height);
84 let dd = DrawingDelegate { dt, show_fn: None };
85 let mut state = EState::new(State::new(width, height, dd));
86 state.state.delegate.clear_graphics();
87 add_stdlib(&mut state);
88 add_drawinglib(&mut state);
89 return Self {state}
90 }
91
92 pub fn render(&mut self, proc_source: &str, cmd_source: &str) -> Result<Vec<u8>, String> {
93 execute_str(&mut self.state, proc_source, cmd_source)?;
94 Ok(Vec::from(self.state.state.delegate.dt.get_data_u8()))
95 }
96}
97