]> git.huck.website - cellseq.git/commitdiff
added: mask area
authorHuck Boles <huck@huck.website>
Tue, 20 Jun 2023 17:11:33 +0000 (12:11 -0500)
committerHuck Boles <huck@huck.website>
Tue, 20 Jun 2023 17:11:33 +0000 (12:11 -0500)
src/lib.rs
src/map.rs
src/mask.rs

index ddad6c2d06fa4ddbdf6ecc7140fa761abd7258f1..814651b13c6fddbd208c74c190d62c67e726490a 100644 (file)
@@ -4,7 +4,7 @@ use iced::time;
 use iced::widget::{button, column, container, row, slider, text};
 use iced::{Alignment, Application, Command, Element, Length, Point, Subscription};
 
-use rustc_hash::{FxHashMap, FxHashSet};
+use rustc_hash::FxHashSet;
 use std::time::{Duration, Instant};
 
 mod map;
@@ -122,7 +122,12 @@ impl Application for CellSeq {
     fn view(&self) -> Element<Message> {
         let bpm = self.bpm;
         let controls = view_controls(self.is_playing, bpm);
-        let map = self.map.view().map(Message::Map);
+        let map = row![
+            self.map.view().map(Message::Map),
+            self.mask.view().map(Message::Mask)
+        ]
+        .width(Length::Fill)
+        .spacing(40);
 
         let content = column![controls, map,];
 
index 9ace573af5291f62f09fa24cf98ddf0da33bd81c..7bb1060f798394c84dc9a40061425cb1c7ec77bb 100644 (file)
@@ -1,7 +1,9 @@
-use iced::mouse::{self, Button::Left, Event::ButtonPressed};
-use iced::widget::canvas;
 use iced::widget::canvas::event::{self, Event};
 use iced::widget::canvas::{Cache, Canvas, Cursor, Geometry, Path};
+use iced::{
+    mouse::{self, Button::Left, Event::ButtonPressed},
+    widget::canvas::Program,
+};
 use iced::{Color, Element, Length, Point, Rectangle, Size, Theme};
 
 use super::*;
@@ -113,7 +115,7 @@ impl Map {
     }
 }
 
-impl canvas::Program<Message> for Map {
+impl Program<Message> for Map {
     type State = bool;
 
     fn update(
index 5fcd1ff86d327ac6f8109d1a2556b39f5a43e592..2948952cf01dbdf79c6a88a005c984313109b9d2 100644 (file)
@@ -1,12 +1,40 @@
-use super::*;
+use iced::mouse::Interaction;
+use iced::widget::canvas::event::{self, Event};
+use iced::widget::canvas::{Cache, Canvas, Cursor, Geometry, Path};
+use iced::{
+    mouse::{Button::Left, Event::ButtonPressed},
+    widget::canvas::Program,
+};
+use iced::{Color, Element, Length, Point, Rectangle, Size, Theme};
 
+use crate::{Cell, CellMap};
+use itertools::Itertools;
 use rustc_hash::FxHashMap;
 
-pub type Note = usize;
+#[derive(Debug, Clone)]
+pub enum Message {
+    Check(Cell),
+    Uncheck(Cell),
+    Tick(CellMap),
+}
+
+#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Hash)]
+pub enum State {
+    #[default]
+    Off,
+    On,
+}
 
-#[derive(Clone, Default)]
+#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct Note {
+    value: usize,
+    action: State,
+}
+
+#[derive(Default, Debug)]
 pub struct Mask {
     cells: FxHashMap<Cell, Note>,
+    mask_cache: Cache,
 }
 
 impl Mask {
@@ -22,7 +50,90 @@ impl Mask {
         let _ = self.cells.remove(&cell);
     }
 
-    pub fn iter(&self) -> impl Iterator<Item = (&Cell, &Note)> {
-        self.cells.iter()
+    pub fn get_note(&self, cell: &Cell) -> Option<&Note> {
+        self.cells.get(cell)
+    }
+
+    pub fn cells(&self) -> impl Iterator<Item = &Cell> {
+        self.cells.keys()
+    }
+
+    pub fn update(&mut self, message: Message) {
+        match message {
+            Message::Check(cell) => self.check(cell),
+            Message::Uncheck(cell) => self.uncheck(cell),
+            Message::Tick(life) => {}
+        }
+    }
+
+    pub fn view(&self) -> Element<Message> {
+        Canvas::new(self)
+            .width(Length::Fixed(Cell::SIZE as f32 * 24.0))
+            .height(Length::Fixed(Cell::SIZE as f32 * 24.0))
+            .into()
+    }
+}
+
+impl Program<Message> for Mask {
+    type State = bool;
+    fn draw(
+        &self,
+        _state: &Self::State,
+        _theme: &Theme,
+        bounds: Rectangle,
+        _cursor: Cursor,
+    ) -> Vec<Geometry> {
+        vec![self.mask_cache.draw(bounds.size(), |frame| {
+            let background = Path::rectangle(Point::ORIGIN, frame.size());
+            frame.fill(&background, Color::from_rgb8(0x26, 0x26, 0x2E));
+
+            frame.with_save(|frame| {
+                frame.scale(Cell::SIZE as f32);
+
+                (0..24)
+                    .cartesian_product(0..24)
+                    .filter(|x| self.contains(&Cell { i: x.1, j: x.0 }))
+                    .for_each(|x| {
+                        frame.fill_rectangle(
+                            Point::new(x.0 as f32, x.1 as f32),
+                            Size::UNIT,
+                            Color::WHITE,
+                        );
+                    })
+            });
+        })]
+    }
+
+    fn update(
+        &self,
+        _state: &mut Self::State,
+        event: Event,
+        bounds: Rectangle,
+        cursor: Cursor,
+    ) -> (event::Status, Option<Message>) {
+        if let Some(position) = cursor.position_in(&bounds) {
+            if let Event::Mouse(ButtonPressed(Left)) = event {
+                let cell = Cell::at(position);
+                return (
+                    event::Status::Captured,
+                    if self.contains(&cell) {
+                        Some(Message::Uncheck(cell))
+                    } else {
+                        Some(Message::Check(cell))
+                    },
+                );
+            }
+        }
+
+        (event::Status::Ignored, None)
+    }
+
+    fn mouse_interaction(
+        &self,
+        _state: &Self::State,
+        _bounds: Rectangle,
+        _cursor: Cursor,
+    ) -> Interaction {
+        Interaction::default()
     }
 }