Skip to content
Snippets Groups Projects
Commit 8ea62832 authored by StarArawn's avatar StarArawn
Browse files

Added horz alignment..

parent ee29cae6
No related branches found
No related tags found
No related merge requests found
......@@ -4,7 +4,7 @@ use bevy::{
sprite2::Rect,
};
use kayak_core::render_primitive::RenderPrimitive;
use kayak_font::{CoordinateSystem, KayakFont};
use kayak_font::{Alignment, CoordinateSystem, KayakFont};
use crate::{
render::unified::pipeline::{ExtractQuadBundle, ExtractedQuad, UIQuadType},
......@@ -54,8 +54,11 @@ pub fn extract_texts(
let chars_layouts = font.get_layout(
CoordinateSystem::PositiveYDown,
Alignment::Start,
Vec2::new(layout.posx, layout.posy),
Vec2::new(layout.width, layout.height),
content,
font_size * 1.2,
font_size,
);
......
......@@ -5,7 +5,7 @@ use bevy::{
window::WindowDescriptor,
PipelinedDefaultPlugins,
};
use kayak_font::{KayakFont, KayakFontPlugin};
use kayak_font::{Alignment, KayakFont, KayakFontPlugin};
mod renderer;
use renderer::FontRenderPlugin;
......@@ -19,11 +19,39 @@ fn startup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands
.spawn()
.insert(Text {
horz_alignment: Alignment::Start,
color: Color::WHITE,
content: "Hello World!".into(),
content: "Hello World! This text should wrap because its super long!".into(),
font_size: 32.0,
line_height: 32.0 * 1.2, // Firefox method of calculating default line heights see: https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
position: Vec2::new(5.0, 5.0),
size: Vec2::new(100.0, 100.0),
size: Vec2::new(250.0, 100.0),
})
.insert(font_handle.clone());
commands
.spawn()
.insert(Text {
horz_alignment: Alignment::End,
color: Color::WHITE,
content: "This is some text that will wrap and also be aligned to the right.".into(),
font_size: 32.0,
line_height: 32.0 * 1.2, // Firefox method of calculating default line heights see: https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
position: Vec2::new(-255.0, 5.0),
size: Vec2::new(250.0, 100.0),
})
.insert(font_handle.clone());
commands
.spawn()
.insert(Text {
horz_alignment: Alignment::Middle,
color: Color::WHITE,
content: "This is some text that will wrap and also be aligned in the middle.".into(),
font_size: 32.0,
line_height: 32.0 * 1.2, // Firefox method of calculating default line heights see: https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
position: Vec2::new(-125.0, -155.0),
size: Vec2::new(250.0, 100.0),
})
.insert(font_handle);
}
......
......@@ -20,8 +20,11 @@ pub fn extract(
if let Some(font) = fonts.get(font_handle) {
let layouts = font.get_layout(
CoordinateSystem::PositiveYUp,
text.horz_alignment,
text.position,
text.size,
&text.content,
text.line_height,
text.font_size,
);
......
use bevy::{math::Vec2, prelude::Component, render2::color::Color};
use kayak_font::Alignment;
#[derive(Component)]
pub struct Text {
pub horz_alignment: Alignment,
pub content: String,
pub position: Vec2,
pub size: Vec2,
pub font_size: f32,
pub line_height: f32,
pub color: Color,
}
......@@ -25,12 +25,19 @@ pub struct LayoutRect {
pub content: char,
}
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CoordinateSystem {
PositiveYUp,
PositiveYDown,
}
#[derive(Copy, Clone, PartialEq)]
pub enum Alignment {
Start,
Middle,
End,
}
impl KayakFont {
pub fn new(sdf: Sdf, atlas_image: Handle<Image>) -> Self {
Self {
......@@ -52,11 +59,36 @@ impl KayakFont {
self.char_ids.get(&c).and_then(|id| Some(*id))
}
pub fn get_word_width(&self, word: &str, font_size: f32) -> f32 {
let mut width = 0.0;
for c in word.chars() {
if let Some(glyph) = self.sdf.glyphs.iter().find(|glyph| glyph.unicode == c) {
let plane_bounds = glyph.plane_bounds.as_ref();
let (_, _, char_width, _) = match plane_bounds {
Some(val) => (
val.left,
val.top,
val.size().x * font_size,
val.size().y * font_size,
),
None => (0.0, 0.0, 0.0, 0.0),
};
width += char_width;
}
}
width
}
pub fn get_layout(
&self,
axis_alignment: CoordinateSystem,
alignment: Alignment,
position: Vec2,
max_size: Vec2,
content: &String,
line_height: f32,
font_size: f32,
) -> Vec<LayoutRect> {
let mut positions_and_size = Vec::new();
......@@ -64,35 +96,90 @@ impl KayakFont {
let font_ratio = font_size / self.sdf.atlas.size;
let resized_max_glyph_size = (max_glyph_size.x * font_ratio, max_glyph_size.y * font_ratio);
let mut x = 0.0;
for c in content.chars() {
if let Some(glyph) = self.sdf.glyphs.iter().find(|glyph| glyph.unicode == c) {
let plane_bounds = glyph.plane_bounds.as_ref();
let (left, top, _width, _height) = match plane_bounds {
Some(val) => (
val.left,
val.top,
val.size().x * font_size,
val.size().y * font_size,
),
None => (0.0, 0.0, 0.0, 0.0),
};
// TODO: Make this configurable?
let split_chars = vec![' ', '\t', '-', '\n'];
let missing_chars: Vec<char> = content
.chars()
.filter(|c| split_chars.iter().any(|c2| c == c2))
.collect();
let shift_sign = match axis_alignment {
CoordinateSystem::PositiveYDown => -1.0,
CoordinateSystem::PositiveYUp => 1.0,
};
let shift_sign = match axis_alignment {
CoordinateSystem::PositiveYDown => -1.0,
CoordinateSystem::PositiveYUp => 1.0,
};
let position_x = position.x + x + left * font_size;
let position_y = (position.y + (shift_sign * top * font_size)) + font_size;
let mut line_widths = Vec::new();
positions_and_size.push(LayoutRect {
position: Vec2::new(position_x, position_y),
size: Vec2::new(resized_max_glyph_size.0, resized_max_glyph_size.1),
content: c,
});
let mut x = 0.0;
let mut y = 0.0;
let mut i = 0;
let mut line_starting_index = 0;
let mut last_width = 0.0;
for word in content.split(&split_chars[..]) {
let word_width = self.get_word_width(word, font_size);
if x + word_width > max_size.x {
y -= shift_sign * line_height;
line_widths.push((x, line_starting_index, positions_and_size.len()));
line_starting_index = positions_and_size.len();
x = 0.0;
}
for c in word.chars() {
if let Some(glyph) = self.sdf.glyphs.iter().find(|glyph| glyph.unicode == c) {
let plane_bounds = glyph.plane_bounds.as_ref();
let (left, top, width, _height) = match plane_bounds {
Some(val) => (
val.left,
val.top,
val.size().x * font_size,
val.size().y * font_size,
),
None => (0.0, 0.0, 0.0, 0.0),
};
last_width = width;
let position_x = x + left * font_size;
let position_y = y + (shift_sign * top * font_size);
positions_and_size.push(LayoutRect {
position: Vec2::new(position_x, position_y),
size: Vec2::new(resized_max_glyph_size.0, resized_max_glyph_size.1),
content: c,
});
x += glyph.advance * font_size;
}
}
if let Some(next_missing) = missing_chars.get(i) {
if let Some(glyph) = self
.sdf
.glyphs
.iter()
.find(|glyph| glyph.unicode == *next_missing)
{
x += glyph.advance * font_size;
}
i += 1;
}
}
x += glyph.advance * font_size;
line_widths.push((
x + last_width,
line_starting_index,
positions_and_size.len(),
));
for (line_width, starting_index, end_index) in line_widths {
let shift_x = match alignment {
Alignment::Start => 0.0,
Alignment::Middle => (max_size.x - line_width) / 2.0,
Alignment::End => max_size.x - line_width,
};
for i in starting_index..end_index {
let layout_rect = &mut positions_and_size[i];
layout_rect.position.x += position.x + shift_x;
layout_rect.position.y += position.y;
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment