Random colors
This commit is contained in:
Generated
+14
@@ -683,6 +683,12 @@ dependencies = [
|
|||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "color"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a18ef4657441fb193b65f34dc39b3781f0dfec23d3bd94d0eeb4e88cde421edb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "combine"
|
name = "combine"
|
||||||
version = "4.6.7"
|
version = "4.6.7"
|
||||||
@@ -3185,10 +3191,12 @@ dependencies = [
|
|||||||
name = "tenori-ish"
|
name = "tenori-ish"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"color",
|
||||||
"eframe",
|
"eframe",
|
||||||
"rfd",
|
"rfd",
|
||||||
"rodio",
|
"rodio",
|
||||||
"serde",
|
"serde",
|
||||||
|
"tinyrand",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
@@ -3281,6 +3289,12 @@ dependencies = [
|
|||||||
"strict-num",
|
"strict-num",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyrand"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87ffaad2263779579369d45f65cad0647c860893d27e4543cdcc1e428d07da2c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinystr"
|
name = "tinystr"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
|
|||||||
+3
-1
@@ -9,4 +9,6 @@ tokio = { version = "1.47.1", features = ["rt", "rt-multi-thread", "macros"] }
|
|||||||
rodio = { version = "0.21.1", features = ["noise"] }
|
rodio = { version = "0.21.1", features = ["noise"] }
|
||||||
toml = "0.9.7"
|
toml = "0.9.7"
|
||||||
serde = { version = "1.0.227", features = ["derive"] }
|
serde = { version = "1.0.227", features = ["derive"] }
|
||||||
rfd = "0.15.4"
|
rfd = "0.15.4"
|
||||||
|
color = "0.3.2"
|
||||||
|
tinyrand = "0.5.0"
|
||||||
+27
-5
@@ -1,6 +1,9 @@
|
|||||||
use std::ops::RangeInclusive;
|
use color::ColorSpace;
|
||||||
|
use std::ops::{DerefMut, RangeInclusive};
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
use eframe::egui::{Color32, Context, Id, PointerButton, Pos2, Rangef, Sense, Ui, Vec2};
|
use eframe::egui::{Color32, Context, Id, PointerButton, Pos2, Rangef, Sense, Ui, Vec2};
|
||||||
|
use tinyrand::{Rand, StdRand};
|
||||||
use crate::gui::Showable;
|
use crate::gui::Showable;
|
||||||
use crate::scale::Scale;
|
use crate::scale::Scale;
|
||||||
use crate::tenori::LOOP_LENGTH;
|
use crate::tenori::LOOP_LENGTH;
|
||||||
@@ -15,11 +18,15 @@ pub struct Grid {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub open: bool,
|
pub open: bool,
|
||||||
pub timbre: Timbre,
|
pub timbre: Timbre,
|
||||||
pub timbre_open: bool
|
pub timbre_open: bool,
|
||||||
|
pub color: Color32,
|
||||||
|
pub rand: Arc<Mutex<StdRand>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Grid {
|
impl Grid {
|
||||||
pub fn new(id: Id) -> Self {
|
pub fn new(id: Id, rand: Arc<Mutex<StdRand>>) -> Self {
|
||||||
|
let color = Self::random_color(rand.lock().unwrap());
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
volume: 1.0,
|
volume: 1.0,
|
||||||
open: true,
|
open: true,
|
||||||
@@ -28,10 +35,21 @@ impl Grid {
|
|||||||
name: "New Track".to_string(),
|
name: "New Track".to_string(),
|
||||||
timbre: Timbre::default(),
|
timbre: Timbre::default(),
|
||||||
timbre_open: false,
|
timbre_open: false,
|
||||||
|
rand,
|
||||||
|
color,
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn random_color<R: Rand, T: DerefMut<Target=R>>(mut rand: T) -> Color32 {
|
||||||
|
let angle = (rand.next_lim_u32(72) * 5) as f32;
|
||||||
|
let rgb = color::Hsl::convert::<color::Srgb>([angle, 100.0, 50.0]);
|
||||||
|
Color32::from_rgb(
|
||||||
|
(rgb[0] * 255.0) as u8,
|
||||||
|
(rgb[1] * 255.0) as u8,
|
||||||
|
(rgb[2] * 255.0) as u8)
|
||||||
|
}
|
||||||
|
|
||||||
fn draw_grid(&mut self, ui: &mut Ui, cursor: f32) {
|
fn draw_grid(&mut self, ui: &mut Ui, cursor: f32) {
|
||||||
let dim = 20.0 * LOOP_LENGTH as f32;
|
let dim = 20.0 * LOOP_LENGTH as f32;
|
||||||
let (rect, response) = ui.allocate_exact_size(Vec2::new(dim, dim), Sense::click_and_drag());
|
let (rect, response) = ui.allocate_exact_size(Vec2::new(dim, dim), Sense::click_and_drag());
|
||||||
@@ -42,7 +60,7 @@ impl Grid {
|
|||||||
(x * 20 + 10) as f32 + rect.left(),
|
(x * 20 + 10) as f32 + rect.left(),
|
||||||
(y * 20 + 10) as f32 + rect.top());
|
(y * 20 + 10) as f32 + rect.top());
|
||||||
if *lit {
|
if *lit {
|
||||||
ui.painter().circle_filled(center, 10.0, Color32::from_rgb(80, 140, 160));
|
ui.painter().circle_filled(center, 10.0, self.color);
|
||||||
} else {
|
} else {
|
||||||
ui.painter().circle_stroke(center, 10.0, (1.0, Color32::from_gray(0x88)));
|
ui.painter().circle_stroke(center, 10.0, (1.0, Color32::from_gray(0x88)));
|
||||||
}
|
}
|
||||||
@@ -51,7 +69,7 @@ impl Grid {
|
|||||||
ui.painter().vline(
|
ui.painter().vline(
|
||||||
cursor * dim + rect.left(),
|
cursor * dim + rect.left(),
|
||||||
Rangef::new(rect.top(), rect.top() + dim),
|
Rangef::new(rect.top(), rect.top() + dim),
|
||||||
(1.0, Color32::from_rgb(80, 140, 160))
|
(1.0, self.color)
|
||||||
);
|
);
|
||||||
|
|
||||||
if response.contains_pointer() {
|
if response.contains_pointer() {
|
||||||
@@ -110,6 +128,10 @@ impl Showable<f32> for Grid {
|
|||||||
|
|
||||||
if ui.button("Timbre...").clicked() {
|
if ui.button("Timbre...").clicked() {
|
||||||
self.timbre_open = !self.timbre_open;
|
self.timbre_open = !self.timbre_open;
|
||||||
|
};
|
||||||
|
|
||||||
|
if ui.button("Color").clicked() {
|
||||||
|
self.color = Self::random_color(self.rand.lock().unwrap());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@ impl Tenori {
|
|||||||
|
|
||||||
if ui.button("Add track").clicked() {
|
if ui.button("Add track").clicked() {
|
||||||
let id = self.window_id();
|
let id = self.window_id();
|
||||||
self.grids.push(Grid::new(id));
|
self.grids.push(Grid::new(id, self.rand.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||||
|
|||||||
+9
-3
@@ -1,5 +1,7 @@
|
|||||||
use eframe::egui::Id;
|
use std::sync::{Arc, Mutex};
|
||||||
|
use eframe::egui::{Color32, Id};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tinyrand::StdRand;
|
||||||
use crate::grid::Grid;
|
use crate::grid::Grid;
|
||||||
use crate::scale::Scale;
|
use crate::scale::Scale;
|
||||||
use crate::tenori::Tenori;
|
use crate::tenori::Tenori;
|
||||||
@@ -22,7 +24,7 @@ impl From<&Tenori> for PersistedTenori {
|
|||||||
|
|
||||||
impl PersistedTenori {
|
impl PersistedTenori {
|
||||||
pub fn apply_to(self, tenori: &mut Tenori) {
|
pub fn apply_to(self, tenori: &mut Tenori) {
|
||||||
tenori.grids = self.grids.into_iter().map(|g| g.into_grid(tenori.window_id())).collect();
|
tenori.grids = self.grids.into_iter().map(|g| g.into_grid(tenori.window_id(), tenori.rand.clone())).collect();
|
||||||
tenori.tempo = self.tempo;
|
tenori.tempo = self.tempo;
|
||||||
tenori.playing = false; // Start paused
|
tenori.playing = false; // Start paused
|
||||||
tenori.timer = 0.0; // Start at the beginning of the loop
|
tenori.timer = 0.0; // Start at the beginning of the loop
|
||||||
@@ -36,6 +38,7 @@ struct PersistedGrid {
|
|||||||
notes: String,
|
notes: String,
|
||||||
name: String,
|
name: String,
|
||||||
timbre: Timbre,
|
timbre: Timbre,
|
||||||
|
color: (u8, u8, u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Grid> for PersistedGrid {
|
impl From<&Grid> for PersistedGrid {
|
||||||
@@ -46,13 +49,14 @@ impl From<&Grid> for PersistedGrid {
|
|||||||
scale: value.scale,
|
scale: value.scale,
|
||||||
name: value.name.clone(),
|
name: value.name.clone(),
|
||||||
timbre: value.timbre,
|
timbre: value.timbre,
|
||||||
|
color: (value.color.r(), value.color.g(), value.color.b()),
|
||||||
notes
|
notes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PersistedGrid {
|
impl PersistedGrid {
|
||||||
pub fn into_grid(self, id: Id) -> Grid {
|
pub fn into_grid(self, id: Id, rand: Arc<Mutex<StdRand>>) -> Grid {
|
||||||
let notes: Vec<_> = self.notes.chars().map(|c| c == '1').collect();
|
let notes: Vec<_> = self.notes.chars().map(|c| c == '1').collect();
|
||||||
Grid {
|
Grid {
|
||||||
volume: self.volume,
|
volume: self.volume,
|
||||||
@@ -61,6 +65,8 @@ impl PersistedGrid {
|
|||||||
timbre: self.timbre,
|
timbre: self.timbre,
|
||||||
open: true,
|
open: true,
|
||||||
timbre_open: false,
|
timbre_open: false,
|
||||||
|
color: Color32::from_rgb(self.color.0, self.color.1, self.color.2),
|
||||||
|
rand,
|
||||||
notes,
|
notes,
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-2
@@ -1,5 +1,7 @@
|
|||||||
use std::time::Instant;
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::time::{Instant, SystemTime, UNIX_EPOCH};
|
||||||
use rodio::OutputStream;
|
use rodio::OutputStream;
|
||||||
|
use tinyrand::{Seeded, StdRand};
|
||||||
use crate::grid::Grid;
|
use crate::grid::Grid;
|
||||||
use crate::dialog::Dialog;
|
use crate::dialog::Dialog;
|
||||||
use crate::noise::Note;
|
use crate::noise::Note;
|
||||||
@@ -33,7 +35,10 @@ pub struct Tenori {
|
|||||||
|
|
||||||
/// If present, we can save to this file without asking the
|
/// If present, we can save to this file without asking the
|
||||||
/// user to select a file first.
|
/// user to select a file first.
|
||||||
pub default_filename: Option<String>
|
pub default_filename: Option<String>,
|
||||||
|
|
||||||
|
/// A random number generator
|
||||||
|
pub rand: Arc<Mutex<StdRand>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Tenori {
|
impl Default for Tenori {
|
||||||
@@ -41,6 +46,8 @@ impl Default for Tenori {
|
|||||||
let output_stream = rodio::OutputStreamBuilder::open_default_stream()
|
let output_stream = rodio::OutputStreamBuilder::open_default_stream()
|
||||||
.expect("Open audio output stream");
|
.expect("Open audio output stream");
|
||||||
|
|
||||||
|
let rand = StdRand::seed(SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs());
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
tempo: 90,
|
tempo: 90,
|
||||||
timer: 0.0,
|
timer: 0.0,
|
||||||
@@ -50,6 +57,7 @@ impl Default for Tenori {
|
|||||||
window_counter: 0,
|
window_counter: 0,
|
||||||
dialogs: vec![],
|
dialogs: vec![],
|
||||||
default_filename: None,
|
default_filename: None,
|
||||||
|
rand: Arc::new(Mutex::new(rand)),
|
||||||
output_stream
|
output_stream
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user