#[allow(dead_code)]
use std::ops::Neg;
use bevy_color::prelude::*;
use bevy_text::prelude::*;
use bevy_ui::prelude::*;
use haalka::futures_signals::prelude::*;
use strum::EnumIter;
pub(crate) static Z_ORDER: &[&str] = &[
"tooltip",
"dropdown",
"target/search",
"scrollbar",
"header",
"inspector",
];
pub(crate) fn z_order(name: &str) -> i32 {
Z_ORDER
.iter()
.position(|&s| s == name)
.map_or(i32::MIN, |i| i32::MAX - (i as i32))
}
pub(crate) fn div(x: f32) -> impl FnMut(f32) -> f32 {
move |y| y / x
}
#[allow(dead_code)]
pub(crate) fn mul(x: f32) -> impl FnMut(f32) -> f32 {
move |y| y * x
}
#[allow(dead_code)]
pub(crate) fn add(x: f32) -> impl FnMut(f32) -> f32 {
move |y| y + x
}
#[allow(dead_code)]
pub(crate) fn sub(x: f32) -> impl FnMut(f32) -> f32 {
move |y| y - x
}
pub fn font_size_style<E: Element>(font_size: impl Signal<Item = f32> + Send + 'static) -> impl FnOnce(E) -> E {
|el| {
el.update_raw_el(|raw_el| {
raw_el.on_signal_with_component::<_, TextFont>(font_size.dedupe(), |mut text_font, font_size| {
text_font.font_size = font_size
})
})
}
}
pub fn text_style<E: Element>(
font_size: impl Signal<Item = f32> + Send + 'static,
color: impl Signal<Item = Color> + Send + 'static,
) -> impl FnOnce(E) -> E {
|el| {
el.update_raw_el(|raw_el| {
raw_el
.on_signal_with_component::<_, TextFont>(font_size.dedupe(), |mut text_font, font_size| {
text_font.font_size = font_size;
})
.component_signal(color.dedupe().map(TextColor))
})
}
}
pub fn column_style<E: Element>(row_gap: impl Signal<Item = f32> + Send + 'static) -> impl FnOnce(E) -> E {
|el| {
el.update_raw_el(|raw_el| {
raw_el.on_signal_with_component::<_, Node>(row_gap.dedupe().map(Val::Px), |mut node, row_gap| {
node.row_gap = row_gap
})
})
}
}
pub fn row_style<E: Element>(column_gap: impl Signal<Item = f32> + Send + 'static) -> impl FnOnce(E) -> E {
|el| {
el.update_raw_el(|raw_el: RawHaalkaEl| {
raw_el.on_signal_with_component::<_, Node>(column_gap.dedupe().map(Val::Px), |mut node, column_gap| {
node.column_gap = column_gap
})
})
}
}
pub fn padding_style<E: RawElWrapper>(
edges: impl IntoIterator<Item = BoxEdge>,
padding: impl Signal<Item = f32> + Send + 'static,
) -> impl FnOnce(E) -> E {
let edges = edges.into_iter().collect::<Vec<_>>();
move |el| {
el.update_raw_el(|raw_el| {
raw_el.on_signal_with_component::<_, Node>(padding.dedupe().map(Val::Px), move |mut node, p| {
let padding = &mut node.padding;
for edge in edges.iter() {
match edge {
BoxEdge::Top => padding.top = p,
BoxEdge::Bottom => padding.bottom = p,
BoxEdge::Left => padding.left = p,
BoxEdge::Right => padding.right = p,
}
}
})
})
}
}
pub fn left_bordered_style<E: Element>(
border_width: impl Signal<Item = f32> + Send + 'static,
border_color: impl Signal<Item = Color> + Send + 'static,
padding: impl Signal<Item = f32> + Send + 'static,
) -> impl FnOnce(E) -> E {
|el| {
el.update_raw_el(|raw_el| {
raw_el.on_signal_with_component::<_, Node>(border_width.dedupe().map(Val::Px), |mut node, width| {
node.border.left = width
})
})
.apply(border_color_style(border_color))
.apply(margin_style([BoxEdge::Bottom], padding.map(div(2.))))
}
}
pub fn square_style<E: Element>(size: impl Signal<Item = f32> + Send + Sync + 'static) -> impl FnOnce(E) -> E {
move |el| {
let size = size.dedupe().broadcast();
el.apply(height_style(size.signal().map(Val::Px)))
.apply(width_style(size.signal().map(Val::Px)))
}
}
pub fn outline_style<E: Element>(
active: impl Signal<Item = bool> + Send + 'static,
width: impl Signal<Item = f32> + Send + Sync + 'static,
offset: impl Signal<Item = f32> + Send + Sync + 'static,
color: impl Signal<Item = Color> + Send + Sync + 'static,
) -> impl FnOnce(E) -> E {
|el| {
el.update_raw_el(|raw_el| {
let width = width.dedupe().map(Val::Px).broadcast();
let offset = offset.dedupe().map(Val::Px).broadcast();
let color = color.dedupe().broadcast();
raw_el.component_signal::<Outline, _>(active.dedupe().map_true_signal(move || {
map_ref! {
let &width = width.signal(),
let &offset = offset.signal(),
let &color = color.signal()
=> Outline {
width,
offset,
color,
}
}
}))
})
}
}
pub fn background_style<E: Element>(
background_color: impl Signal<Item = Color> + Send + 'static,
) -> impl FnOnce(E) -> E {
|el| {
el.update_raw_el(|raw_el| {
raw_el.component_signal::<BackgroundColor, _>(background_color.dedupe().map(BackgroundColor))
})
}
}
pub fn height_style<E: Element>(height: impl Signal<Item = Val> + Send + 'static) -> impl FnOnce(E) -> E {
|el| {
el.update_raw_el(|raw_el| {
raw_el.on_signal_with_component::<_, Node>(height.dedupe(), |mut node, height| node.height = height)
})
}
}
pub fn width_style<E: Element>(width: impl Signal<Item = Val> + Send + 'static) -> impl FnOnce(E) -> E {
|el| {
el.update_raw_el(|raw_el| {
raw_el.on_signal_with_component::<_, Node>(width.dedupe(), |mut node, width| node.width = width)
})
}
}
pub fn border_style<E: Element>(
border_width: impl Signal<Item = f32> + Send + 'static,
border_color: impl Signal<Item = Color> + Send + 'static,
) -> impl FnOnce(E) -> E {
|el| {
el.update_raw_el(|raw_el| {
raw_el
.component_signal::<BorderColor, _>(border_color.dedupe().map(BorderColor::all))
.on_signal_with_component::<_, Node>(
border_width.dedupe().map(Val::Px).map(UiRect::all),
|mut node, width| node.border = width,
)
})
}
}
pub fn border_color_style<E: Element>(
border_color: impl Signal<Item = impl Into<Option<Color>> + 'static> + Send + 'static,
) -> impl FnOnce(E) -> E {
|el| {
let border_color = border_color.map(Into::into);
el.update_raw_el(|raw_el| {
raw_el.component_signal::<BorderColor, _>(border_color.dedupe().map_some(BorderColor::all))
})
}
}
pub fn left_style<E: Element>(left: impl Signal<Item = f32> + Send + 'static) -> impl FnOnce(E) -> E {
|el| {
el.update_raw_el(|raw_el| {
raw_el.on_signal_with_component::<_, Node>(left.dedupe().map(Val::Px), |mut node, left| node.left = left)
})
}
}
pub fn top_style<E: Element>(top: impl Signal<Item = f32> + Send + 'static) -> impl FnOnce(E) -> E {
|el| {
el.update_raw_el(|raw_el| {
raw_el.on_signal_with_component::<_, Node>(top.dedupe().map(Val::Px), |mut node, top| node.top = top)
})
}
}
#[derive(Clone, Copy, EnumIter, PartialEq, Debug)]
pub enum BoxEdge {
Top,
Bottom,
Left,
Right,
}
impl BoxEdge {
pub const ALL: [BoxEdge; 4] = [BoxEdge::Top, BoxEdge::Bottom, BoxEdge::Left, BoxEdge::Right];
pub const VERTICAL: [BoxEdge; 2] = [BoxEdge::Top, BoxEdge::Bottom];
pub const HORIZONTAL: [BoxEdge; 2] = [BoxEdge::Left, BoxEdge::Right];
}
#[derive(Clone, Copy, EnumIter, PartialEq, Debug)]
pub enum BoxCorner {
TopLeft,
TopRight,
BottomLeft,
BottomRight,
}
impl BoxCorner {
pub const ALL: [BoxCorner; 4] = [
BoxCorner::TopLeft,
BoxCorner::TopRight,
BoxCorner::BottomLeft,
BoxCorner::BottomRight,
];
pub const TOP: [BoxCorner; 2] = [BoxCorner::TopLeft, BoxCorner::TopRight];
pub const BOTTOM: [BoxCorner; 2] = [BoxCorner::BottomLeft, BoxCorner::BottomRight];
pub const LEFT: [BoxCorner; 2] = [BoxCorner::TopLeft, BoxCorner::BottomLeft];
pub const RIGHT: [BoxCorner; 2] = [BoxCorner::TopRight, BoxCorner::BottomRight];
}
pub fn border_width_style<E: Element>(
edges: impl IntoIterator<Item = BoxEdge>,
border_width: impl Signal<Item = f32> + Send + 'static,
) -> impl FnOnce(E) -> E {
let edges = edges.into_iter().collect::<Vec<_>>();
move |el| {
el.update_raw_el(|raw_el| {
raw_el.on_signal_with_component::<_, Node>(
border_width.dedupe().map(Val::Px),
move |mut node, border_width| {
let border = &mut node.border;
for edge in edges.iter() {
match edge {
BoxEdge::Top => border.top = border_width,
BoxEdge::Bottom => border.bottom = border_width,
BoxEdge::Left => border.left = border_width,
BoxEdge::Right => border.right = border_width,
}
}
},
)
})
}
}
pub fn border_radius_style<E: Element>(
corners: impl IntoIterator<Item = BoxCorner>,
border_radius: impl Signal<Item = f32> + Send + 'static,
) -> impl FnOnce(E) -> E {
let corners = corners.into_iter().collect::<Vec<_>>();
move |el| {
el.update_raw_el(|raw_el| {
raw_el.on_signal_with_component::<_, Node>(border_radius.dedupe().map(Val::Px), move |mut node, radius| {
for corner in corners.iter() {
match corner {
BoxCorner::TopLeft => node.border_radius.top_left = radius,
BoxCorner::TopRight => node.border_radius.top_right = radius,
BoxCorner::BottomLeft => node.border_radius.bottom_left = radius,
BoxCorner::BottomRight => node.border_radius.bottom_right = radius,
}
}
})
})
}
}
pub fn margin_style<E: Element>(
edges: impl IntoIterator<Item = BoxEdge>,
margin: impl Signal<Item = f32> + Send + 'static,
) -> impl FnOnce(E) -> E {
let edges = edges.into_iter().collect::<Vec<_>>();
move |el| {
el.update_raw_el(|raw_el| {
raw_el.on_signal_with_component::<_, Node>(margin.dedupe().map(Val::Px), move |mut node, m| {
let margin = &mut node.margin;
for edge in edges.iter() {
match edge {
BoxEdge::Top => margin.top = m,
BoxEdge::Bottom => margin.bottom = m,
BoxEdge::Left => margin.left = m,
BoxEdge::Right => margin.right = m,
}
}
})
})
}
}
#[derive(Clone, Copy)]
pub enum Move_ {
Up,
Down,
Left,
Right,
}
pub fn move_style<E: Element>(
move_: Move_,
magnitude: impl Signal<Item = f32> + Send + 'static,
) -> impl FnOnce(E) -> E {
move |el| {
el.update_raw_el(move |raw_el| {
raw_el.on_signal_with_component::<_, Node>(magnitude.dedupe().map(Val::Px), move |mut node, magnitude| {
match move_ {
Move_::Up => node.top = magnitude.neg(),
Move_::Down => node.top = magnitude,
Move_::Left => node.left = magnitude.neg(),
Move_::Right => node.left = magnitude,
}
})
})
}
}