canary-rs/crates/sao-ui-rs/src/widgets/text.rs

130 lines
3.3 KiB
Rust

// Copyright (c) 2022 Marceline Cramer
// SPDX-License-Identifier: AGPL-3.0-or-later
use super::prelude::*;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum HorizontalAlignment {
Left,
Center,
Right,
}
pub struct LabelText {
pub font: Font,
pub text: String,
}
pub struct Label {
text: LabelText,
alignment: HorizontalAlignment,
scale: f32,
color: Color,
left: f32,
right: f32,
baseline: f32,
dirty: bool,
layout: Option<TextLayout>,
bounds: Rect,
offset: Vec2,
}
impl Label {
pub fn new(
text: LabelText,
alignment: HorizontalAlignment,
scale: f32,
color: Color,
left: f32,
right: f32,
baseline: f32,
) -> Self {
Self {
text,
alignment,
scale,
color,
left,
right,
baseline,
dirty: true,
layout: None,
bounds: Rect::from_xy_size(Vec2::ZERO, Vec2::ZERO),
offset: Vec2::ZERO,
}
}
}
impl Widget for Label {
fn draw(&mut self, ctx: &DrawContext) {
if self.dirty {
let layout = TextLayout::new(&self.text.font, &self.text.text);
let bounds = Rect::from(layout.get_bounds()).scale(self.scale);
self.bounds = bounds;
let xoff = match self.alignment {
HorizontalAlignment::Left => self.left - bounds.bl.x,
HorizontalAlignment::Right => self.right - bounds.tr.x,
HorizontalAlignment::Center => {
let available = self.right - self.left;
let halfway = available / 2.0 + self.left;
let width = bounds.tr.x - bounds.bl.x;
let left = halfway - width / 2.0;
left - bounds.bl.x
}
};
self.offset = Vec2::new(xoff, self.baseline);
self.dirty = false;
self.layout = Some(layout);
}
if let Some(layout) = self.layout.as_ref() {
ctx.draw_text_layout(layout, self.offset, self.scale, self.color);
}
}
}
pub struct Icon {
text: LabelText,
scale: f32,
color: Color,
center: Vec2,
dirty: bool,
layout: Option<TextLayout>,
bounds: Rect,
offset: Vec2,
}
impl Icon {
pub fn new(text: LabelText, scale: f32, color: Color, center: Vec2) -> Self {
Self {
text,
scale,
color,
center,
dirty: true,
layout: None,
bounds: Rect::from_xy_size(Vec2::ZERO, Vec2::ZERO),
offset: Vec2::ZERO,
}
}
}
impl Widget for Icon {
fn draw(&mut self, ctx: &DrawContext) {
if self.dirty {
let layout = TextLayout::new(&self.text.font, &self.text.text);
let bounds = Rect::from(layout.get_bounds()).scale(self.scale);
self.bounds = bounds;
self.offset = self.center - bounds.size() / 2.0;
self.offset.y -= bounds.bl.y;
self.dirty = false;
self.layout = Some(layout);
}
if let Some(layout) = self.layout.as_ref() {
ctx.draw_text_layout(layout, self.offset, self.scale, self.color);
}
}
}