use bevy::prelude::*;
pub use bevy_tailwind_macro::tw;
pub struct TailwindPlugin;
impl Plugin for TailwindPlugin {
fn build(&self, app: &mut App) {
app.add_systems(PostUpdate, apply_picking_style);
}
}
fn apply_picking_style(
mut query: Query<
(
&PickingStyles,
Ref<Interaction>,
Option<&mut Node>,
Option<&mut BackgroundColor>,
Option<&mut ZIndex>,
Option<&mut BorderRadius>,
Option<&mut BorderColor>,
Option<&mut Outline>,
Option<&mut TextFont>,
Option<&mut TextLayout>,
Option<&mut TextColor>,
Option<&mut UiTransform>,
),
Changed<Interaction>,
>,
) {
for (
picking_styles,
interaction,
node,
background_color,
z_index,
border_radius,
border_color,
outline,
text_font,
text_layout,
text_color,
ui_transform,
) in query.iter_mut()
{
if interaction.is_added() {
continue;
}
fn apply_style(
picking: &PickingStyle,
node: Option<Mut<Node>>,
background_color: Option<Mut<BackgroundColor>>,
z_index: Option<Mut<ZIndex>>,
border_radius: Option<Mut<BorderRadius>>,
border_color: Option<Mut<BorderColor>>,
outline: Option<Mut<Outline>>,
text_font: Option<Mut<TextFont>>,
text_layout: Option<Mut<TextLayout>>,
text_color: Option<Mut<TextColor>>,
ui_transform: Option<Mut<UiTransform>>,
) {
macro_rules! apply_style {
($(($picking_prop:ident, $lhs:expr)),+) => {
$(
if let Some(prop) = &picking.$picking_prop {
$lhs = prop.clone();
}
)+
};
}
if let Some(mut node) = node {
apply_style!(
(aspect_ratio, node.aspect_ratio),
(display, node.display),
(overflow_x, node.overflow.x),
(overflow_y, node.overflow.y),
(position, node.position_type),
(top, node.top),
(right, node.right),
(bottom, node.bottom),
(left, node.left),
(flex_basis, node.flex_basis),
(flex_direction, node.flex_direction),
(flex_wrap, node.flex_wrap),
(flex_grow, node.flex_grow),
(flex_shrink, node.flex_shrink),
(grid_template_columns, node.grid_template_columns),
(grid_template_rows, node.grid_template_rows),
(grid_auto_flow, node.grid_auto_flow),
(grid_auto_columns, node.grid_auto_columns),
(grid_auto_rows, node.grid_auto_rows),
(column_gap, node.column_gap),
(row_gap, node.row_gap),
(justify_content, node.justify_content),
(justify_items, node.justify_items),
(justify_self, node.justify_self),
(align_content, node.align_content),
(align_items, node.align_items),
(align_self, node.align_self),
(padding_top, node.padding.top),
(padding_right, node.padding.right),
(padding_bottom, node.padding.bottom),
(padding_left, node.padding.left),
(margin_top, node.margin.top),
(margin_right, node.margin.right),
(margin_bottom, node.margin.bottom),
(margin_left, node.margin.left),
(width, node.width),
(min_width, node.min_width),
(max_width, node.max_width),
(height, node.height),
(min_height, node.min_height),
(max_height, node.max_height),
(border_top, node.border.top),
(border_right, node.border.right),
(border_bottom, node.border.bottom),
(border_left, node.border.left)
);
}
if let Some(mut background_color) = background_color {
apply_style!((background_color, background_color.0));
}
if let Some(mut z_index) = z_index {
apply_style!((z_index, z_index.0));
}
if let Some(mut border_radius) = border_radius {
apply_style!(
(border_radius_tl, border_radius.top_left),
(border_radius_tr, border_radius.top_right),
(border_radius_br, border_radius.bottom_right),
(border_radius_bl, border_radius.bottom_left)
);
}
if let Some(mut border_color) = border_color {
apply_style!(
(border_color_top, border_color.top),
(border_color_right, border_color.right),
(border_color_bottom, border_color.bottom),
(border_color_left, border_color.left)
);
}
if let Some(mut outline) = outline {
apply_style!(
(outline_width, outline.width),
(outline_color, outline.color),
(outline_offset, outline.offset)
);
}
if let Some(mut text_font) = text_font {
apply_style!((font_size, text_font.font_size));
}
if let Some(mut text_layout) = text_layout {
apply_style!(
(text_justity, text_layout.justify),
(text_linebreak, text_layout.linebreak)
);
}
if let Some(mut text_color) = text_color {
apply_style!((text_color, text_color.0));
}
if let Some(mut ui_transform) = ui_transform {
apply_style!(
(translate_x, ui_transform.translation),
(translate_y, ui_transform.translation),
(scale_x, ui_transform.scale),
(scale_y, ui_transform.scale),
(rotation, ui_transform.rotation)
);
}
}
match interaction.into_inner() {
Interaction::None => {
apply_style(
&picking_styles.base,
node,
background_color,
z_index,
border_radius,
border_color,
outline,
text_font,
text_layout,
text_color,
ui_transform,
);
}
Interaction::Hovered => {
apply_style(
&picking_styles.hover,
node,
background_color,
z_index,
border_radius,
border_color,
outline,
text_font,
text_layout,
text_color,
ui_transform,
);
}
Interaction::Pressed => {
apply_style(
&picking_styles.focus,
node,
background_color,
z_index,
border_radius,
border_color,
outline,
text_font,
text_layout,
text_color,
ui_transform,
);
}
}
}
}
#[derive(Default, Component)]
#[require(Interaction)]
pub struct PickingStyles {
pub base: PickingStyle,
pub hover: PickingStyle,
pub focus: PickingStyle,
}
#[derive(Default)]
pub struct PickingStyle {
pub aspect_ratio: Option<Option<f32>>,
pub display: Option<Display>,
pub overflow_x: Option<OverflowAxis>,
pub overflow_y: Option<OverflowAxis>,
pub position: Option<PositionType>,
pub top: Option<Val>,
pub right: Option<Val>,
pub bottom: Option<Val>,
pub left: Option<Val>,
pub z_index: Option<i32>,
pub flex_basis: Option<Val>,
pub flex_direction: Option<FlexDirection>,
pub flex_wrap: Option<FlexWrap>,
pub flex_grow: Option<f32>,
pub flex_shrink: Option<f32>,
pub grid_template_columns: Option<Vec<RepeatedGridTrack>>,
pub grid_template_rows: Option<Vec<RepeatedGridTrack>>,
pub grid_auto_flow: Option<GridAutoFlow>,
pub grid_auto_columns: Option<Vec<GridTrack>>,
pub grid_auto_rows: Option<Vec<GridTrack>>,
pub column_gap: Option<Val>,
pub row_gap: Option<Val>,
pub justify_content: Option<JustifyContent>,
pub justify_items: Option<JustifyItems>,
pub justify_self: Option<JustifySelf>,
pub align_content: Option<AlignContent>,
pub align_items: Option<AlignItems>,
pub align_self: Option<AlignSelf>,
pub padding_top: Option<Val>,
pub padding_right: Option<Val>,
pub padding_bottom: Option<Val>,
pub padding_left: Option<Val>,
pub margin_top: Option<Val>,
pub margin_right: Option<Val>,
pub margin_bottom: Option<Val>,
pub margin_left: Option<Val>,
pub width: Option<Val>,
pub min_width: Option<Val>,
pub max_width: Option<Val>,
pub height: Option<Val>,
pub min_height: Option<Val>,
pub max_height: Option<Val>,
pub font_size: Option<f32>,
pub text_justity: Option<Justify>,
pub text_color: Option<Color>,
pub text_linebreak: Option<LineBreak>,
pub background_color: Option<Color>,
pub border_radius_tl: Option<Val>,
pub border_radius_tr: Option<Val>,
pub border_radius_br: Option<Val>,
pub border_radius_bl: Option<Val>,
pub border_top: Option<Val>,
pub border_right: Option<Val>,
pub border_bottom: Option<Val>,
pub border_left: Option<Val>,
pub border_color_top: Option<Color>,
pub border_color_right: Option<Color>,
pub border_color_bottom: Option<Color>,
pub border_color_left: Option<Color>,
pub outline_width: Option<Val>,
pub outline_color: Option<Color>,
pub outline_offset: Option<Val>,
pub translate_x: Option<Val2>,
pub translate_y: Option<Val2>,
pub scale_x: Option<Vec2>,
pub scale_y: Option<Vec2>,
pub rotation: Option<Rot2>,
}