From 5602ae258d6e6e2d96ca58244c3af4ea45f16b1a Mon Sep 17 00:00:00 2001 From: Ross Andrews Date: Sat, 20 Sep 2025 22:44:26 -0500 Subject: [PATCH] ui --- src/grid.rs | 125 +++++++++++++++++++++++++++++++++++----------------- src/gui.rs | 12 +++++ 2 files changed, 97 insertions(+), 40 deletions(-) diff --git a/src/grid.rs b/src/grid.rs index ba76720..ebecd67 100644 --- a/src/grid.rs +++ b/src/grid.rs @@ -1,5 +1,6 @@ +use std::ops::RangeInclusive; use eframe::egui; -use eframe::egui::{Color32, Context, Id, Margin, PointerButton, Pos2, Rangef, Response, Stroke, TopBottomPanel, Ui, Vec2, Widget}; +use eframe::egui::{Color32, Context, Id, Margin, PointerButton, Pos2, Rangef, Response, Sense, Stroke, TopBottomPanel, Ui, Vec2, Widget}; use crate::nome::LOOP_LENGTH; pub enum NoteType { @@ -17,7 +18,7 @@ impl NoteType { NoteType::Triangle => Color32::from_rgb(252, 202, 3), NoteType::Sawtooth => Color32::from_rgb(252, 18, 61), NoteType::Square => Color32::from_rgb(4, 219, 51), - NoteType::Noise => Color32::from_rgb(120, 120, 120), + NoteType::Noise => Color32::from_rgb(240, 240, 240), } } } @@ -33,7 +34,7 @@ impl Grid { pub fn for_note_type(note_type: NoteType, counter: usize) -> Self { Self { note_type, - volume: 1.0, + volume: 50.0, notes: vec![false; (LOOP_LENGTH * LOOP_LENGTH) as usize], id: format!("Track {}", counter) } @@ -41,53 +42,97 @@ impl Grid { pub fn show(&mut self, ctx: &Context, cursor: f32) { let id = Id::from(self.id.clone()); - let win = egui::Window::new(&self.id).resizable(false).id(id).scroll([false, false]); + let win = egui::Window::new(&self.id).resizable(false).scroll([false, false]); win.show(ctx, |ui| { - self.frame(ui, cursor) + egui::MenuBar::new().ui(ui, |ui| { + ui.label("Volume"); + ui.add(egui::Slider::new(&mut self.volume, RangeInclusive::new(0.0, 100.0))); + }); + + egui::Frame::new().inner_margin(3).show(ui, |ui| { + self.draw_grid(ui, cursor) + }); }); } - fn frame(&mut self, ui: &mut Ui, cursor: f32) { - egui::Frame::new().inner_margin(3).show(ui, |ui| { - let dim = 20.0 * LOOP_LENGTH as f32; - ui.set_width(dim); - ui.set_height(dim); - let rect = ui.clip_rect().translate(Vec2::new(6.0, 6.0)); - //ui.painter().debug_rect(rect, Color32::from_rgb(0, 255, 0), "blah"); - for (i, lit) in self.notes.iter().enumerate() { - let (x, y) = (i as u32 % LOOP_LENGTH, i as u32 / LOOP_LENGTH); - let center = Pos2::new( - (x * 20 + 10) as f32 + rect.left(), - (y * 20 + 10) as f32 + rect.top()); - if *lit { - ui.painter().circle_filled(center, 10.0, self.note_type.color()); - } else { - ui.painter().circle_stroke(center, 10.0, (1.0, Color32::from_gray(0x88))); - } + fn draw_grid(&mut self, ui: &mut Ui, cursor: f32) { + let dim = 20.0 * LOOP_LENGTH as f32; + let (rect, response) = ui.allocate_exact_size(Vec2::new(dim, dim), Sense::click_and_drag()); + + for (i, lit) in self.notes.iter().enumerate() { + let (x, y) = (i as u32 % LOOP_LENGTH, i as u32 / LOOP_LENGTH); + let center = Pos2::new( + (x * 20 + 10) as f32 + rect.left(), + (y * 20 + 10) as f32 + rect.top()); + if *lit { + ui.painter().circle_filled(center, 10.0, self.note_type.color()); + } else { + ui.painter().circle_stroke(center, 10.0, (1.0, Color32::from_gray(0x88))); } + } - ui.painter().vline( - cursor * dim + rect.left(), - Rangef::new(rect.top(), rect.top() + dim), - (1.0, self.note_type.color()) - ); + ui.painter().vline( + cursor * dim + rect.left(), + Rangef::new(rect.top(), rect.top() + dim), + (1.0, self.note_type.color()) + ); - if ui.response().contains_pointer() { - ui.input(|input| { - if input.pointer.button_clicked(PointerButton::Primary) { - if let Some(pos) = input.pointer.latest_pos() { - println!("window: {} pos: {} {}", self.id, pos.x - rect.left(), pos.y - rect.top()); - let x = ((pos.x - rect.left()) / 20.0).floor() as usize; - let y = ((pos.y - rect.top()) / 20.0).floor() as usize; - let n = x + y * LOOP_LENGTH as usize; - self.notes[n] = !self.notes[n] - } + if response.contains_pointer() { + ui.input(|input| { + if input.pointer.button_clicked(PointerButton::Primary) { + if let Some(pos) = input.pointer.latest_pos() { + println!("window: {} pos: {} {}", self.id, pos.x - rect.left(), pos.y - rect.top()); + let x = ((pos.x - rect.left()) / 20.0).floor() as usize; + let y = ((pos.y - rect.top()) / 20.0).floor() as usize; + let n = x + y * LOOP_LENGTH as usize; + self.notes[n] = !self.notes[n] } - }) - } - }); + } + }) + } } + // fn frame(&mut self, ui: &mut Ui, cursor: f32) { + // egui::Frame::new().inner_margin(3).show(ui, |ui| { + // let dim = 20.0 * LOOP_LENGTH as f32; + // ui.set_width(dim); + // ui.set_height(dim); + // let rect = ui.clip_rect().translate(Vec2::new(6.0, 6.0)); + // //ui.painter().debug_rect(rect, Color32::from_rgb(0, 255, 0), "blah"); + // for (i, lit) in self.notes.iter().enumerate() { + // let (x, y) = (i as u32 % LOOP_LENGTH, i as u32 / LOOP_LENGTH); + // let center = Pos2::new( + // (x * 20 + 10) as f32 + rect.left(), + // (y * 20 + 10) as f32 + rect.top()); + // if *lit { + // ui.painter().circle_filled(center, 10.0, self.note_type.color()); + // } else { + // ui.painter().circle_stroke(center, 10.0, (1.0, Color32::from_gray(0x88))); + // } + // } + // + // ui.painter().vline( + // cursor * dim + rect.left(), + // Rangef::new(rect.top(), rect.top() + dim), + // (1.0, self.note_type.color()) + // ); + // + // if ui.response().contains_pointer() { + // ui.input(|input| { + // if input.pointer.button_clicked(PointerButton::Primary) { + // if let Some(pos) = input.pointer.latest_pos() { + // println!("window: {} pos: {} {}", self.id, pos.x - rect.left(), pos.y - rect.top()); + // let x = ((pos.x - rect.left()) / 20.0).floor() as usize; + // let y = ((pos.y - rect.top()) / 20.0).floor() as usize; + // let n = x + y * LOOP_LENGTH as usize; + // self.notes[n] = !self.notes[n] + // } + // } + // }) + // } + // }); + // } + pub fn notes(&self, beat: u32) -> Vec { let mut notes = vec![]; for y in 0..LOOP_LENGTH { diff --git a/src/gui.rs b/src/gui.rs index fcfc8d2..11ce2a0 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -8,9 +8,21 @@ impl Nome { pub fn menu(&mut self, ctx: &Context) { TopBottomPanel::top("menu_panel").show(ctx, |ui| { egui::MenuBar::new().ui(ui, |ui| { + if ui.button("Square").clicked() { + self.add_window(NoteType::Square) + } if ui.button("Sine").clicked() { self.add_window(NoteType::Sine) } + if ui.button("Triangle").clicked() { + self.add_window(NoteType::Triangle) + } + if ui.button("Sawtooth").clicked() { + self.add_window(NoteType::Sawtooth) + } + if ui.button("Noise").clicked() { + self.add_window(NoteType::Noise) + } ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { ui.add(egui::Slider::new(&mut self.tempo, RangeInclusive::new(20, 180)));