use crate::color::Color;
use crate::device_scale::device_scale;
use crate::draw_ctx::DrawCtx;
use crate::event::{Event, EventResult};
use crate::geometry::{Rect, Size};
use crate::layout_props::{resolve_fit_or_stretch, HAnchor, Insets, VAnchor, WidgetBase};
use crate::widget::Widget;
pub struct Stack {
bounds: Rect,
children: Vec<Box<dyn Widget>>,
base: WidgetBase,
}
impl Stack {
pub fn new() -> Self {
Self {
bounds: Rect::default(),
children: Vec::new(),
base: WidgetBase::new(),
}
}
pub fn add(mut self, child: Box<dyn Widget>) -> Self {
self.children.push(child);
self
}
pub fn with_margin(mut self, m: Insets) -> Self {
self.base.margin = m;
self
}
pub fn with_h_anchor(mut self, h: HAnchor) -> Self {
self.base.h_anchor = h;
self
}
pub fn with_v_anchor(mut self, v: VAnchor) -> Self {
self.base.v_anchor = v;
self
}
pub fn with_min_size(mut self, s: Size) -> Self {
self.base.min_size = s;
self
}
pub fn with_max_size(mut self, s: Size) -> Self {
self.base.max_size = s;
self
}
}
impl Default for Stack {
fn default() -> Self {
Self::new()
}
}
impl Widget for Stack {
fn type_name(&self) -> &'static str {
"Stack"
}
fn bounds(&self) -> Rect {
self.bounds
}
fn set_bounds(&mut self, b: Rect) {
self.bounds = b;
}
fn children(&self) -> &[Box<dyn Widget>] {
&self.children
}
fn children_mut(&mut self) -> &mut Vec<Box<dyn Widget>> {
&mut self.children
}
fn margin(&self) -> Insets {
self.base.margin
}
fn widget_base(&self) -> Option<&WidgetBase> {
Some(&self.base)
}
fn widget_base_mut(&mut self) -> Option<&mut WidgetBase> {
Some(&mut self.base)
}
fn h_anchor(&self) -> HAnchor {
self.base.h_anchor
}
fn v_anchor(&self) -> VAnchor {
self.base.v_anchor
}
fn min_size(&self) -> Size {
self.base.min_size
}
fn max_size(&self) -> Size {
self.base.max_size
}
fn layout(&mut self, available: Size) -> Size {
for child in &mut self.children {
child.layout(available);
child.set_bounds(Rect::new(0.0, 0.0, available.width, available.height));
}
let mut i = 0;
let mut raised: Vec<Box<dyn Widget>> = Vec::new();
while i < self.children.len() {
if self.children[i].take_raise_request() {
raised.push(self.children.remove(i));
} else {
i += 1;
}
}
for r in raised {
self.children.push(r);
}
available
}
fn paint(&mut self, _ctx: &mut dyn DrawCtx) {}
fn on_event(&mut self, _: &Event) -> EventResult {
EventResult::Ignored
}
}
pub struct Padding {
bounds: Rect,
children: Vec<Box<dyn Widget>>,
base: WidgetBase,
insets: Insets,
}
impl Padding {
pub fn new(insets: Insets, child: Box<dyn Widget>) -> Self {
Self {
bounds: Rect::default(),
children: vec![child],
base: WidgetBase::new(),
insets,
}
}
pub fn uniform(amount: f64, child: Box<dyn Widget>) -> Self {
Self::new(Insets::all(amount), child)
}
pub fn with_margin(mut self, m: Insets) -> Self {
self.base.margin = m;
self
}
pub fn with_h_anchor(mut self, h: HAnchor) -> Self {
self.base.h_anchor = h;
self
}
pub fn with_v_anchor(mut self, v: VAnchor) -> Self {
self.base.v_anchor = v;
self
}
pub fn with_min_size(mut self, s: Size) -> Self {
self.base.min_size = s;
self
}
pub fn with_max_size(mut self, s: Size) -> Self {
self.base.max_size = s;
self
}
}
impl Widget for Padding {
fn type_name(&self) -> &'static str {
"Padding"
}
fn bounds(&self) -> Rect {
self.bounds
}
fn set_bounds(&mut self, b: Rect) {
self.bounds = b;
}
fn children(&self) -> &[Box<dyn Widget>] {
&self.children
}
fn children_mut(&mut self) -> &mut Vec<Box<dyn Widget>> {
&mut self.children
}
fn margin(&self) -> Insets {
self.base.margin
}
fn widget_base(&self) -> Option<&WidgetBase> {
Some(&self.base)
}
fn widget_base_mut(&mut self) -> Option<&mut WidgetBase> {
Some(&mut self.base)
}
fn h_anchor(&self) -> HAnchor {
self.base.h_anchor
}
fn v_anchor(&self) -> VAnchor {
self.base.v_anchor
}
fn min_size(&self) -> Size {
self.base.min_size
}
fn max_size(&self) -> Size {
self.base.max_size
}
fn layout(&mut self, available: Size) -> Size {
let p = &self.insets;
let inner = Size::new(
(available.width - p.left - p.right).max(0.0),
(available.height - p.top - p.bottom).max(0.0),
);
if let Some(child) = self.children.first_mut() {
let desired = child.layout(inner);
child.set_bounds(Rect::new(p.left, p.bottom, desired.width, desired.height));
}
let content_w = self.children.first().map_or(0.0, |c| c.bounds().width);
let content_h = self.children.first().map_or(0.0, |c| c.bounds().height);
Size::new(content_w + p.left + p.right, content_h + p.top + p.bottom)
}
fn paint(&mut self, _ctx: &mut dyn DrawCtx) {}
fn on_event(&mut self, _: &Event) -> EventResult {
EventResult::Ignored
}
}
pub struct SizedBox {
bounds: Rect,
children: Vec<Box<dyn Widget>>,
base: WidgetBase,
pub width: Option<f64>,
pub height: Option<f64>,
}
impl SizedBox {
pub fn new() -> Self {
Self {
bounds: Rect::default(),
children: Vec::new(),
base: WidgetBase::new(),
width: None,
height: None,
}
}
pub fn with_width(mut self, w: f64) -> Self {
self.width = Some(w);
self
}
pub fn with_height(mut self, h: f64) -> Self {
self.height = Some(h);
self
}
pub fn with_child(mut self, child: Box<dyn Widget>) -> Self {
self.children.clear();
self.children.push(child);
self
}
pub fn fixed(width: f64, height: f64) -> Self {
Self::new().with_width(width).with_height(height)
}
pub fn with_margin(mut self, m: Insets) -> Self {
self.base.margin = m;
self
}
pub fn with_h_anchor(mut self, h: HAnchor) -> Self {
self.base.h_anchor = h;
self
}
pub fn with_v_anchor(mut self, v: VAnchor) -> Self {
self.base.v_anchor = v;
self
}
pub fn with_min_size(mut self, s: Size) -> Self {
self.base.min_size = s;
self
}
pub fn with_max_size(mut self, s: Size) -> Self {
self.base.max_size = s;
self
}
}
impl Default for SizedBox {
fn default() -> Self {
Self::new()
}
}
impl Widget for SizedBox {
fn type_name(&self) -> &'static str {
"SizedBox"
}
fn bounds(&self) -> Rect {
self.bounds
}
fn set_bounds(&mut self, b: Rect) {
self.bounds = b;
}
fn children(&self) -> &[Box<dyn Widget>] {
&self.children
}
fn children_mut(&mut self) -> &mut Vec<Box<dyn Widget>> {
&mut self.children
}
fn margin(&self) -> Insets {
self.base.margin
}
fn widget_base(&self) -> Option<&WidgetBase> {
Some(&self.base)
}
fn widget_base_mut(&mut self) -> Option<&mut WidgetBase> {
Some(&mut self.base)
}
fn h_anchor(&self) -> HAnchor {
self.base.h_anchor
}
fn v_anchor(&self) -> VAnchor {
self.base.v_anchor
}
fn min_size(&self) -> Size {
self.base.min_size
}
fn max_size(&self) -> Size {
self.base.max_size
}
fn layout(&mut self, available: Size) -> Size {
let w = self.width.unwrap_or(available.width);
let mut h = self.height.unwrap_or_else(|| {
if self.children.is_empty() {
0.0
} else {
available.height
}
});
if let Some(child) = self.children.first_mut() {
let scale = device_scale();
let m = child.margin().scale(scale);
let slot_w = (w - m.left - m.right).max(0.0);
let slot_h = (h - m.top - m.bottom).max(0.0);
let desired = child.layout(Size::new(slot_w, slot_h));
if self.height.is_none() {
h = (desired.height + m.vertical())
.clamp(self.base.min_size.height, self.base.max_size.height);
}
let h_anchor = child.h_anchor();
let min_w = child.min_size().width;
let max_w = child.max_size().width;
let child_w = if h_anchor.is_stretch() {
slot_w.clamp(min_w, max_w)
} else if h_anchor == HAnchor::MAX_FIT_OR_STRETCH {
resolve_fit_or_stretch(desired.width, slot_w, true).clamp(min_w, max_w)
} else if h_anchor == HAnchor::MIN_FIT_OR_STRETCH {
resolve_fit_or_stretch(desired.width, slot_w, false).clamp(min_w, max_w)
} else {
desired.width.clamp(min_w, max_w)
};
let child_x = if h_anchor.contains(HAnchor::RIGHT) && !h_anchor.contains(HAnchor::LEFT)
{
(w - m.right - child_w).max(0.0)
} else if h_anchor.contains(HAnchor::CENTER) && !h_anchor.is_stretch() {
m.left + (slot_w - child_w) * 0.5
} else {
m.left
};
let v_anchor = child.v_anchor();
let min_h = child.min_size().height;
let max_h = child.max_size().height;
let child_h = if v_anchor.is_stretch() {
slot_h.clamp(min_h, max_h)
} else if v_anchor == VAnchor::MAX_FIT_OR_STRETCH {
resolve_fit_or_stretch(desired.height, slot_h, true).clamp(min_h, max_h)
} else if v_anchor == VAnchor::MIN_FIT_OR_STRETCH {
resolve_fit_or_stretch(desired.height, slot_h, false).clamp(min_h, max_h)
} else {
desired.height.clamp(min_h, max_h)
};
let child_w = if self.width.is_some() {
child_w.min(slot_w)
} else {
child_w
};
let child_h = if self.height.is_some() {
child_h.min(slot_h)
} else {
child_h
};
let child_y = if v_anchor.contains(VAnchor::TOP) && !v_anchor.contains(VAnchor::BOTTOM)
{
(h - m.top - child_h).max(0.0)
} else if v_anchor.contains(VAnchor::CENTER) && !v_anchor.is_stretch() {
m.bottom + (slot_h - child_h) * 0.5
} else {
m.bottom
};
child.set_bounds(Rect::new(child_x, child_y, child_w, child_h));
}
Size::new(w, h)
}
fn paint(&mut self, _ctx: &mut dyn DrawCtx) {}
fn on_event(&mut self, _: &Event) -> EventResult {
EventResult::Ignored
}
}
pub struct Spacer {
bounds: Rect,
children: Vec<Box<dyn Widget>>,
base: WidgetBase,
}
impl Spacer {
pub fn new() -> Self {
Self {
bounds: Rect::default(),
children: Vec::new(),
base: WidgetBase::new(),
}
}
pub fn with_margin(mut self, m: Insets) -> Self {
self.base.margin = m;
self
}
pub fn with_h_anchor(mut self, h: HAnchor) -> Self {
self.base.h_anchor = h;
self
}
pub fn with_v_anchor(mut self, v: VAnchor) -> Self {
self.base.v_anchor = v;
self
}
pub fn with_min_size(mut self, s: Size) -> Self {
self.base.min_size = s;
self
}
pub fn with_max_size(mut self, s: Size) -> Self {
self.base.max_size = s;
self
}
}
impl Default for Spacer {
fn default() -> Self {
Self::new()
}
}
impl Widget for Spacer {
fn type_name(&self) -> &'static str {
"Spacer"
}
fn bounds(&self) -> Rect {
self.bounds
}
fn set_bounds(&mut self, b: Rect) {
self.bounds = b;
}
fn children(&self) -> &[Box<dyn Widget>] {
&self.children
}
fn children_mut(&mut self) -> &mut Vec<Box<dyn Widget>> {
&mut self.children
}
fn margin(&self) -> Insets {
self.base.margin
}
fn widget_base(&self) -> Option<&WidgetBase> {
Some(&self.base)
}
fn widget_base_mut(&mut self) -> Option<&mut WidgetBase> {
Some(&mut self.base)
}
fn h_anchor(&self) -> HAnchor {
self.base.h_anchor
}
fn v_anchor(&self) -> VAnchor {
self.base.v_anchor
}
fn min_size(&self) -> Size {
self.base.min_size
}
fn max_size(&self) -> Size {
self.base.max_size
}
fn layout(&mut self, available: Size) -> Size {
available
}
fn paint(&mut self, _ctx: &mut dyn DrawCtx) {}
fn on_event(&mut self, _: &Event) -> EventResult {
EventResult::Ignored
}
}
pub struct Separator {
bounds: Rect,
children: Vec<Box<dyn Widget>>,
base: WidgetBase,
vertical: bool,
line_inset: f64,
color: Option<Color>,
}
impl Separator {
pub fn horizontal() -> Self {
Self {
bounds: Rect::default(),
children: Vec::new(),
base: WidgetBase::new(),
vertical: false,
line_inset: 4.0,
color: None,
}
}
pub fn vertical() -> Self {
Self {
vertical: true,
..Self::horizontal()
}
}
pub fn with_line_inset(mut self, m: f64) -> Self {
self.line_inset = m;
self
}
pub fn with_color(mut self, c: Color) -> Self {
self.color = Some(c);
self
}
pub fn with_margin(mut self, m: Insets) -> Self {
self.base.margin = m;
self
}
pub fn with_h_anchor(mut self, h: HAnchor) -> Self {
self.base.h_anchor = h;
self
}
pub fn with_v_anchor(mut self, v: VAnchor) -> Self {
self.base.v_anchor = v;
self
}
pub fn with_min_size(mut self, s: Size) -> Self {
self.base.min_size = s;
self
}
pub fn with_max_size(mut self, s: Size) -> Self {
self.base.max_size = s;
self
}
}
impl Widget for Separator {
fn type_name(&self) -> &'static str {
"Separator"
}
fn bounds(&self) -> Rect {
self.bounds
}
fn set_bounds(&mut self, b: Rect) {
self.bounds = b;
}
fn children(&self) -> &[Box<dyn Widget>] {
&self.children
}
fn children_mut(&mut self) -> &mut Vec<Box<dyn Widget>> {
&mut self.children
}
fn margin(&self) -> Insets {
self.base.margin
}
fn widget_base(&self) -> Option<&WidgetBase> {
Some(&self.base)
}
fn widget_base_mut(&mut self) -> Option<&mut WidgetBase> {
Some(&mut self.base)
}
fn h_anchor(&self) -> HAnchor {
self.base.h_anchor
}
fn v_anchor(&self) -> VAnchor {
self.base.v_anchor
}
fn min_size(&self) -> Size {
self.base.min_size
}
fn max_size(&self) -> Size {
self.base.max_size
}
fn layout(&mut self, available: Size) -> Size {
if self.vertical {
Size::new(1.0 + self.line_inset * 2.0, available.height)
} else {
Size::new(available.width, 1.0 + self.line_inset * 2.0)
}
}
fn paint(&mut self, ctx: &mut dyn DrawCtx) {
let w = self.bounds.width;
let h = self.bounds.height;
let color = self.color.unwrap_or_else(|| ctx.visuals().separator);
ctx.set_fill_color(color);
ctx.begin_path();
if self.vertical {
ctx.rect(self.line_inset, 0.0, 1.0, h);
} else {
ctx.rect(0.0, self.line_inset, w, 1.0);
}
ctx.fill();
}
fn on_event(&mut self, _: &Event) -> EventResult {
EventResult::Ignored
}
}