#![allow(clippy::new_without_default)] use crate::{layout::Direction, *}; mod slider; pub mod text_edit; pub use {paint::*, slider::*, text_edit::*}; // ---------------------------------------------------------------------------- /// Anything implementing Widget can be added to a Ui with `Ui::add` pub trait Widget { fn ui(self, ui: &mut Ui) -> InteractInfo; } // ---------------------------------------------------------------------------- pub struct Label { // TODO: not pub pub(crate) text: String, pub(crate) multiline: bool, auto_shrink: bool, pub(crate) text_style: TextStyle, // TODO: Option, where None means "use the default for the ui" pub(crate) text_color: Option, } impl Label { pub fn new(text: impl Into) -> Self { Self { text: text.into(), multiline: true, auto_shrink: false, text_style: TextStyle::Body, text_color: None, } } pub fn text(&self) -> &str { &self.text } pub fn multiline(mut self, multiline: bool) -> Self { self.multiline = multiline; self } /// If true, will word wrap to `ui.available_finite().width()`. /// If false (default), will word wrap to `ui.available().width()`. /// This only makes a difference for auto-sized parents. pub fn auto_shrink(mut self) -> Self { self.auto_shrink = true; self } pub fn text_style(mut self, text_style: TextStyle) -> Self { self.text_style = text_style; self } pub fn text_color(mut self, text_color: Color) -> Self { self.text_color = Some(text_color); self } pub fn layout(&self, ui: &Ui) -> font::Galley { let max_width = if self.auto_shrink { ui.available_finite().width() } else { ui.available().width() }; self.layout_width(ui, max_width) } pub fn layout_width(&self, ui: &Ui, max_width: f32) -> font::Galley { let font = &ui.fonts()[self.text_style]; if self.multiline { font.layout_multiline(self.text.clone(), max_width) // TODO: avoid clone } else { font.layout_single_line(self.text.clone()) // TODO: avoid clone } } pub fn font_height(&self, ui: &Ui) -> f32 { ui.fonts()[self.text_style].height() } // TODO: this should return a LabelLayout which has a paint method. // We can then split Widget::Ui in two: layout + allocating space, and painting. // this allows us to assemble lables, THEN detect interaction, THEN chose color style based on that. // pub fn layout(self, ui: &mut ui) -> LabelLayout { } // TODO: a paint method for painting anywhere in a ui. // This should be the easiest method of putting text anywhere. pub fn paint_galley(&self, ui: &mut Ui, pos: Pos2, galley: font::Galley) { ui.add_galley(pos, galley, self.text_style, self.text_color); } } /// Usage: label!("Foo: {}", bar) #[macro_export] macro_rules! label { ($fmt:expr) => ($crate::widgets::Label::new($fmt)); ($fmt:expr, $($arg:tt)*) => ($crate::widgets::Label::new(format!($fmt, $($arg)*))); } impl Widget for Label { fn ui(self, ui: &mut Ui) -> InteractInfo { let galley = self.layout(ui); let rect = ui.allocate_space(galley.size); self.paint_galley(ui, rect.min, galley); ui.interact_hover(rect) } } impl Into