use std::str;
use bevy::math::{Rect, Vec2};
use bevy::prelude::*;
use bevy::sprite::Anchor;
use bevy::text::TextLayoutInfo;
use crate::{
canvas::{Canvas, LinePrimitive, RectPrimitive, TextPrimitive},
shapes::Shape,
ShapeRef,
};
#[derive(Debug, Clone)]
pub struct Brush {
color: Color,
}
impl Default for Brush {
fn default() -> Self {
Self {
color: Color::BLACK,
}
}
}
impl From<Color> for Brush {
fn from(color: Color) -> Self {
Self { color }
}
}
impl From<&Color> for Brush {
fn from(color: &Color) -> Self {
Self { color: *color }
}
}
impl Brush {
pub fn color(&self) -> Color {
self.color.clone()
}
}
pub trait TextStorage: 'static {
fn as_str(&self) -> &str;
}
impl TextStorage for String {
fn as_str(&self) -> &str {
&self[..]
}
}
impl TextStorage for &'static str {
fn as_str(&self) -> &str {
self
}
}
#[derive(Debug, Clone)]
pub struct TextLayout {
pub(crate) id: u32,
pub(crate) sections: Vec<TextSection>,
pub(crate) anchor: Anchor,
pub(crate) justify: JustifyText,
pub(crate) bounds: Vec2,
pub(crate) calculated_size: Vec2,
pub(crate) layout_info: Option<TextLayoutInfo>,
}
impl Default for TextLayout {
fn default() -> Self {
Self {
id: 0,
sections: vec![],
anchor: Anchor::default(),
justify: JustifyText::Left,
bounds: Vec2::ZERO,
calculated_size: Vec2::ZERO,
layout_info: None,
}
}
}
pub struct TextLayoutBuilder<'c> {
canvas: &'c mut Canvas,
style: TextStyle,
value: String,
bounds: Vec2,
anchor: Anchor,
alignment: JustifyText,
}
impl<'c> TextLayoutBuilder<'c> {
fn new(canvas: &'c mut Canvas, storage: impl TextStorage) -> Self {
Self {
canvas,
style: TextStyle::default(),
value: storage.as_str().to_owned(),
bounds: Vec2::new(f32::MAX, f32::MAX),
anchor: Anchor::default(),
alignment: JustifyText::Left, }
}
pub fn font(mut self, font: Handle<Font>) -> Self {
self.style.font = font;
self
}
pub fn font_size(mut self, font_size: f32) -> Self {
self.style.font_size = font_size;
self
}
pub fn color(mut self, color: Color) -> Self {
self.style.color = color;
self
}
pub fn bounds(mut self, bounds: Vec2) -> Self {
self.bounds = bounds;
self
}
pub fn anchor(mut self, anchor: Anchor) -> Self {
self.anchor = anchor;
self
}
pub fn alignment(mut self, alignment: JustifyText) -> Self {
self.alignment = alignment;
self
}
pub fn build(self) -> u32 {
let layout = TextLayout {
id: 0, sections: vec![TextSection {
style: self.style,
value: self.value,
}],
anchor: self.anchor,
justify: self.alignment,
bounds: self.bounds,
calculated_size: Vec2::ZERO, layout_info: None,
};
self.canvas.finish_layout(layout)
}
}
#[derive(Debug, Clone, Copy)]
pub enum ImageScaling {
Uniform(f32),
FitWidth(bool),
FitHeight(bool),
Fit(bool),
Stretch,
}
impl Default for ImageScaling {
fn default() -> Self {
Self::Uniform(1.0)
}
}
pub struct RenderContext<'c> {
canvas: &'c mut Canvas,
}
impl<'c> RenderContext<'c> {
pub fn new(canvas: &'c mut Canvas) -> Self {
Self {
canvas,
}
}
pub fn solid_brush(&mut self, color: Color) -> Brush {
color.into()
}
pub fn clear(&mut self, region: Option<Rect>, color: Color) {
if let Some(rect) = region {
self.fill(rect, &Brush { color });
} else {
self.canvas.clear();
self.fill(self.canvas.rect(), &Brush { color });
}
}
pub fn fill(&mut self, shape: impl Shape, brush: &Brush) -> ShapeRef {
shape.fill(self.canvas, brush)
}
pub fn line(&mut self, p0: Vec2, p1: Vec2, brush: &Brush, thickness: f32) -> ShapeRef {
self.canvas.draw(LinePrimitive {
start: p0,
end: p1,
color: brush.color(),
thickness,
..default()
})
}
pub fn new_layout(&mut self, text: impl TextStorage) -> TextLayoutBuilder {
TextLayoutBuilder::new(self.canvas, text)
}
pub fn draw_text(&mut self, text_id: u32, pos: Vec2) {
self.canvas.draw(TextPrimitive {
id: text_id,
rect: Rect { min: pos, max: pos },
});
}
pub fn draw_image(&mut self, shape: Rect, image: Handle<Image>, scaling: ImageScaling) {
self.canvas.draw(RectPrimitive {
rect: shape,
color: Color::WHITE,
image: Some(image.id()),
image_scaling: scaling,
..Default::default()
});
}
}
impl<'c> Drop for RenderContext<'c> {
fn drop(&mut self) {
self.canvas.finish();
}
}