158 lines
3.9 KiB
Rust
158 lines
3.9 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,
|
|
}
|
|
}
|
|
|
|
pub fn new_centered(text: LabelText, scale: f32, color: Color) -> Self {
|
|
Self::new(
|
|
text,
|
|
HorizontalAlignment::Center,
|
|
scale,
|
|
color,
|
|
0.0,
|
|
0.0,
|
|
0.0,
|
|
)
|
|
}
|
|
|
|
pub fn set_text(&mut self, text: &str) {
|
|
if self.text.text != text {
|
|
self.text.text = text.to_string();
|
|
self.layout = None;
|
|
self.dirty = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
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.tl.x,
|
|
HorizontalAlignment::Right => self.right - bounds.br.x,
|
|
HorizontalAlignment::Center => {
|
|
let available = self.right - self.left;
|
|
let halfway = available / 2.0 + self.left;
|
|
let width = bounds.br.x - bounds.tl.x;
|
|
let left = halfway - width / 2.0;
|
|
left - bounds.tl.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,
|
|
}
|
|
}
|
|
|
|
pub fn set_text(&mut self, text: &str) {
|
|
if self.text.text != text {
|
|
self.text.text = text.to_string();
|
|
self.layout = None;
|
|
self.dirty = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
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.tl.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);
|
|
}
|
|
}
|
|
}
|