use std::borrow::Cow;
use bevy::prelude::{Component, Deref, Handle, Name, Reflect, ReflectComponent};
use crate::StyleSheetAsset;
#[derive(Debug, Reflect, Component, Default, Clone, Deref)]
#[reflect(Component)]
pub struct Class(Cow<'static, str>);
impl Class {
pub fn new(class: impl Into<Cow<'static, str>>) -> Self {
Self(class.into())
}
fn matches(&self, class: &str) -> bool {
self.0.split_ascii_whitespace().any(|c| c == class)
}
pub fn add(&mut self, class: &str) -> bool {
if self.matches(class) {
return false;
}
if self.0.is_empty() {
self.0.to_mut().push_str(class);
} else {
self.0.to_mut().push(' ');
self.0.to_mut().push_str(class);
}
true
}
pub fn remove(&mut self, class: &str) -> bool {
if !self.matches(class) {
return false;
}
self.0 = self
.0
.split_ascii_whitespace()
.filter(move |c| c != &class)
.collect::<Vec<_>>()
.join(" ")
.into();
true
}
pub fn set(&mut self, class: impl Into<Cow<'static, str>>) -> bool {
let class = class.into();
if self.0 == class {
return false;
}
self.0 = class;
true
}
}
#[derive(Component, Debug, Default, Reflect)]
pub struct StyleSheet {
sheets: Vec<Handle<StyleSheetAsset>>,
}
impl StyleSheet {
pub fn new(handle: Handle<StyleSheetAsset>) -> Self {
Self {
sheets: vec![handle],
}
}
pub fn from_handles(handles: Vec<Handle<StyleSheetAsset>>) -> Self {
Self { sheets: handles }
}
pub fn refresh(&mut self) {
}
#[deprecated(since = "0.6.0", note = "Use `handles` instead")]
pub fn handle(&self) -> &Handle<StyleSheetAsset> {
assert_eq!(self.sheets.len(), 1, "Use `handles` instead");
self.sheets.first().unwrap()
}
pub fn handles(&self) -> &[Handle<StyleSheetAsset>] {
&self.sheets
}
#[deprecated(since = "0.6.0", note = "Use `set_handles` instead")]
pub fn set(&mut self, handle: Handle<StyleSheetAsset>) {
assert_eq!(self.sheets.len(), 1, "Use `set_handles` instead");
self.sheets = vec![handle];
}
pub fn set_handles(&mut self, handles: Vec<Handle<StyleSheetAsset>>) {
self.sheets = handles;
}
}
impl PartialEq for StyleSheet {
fn eq(&self, other: &Self) -> bool {
self.sheets == other.sheets
}
}
pub(crate) trait MatchSelectorElement {
fn matches(&self, element: &str) -> bool;
}
impl MatchSelectorElement for Class {
fn matches(&self, element: &str) -> bool {
self.matches(element)
}
}
impl MatchSelectorElement for Name {
fn matches(&self, element: &str) -> bool {
self.as_str() == element
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn modify_class() {
let mut class = Class::new("yellow-button");
assert!(class.add("enabled"));
assert_eq!(class.0, "yellow-button enabled");
assert!(!class.add("enabled"));
assert_eq!(class.0, "yellow-button enabled");
assert!(!class.remove("disabled"));
assert_eq!(class.0, "yellow-button enabled");
assert!(class.remove("enabled"));
assert_eq!(class.0, "yellow-button");
assert!(class.set("blue-button enabled"));
assert_eq!(class.0, "blue-button enabled");
assert!(!class.set("blue-button enabled"));
assert_eq!(class.0, "blue-button enabled");
}
}