diff --git a/Cargo.lock b/Cargo.lock index 504e1ac..95c29e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,6 +95,7 @@ name = "ants" version = "0.0.0" dependencies = [ "nannou", + "rand_derive2", ] [[package]] @@ -1580,6 +1581,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc_macro2_helper" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79528bef70da112116feb5ecb6b64f1394e5360660d6474a760789ea07885501" +dependencies = [ + "proc-macro2", + "syn 2.0.58", +] + [[package]] name = "profiling" version = "1.0.15" @@ -1657,6 +1668,18 @@ dependencies = [ "getrandom 0.2.14", ] +[[package]] +name = "rand_derive2" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e07d80c051ce2007c5cbb87ae0a6be7c5e5345cb03e06717b64ed5c426cbfb3" +dependencies = [ + "proc-macro2", + "proc_macro2_helper", + "quote", + "syn 2.0.58", +] + [[package]] name = "rand_hc" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index ddeb36b..6dd587b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,3 +27,6 @@ codegen-units = 1 [dependencies.nannou] version = "0.19" + +[dependencies.rand_derive2] +version = "0.1" diff --git a/src/main.rs b/src/main.rs index 2a283aa..dc6d3f2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,17 @@ #![warn(clippy::all, clippy::pedantic, clippy::nursery)] +mod card; pub(crate) mod rect_helper; +use std::sync::RwLock; + use crate::rect_helper::RectHelper; +use card::Card; use nannou::{ image::{self, ImageFormat}, prelude::*, text::Font, + winit::window::CursorIcon, }; fn main() { @@ -22,7 +27,8 @@ struct Model { font: Font, texture: wgpu::Texture, ups: f64, - ant_count: u8, + just_clicked: RwLock, + hand: [Card; HAND_CARD_COUNT], } impl Model { @@ -56,53 +62,101 @@ impl Model { ))) .expect("Failed to load font"), ups: 0f64, - ant_count: 1, + just_clicked: RwLock::new(false), + hand: random(), } } } fn update(_app: &App, model: &mut Model, update: Update) { model.ups = (1f64 / update.since_last.as_secs_f64()).round(); - let new_ant_count = ((update.since_start.as_secs() + 1) % 12) - .try_into() - .expect("Failed to convert number to u8"); - if model.ant_count != new_ant_count { - model.ant_count = new_ant_count; - } } // Handle events related to the window and update the model if necessary -fn event(_app: &App, _model: &mut Model, event: WindowEvent) { +fn event(_app: &App, model: &mut Model, event: WindowEvent) { + match event { + MousePressed(MouseButton::Left) => { + let mut just_clicked = model.just_clicked.write().expect("click handler poisoned"); + if !*just_clicked { + *just_clicked = true; + } + } + MouseReleased(MouseButton::Left) => { + let mut just_clicked = model.just_clicked.write().expect("click handler poisoned"); + if *just_clicked { + *just_clicked = false; + } + } + KeyPressed(Key::R) => { + model.hand = random(); + } + _ => {} + } drop(event); } -const HAND_COUNT: usize = 8; +const HAND_CARD_COUNT: usize = 8; +const HAND_ASPECT_WIDTH: f32 = 1f32; +const HAND_ASPECT_HEIGHT: f32 = 2f32; // Draw the state of your `Model` into the given `Frame` here. fn view(app: &App, model: &Model, frame: Frame) { let window = app.window(model.window).unwrap(); + window.set_cursor_icon(CursorIcon::Default); frame.clear(BLACK); + let mut can_click = *model.just_clicked.read().expect("click handler poisoned"); + + let mouse = &app.mouse; + + let mouse_position = if mouse.window == Some(model.window) { + Some(mouse.position()) + } else { + None + }; + let draw = app.draw(); - let rect = window.rect().bottom_part(0.2); - draw.rect().wh(rect.wh()).xy(rect.xy()).color(RED).finish(); - let rect = window.rect().left_part(0.2); - draw.rect().wh(rect.wh()).xy(rect.xy()).color(BLUE).finish(); - let rect = window.rect().right_part(0.2); - draw.rect() - .wh(rect.wh()) - .xy(rect.xy()) - .color(YELLOW) - .finish(); - let rect = window.rect().top_part(0.2); - draw.rect() - .wh(rect.wh()) - .xy(rect.xy()) - .color(GREEN) - .finish(); + let window_rect = window.rect(); + let hand_bounds = window_rect.bottom_part(0.3); + #[allow(clippy::cast_precision_loss)] + let hand_rect = Rect::from_x_y_w_h( + hand_bounds.x(), + hand_bounds.y(), + HAND_CARD_COUNT as f32 * HAND_ASPECT_WIDTH, + HAND_ASPECT_HEIGHT, + ) + .fit_into(&hand_bounds) + .align_bottom_of(hand_bounds); - for rect in rect.split_horizontal::() { - draw.texture(&model.texture).xy(rect.xy()).wh(rect.wh()); + for (idx, rect) in hand_rect + .split_horizontal::() + .iter() + .enumerate() + { + #[allow(clippy::cast_precision_loss)] + draw.rect() + .xy(rect.xy()) + .wh(rect.wh()) + .color(model.hand[idx].color()); + let image_rect = Rect::from_x_y_w_h(rect.x(), rect.y(), 1401f32, 1061f32) + .fit_into(rect) + .align_bottom_of(*rect); + draw.texture(&model.texture) + .xy(image_rect.xy()) + .wh(image_rect.wh()); + + if matches!(mouse_position, Some(mouse_position) if rect.contains(mouse_position)) { + window.set_cursor_icon(CursorIcon::Hand); + + if can_click { + println!( + "Click! {idx} {:?} {:?}", + model.hand[idx], + model.hand[idx].color() + ); + can_click = false; + } + } } if cfg!(debug_assertions) { @@ -113,6 +167,8 @@ fn view(app: &App, model: &Model, frame: Frame) { .left_justify(); } + *model.just_clicked.write().expect("click handler poisoned") = false; + draw.to_frame(app, &frame).unwrap(); drop(frame); } diff --git a/src/rect_helper.rs b/src/rect_helper.rs index a56d036..f4aa051 100644 --- a/src/rect_helper.rs +++ b/src/rect_helper.rs @@ -1,6 +1,8 @@ use nannou::geom::Rect; pub trait RectHelper { + fn fit_into(&self, bounds: &Rect) -> Rect; + fn bottom_half(&self) -> Rect; fn bottom_part(&self, part: f32) -> Rect; @@ -20,6 +22,27 @@ pub trait RectHelper { } impl RectHelper for Rect { + fn fit_into(&self, bounds: &Rect) -> Self { + let content_aspect_ratio = self.w() / self.h(); + let bounds_aspect_ratio = bounds.w() / bounds.h(); + + if bounds_aspect_ratio > content_aspect_ratio { + Self::from_x_y_w_h( + self.x(), + self.y(), + self.w() * bounds.h() / self.h(), + bounds.h(), + ) + } else { + Self::from_x_y_w_h( + self.x(), + self.y(), + bounds.w(), + self.h() * bounds.w() / self.w(), + ) + } + } + fn bottom_half(&self) -> Self { Self::from_corners(self.mid_left(), self.bottom_right()) }