ltk::text_edit

Struct TextEdit

Source
pub struct TextEdit<Msg: Clone> {
Show 17 fields pub placeholder: String, pub value: String, pub on_change: Option<Arc<dyn Fn(String) -> Msg>>, pub on_submit: Option<Msg>, pub secure: bool, pub multiline: bool, pub rows: u32, pub cursor_pos: usize, pub id: Option<WidgetId>, pub cursor: Option<CursorShape>, pub align: TextAlign, pub borderless: bool, pub fixed_width: Option<f32>, pub font_size: f32, pub select_on_focus: bool, pub password_toggle: Option<(bool, Msg)>, pub read_only: bool,
}
Expand description

A text input field.

Single-line by default; switches to a multi-row text-area via Self::multiline. Single-line mode honours the optional inline builders for picker-style fields:

  • Self::align — horizontal alignment of the displayed text;
  • Self::borderless — drop the surrounding pill / border so the field can sit inside a parent that already paints its own surface;
  • Self::fixed_width — pin the preferred width to a specific number of pixels instead of claiming max_width;
  • Self::font_size — override the text font size;
  • Self::select_on_focus — auto-select the value on focus so the next keystroke replaces it (numeric pickers, short-form inputs).
  • Self::password_toggle — pin a built-in show / hide-password eye icon to the right edge of the field; the bullet substitution flips with the externally-owned visible state on each tap.
text_edit( "Username", &self.username )
    .on_change( |s| Msg::UsernameChanged( s ) )
    .on_submit( Msg::Submit )
.into()

§Password field with show / hide toggle

text_edit( "Password", &self.password )
    .on_change( |s| Msg::PasswordChanged( s ) )
    .password_toggle( self.password_visible, Msg::TogglePassword )
.into()

password_toggle overrides Self::secure when both are set — the toggle’s visible parameter drives the bullet substitution from then on. The widget still wipes the buffer on drop and skips the IME registration (the same hardening Self::secure gives) regardless of the current visibility, so flipping the eye does not weaken the field’s threat model at runtime.

Fields§

§placeholder: String

Placeholder text shown when the field is empty.

§value: String

Current field value.

§on_change: Option<Arc<dyn Fn(String) -> Msg>>

Callback invoked with the new value on every keystroke. Arc (not Box) so the layout pass can clone it into the per-leaf handler snapshot for O(1) dispatch on input events.

§on_submit: Option<Msg>

Message emitted when the user presses Enter.

§secure: bool

When true, the value is rendered as bullet characters (password mode).

§multiline: bool

When true, the widget renders as a multi-row text area: the box grows to Self::rows visible rows, line breaks in the value are honoured at draw time, and pressing Enter inserts a \n rather than firing Self::on_submit. Ignored when Self::secure is set — passwords are always single-line.

§rows: u32

Visible row count when multiline is true. Drives preferred_size’s height calculation so a multiline field claims a sensible vertical slot in the parent layout. Ignored when multiline is false.

§cursor_pos: usize

Byte offset of the text cursor within value (used by insert_str/backspace).

§id: Option<WidgetId>

Optional stable identifier for focus management.

§cursor: Option<CursorShape>

Override the pointer cursor shape on hover. None falls back to the I-beam default that matches every desktop convention.

§align: TextAlign

Horizontal alignment of the displayed text inside the inner content rect. Only takes effect on the single-line path when the value fits inside the inner width — once the value overflows, the internal single_line_scroll_x helper takes over and the alignment offset collapses to 0 so scrolling reads naturally. Default TextAlign::Left.

§borderless: bool

Skip the field’s background fill and border stroke. Useful when the TextEdit is dropped inside another container that paints its own surface (e.g. the digit cells inside crate::widget::time_picker::TimePicker) and a second pill would only add visual noise.

§fixed_width: Option<f32>

Override the preferred width reported to the parent layout. Without this the single-line TextEdit claims max_width and fills whatever rect the parent allocates — which is the right default for forms but wrong when the field needs to be sized to fit a fixed number of glyphs (date / time pickers, inline numeric inputs).

§font_size: f32

Font size in pixels for the single-line draw path. Defaults to the theme’s FONT_SIZE constant. Multiline mode ignores this for now and always uses the default — multiline soft-wrap layout depends on the constant in several places that are not yet parameterised.

§select_on_focus: bool

When true, focusing the field selects the whole value so the next keystroke replaces it. Standard behaviour for numeric pickers and short-form fields where the user usually wants to retype rather than edit. Default false — long-form fields keep the cursor at the end on focus.

§password_toggle: Option<(bool, Msg)>

Self-managed “show / hide password” eye affordance — when Some( ( visible, on_toggle ) ) the field renders an actions/visibleactions/invisible icon at its right edge, taps on that icon dispatch on_toggle instead of placing the cursor, and the bullet substitution flips with visible (overriding secure). Set on a field that already has secure( true ) and the explicit flag becomes redundant — the toggle controls the visibility from then on.

§read_only: bool

When true, the field renders its box and value but takes no keyboard focus and accepts no input — a read-only display styled as a text field.

Implementations§

Source§

impl<Msg: Clone> TextEdit<Msg>

Source

pub fn draw( &self, canvas: &mut Canvas, rect: Rect, focused: bool, cursor_pos: usize, selection_anchor: usize, )

Draw the field into canvas at rect.

cursor_pos is the byte offset of the text cursor — supplied by the runtime from its persistent cursor state rather than from the widget itself. selection_anchor is the other end of the selection range; when selection_anchor == cursor_pos no highlight is painted.

Source§

impl<Msg: Clone> TextEdit<Msg>

Source

pub fn new(placeholder: String, value: String) -> Self

Create a text field with the given placeholder and initial value.

The cursor is placed at the end of the initial value.

Source

pub fn password_toggle(self, visible: bool, on_toggle: Msg) -> Self

Add a “show / hide password” eye toggle pinned to the right edge of the field. visible controls whether the value renders as bullets (false) or plain text (true); a tap on the icon emits on_toggle so the caller can flip its own bool state and re-render. Works with or without an explicit Self::secure — when this is set, the toggle’s visible drives the bullet substitution and the secure field is ignored.

Source

pub fn effective_secure(&self) -> bool

Effective secure flag honoured by drawing / measurement / hit-testing — Self::password_toggle takes precedence over the manual Self::secure when both are set.

Source

pub fn font_size(self, px: f32) -> Self

Override the font size used by the single-line draw path. Defaults to the theme’s FONT_SIZE constant. Ignored in multiline mode.

Source

pub fn select_on_focus(self, on: bool) -> Self

Select the whole value when the field receives focus, so the next keystroke replaces it. Default false.

Source

pub fn align(self, a: TextAlign) -> Self

Set the horizontal alignment of the displayed text. Default TextAlign::Left.

Source

pub fn borderless(self, on: bool) -> Self

Skip the field’s background fill and border stroke — useful when the field is nested inside a container that already paints its own surface.

Source

pub fn fixed_width(self, w: f32) -> Self

Override the preferred width reported to the parent layout. Pass None (default) to fall back to claiming max_width.

Source

pub fn cursor(self, shape: CursorShape) -> Self

Override the pointer cursor shape shown on hover. Defaults to CursorShape::Text (I-beam).

Source

pub fn multiline(self, m: bool) -> Self

Switch to multiline (text-area) mode. The box is laid out with Self::rows visible rows of height, line breaks in the value are rendered as separate rows, and Enter inserts a \n instead of firing Self::on_submit. Ignored when Self::secure is true.

Source

pub fn rows(self, n: u32) -> Self

Configure the number of visible rows in multiline mode. Defaults to 5; ignored when Self::multiline is false.

Source

pub fn on_change(self, f: impl Fn(String) -> Msg + 'static) -> Self

Set the callback invoked on every keystroke with the updated value.

Source

pub fn on_submit(self, msg: Msg) -> Self

Set the message emitted when Enter is pressed.

Source

pub fn secure(self, s: bool) -> Self

Enable or disable password mode.

When true, this widget:

  1. Renders the value as bullet characters () instead of the raw glyphs.
  2. Forces single-line mode (multiline + secure is mutually exclusive — passwords don’t have line breaks).
  3. Wipes the underlying byte buffer with zero before the String allocation is returned to the allocator. The wipe runs in Drop for both the TextEdit itself and for the per-frame crate::widget::WidgetHandlers::TextEdit snapshot the runtime keeps for input dispatch — so the in-tree copies that ltk owns never linger as plain text in freed memory.
§Threat model — what secure covers

Inside the widget tree the runtime keeps two copies of the value for the lifetime of one frame: the TextEdit itself and the WidgetHandlers snapshot. Both run the secure_zero wipe on Drop, so when the next frame replaces them (the typical case — view() rebuilds every frame) the freed allocations are overwritten before being released back to the allocator. The wipe uses volatile writes + a compiler_fence so the optimiser cannot elide it as dead code (the implementation is in the crate-private secure_mem module).

§What secure does not cover
  • The application’s own state. The String you pass in through text_edit( placeholder, &self.password ) lives on your struct, not on the widget. Wiping it is your job — typically a Drop impl on the credential container, or an explicit secure_mem::secure_zero( password.as_bytes_mut() ) after the auth handshake completes.
  • Callback-allocated copies. Every keystroke passes through on_change( |s: String| ... ), which receives a fresh String clone. If your closure stores or forwards that String (e.g. clone it into a worker thread for PAM), each stored copy is the consumer’s responsibility to wipe. ltk only owns the buffers it allocated itself.
  • OS-level disclosure surfaces. Swap-out, hibernation images, and core dumps are outside any user-space wipe’s reach. For threat models that require resistance to these, compile against an mlock-aware allocator, disable swap on the credential mount, and restrict core-dump capability with prctl( PR_SET_DUMPABLE, 0 ) on the process.
  • Compositor-side records. Wayland text-input protocols can surface preedit / commit strings to the compositor’s IME stack. secure does not suppress text-input-v3 — the field still registers so the on-screen keyboard activates on it — but it is flagged Password with SensitiveData | HiddenText, asking the IME / OSK to skip prediction, autocorrect and storing the value. The value still reaches the (trusted) compositor/IME; for a stricter threat model, suppress text-input on secure fields instead (at the cost of losing the OSK there).

See the in-repo SECURITY.md for the full threat-model write-up (the Hardening features section enumerates each guarantee and its boundary).

Source

pub fn read_only(self, on: bool) -> Self

Render the field read-only: shows the value styled as a field but takes no focus and accepts no input.

Source

pub fn id(self, id: WidgetId) -> Self

Assign a stable identifier for focus management.

Source

pub fn preferred_size(&self, max_width: f32, _canvas: &Canvas) -> (f32, f32)

Return the preferred (width, height) given available max_width.

Single-line: theme-defined HEIGHT. Multiline: enough room for Self::rows lines plus padding.

Source

pub fn is_multiline(&self) -> bool

true when the widget is laid out as a multi-row text area — i.e. Self::multiline was set and Self::effective_secure is false. A password_toggle field collapses to single-line like an explicit secure( true ) does.

Source

pub fn byte_offset_at_self( &self, canvas: &Canvas, rect: Rect, pos: Point, cursor_pos: usize, ) -> usize

Translate a pointer position inside rect to the byte offset in Self::value that the cursor should land on. Thin wrapper around byte_offset_at using this widget’s value / flags.

Source

pub fn paint_bounds(&self, rect: Rect) -> Rect

Border stroke is centered on rect, so half the stroke width plus ~1 px of antialiasing bleed sits outside. The widest stroke is the focused border, so use that as the envelope.

Source

pub fn display_text(&self) -> String

Return the display string — bullet characters in secure mode, plain value otherwise.

Source

pub fn into_element(self) -> Element<Msg>

Wrap this widget in an Element.

Source

pub fn insert_str(&mut self, s: &str) -> Option<Msg>

Insert a string at the current cursor position, advance the cursor, and return the on_change message if one is set.

Source

pub fn backspace(&mut self) -> Option<Msg>

Delete the character before the cursor and return the on_change message if one is set. Does nothing if the cursor is already at position 0.

Trait Implementations§

Source§

impl<Msg: Clone> Drop for TextEdit<Msg>

Source§

fn drop(&mut self)

When secure( true ) is set, scrub the value bytes before the underlying String allocation is returned to the allocator. The non-secure path is a no-op so the cost is paid only by widgets that opted into credential handling.

Source§

impl<Msg: Clone> From<TextEdit<Msg>> for Element<Msg>

Source§

fn from(t: TextEdit<Msg>) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl<Msg> Freeze for TextEdit<Msg>
where Msg: Freeze,

§

impl<Msg> !RefUnwindSafe for TextEdit<Msg>

§

impl<Msg> !Send for TextEdit<Msg>

§

impl<Msg> !Sync for TextEdit<Msg>

§

impl<Msg> Unpin for TextEdit<Msg>
where Msg: Unpin,

§

impl<Msg> !UnwindSafe for TextEdit<Msg>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> Downcast<T> for T

§

fn downcast(&self) -> &T

§

impl<T> Downcast for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> Upcast<T> for T

§

fn upcast(&self) -> Option<&T>

§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more