use peniko::Color;
use crate::events::KeyInput;
use crate::style::{Length, Paint, Style, TextAlign, TextWrap, ThemedFn, Transition};
use crate::theme::Theme;
use crate::tokens::{ShadowToken, TextSize, Weight};
pub(crate) type TypeAheadFn<Msg> = Box<dyn Fn(&str) -> Option<Msg>>;
pub(crate) type KeyFn<Msg> = Box<dyn Fn(&KeyInput) -> Option<Msg>>;
pub(crate) type DragFn<Msg> = Box<dyn Fn(f32, f32) -> Option<Msg>>;
pub(crate) type InputFn<Msg> = Box<dyn Fn(&str) -> Msg>;
pub(crate) type FileDropFn<Msg> = Box<dyn Fn(&std::path::Path) -> Msg>;
pub(crate) type DropFn<Msg> = Box<dyn Fn(&str) -> Option<Msg>>;
pub(crate) type ContentFn = Box<dyn Fn(&Theme) -> Color>;
#[derive(Debug, Clone, PartialEq)]
pub enum Kind {
Box,
Text(String),
Rich(Vec<Span>),
Divider,
Path(PathData),
Input(InputData),
Image(ImageData),
}
pub struct VirtualData<Msg> {
pub(crate) count: usize,
pub(crate) row_height: f32,
pub(crate) variable: bool,
pub(crate) builder: std::rc::Rc<dyn Fn(usize) -> Element<Msg>>,
}
impl<Msg> Clone for VirtualData<Msg> {
fn clone(&self) -> Self {
Self {
count: self.count,
row_height: self.row_height,
variable: self.variable,
builder: std::rc::Rc::clone(&self.builder),
}
}
}
#[derive(Debug, Clone)]
pub struct ImageData {
pub image: peniko::ImageData,
}
impl PartialEq for ImageData {
fn eq(&self, other: &Self) -> bool {
self.image.data.id() == other.image.data.id()
&& self.image.width == other.image.width
&& self.image.height == other.image.height
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InputData {
pub value: String,
pub placeholder: String,
pub multiline: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct PathData {
pub path: std::sync::Arc<kurbo::BezPath>,
pub viewbox: (f64, f64),
pub stroke: Option<f64>,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum OverlayMode {
Open,
Toggle,
Hover {
delay_ms: f32,
},
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum OverlayPlacement {
Below {
gap: f32,
},
BelowCenter {
gap: f32,
},
Center,
TopRight {
margin: f32,
},
Pointer {
gap: f32,
},
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Overlay {
pub mode: OverlayMode,
pub placement: OverlayPlacement,
pub backdrop: bool,
pub trap_focus: bool,
}
impl Overlay {
pub fn menu() -> Self {
Self {
mode: OverlayMode::Toggle,
placement: OverlayPlacement::Below { gap: 4.0 },
backdrop: false,
trap_focus: false,
}
}
pub fn tooltip() -> Self {
Self {
mode: OverlayMode::Hover { delay_ms: 400.0 },
placement: OverlayPlacement::BelowCenter { gap: 6.0 },
backdrop: false,
trap_focus: false,
}
}
pub fn modal() -> Self {
Self {
mode: OverlayMode::Open,
placement: OverlayPlacement::Center,
backdrop: true,
trap_focus: true,
}
}
pub fn context() -> Self {
Self {
mode: OverlayMode::Open,
placement: OverlayPlacement::Pointer { gap: 2.0 },
backdrop: false,
trap_focus: false,
}
}
pub fn toasts() -> Self {
Self {
mode: OverlayMode::Open,
placement: OverlayPlacement::TopRight { margin: 16.0 },
backdrop: false,
trap_focus: false,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Semantics {
Button,
Checkbox {
checked: bool,
},
Switch {
on: bool,
},
Radio {
selected: bool,
},
Slider {
value: f32,
min: f32,
max: f32,
},
TextInput {
multiline: bool,
},
ComboBox,
Dialog,
Tab {
selected: bool,
},
Alert,
Label,
Image,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Span {
pub(crate) text: String,
pub(crate) weight: Option<crate::tokens::Weight>,
pub(crate) color: Option<Color>,
pub(crate) size_px: Option<f32>,
pub(crate) family: Option<crate::tokens::FamilyRole>,
pub(crate) italic: bool,
}
pub fn span(text: impl Into<String>) -> Span {
Span {
text: text.into(),
weight: None,
color: None,
size_px: None,
family: None,
italic: false,
}
}
impl Span {
pub fn weight(mut self, weight: crate::tokens::Weight) -> Self {
self.weight = Some(weight);
self
}
pub fn color(mut self, color: Color) -> Self {
self.color = Some(color);
self
}
pub fn size_px(mut self, px: f32) -> Self {
self.size_px = Some(px);
self
}
pub fn family(mut self, family: crate::tokens::FamilyRole) -> Self {
self.family = Some(family);
self
}
pub fn italic(mut self) -> Self {
self.italic = true;
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Cursor {
Default,
Pointer,
Text,
NotAllowed,
}
pub struct Element<Msg> {
pub(crate) kind: Kind,
pub(crate) style: Style,
pub(crate) children: Vec<Element<Msg>>,
pub(crate) key: Option<String>,
pub(crate) source: &'static std::panic::Location<'static>,
pub(crate) stack: bool,
pub(crate) focusable: bool,
pub(crate) autofocus: bool,
pub(crate) stick_bottom: bool,
pub(crate) cursor: Option<Cursor>,
pub(crate) disabled: bool,
pub(crate) on_click: Option<Msg>,
pub(crate) on_double_click: Option<Msg>,
pub(crate) on_right_click: Option<Msg>,
pub(crate) on_hover: Option<Msg>,
pub(crate) on_key: Option<KeyFn<Msg>>,
pub(crate) on_drag: Option<DragFn<Msg>>,
pub(crate) on_input: Option<InputFn<Msg>>,
pub(crate) on_close: Option<Msg>,
pub(crate) on_file_drop: Option<FileDropFn<Msg>>,
pub(crate) drag_source: Option<String>,
pub(crate) on_drop: Option<DropFn<Msg>>,
pub(crate) overlay: Option<Overlay>,
pub(crate) spin: Option<f32>,
pub(crate) keyframes: Option<crate::style::Keyframes>,
pub(crate) virtual_rows: Option<VirtualData<Msg>>,
pub(crate) semantics: Option<Semantics>,
pub(crate) live: bool,
pub(crate) selectable: bool,
pub(crate) enter: Option<crate::style::Transition>,
pub(crate) on_type_ahead: Option<TypeAheadFn<Msg>>,
pub(crate) label: Option<String>,
pub(crate) themed: Option<ThemedFn>,
pub(crate) hover_style: Option<ThemedFn>,
pub(crate) active_style: Option<ThemedFn>,
pub(crate) focus_style: Option<ThemedFn>,
pub(crate) state_layer: Option<ContentFn>,
pub(crate) press_scale: bool,
pub(crate) invalid: bool,
pub(crate) transition: Option<Transition>,
}
impl<Msg> Element<Msg> {
#[track_caller]
fn new(kind: Kind) -> Self {
Self {
kind,
style: Style::default(),
children: Vec::new(),
key: None,
source: std::panic::Location::caller(),
stack: false,
focusable: false,
autofocus: false,
stick_bottom: false,
cursor: None,
disabled: false,
on_click: None,
on_double_click: None,
on_right_click: None,
on_hover: None,
on_key: None,
on_drag: None,
on_input: None,
on_close: None,
on_file_drop: None,
drag_source: None,
on_drop: None,
overlay: None,
spin: None,
keyframes: None,
virtual_rows: None,
semantics: None,
live: false,
selectable: false,
enter: None,
on_type_ahead: None,
label: None,
themed: None,
hover_style: None,
active_style: None,
focus_style: None,
state_layer: None,
press_scale: false,
invalid: false,
transition: None,
}
}
pub fn style(&self) -> &Style {
&self.style
}
pub fn children<M>(mut self, children: impl crate::IntoChildren<Msg, M>) -> Self {
self.children.extend(children.into_children());
self
}
pub fn child(mut self, child: impl Into<Element<Msg>>) -> Self {
self.children.push(child.into());
self
}
pub fn id(mut self, key: &str) -> Self {
self.key = Some(key.to_owned());
self
}
pub fn on_click(mut self, msg: Msg) -> Self {
self.on_click = Some(msg);
self.focusable = true;
if self.cursor.is_none() {
self.cursor = Some(Cursor::Pointer);
}
self
}
pub fn hover(mut self, f: impl Fn(Style) -> Style + 'static) -> Self {
self.hover_style = Some(Box::new(move |_, s| f(s)));
self
}
pub fn hover_themed(mut self, f: impl Fn(&Theme, Style) -> Style + 'static) -> Self {
self.hover_style = Some(Box::new(f));
self
}
pub fn active(mut self, f: impl Fn(Style) -> Style + 'static) -> Self {
self.active_style = Some(Box::new(move |_, s| f(s)));
self
}
pub fn active_themed(mut self, f: impl Fn(&Theme, Style) -> Style + 'static) -> Self {
self.active_style = Some(Box::new(f));
self
}
pub fn focus(mut self, f: impl Fn(Style) -> Style + 'static) -> Self {
self.focus_style = Some(Box::new(move |_, s| f(s)));
self
}
pub fn focus_themed(mut self, f: impl Fn(&Theme, Style) -> Style + 'static) -> Self {
self.focus_style = Some(Box::new(f));
self
}
pub fn state_layer(mut self, content: impl Fn(&Theme) -> Color + 'static) -> Self {
self.state_layer = Some(Box::new(content));
self
}
pub fn press_scale(mut self) -> Self {
self.press_scale = true;
self
}
pub fn invalid(mut self, invalid: bool) -> Self {
self.invalid = invalid;
self
}
pub fn themed(mut self, f: impl Fn(&Theme, Style) -> Style + 'static) -> Self {
self.themed = Some(match self.themed.take() {
Some(prev) => Box::new(move |t, s| f(t, prev(t, s))),
None => Box::new(f),
});
self
}
pub fn on_double_click(mut self, msg: Msg) -> Self {
self.on_double_click = Some(msg);
self
}
pub fn on_right_click(mut self, msg: Msg) -> Self {
self.on_right_click = Some(msg);
self
}
pub fn on_hover(mut self, msg: Msg) -> Self {
self.on_hover = Some(msg);
self
}
pub fn on_key(mut self, f: impl Fn(&KeyInput) -> Option<Msg> + 'static) -> Self {
self.on_key = Some(Box::new(f));
self.focusable = true;
self
}
pub fn on_drag(mut self, f: impl Fn(f32, f32) -> Option<Msg> + 'static) -> Self {
self.on_drag = Some(Box::new(f));
self
}
pub fn on_input(mut self, f: impl Fn(&str) -> Msg + 'static) -> Self {
self.on_input = Some(Box::new(f));
self
}
pub fn on_file_drop(mut self, f: impl Fn(&std::path::Path) -> Msg + 'static) -> Self {
self.on_file_drop = Some(Box::new(f));
self
}
pub fn drag_source(mut self, payload: impl Into<String>) -> Self {
self.drag_source = Some(payload.into());
self
}
pub fn on_drop(mut self, f: impl Fn(&str) -> Option<Msg> + 'static) -> Self {
self.on_drop = Some(Box::new(f));
self
}
pub fn overlay(mut self, overlay: Overlay) -> Self {
self.overlay = Some(overlay);
self
}
pub fn on_close(mut self, msg: Msg) -> Self {
self.on_close = Some(msg);
self
}
pub fn spin(mut self, period_ms: f32) -> Self {
self.spin = Some(period_ms);
self
}
pub fn keyframes(mut self, keyframes: crate::style::Keyframes) -> Self {
self.keyframes = Some(keyframes);
self
}
pub fn virtual_rows(
mut self,
count: usize,
row_height: f32,
builder: impl Fn(usize) -> Element<Msg> + 'static,
) -> Self {
self.virtual_rows = Some(VirtualData {
count,
row_height,
variable: false,
builder: std::rc::Rc::new(builder),
});
self
}
pub fn virtual_rows_variable(
mut self,
count: usize,
estimated_height: f32,
builder: impl Fn(usize) -> Element<Msg> + 'static,
) -> Self {
self.virtual_rows = Some(VirtualData {
count,
row_height: estimated_height,
variable: true,
builder: std::rc::Rc::new(builder),
});
self
}
pub fn on_type_ahead(mut self, f: impl Fn(&str) -> Option<Msg> + 'static) -> Self {
self.on_type_ahead = Some(Box::new(f));
self
}
pub fn enter(mut self, transition: crate::style::Transition) -> Self {
self.enter = Some(crate::style::Transition {
opacity: true,
..transition
});
self
}
pub fn selectable(mut self) -> Self {
self.selectable = true;
self
}
pub fn live(mut self) -> Self {
self.live = true;
self
}
pub fn semantics(mut self, semantics: Semantics) -> Self {
self.semantics = Some(semantics);
self
}
pub fn label(mut self, label: impl Into<String>) -> Self {
self.label = Some(label.into());
self
}
pub fn disabled(mut self, disabled: bool) -> Self {
self.disabled = disabled;
self
}
pub fn transition(mut self, t: Transition) -> Self {
self.transition = Some(t);
self
}
pub fn focusable(mut self, focusable: bool) -> Self {
self.focusable = focusable;
self
}
pub fn autofocus(mut self) -> Self {
self.autofocus = true;
self.focusable = true;
self
}
pub fn cursor(mut self, cursor: Cursor) -> Self {
self.cursor = Some(cursor);
self
}
pub fn p(mut self, v: f32) -> Self {
self.style = self.style.p(v);
self
}
pub fn px(mut self, v: f32) -> Self {
self.style = self.style.px(v);
self
}
pub fn py(mut self, v: f32) -> Self {
self.style = self.style.py(v);
self
}
pub fn pt(mut self, v: f32) -> Self {
self.style = self.style.pt(v);
self
}
pub fn pr(mut self, v: f32) -> Self {
self.style = self.style.pr(v);
self
}
pub fn pb(mut self, v: f32) -> Self {
self.style = self.style.pb(v);
self
}
pub fn pl(mut self, v: f32) -> Self {
self.style = self.style.pl(v);
self
}
pub fn m(mut self, v: f32) -> Self {
self.style = self.style.m(v);
self
}
pub fn mx(mut self, v: f32) -> Self {
self.style = self.style.mx(v);
self
}
pub fn my(mut self, v: f32) -> Self {
self.style = self.style.my(v);
self
}
pub fn mt(mut self, v: f32) -> Self {
self.style = self.style.mt(v);
self
}
pub fn mr(mut self, v: f32) -> Self {
self.style = self.style.mr(v);
self
}
pub fn mb(mut self, v: f32) -> Self {
self.style = self.style.mb(v);
self
}
pub fn ml(mut self, v: f32) -> Self {
self.style = self.style.ml(v);
self
}
pub fn gap(mut self, v: f32) -> Self {
self.style = self.style.gap(v);
self
}
pub fn w(mut self, v: impl Into<Length>) -> Self {
self.style = self.style.w(v);
self
}
pub fn h(mut self, v: impl Into<Length>) -> Self {
self.style = self.style.h(v);
self
}
pub fn min_w(mut self, v: impl Into<Length>) -> Self {
self.style = self.style.min_w(v);
self
}
pub fn max_w(mut self, v: impl Into<Length>) -> Self {
self.style = self.style.max_w(v);
self
}
pub fn min_h(mut self, v: impl Into<Length>) -> Self {
self.style = self.style.min_h(v);
self
}
pub fn max_h(mut self, v: impl Into<Length>) -> Self {
self.style = self.style.max_h(v);
self
}
pub fn measure(mut self, chars: f32) -> Self {
self.style = self.style.measure(chars);
self
}
pub fn w_ch(mut self, chars: f32) -> Self {
self.style = self.style.w_ch(chars);
self
}
pub fn min_w_ch(mut self, chars: f32) -> Self {
self.style = self.style.min_w_ch(chars);
self
}
pub fn max_w_ch(mut self, chars: f32) -> Self {
self.style = self.style.max_w_ch(chars);
self
}
pub fn w_full(mut self) -> Self {
self.style = self.style.w_full();
self
}
pub fn h_full(mut self) -> Self {
self.style = self.style.h_full();
self
}
pub fn grow(mut self) -> Self {
self.style = self.style.grow();
self
}
pub fn shrink0(mut self) -> Self {
self.style = self.style.shrink0();
self
}
pub fn items_start(mut self) -> Self {
self.style = self.style.items_start();
self
}
pub fn items_center(mut self) -> Self {
self.style = self.style.items_center();
self
}
pub fn items_end(mut self) -> Self {
self.style = self.style.items_end();
self
}
pub fn items_baseline(mut self) -> Self {
self.style = self.style.items_baseline();
self
}
pub fn justify_start(mut self) -> Self {
self.style = self.style.justify_start();
self
}
pub fn justify_center(mut self) -> Self {
self.style = self.style.justify_center();
self
}
pub fn justify_end(mut self) -> Self {
self.style = self.style.justify_end();
self
}
pub fn justify_between(mut self) -> Self {
self.style = self.style.justify_between();
self
}
pub fn wrap(mut self) -> Self {
self.style = self.style.wrap();
self
}
pub fn absolute(mut self) -> Self {
self.style = self.style.absolute();
self
}
pub fn top(mut self, v: f32) -> Self {
self.style = self.style.top(v);
self
}
pub fn right(mut self, v: f32) -> Self {
self.style = self.style.right(v);
self
}
pub fn bottom(mut self, v: f32) -> Self {
self.style = self.style.bottom(v);
self
}
pub fn left(mut self, v: f32) -> Self {
self.style = self.style.left(v);
self
}
pub fn overflow_hidden(mut self) -> Self {
self.style = self.style.overflow_hidden();
self
}
pub fn scroll_y(mut self) -> Self {
self.style = self.style.scroll_y();
self
}
pub fn stick_to_bottom(mut self) -> Self {
self.stick_bottom = true;
self
}
pub fn bg(mut self, paint: impl Into<Paint>) -> Self {
self.style = self.style.bg(paint);
self
}
pub fn border(mut self, width: f32, color: Color) -> Self {
self.style = self.style.border(width, color);
self
}
pub fn rounded(mut self, r: f32) -> Self {
self.style = self.style.rounded(r);
self
}
pub fn rounded_full(mut self) -> Self {
self.style = self.style.rounded_full();
self
}
pub fn shadow(mut self, token: ShadowToken) -> Self {
self.style = self.style.shadow(token);
self
}
pub fn opacity(mut self, v: f32) -> Self {
self.style = self.style.opacity(v);
self
}
pub fn trim(mut self, v: f32) -> Self {
self.style = self.style.trim(v);
self
}
pub fn size(mut self, size: TextSize) -> Self {
self.style = self.style.size(size);
self
}
pub fn size_px(mut self, px: f32) -> Self {
self.style = self.style.size_px(px);
self
}
pub fn tracking(mut self, em: f32) -> Self {
self.style = self.style.tracking(em);
self
}
pub fn leading(mut self, multiple: f32) -> Self {
self.style = self.style.leading(multiple);
self
}
pub fn tabular(mut self) -> Self {
self.style = self.style.tabular();
self
}
pub fn proportional_nums(mut self) -> Self {
self.style = self.style.proportional_nums();
self
}
pub fn oldstyle_nums(mut self) -> Self {
self.style = self.style.oldstyle_nums();
self
}
pub fn lining_nums(mut self) -> Self {
self.style = self.style.lining_nums();
self
}
pub fn small_caps(mut self) -> Self {
self.style = self.style.small_caps();
self
}
pub fn ligatures(mut self, on: bool) -> Self {
self.style = self.style.ligatures(on);
self
}
pub fn fractions(mut self) -> Self {
self.style = self.style.fractions();
self
}
pub fn family(mut self, family: crate::tokens::FamilyRole) -> Self {
self.style = self.style.family(family);
self
}
pub fn weight(mut self, weight: Weight) -> Self {
self.style = self.style.weight(weight);
self
}
pub fn color(mut self, color: Color) -> Self {
self.style = self.style.color(color);
self
}
pub fn mono(mut self) -> Self {
self.style = self.style.mono();
self
}
pub fn truncate(mut self) -> Self {
self.style = self.style.truncate();
self
}
pub fn text_align(mut self, align: TextAlign) -> Self {
self.style = self.style.text_align(align);
self
}
pub fn balance(mut self) -> Self {
self.style = self.style.balance();
self
}
pub fn pretty(mut self) -> Self {
self.style = self.style.pretty();
self
}
pub fn text_wrap(mut self, wrap: TextWrap) -> Self {
self.style = self.style.text_wrap(wrap);
self
}
}
#[track_caller]
pub fn div<Msg>() -> Element<Msg> {
Element::new(Kind::Box)
}
#[track_caller]
pub fn row<Msg>() -> Element<Msg> {
Element::new(Kind::Box)
}
#[track_caller]
pub fn col<Msg>() -> Element<Msg> {
let mut el = Element::new(Kind::Box);
el.style.direction = crate::style::Direction::Column;
el
}
#[track_caller]
pub fn stack<Msg>() -> Element<Msg> {
let mut el = Element::new(Kind::Box);
el.style.display = crate::style::Display::Grid;
el.stack = true;
el
}
#[track_caller]
pub fn rich_text<Msg>(spans: impl IntoIterator<Item = Span>) -> Element<Msg> {
Element::new(Kind::Rich(spans.into_iter().collect()))
}
#[track_caller]
pub fn text<Msg>(content: impl Into<String>) -> Element<Msg> {
Element::new(Kind::Text(content.into()))
}
#[track_caller]
pub fn spacer<Msg>() -> Element<Msg> {
Element::new(Kind::Box).grow()
}
#[track_caller]
pub fn divider<Msg>() -> Element<Msg> {
Element::new(Kind::Divider).w_full().h(1.0).shrink0()
}
#[track_caller]
pub fn raw_input<Msg>(value: impl Into<String>, placeholder: impl Into<String>) -> Element<Msg> {
Element::new(Kind::Input(InputData {
value: value.into(),
placeholder: placeholder.into(),
multiline: false,
}))
.focusable(true)
.cursor(Cursor::Text)
}
#[track_caller]
pub fn raw_text_area<Msg>(
value: impl Into<String>,
placeholder: impl Into<String>,
) -> Element<Msg> {
Element::new(Kind::Input(InputData {
value: value.into(),
placeholder: placeholder.into(),
multiline: true,
}))
.focusable(true)
.cursor(Cursor::Text)
}
#[track_caller]
pub fn image_rgba8<Msg>(width: u32, height: u32, mut pixels: Vec<u8>) -> Element<Msg> {
let row = width as usize * 4;
let rows = pixels
.len()
.checked_div(row)
.unwrap_or(0)
.min(height as usize);
pixels.truncate(row * rows);
#[expect(clippy::cast_possible_truncation, reason = "rows <= height: u32")]
let height = rows as u32;
let image = peniko::ImageData {
data: pixels.into(),
format: peniko::ImageFormat::Rgba8,
alpha_type: peniko::ImageAlphaType::Alpha,
width,
height,
};
#[expect(clippy::cast_precision_loss, reason = "image sizes fit in f32")]
Element::new(Kind::Image(ImageData { image }))
.w(width as f32)
.h(height as f32)
.shrink0()
}
#[track_caller]
pub fn path<Msg>(bez: kurbo::BezPath, viewbox: (f64, f64), stroke: Option<f64>) -> Element<Msg> {
#[expect(clippy::cast_possible_truncation, reason = "viewbox sizes are small")]
Element::new(Kind::Path(PathData {
path: std::sync::Arc::new(bez),
viewbox,
stroke,
}))
.w(viewbox.0 as f32)
.h(viewbox.1 as f32)
.shrink0()
}
impl<Msg: 'static> Element<Msg> {
pub fn map<B: 'static>(self, f: impl Fn(Msg) -> B + Clone + 'static) -> Element<B> {
Element {
kind: self.kind,
style: self.style,
children: self
.children
.into_iter()
.map(|c| c.map(f.clone()))
.collect(),
key: self.key,
source: self.source,
stack: self.stack,
focusable: self.focusable,
autofocus: self.autofocus,
stick_bottom: self.stick_bottom,
cursor: self.cursor,
disabled: self.disabled,
on_click: self.on_click.map(&f),
on_double_click: self.on_double_click.map(&f),
on_right_click: self.on_right_click.map(&f),
on_hover: self.on_hover.map(&f),
on_key: self.on_key.map(|k| {
let f = f.clone();
Box::new(move |key: &KeyInput| k(key).map(&f)) as KeyFn<B>
}),
on_type_ahead: self.on_type_ahead.map(|k| {
let f = f.clone();
Box::new(move |buffer: &str| k(buffer).map(&f)) as TypeAheadFn<B>
}),
on_drag: self.on_drag.map(|d| {
let f = f.clone();
Box::new(move |x: f32, y: f32| d(x, y).map(&f)) as DragFn<B>
}),
on_input: self.on_input.map(|i| {
let f = f.clone();
Box::new(move |s: &str| f(i(s))) as InputFn<B>
}),
on_close: self.on_close.map(&f),
on_file_drop: self.on_file_drop.map(|d| {
let f = f.clone();
Box::new(move |p: &std::path::Path| f(d(p))) as FileDropFn<B>
}),
drag_source: self.drag_source,
on_drop: self.on_drop.map(|d| {
let f = f.clone();
Box::new(move |payload: &str| d(payload).map(&f)) as DropFn<B>
}),
overlay: self.overlay,
spin: self.spin,
keyframes: self.keyframes,
virtual_rows: self.virtual_rows.map(|v| {
let f = f.clone();
let builder = v.builder;
VirtualData {
count: v.count,
row_height: v.row_height,
variable: v.variable,
builder: std::rc::Rc::new(move |i| builder(i).map(f.clone())),
}
}),
semantics: self.semantics,
live: self.live,
selectable: self.selectable,
enter: self.enter,
label: self.label,
themed: self.themed,
hover_style: self.hover_style,
active_style: self.active_style,
focus_style: self.focus_style,
state_layer: self.state_layer,
press_scale: self.press_scale,
invalid: self.invalid,
transition: self.transition,
}
}
}
impl<Msg> Element<Msg> {
pub fn grid_cols(mut self, tracks: impl IntoIterator<Item = crate::style::Track>) -> Self {
self.style = self.style.grid_cols(tracks);
self
}
pub fn grid_rows(mut self, tracks: impl IntoIterator<Item = crate::style::Track>) -> Self {
self.style = self.style.grid_rows(tracks);
self
}
pub fn grid_col(mut self, start: i16, span: u16) -> Self {
self.style = self.style.grid_col(start, span);
self
}
pub fn grid_row(mut self, start: i16, span: u16) -> Self {
self.style = self.style.grid_row(start, span);
self
}
}