T06a forms text: text input core, fields, numbers, masks, pin, inline, groups, tags, pairs, path, regex, expression, hotkey, mention
This commit is contained in:
41 files changed
+6233
-45
No files matched your search
@@ -0,0 +1,93 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use gpui::{
|
||||
App, ElementId, InteractiveElement, IntoElement, MouseButton, ParentElement, RenderOnce,
|
||||
SharedString, StatefulInteractiveElement, Styled, Window, div,
|
||||
};
|
||||
|
||||
use super::NumberInput;
|
||||
use crate::theme::{ActiveTheme, Radius};
|
||||
|
||||
type OnUnit = Rc<dyn Fn(&SharedString, &mut Window, &mut App)>;
|
||||
|
||||
/// A number with a unit you click through, such as px, % and em.
|
||||
#[derive(IntoElement)]
|
||||
pub struct UnitInput {
|
||||
field: NumberInput,
|
||||
units: Vec<SharedString>,
|
||||
unit: SharedString,
|
||||
on_unit: Option<OnUnit>,
|
||||
}
|
||||
|
||||
impl UnitInput {
|
||||
pub fn new(
|
||||
id: impl Into<ElementId>,
|
||||
value: f64,
|
||||
units: impl IntoIterator<Item = impl Into<SharedString>>,
|
||||
unit: impl Into<SharedString>,
|
||||
) -> Self {
|
||||
let units: Vec<SharedString> = units.into_iter().map(Into::into).collect();
|
||||
let unit = unit.into();
|
||||
assert!(units.contains(&unit), "unit {unit} is not among {units:?}");
|
||||
Self {
|
||||
field: NumberInput::new(id, value),
|
||||
units,
|
||||
unit,
|
||||
on_unit: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn range(mut self, min: f64, max: f64) -> Self {
|
||||
self.field = self.field.range(min, max);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn precision(mut self, places: usize) -> Self {
|
||||
self.field = self.field.precision(places);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_change(mut self, handler: impl Fn(f64, &mut Window, &mut App) + 'static) -> Self {
|
||||
self.field = self.field.on_change(handler);
|
||||
self
|
||||
}
|
||||
|
||||
/// Runs with the next unit when the unit is clicked.
|
||||
pub fn on_unit(
|
||||
mut self,
|
||||
handler: impl Fn(&SharedString, &mut Window, &mut App) + 'static,
|
||||
) -> Self {
|
||||
self.on_unit = Some(Rc::new(handler));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for UnitInput {
|
||||
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let theme = cx.theme();
|
||||
let position = self
|
||||
.units
|
||||
.iter()
|
||||
.position(|unit| *unit == self.unit)
|
||||
.expect("checked at construction");
|
||||
let next = self.units[(position + 1) % self.units.len()].clone();
|
||||
let on_unit = self.on_unit;
|
||||
let hover = theme.colors.hover;
|
||||
let unit = div()
|
||||
.id((self.field.id.clone(), "unit"))
|
||||
.px_1p5()
|
||||
.rounded(theme.radius(Radius::Sm))
|
||||
.text_color(theme.colors.fg_muted)
|
||||
.cursor_pointer()
|
||||
.hover(|style| style.bg(hover))
|
||||
.on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
|
||||
.on_click(move |_, window, cx| {
|
||||
log::info!("unit input: {next}");
|
||||
if let Some(on_unit) = &on_unit {
|
||||
on_unit(&next, window, cx);
|
||||
}
|
||||
})
|
||||
.child(self.unit);
|
||||
self.field.suffix(unit)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user