ui: text alignment and more complete button example event handling

This commit is contained in:
Carter Anderson 2020-07-18 17:03:37 -07:00
parent a531c906a6
commit 6db82714dc
10 changed files with 112 additions and 76 deletions

View File

@ -1,7 +1,7 @@
use crate::{Font, FontAtlasSet};
use ab_glyph::{Glyph, PxScale, ScaleFont};
use ab_glyph::{FontVec, Glyph, PxScale, PxScaleFont, ScaleFont};
use bevy_asset::Assets;
use bevy_math::{Mat4, Vec3};
use bevy_math::{Mat4, Vec3, Vec2};
use bevy_render::{
color::Color,
draw::{Draw, DrawContext, DrawError, Drawable},
@ -17,41 +17,61 @@ use bevy_sprite::{TextureAtlas, TextureAtlasSprite};
pub struct TextStyle {
pub font_size: f32,
pub color: Color,
pub align: TextAlign,
}
impl Default for TextStyle {
fn default() -> Self {
Self {
color: Color::WHITE,
font_size: 12.0,
align: TextAlign::default(),
}
}
}
pub enum TextAlign {
Left,
Center,
Right,
}
impl Default for TextAlign {
fn default() -> Self {
TextAlign::Left
}
}
pub struct DrawableText<'a> {
font: &'a Font,
font_atlas_set: &'a FontAtlasSet,
texture_atlases: &'a Assets<TextureAtlas>,
render_resource_bindings: &'a mut RenderResourceBindings,
asset_render_resource_bindings: &'a mut AssetRenderResourceBindings,
position: Vec3,
style: &'a TextStyle,
text: &'a str,
pub font: &'a Font,
pub font_atlas_set: &'a FontAtlasSet,
pub texture_atlases: &'a Assets<TextureAtlas>,
pub render_resource_bindings: &'a mut RenderResourceBindings,
pub asset_render_resource_bindings: &'a mut AssetRenderResourceBindings,
pub position: Vec3,
pub container_size: Vec2,
pub style: &'a TextStyle,
pub text: &'a str,
}
impl<'a> DrawableText<'a> {
pub fn new(
font: &'a Font,
font_atlas_set: &'a FontAtlasSet,
texture_atlases: &'a Assets<TextureAtlas>,
render_resource_bindings: &'a mut RenderResourceBindings,
asset_render_resource_bindings: &'a mut AssetRenderResourceBindings,
position: Vec3,
style: &'a TextStyle,
text: &'a str,
) -> Self {
Self {
font,
font_atlas_set,
texture_atlases,
render_resource_bindings,
asset_render_resource_bindings,
position,
style,
text,
fn get_text_width(text: &str, scaled_font: &PxScaleFont<&&FontVec>) -> f32 {
let mut last_glyph: Option<Glyph> = None;
let mut position = 0.0;
for character in text.chars() {
if character.is_control() {
continue;
}
let glyph = scaled_font.scaled_glyph(character);
if let Some(last_glyph) = last_glyph.take() {
position += scaled_font.kern(last_glyph.id, glyph.id);
}
position += scaled_font.h_advance(glyph.id);
last_glyph = Some(glyph);
}
position
}
impl<'a> Drawable for DrawableText<'a> {
@ -89,6 +109,14 @@ impl<'a> Drawable for DrawableText<'a> {
let scale = PxScale::from(self.style.font_size);
let scaled_font = ab_glyph::Font::as_scaled(&font, scale);
let mut caret = self.position;
match self.style.align {
TextAlign::Left => { /* already aligned left by default */ }
TextAlign::Center => {
*caret.x_mut() += self.container_size.x() / 2.0 - get_text_width(&self.text, &scaled_font) / 2.0
}
TextAlign::Right => *caret.x_mut() = self.container_size.x() - get_text_width(&self.text, &scaled_font),
}
let mut last_glyph: Option<Glyph> = None;
// set local per-character bindings

View File

@ -11,7 +11,7 @@ pub use font_atlas_set::*;
pub use font_loader::*;
pub mod prelude {
pub use crate::{Font, TextStyle};
pub use crate::{Font, TextStyle, TextAlign};
}
use bevy_app::prelude::*;

View File

@ -42,11 +42,11 @@ impl<'a> ChildBuilder<'a> {
}
pub trait BuildChildren {
fn with_children(&mut self, spawn_children: impl FnMut(&mut ChildBuilder)) -> &mut Self;
fn with_children(&mut self, parent: impl FnMut(&mut ChildBuilder)) -> &mut Self;
}
impl BuildChildren for Commands {
fn with_children(&mut self, mut spawn_children: impl FnMut(&mut ChildBuilder)) -> &mut Self {
fn with_children(&mut self, mut parent: impl FnMut(&mut ChildBuilder)) -> &mut Self {
{
let mut commands = self.commands.lock().unwrap();
let current_entity = commands.current_entity.expect("Cannot add children because the 'current entity' is not set. You should spawn an entity first.");
@ -55,7 +55,7 @@ impl BuildChildren for Commands {
parent_entities: vec![current_entity],
};
spawn_children(&mut builder);
parent(&mut builder);
}
self
}

View File

@ -65,6 +65,7 @@ pub struct LabelComponents {
pub node: Node,
pub draw: Draw,
pub label: Label,
pub focus_policy: FocusPolicy,
pub transform: Transform,
pub translation: Translation,
pub rotation: Rotation,
@ -76,6 +77,7 @@ impl Default for LabelComponents {
LabelComponents {
label: Label::default(),
node: Default::default(),
focus_policy: FocusPolicy::Pass,
draw: Draw {
is_transparent: true,
..Default::default()

View File

@ -2,7 +2,6 @@ use crate::Node;
use bevy_asset::{Assets, Handle};
use bevy_ecs::{Query, Res, ResMut};
use bevy_render::{
color::Color,
draw::{Draw, DrawContext, Drawable},
renderer::{AssetRenderResourceBindings, RenderResourceBindings},
texture::Texture,
@ -11,25 +10,13 @@ use bevy_sprite::TextureAtlas;
use bevy_text::{DrawableText, Font, FontAtlasSet, TextStyle};
use bevy_transform::prelude::Transform;
#[derive(Default)]
pub struct Label {
pub text: String,
pub font: Handle<Font>,
pub style: TextStyle,
}
impl Default for Label {
fn default() -> Self {
Label {
text: String::new(),
style: TextStyle {
color: Color::WHITE,
font_size: 12.0,
},
font: Handle::default(),
}
}
}
impl Label {
pub fn label_system(
mut textures: ResMut<Assets<Texture>>,
@ -69,21 +56,21 @@ impl Label {
mut query: Query<(&mut Draw, &Label, &Node, &Transform)>,
) {
for (mut draw, label, node, transform) in &mut query.iter() {
// let position = transform.0 - quad.size / 2.0;
let position = transform.value.w_axis().truncate() - (node.size / 2.0).extend(0.0);
let mut drawable_text = DrawableText::new(
fonts.get(&label.font).unwrap(),
font_atlas_sets
let mut drawable_text = DrawableText {
font: fonts.get(&label.font).unwrap(),
font_atlas_set: font_atlas_sets
.get(&label.font.as_handle::<FontAtlasSet>())
.unwrap(),
&texture_atlases,
&mut render_resource_bindings,
&mut asset_render_resource_bindings,
texture_atlases: &texture_atlases,
render_resource_bindings: &mut render_resource_bindings,
asset_render_resource_bindings: &mut asset_render_resource_bindings,
position,
&label.style,
&label.text,
);
style: &label.style,
text: &label.text,
container_size: node.size,
};
drawable_text.draw(&mut draw, &mut draw_context).unwrap();
}
}

View File

@ -71,6 +71,7 @@ fn setup(
style: TextStyle {
color: Color::rgb(0.2, 0.2, 0.8).into(),
font_size: 40.0,
..Default::default()
},
},
node: Node::new(Anchors::TOP_LEFT, Margins::new(10.0, 50.0, 10.0, 50.0)),

View File

@ -31,18 +31,41 @@ fn button_system(
mut click_query: Query<(
&Button,
Changed<Click>,
Option<&Hover>,
&mut Handle<ColorMaterial>,
&Children,
)>,
mut hover_query: Query<(
&Button,
Changed<Hover>,
Option<&Click>,
&mut Handle<ColorMaterial>,
&Children,
)>,
label_query: Query<&mut Label>,
) {
for (_button, click, mut material, children) in &mut click_query.iter() {
for (_button, hover, click, mut material, children) in &mut hover_query.iter() {
let mut label = label_query.get_mut::<Label>(children[0]).unwrap();
match *hover {
Hover::Hovered => {
if let Some(Click::Released) = click {
label.text = "Hover".to_string();
*material = button_materials.hovered;
}
}
Hover::NotHovered => {
if let Some(Click::Pressed) = click {
label.text = "Press".to_string();
*material = button_materials.pressed;
} else {
label.text = "Button".to_string();
*material = button_materials.normal;
}
}
}
}
for (_button, click, hover, mut material, children) in &mut click_query.iter() {
let mut label = label_query.get_mut::<Label>(children[0]).unwrap();
match *click {
Click::Pressed => {
@ -50,22 +73,13 @@ fn button_system(
*material = button_materials.pressed;
}
Click::Released => {
label.text = "Button".to_string();
*material = button_materials.normal;
}
}
}
for (_button, hover, mut material, children) in &mut hover_query.iter() {
let mut label = label_query.get_mut::<Label>(children[0]).unwrap();
match *hover {
Hover::Hovered => {
label.text = "Hover".to_string();
*material = button_materials.hovered;
}
Hover::NotHovered => {
label.text = "Button".to_string();
*material = button_materials.normal;
if let Some(Hover::Hovered) = hover {
label.text = "Hover".to_string();
*material = button_materials.hovered;
} else {
label.text = "Button".to_string();
*material = button_materials.normal;
}
}
}
}
@ -86,13 +100,14 @@ fn setup(
})
.with_children(|parent| {
parent.spawn(LabelComponents {
node: Node::new(Anchors::CENTER, Margins::new(52.0, 10.0, 20.0, 20.0)),
node: Node::new(Anchors::FULL, Margins::new(0.0, 0.0, 12.0, 0.0)),
label: Label {
text: "Button".to_string(),
font: asset_server.load("assets/fonts/FiraSans-Bold.ttf").unwrap(),
style: TextStyle {
font_size: 40.0,
color: Color::rgb(0.8, 0.8, 0.8),
align: TextAlign::Center,
},
},
..Default::default()

View File

@ -75,6 +75,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut state: ResM
style: TextStyle {
font_size: 60.0,
color: Color::WHITE,
..Default::default()
},
},
..Default::default()

View File

@ -36,6 +36,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
style: TextStyle {
font_size: 60.0,
color: Color::WHITE,
align: TextAlign::Left,
},
},
..Default::default()

View File

@ -47,6 +47,7 @@ fn setup(
style: TextStyle {
font_size: 30.0,
color: Color::WHITE,
..Default::default()
},
},
..Default::default()