From d2c63918d0f0509103b2609e599380a4cafeffdd Mon Sep 17 00:00:00 2001 From: Huck Boles Date: Tue, 20 Jun 2023 12:11:33 -0500 Subject: [PATCH] added: mask area --- src/lib.rs | 9 +++- src/map.rs | 8 ++-- src/mask.rs | 121 +++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 128 insertions(+), 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ddad6c2..814651b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 { 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,]; diff --git a/src/map.rs b/src/map.rs index 9ace573..7bb1060 100644 --- a/src/map.rs +++ b/src/map.rs @@ -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 for Map { +impl Program for Map { type State = bool; fn update( diff --git a/src/mask.rs b/src/mask.rs index 5fcd1ff..2948952 100644 --- a/src/mask.rs +++ b/src/mask.rs @@ -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, + mask_cache: Cache, } impl Mask { @@ -22,7 +50,90 @@ impl Mask { let _ = self.cells.remove(&cell); } - pub fn iter(&self) -> impl Iterator { - self.cells.iter() + pub fn get_note(&self, cell: &Cell) -> Option<&Note> { + self.cells.get(cell) + } + + pub fn cells(&self) -> impl Iterator { + 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 { + Canvas::new(self) + .width(Length::Fixed(Cell::SIZE as f32 * 24.0)) + .height(Length::Fixed(Cell::SIZE as f32 * 24.0)) + .into() + } +} + +impl Program for Mask { + type State = bool; + fn draw( + &self, + _state: &Self::State, + _theme: &Theme, + bounds: Rectangle, + _cursor: Cursor, + ) -> Vec { + 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) { + 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() } } -- 2.44.2