diff --git a/falling-sand/src/main.rs b/falling-sand/src/main.rs index 7d80c4a..0f43070 100644 --- a/falling-sand/src/main.rs +++ b/falling-sand/src/main.rs @@ -1,38 +1,122 @@ -use cairo::Context; use glib::Object; use gtk::{prelude::*, subclass::prelude::*}; +use std::cell::RefCell; -const WIDTH: i32 = 600; -const HEIGHT: i32 = 600; +const WIDTH: usize = 601; +const HEIGHT: usize = 601; +const CELL_SIZE: usize = 10; #[derive(Debug, Default)] -pub struct SandPrivate; +pub struct SandViewPrivate { + area: RefCell, +} #[glib::object_subclass] -impl ObjectSubclass for SandPrivate { - const NAME: &'static str = "Sand"; - type Type = Sand; +impl ObjectSubclass for SandViewPrivate { + const NAME: &'static str = "SandView"; + type Type = SandView; type ParentType = gtk::DrawingArea; } -impl ObjectImpl for SandPrivate {} -impl WidgetImpl for SandPrivate {} -impl DrawingAreaImpl for SandPrivate {} +impl ObjectImpl for SandViewPrivate {} +impl WidgetImpl for SandViewPrivate {} +impl DrawingAreaImpl for SandViewPrivate {} glib::wrapper! { - pub struct Sand(ObjectSubclass) @extends gtk::DrawingArea, gtk::Widget; + pub struct SandView(ObjectSubclass) @extends gtk::DrawingArea, gtk::Widget; } -impl Sand { - pub fn new() -> Self { +impl Default for SandView { + fn default() -> Self { let s: Self = Object::builder().build(); - s.set_width_request(WIDTH); - s.set_height_request(HEIGHT); + s.set_width_request(WIDTH as i32); + s.set_height_request(HEIGHT as i32); + + s.set_draw_func({ + let s = s.clone(); + move |_, context, width, height| { + println!("{} {}", width, height); + context.set_source_rgb(0., 0., 0.); + let _ = context.paint(); + context.set_source_rgb(0.1, 0.1, 0.1); + for x in (0..width).step_by(CELL_SIZE) { + context.move_to(x as f64, 0.); + context.line_to(x as f64, HEIGHT as f64); + } + for y in (0..height).step_by(CELL_SIZE) { + context.move_to(0., y as f64); + context.line_to(WIDTH as f64, y as f64); + } + let _ = context.stroke(); + + let area = s.imp().area.borrow(); + for x in 0..area.width { + for y in 0..area.height { + if area.grain(x, y) { + context.set_source_rgb(0.8, 0.8, 0.8); + } else { + context.set_source_rgb(0., 0., 0.); + } + context.rectangle( + (x * CELL_SIZE + 1) as f64, + (y * CELL_SIZE + 1) as f64, + (CELL_SIZE - 2) as f64, + (CELL_SIZE - 2) as f64, + ); + let _ = context.fill(); + } + } + } + }); s } } +impl SandView { + fn set_area(&self, area: SandArea) { + *self.imp().area.borrow_mut() = area; + } +} + +#[derive(Clone, Debug)] +struct SandArea { + width: usize, + height: usize, + grains: Vec, +} + +impl Default for SandArea { + fn default() -> Self { + let width = WIDTH / CELL_SIZE; + let height = HEIGHT / CELL_SIZE; + Self { + width, + height, + grains: vec![false; width * height], + } + } +} + +impl SandArea { + pub fn add_grain(&mut self, x: usize, y: usize) { + let addr = self.addr(x, y); + self.grains[addr] = true; + } + + pub fn grain(&self, x: usize, y: usize) -> bool { + self.grains[self.addr(x, y)] + } + + pub fn tick(self) -> Self { + unimplemented!() + } + + fn addr(&self, x: usize, y: usize) -> usize { + y * self.width + x + } +} + fn main() { let app = gtk::Application::builder() .application_id("com.luminescent-dreams.falling-sand") @@ -42,9 +126,12 @@ fn main() { let window = gtk::ApplicationWindow::new(app); window.present(); - let sand = Sand::new(); + let view = SandView::default(); + let mut sand_area = SandArea::default(); + sand_area.add_grain(20, 20); + view.set_area(sand_area.clone()); - window.set_child(Some(&sand)); + window.set_child(Some(&view)); }); app.run();