use bevy::prelude::*;
use bevy::ui::UiTargetCamera;
use super::super::fit::Edge;
use super::super::support::ScreenSpaceBounds;
use super::screen_space;
const LABEL_FONT_SIZE: f32 = 11.0;
const LABEL_PIXEL_OFFSET: f32 = 8.0;
#[derive(Component, Reflect)]
#[reflect(Component)]
pub struct MarginLabel {
pub edge: Edge,
pub camera: Entity,
}
pub struct MarginLabelParams {
pub camera: Entity,
pub edge: Edge,
pub text: String,
pub color: Color,
pub screen_pos: Vec2,
pub viewport_size: Vec2,
}
#[derive(Component, Reflect)]
#[reflect(Component)]
pub struct BoundsLabel {
pub camera: Entity,
}
pub fn calculate_label_pixel_position(
edge: Edge,
bounds: &ScreenSpaceBounds,
viewport_size: Vec2,
) -> Vec2 {
let (screen_x, screen_y) = screen_space::screen_edge_center(bounds, edge);
let px = screen_space::norm_to_viewport(
screen_x,
screen_y,
bounds.half_extent_x,
bounds.half_extent_y,
viewport_size,
);
let above_line = px.y - LABEL_FONT_SIZE - LABEL_PIXEL_OFFSET;
match edge {
Edge::Left => Vec2::new(LABEL_PIXEL_OFFSET, above_line),
Edge::Right => Vec2::new(viewport_size.x - LABEL_PIXEL_OFFSET, above_line),
Edge::Top => Vec2::new(px.x + LABEL_PIXEL_OFFSET, LABEL_PIXEL_OFFSET),
Edge::Bottom => Vec2::new(
px.x + LABEL_PIXEL_OFFSET,
viewport_size.y - LABEL_PIXEL_OFFSET,
),
}
}
pub fn bounds_label_position(upper_left: Vec2) -> Vec2 {
Vec2::new(
upper_left.x + LABEL_PIXEL_OFFSET,
upper_left.y - LABEL_FONT_SIZE - LABEL_PIXEL_OFFSET,
)
}
fn apply_margin_label_anchor(node: &mut Node, edge: Edge, screen_pos: Vec2, viewport_size: Vec2) {
match edge {
Edge::Left | Edge::Top => {
node.left = Val::Px(screen_pos.x);
node.top = Val::Px(screen_pos.y);
node.right = Val::Auto;
node.bottom = Val::Auto;
},
Edge::Right => {
node.right = Val::Px(viewport_size.x - screen_pos.x);
node.top = Val::Px(screen_pos.y);
node.left = Val::Auto;
node.bottom = Val::Auto;
},
Edge::Bottom => {
node.left = Val::Px(screen_pos.x);
node.bottom = Val::Px(viewport_size.y - screen_pos.y);
node.right = Val::Auto;
node.top = Val::Auto;
},
}
}
fn margin_label_node(edge: Edge, screen_pos: Vec2, viewport_size: Vec2) -> Node {
let mut node = Node {
position_type: PositionType::Absolute,
..default()
};
apply_margin_label_anchor(&mut node, edge, screen_pos, viewport_size);
node
}
pub fn update_or_create_margin_label(
commands: &mut Commands,
label_query: &mut Query<(Entity, &MarginLabel, &mut Text, &mut Node, &mut TextColor)>,
params: MarginLabelParams,
) {
let mut found = false;
for (_, label, mut label_text, mut node, mut text_color) in label_query {
if label.camera == params.camera && label.edge == params.edge {
(**label_text).clone_from(¶ms.text);
text_color.0 = params.color;
apply_margin_label_anchor(
&mut node,
params.edge,
params.screen_pos,
params.viewport_size,
);
found = true;
break;
}
}
if !found {
commands.spawn((
Text::new(params.text),
TextFont {
font_size: LABEL_FONT_SIZE,
..default()
},
TextColor(params.color),
margin_label_node(params.edge, params.screen_pos, params.viewport_size),
MarginLabel {
edge: params.edge,
camera: params.camera,
},
UiTargetCamera(params.camera),
));
}
}
pub fn update_or_create_bounds_label(
commands: &mut Commands,
bounds_query: &mut Query<(Entity, &BoundsLabel, &mut Node), Without<MarginLabel>>,
camera: Entity,
screen_pos: Vec2,
) {
let mut found = false;
for (_, label, mut node) in bounds_query.iter_mut() {
if label.camera == camera {
node.left = Val::Px(screen_pos.x);
node.top = Val::Px(screen_pos.y);
found = true;
break;
}
}
if !found {
commands.spawn((
Text::new("screen space bounds"),
TextFont {
font_size: LABEL_FONT_SIZE,
..default()
},
TextColor(Color::srgb(1.0, 1.0, 0.0)),
Node {
position_type: PositionType::Absolute,
left: Val::Px(screen_pos.x),
top: Val::Px(screen_pos.y),
..default()
},
BoundsLabel { camera },
UiTargetCamera(camera),
));
}
}