various grid fixes

This commit is contained in:
2025-10-04 13:24:53 -05:00
parent 87d842c2ad
commit b8bcba2585
4 changed files with 97 additions and 22 deletions
+29 -9
View File
@@ -1,7 +1,6 @@
use std::ops::RangeInclusive;
use eframe::egui;
use eframe::egui::{Color32, Context, PointerButton, Pos2, Rangef, Sense, Ui, Vec2};
use serde::{Deserialize, Serialize};
use eframe::egui::{Color32, Context, Id, PointerButton, Pos2, Rangef, Sense, Ui, Vec2};
use crate::gui::Showable;
use crate::noise::NoteType;
use crate::scale::Scale;
@@ -17,27 +16,41 @@ impl NoteType {
NoteType::Noise => Color32::from_rgb(240, 240, 240),
}
}
fn name(&self) -> &'static str {
match self {
NoteType::Sine => "Sine",
NoteType::Triangle => "Triangle",
NoteType::Sawtooth => "Sawtooth",
NoteType::Square => "Square",
NoteType::Noise => "Noise"
}
}
}
#[derive(Serialize, Deserialize, Clone)]
#[derive(Clone)]
pub struct Grid {
pub note_type: NoteType,
pub volume: f32,
pub length: u64,
scale: Scale,
notes: Vec<bool>,
id: String
pub scale: Scale,
pub notes: Vec<bool>,
pub id: Id,
pub name: String,
pub open: bool
}
impl Grid {
pub fn for_note_type(note_type: NoteType, counter: usize) -> Self {
pub fn for_note_type(note_type: NoteType, id: Id) -> Self {
Self {
note_type,
volume: 1.0,
length: 250,
open: true,
scale: Scale::CMajor,
notes: vec![false; (LOOP_LENGTH * LOOP_LENGTH) as usize],
id: format!("Track {}", counter)
name: format!("{} Track", note_type.name()),
id
}
}
@@ -91,7 +104,12 @@ impl Grid {
impl Showable<f32> for Grid {
fn show(&mut self, ctx: &Context, cursor: &f32) {
let win = egui::Window::new(&self.id).resizable(false).scroll([false, false]);
let mut open = true;
let win = egui::Window::new(&self.name)
.id(self.id)
.resizable(false)
.scroll([false, false])
.open(&mut open);
win.show(ctx, |ui| {
egui::MenuBar::new().ui(ui, |ui| {
if ui.button("Clear").clicked() {
@@ -128,5 +146,7 @@ impl Showable<f32> for Grid {
self.draw_grid(ui, *cursor)
});
});
self.open = open;
}
}
+9 -6
View File
@@ -2,7 +2,7 @@ use std::fs;
use std::ops::RangeInclusive;
use std::path::Path;
use eframe::egui;
use eframe::egui::{Context, TopBottomPanel};
use eframe::egui::{Context, Id, TopBottomPanel};
use crate::noise::NoteType;
use crate::saveload::PersistedTenori;
use crate::Tenori;
@@ -90,11 +90,7 @@ impl Tenori {
.pick_file() {
let serialized = fs::read_to_string(path).map_err(|e| e.to_string())?;
let persisted = toml::from_str::<PersistedTenori>(serialized.as_str()).map_err(|e| e.to_string())?;
self.grids = persisted.grids;
self.tempo = persisted.tempo;
self.playing = false;
self.timer = 0.0;
persisted.apply_to(self);
}
Ok(())
}
@@ -103,6 +99,13 @@ impl Tenori {
for g in self.grids.iter_mut() {
g.show(ctx, cursor)
}
self.grids.retain(|g| g.open);
}
/// Return a unique (among all the windows created since a file load) id string for a window.
pub fn window_id(&mut self) -> Id {
self.window_counter += 1;
format!("window {}", self.window_counter).into()
}
}
+55 -3
View File
@@ -1,18 +1,70 @@
use eframe::egui::Id;
use serde::{Deserialize, Serialize};
use crate::grid::Grid;
use crate::noise::NoteType;
use crate::scale::Scale;
use crate::tenori::Tenori;
#[derive(Serialize, Deserialize)]
pub struct PersistedTenori {
pub tempo: u32,
pub grids: Vec<Grid>
tempo: u32,
grids: Vec<PersistedGrid>
}
impl From<&Tenori> for PersistedTenori {
fn from(value: &Tenori) -> Self {
Self {
tempo: value.tempo,
grids: value.grids.iter().map(Grid::clone).collect()
grids: value.grids.iter().map(PersistedGrid::from).collect()
}
}
}
impl PersistedTenori {
pub fn apply_to(self, tenori: &mut Tenori) {
tenori.grids = self.grids.into_iter().map(|g| g.into_grid(tenori.window_id())).collect();
tenori.tempo = self.tempo;
tenori.playing = false; // Start paused
tenori.timer = 0.0; // Start at the beginning of the loop
}
}
#[derive(Serialize, Deserialize)]
struct PersistedGrid {
note_type: NoteType,
volume: f32,
length: u64,
scale: Scale,
notes: String,
name: String
}
impl From<&Grid> for PersistedGrid {
fn from(value: &Grid) -> Self {
let notes: String = value.notes.iter().map(|n| if *n { '1' } else { '0' }).collect();
Self {
note_type: value.note_type,
volume: value.volume,
length: value.length,
scale: value.scale,
name: value.name.clone(),
notes
}
}
}
impl PersistedGrid {
pub fn into_grid(self, id: Id) -> Grid {
let notes: Vec<_> = self.notes.chars().map(|c| c == '1').collect();
Grid {
note_type: self.note_type,
volume: self.volume,
length: self.length,
scale: self.scale,
name: self.name,
open: true,
notes,
id
}
}
}
+4 -4
View File
@@ -22,8 +22,8 @@ pub struct Tenori {
/// The grids that we currently have going
pub grids: Vec<Grid>,
// Running count of windows created (for ids)
window_counter: usize,
/// Running count of windows created (for ids)
pub window_counter: usize,
// The audio output stream to which we will play notes
output_stream: OutputStream,
@@ -91,8 +91,8 @@ impl Tenori {
}
pub fn add_window(&mut self, note_type: NoteType) {
self.window_counter += 1;
self.grids.push(Grid::for_note_type(note_type, self.window_counter));
let id = self.window_id();
self.grids.push(Grid::for_note_type(note_type, id));
}
pub fn notes_for_beat(&self) -> Vec<Note> {