Text Input

Ply has a full built-in text input system with cursor movement, selection, undo/redo, multiline editing, password mode, and click-to-position.

πŸ”—Basic text input

Add .text_input() to an element. The element needs an explicit .id() so the engine can persist input state across frames:

Click to focus, type to enter text. The cursor blinks, selection highlights, and all standard keyboard shortcuts work.

πŸ”—Configuration

MethodWhat it doesDefault
.placeholder("text")Ghost text when emptynone
.font_size(14)Text size in pixels0
.font(&FONT_ASSET)Which font to usedefault font
.text_color(0xFFFFFF)Input text colorwhite
.placeholder_color(0x99)Placeholder text colorgray
.cursor_color(0xFFC32C)Cursor line colorwhite
.selection_color(c)Selection highlight colorsemi-transparent blue
.max_length(100)Maximum character countunlimited
.password(true)Show dots instead of charactersfalse
.multiline(true)Enable multiline editingfalse
.no_styles_movement()Cursor skips style markup (text-styling)false

πŸ”—Reading text

let username = ply.get_text_value("username");

or use callbacks to react to changes:

.text_input(|t| t
  .font_size(14)
  .on_changed(|text| {
    println!("Text changed: {}", text);
  })
  .on_submit(|text| {
    println!("Submitted: {}", text);
  })
)

.on_changed() fires after every keystroke. .on_submit() fires when Enter is pressed (in single-line mode). If you call either method more than once, the last callback wins.

πŸ”—Multiline

Enable with .multiline(true):

ui.element()
  .id("editor")
  .width(grow!())
  .height(grow!())
  .background_color(0x262220)
  .corner_radius(8.0)
  .text_input(|t| t
    .multiline(true)
    .font_size(14)
    .text_color(0xE8E0DC)
  )
  .empty();

In multiline mode:

  • Enter inserts a newline (instead of triggering submit)
  • Up/Down arrows navigate between lines (it remembers the x position)
  • The input scrolls vertically when content overflows

πŸ”—Password mode

.text_input(|t| t
  .password(true)
  .font_size(14)
  .placeholder("Enter password")
)

Characters are displayed as dots. Copy/cut is disabled.

πŸ”—Programmatic control

Manipulate text input state by ID:

ply.set_text_value("editor", "Hello world");

ply.set_cursor_pos("editor", 5);

let pos = ply.get_cursor_pos("editor");

ply.set_selection("editor", 0, 5);  // select "Hello"

if let Some((start, end)) = ply.get_selection_range("editor") {
    // active selection from start to end
}

πŸ”—Keyboard operations

All standard text editing shortcuts work out of the box:

ShortcutAction
Arrow keysMove cursor
Shift + arrowsExtend selection
Ctrl/Cmd + Left/RightMove by word
Home / EndStart/end of line
Ctrl/Cmd + ASelect all
Ctrl/Cmd + ZUndo
Ctrl/Cmd + YRedo
Double-clickSelect word

πŸ”—Login form example

ui.element()
  .width(fixed!(320.0))
  .height(fit!())
  .background_color(0x2E2A28)
  .corner_radius(12.0)
  .layout(|l| l.direction(TopToBottom).padding(24).gap(16))
  .children(|ui| {
    ui.text("Sign In", |t| t.font_size(20).color(0xFFFFFF));

    ui.element()
      .id("email")
      .width(grow!())
      .height(fixed!(36.0))
      .background_color(0x262220)
      .corner_radius(6.0)
      .text_input(|t| t
        .placeholder("Email")
        .font_size(14)
        .text_color(0xE8E0DC)
        .placeholder_color(0x6E6560)
      )
      .empty();

    ui.element()
      .id("password")
      .width(grow!())
      .height(fixed!(36.0))
      .background_color(0x262220)
      .corner_radius(6.0)
      .text_input(|t| t
        .password(true)
        .placeholder("Password")
        .font_size(14)
        .text_color(0xE8E0DC)
        .placeholder_color(0x6E6560)
      )
      .empty();

    button(ui, "Sign In", |_| {
      // ply.get_text_value("email"), ply.get_text_value("password")
    });
  });

πŸ”—Next steps

β†’ Text Styling