refactor(colorscheme): add RosePine enum

This commit is contained in:
Kristofers Solo 2024-12-27 14:01:52 +02:00
parent 4635b0f134
commit 3b5c92e998
10 changed files with 206 additions and 52 deletions

View File

@ -27,9 +27,7 @@ jobs:
sweep-cache: true sweep-cache: true
- name: Run tests - name: Run tests
run: | run: |
cargo test --locked --workspace --all-features --all-targets cargo test --locked --workspace --no-default-features
# Workaround for https://github.com/rust-lang/cargo/issues/6669
cargo test --locked --workspace --all-features --doc
# Run clippy lints. # Run clippy lints.
clippy: clippy:
name: Clippy name: Clippy

41
Cargo.lock generated
View File

@ -2645,6 +2645,12 @@ dependencies = [
"foldhash", "foldhash",
] ]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.4.0" version = "0.4.0"
@ -2669,9 +2675,9 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
[[package]] [[package]]
name = "hexlab" name = "hexlab"
version = "0.4.0" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94f91bb99b0ef58661cc4c18e9bab7bba9e66a3d3047fec9af76e31381647442" checksum = "f19ccfce524b2ad659c08508de50522933909ed9787e4c4001cf80d4d380e789"
dependencies = [ dependencies = [
"bevy_reflect", "bevy_reflect",
"bevy_utils", "bevy_utils",
@ -3159,7 +3165,7 @@ dependencies = [
[[package]] [[package]]
name = "maze-ascension" name = "maze-ascension"
version = "0.2.3" version = "0.3.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bevy", "bevy",
@ -3171,6 +3177,7 @@ dependencies = [
"rand", "rand",
"rstest", "rstest",
"rstest_reuse", "rstest_reuse",
"strum",
"test-log", "test-log",
"thiserror 2.0.6", "thiserror 2.0.6",
"tracing", "tracing",
@ -4227,6 +4234,12 @@ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
[[package]]
name = "rustversion"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
[[package]] [[package]]
name = "rustybuzz" name = "rustybuzz"
version = "0.14.1" version = "0.14.1"
@ -4465,6 +4478,28 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
[[package]]
name = "strum"
version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]] [[package]]
name = "svg_fmt" name = "svg_fmt"
version = "0.4.4" version = "0.4.4"

View File

@ -1,7 +1,7 @@
[package] [package]
name = "maze-ascension" name = "maze-ascension"
authors = ["Kristofers Solo <dev@kristofers.xyz>"] authors = ["Kristofers Solo <dev@kristofers.xyz>"]
version = "0.2.3" version = "0.3.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
@ -18,11 +18,12 @@ tracing = { version = "0.1", features = [
"release_max_level_warn", "release_max_level_warn",
] } ] }
hexx = { version = "0.19", features = ["bevy_reflect", "grid"] } hexx = { version = "0.19", features = ["bevy_reflect", "grid"] }
hexlab = { version = "0.4", features = ["bevy_reflect"] } hexlab = { version = "0.5", features = ["bevy_reflect"] }
bevy-inspector-egui = { version = "0.28", optional = true } bevy-inspector-egui = { version = "0.28", optional = true }
bevy_egui = { version = "0.31", optional = true } bevy_egui = { version = "0.31", optional = true }
thiserror = "2.0" thiserror = "2.0"
anyhow = "1" anyhow = "1"
strum = { version = "0.26", features = ["derive"] }
[dev-dependencies] [dev-dependencies]
rstest = "0.23" rstest = "0.23"

View File

@ -14,7 +14,7 @@ impl TransitionFloor {
self.into() self.into()
} }
pub fn opposite(&self) -> Self { pub const fn opposite(&self) -> Self {
match self { match self {
Self::Ascend => Self::Descend, Self::Ascend => Self::Descend,
Self::Descend => Self::Ascend, Self::Descend => Self::Ascend,
@ -31,7 +31,7 @@ impl TransitionFloor {
impl From<TransitionFloor> for f32 { impl From<TransitionFloor> for f32 {
fn from(value: TransitionFloor) -> Self { fn from(value: TransitionFloor) -> Self {
f32::from(&value) Self::from(&value)
} }
} }

View File

@ -1,8 +1,8 @@
use crate::theme::palette::rose_pine::{LOVE, PINE};
use super::resources::GlobalMazeConfig; use super::resources::GlobalMazeConfig;
use crate::theme::{palette::rose_pine::RosePine, prelude::ColorScheme};
use bevy::{prelude::*, utils::HashMap}; use bevy::{prelude::*, utils::HashMap};
use std::f32::consts::FRAC_PI_2; use std::f32::consts::FRAC_PI_2;
use strum::IntoEnumIterator;
const WALL_OVERLAP_MODIFIER: f32 = 1.25; const WALL_OVERLAP_MODIFIER: f32 = 1.25;
const HEX_SIDES: u32 = 6; const HEX_SIDES: u32 = 6;
@ -13,7 +13,7 @@ pub struct MazeAssets {
pub wall_mesh: Handle<Mesh>, pub wall_mesh: Handle<Mesh>,
pub hex_material: Handle<StandardMaterial>, pub hex_material: Handle<StandardMaterial>,
pub wall_material: Handle<StandardMaterial>, pub wall_material: Handle<StandardMaterial>,
pub custom_materials: HashMap<String, Handle<StandardMaterial>>, pub custom_materials: HashMap<RosePine, Handle<StandardMaterial>>,
} }
impl MazeAssets { impl MazeAssets {
@ -22,11 +22,9 @@ impl MazeAssets {
materials: &mut ResMut<Assets<StandardMaterial>>, materials: &mut ResMut<Assets<StandardMaterial>>,
global_config: &GlobalMazeConfig, global_config: &GlobalMazeConfig,
) -> Self { ) -> Self {
let mut custom_materials = HashMap::new(); let custom_materials = RosePine::iter()
custom_materials.extend(vec![ .map(|color| (color, materials.add(color.to_standart_material())))
("LOVE".to_string(), materials.add(red_material())), .collect();
("PINE".to_string(), materials.add(blue_material())),
]);
Self { Self {
hex_mesh: meshes.add(generate_hex_mesh( hex_mesh: meshes.add(generate_hex_mesh(
global_config.hex_size, global_config.hex_size,
@ -73,17 +71,3 @@ pub fn white_material() -> StandardMaterial {
..default() ..default()
} }
} }
pub fn red_material() -> StandardMaterial {
StandardMaterial {
emissive: LOVE.to_linear(),
..default()
}
}
pub fn blue_material() -> StandardMaterial {
StandardMaterial {
emissive: PINE.to_linear(),
..default()
}
}

View File

@ -7,6 +7,7 @@ use crate::{
events::SpawnMaze, events::SpawnMaze,
resources::GlobalMazeConfig, resources::GlobalMazeConfig,
}, },
theme::palette::rose_pine::RosePine,
}; };
use bevy::prelude::*; use bevy::prelude::*;
use hexlab::prelude::*; use hexlab::prelude::*;
@ -100,12 +101,12 @@ pub(super) fn spawn_single_hex_tile(
let material = match tile.pos() { let material = match tile.pos() {
pos if pos == maze_config.start_pos => assets pos if pos == maze_config.start_pos => assets
.custom_materials .custom_materials
.get("PINE") .get(&RosePine::Pine)
.cloned() .cloned()
.unwrap_or_default(), .unwrap_or_default(),
pos if pos == maze_config.end_pos => assets pos if pos == maze_config.end_pos => assets
.custom_materials .custom_materials
.get("LOVE") .get(&RosePine::Love)
.cloned() .cloned()
.unwrap_or_default(), .unwrap_or_default(),
_ => assets.hex_material.clone(), _ => assets.hex_material.clone(),

View File

@ -1,6 +1,7 @@
use crate::theme::palette::rose_pine::PINE;
use bevy::prelude::*; use bevy::prelude::*;
use crate::theme::{palette::rose_pine::RosePine, prelude::ColorScheme};
pub(super) fn generate_pill_mesh(radius: f32, half_length: f32) -> Mesh { pub(super) fn generate_pill_mesh(radius: f32, half_length: f32) -> Mesh {
Mesh::from(Capsule3d { Mesh::from(Capsule3d {
radius, radius,
@ -9,9 +10,10 @@ pub(super) fn generate_pill_mesh(radius: f32, half_length: f32) -> Mesh {
} }
pub(super) fn blue_material() -> StandardMaterial { pub(super) fn blue_material() -> StandardMaterial {
let color = RosePine::Pine;
StandardMaterial { StandardMaterial {
base_color: PINE, base_color: color.to_color(),
emissive: PINE.to_linear() * 3., emissive: color.to_linear_rgba() * 3.,
..default() ..default()
} }
} }

104
src/theme/colorscheme.rs Normal file
View File

@ -0,0 +1,104 @@
use bevy::prelude::*;
use std::ops::Deref;
/// A trait for types that can be converted to a Bevy `Color`.
///
/// Implementing this trait allows a type to be easily converted to various Bevy color types.
///
/// # Examples
///
/// ```
/// use bevy::prelude::*;
/// use maze_ascension::theme::prelude::ColorScheme;
///
/// struct MyColor(u8, u8, u8);
///
/// impl ColorScheme for MyColor {
/// fn to_color(&self) -> Color {
/// Color::srgb(
/// self.0 as f32 / 255.0,
/// self.1 as f32 / 255.0,
/// self.2 as f32 / 255.0
/// )
/// }
/// }
///
/// let my_color = MyColor(255, 0, 0);
/// let bevy_color: Color = my_color.to_color();
/// assert_eq!(bevy_color, Color::srgb(1., 0., 0.));
/// ```
pub trait ColorScheme {
/// Converts the implementing type to a Bevy `Color`.
fn to_color(&self) -> Color;
/// Converts the implementing type to a Bevy `LinearRgba`.
///
/// This method provides a default implementation based on `to_color()`.
fn to_linear_rgba(&self) -> LinearRgba {
self.to_color().to_linear()
}
/// Converts the implementing type to a Bevy `StandardMaterial`.
///
/// This method provides a default implementation that sets the emissive color.
fn to_standart_material(&self) -> StandardMaterial {
StandardMaterial {
emissive: self.to_linear_rgba(),
..default()
}
}
}
/// A wrapper type that implements `From` traits for types implementing `ColorScheme`.
///
/// This wrapper allows for easy conversion from `ColorScheme` types to Bevy color types.
///
/// # Examples
///
/// ```
/// use bevy::prelude::*;
/// use maze_ascension::theme::prelude::{ColorScheme, ColorSchemeWrapper};
///
/// struct MyColor(u8, u8, u8);
///
/// impl ColorScheme for MyColor {
/// fn to_color(&self) -> Color {
/// Color::srgb(
/// self.0 as f32 / 255.0,
/// self.1 as f32 / 255.0,
/// self.2 as f32 / 255.0
/// )
/// }
/// }
///
/// let my_color = MyColor(0, 255, 0);
/// let wrapper = ColorSchemeWrapper(my_color);
/// let bevy_color: Color = wrapper.into();
/// assert_eq!(bevy_color, Color::srgb(0., 1., 0.));
/// ```
pub struct ColorSchemeWrapper<T: ColorScheme>(pub T);
impl<T: ColorScheme> From<T> for ColorSchemeWrapper<T> {
fn from(value: T) -> Self {
Self(value)
}
}
impl<T: ColorScheme> Deref for ColorSchemeWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: ColorScheme> From<ColorSchemeWrapper<T>> for Color {
fn from(value: ColorSchemeWrapper<T>) -> Self {
value.to_color()
}
}
impl<T: ColorScheme> From<ColorSchemeWrapper<T>> for LinearRgba {
fn from(value: ColorSchemeWrapper<T>) -> Self {
value.to_linear_rgba()
}
}

View File

@ -2,6 +2,7 @@
// Unused utilities may trigger this lints undesirably. // Unused utilities may trigger this lints undesirably.
mod colorscheme;
pub mod interaction; pub mod interaction;
pub mod palette; pub mod palette;
mod widgets; mod widgets;
@ -9,6 +10,7 @@ mod widgets;
#[allow(unused_imports)] #[allow(unused_imports)]
pub mod prelude { pub mod prelude {
pub use super::{ pub use super::{
colorscheme::{ColorScheme, ColorSchemeWrapper},
interaction::{InteractionPalette, OnPress}, interaction::{InteractionPalette, OnPress},
palette as ui_palette, palette as ui_palette,
widgets::{Containers as _, Widgets as _}, widgets::{Containers as _, Widgets as _},

View File

@ -1,18 +1,45 @@
use super::rgb_u8; use super::rgb_u8;
use crate::theme::prelude::ColorScheme;
use bevy::prelude::*; use bevy::prelude::*;
use strum::EnumIter;
pub const BASE: Color = rgb_u8(25, 23, 36); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)]
pub const SURFACE: Color = rgb_u8(31, 29, 46); pub enum RosePine {
pub const OVERLAY: Color = rgb_u8(38, 35, 58); Base,
pub const MUTED: Color = rgb_u8(110, 106, 134); Surface,
pub const SUBTLE: Color = rgb_u8(144, 140, 170); Overlay,
pub const TEXT: Color = rgb_u8(224, 222, 244); Muted,
pub const LOVE: Color = rgb_u8(235, 111, 146); Subtle,
pub const GOLD: Color = rgb_u8(246, 193, 119); Text,
pub const ROSE: Color = rgb_u8(235, 188, 186); Love,
pub const PINE: Color = rgb_u8(49, 116, 143); Gold,
pub const FOAM: Color = rgb_u8(156, 207, 216); Rose,
pub const IRIS: Color = rgb_u8(196, 167, 231); Pine,
pub const HIGHLIGHT_LOW: Color = rgb_u8(33, 32, 46); Foam,
pub const HIGHLIGHT_MED: Color = rgb_u8(64, 61, 82); Iris,
pub const HIGHLIGHT_HIGH: Color = rgb_u8(82, 79, 103); HighlightLow,
HighlightMed,
HighlightHigh,
}
impl ColorScheme for RosePine {
fn to_color(&self) -> Color {
match self {
Self::Base => rgb_u8(25, 23, 36),
Self::Surface => rgb_u8(31, 29, 46),
Self::Overlay => rgb_u8(38, 35, 58),
Self::Muted => rgb_u8(110, 106, 134),
Self::Subtle => rgb_u8(144, 140, 170),
Self::Text => rgb_u8(224, 222, 244),
Self::Love => rgb_u8(235, 111, 146),
Self::Gold => rgb_u8(246, 193, 119),
Self::Rose => rgb_u8(235, 188, 186),
Self::Pine => rgb_u8(49, 116, 143),
Self::Foam => rgb_u8(156, 207, 216),
Self::Iris => rgb_u8(196, 167, 231),
Self::HighlightLow => rgb_u8(33, 32, 46),
Self::HighlightMed => rgb_u8(64, 61, 82),
Self::HighlightHigh => rgb_u8(82, 79, 103),
}
}
}