docs
Loading...
Searching...
No Matches
Editorabstract

#include <Ultralight/Editor.h>

Overview

Text-editing interface for a View.

The editor executes editing commands and manages composition state for the focused element in a View.

Standard keyboard shortcuts like Ctrl+C and Ctrl+V run automatically when you forward key events to a View. You use the editor to connect native UI controls like Edit menus and on-screen keyboards directly to the page, and to relay text from an OS input method.

This example updates native Edit menu items before display and runs the command the user picks:

void UpdateEditMenu() {
Editor* editor = view->editor();
SetMenuItemEnabled("Cut", editor->CanExecute(EditorCommand::Cut));
SetMenuItemEnabled("Copy", editor->CanExecute(EditorCommand::Copy));
SetMenuItemEnabled("Paste", editor->CanExecute(EditorCommand::Paste));
}
void OnEditMenuCommand(EditorCommand command) {
view->editor()->Execute(command);
}
Text-editing interface for a View.
Definition Editor.h:332
virtual bool CanExecute(EditorCommand command) const =0
Whether or not a command would do anything right now.
EditorCommand
The editing commands you can run with Editor::Execute().
Definition Editor.h:26
@ Paste
Paste the clipboard's contents.
Definition Editor.h:30
@ Copy
Copy the selection to the clipboard.
Definition Editor.h:29
@ Cut
Cut the selection to the clipboard.
Definition Editor.h:28

Running Commands

Call View::editor() to obtain the View's Editor instance. Commands target the focused element in the active frame.

Calling Execute() runs an EditorCommand on that element. It returns false when the command can't run, such as copying without an active selection or undoing with an empty history.

Call CanExecute() to test whether a command would succeed right now, which lets you enable or disable native menu items before presenting them.

Note
ViewConfig::clipboard_read_policy restricts clipboard reads attempted by page scripts, but it doesn't restrict pastes executed through Execute().

Inserting Text

Call InsertText() to insert text at the caret, such as when forwarding input from an on-screen keyboard. The text replaces any active selection, exactly as if the user typed it.

This callback forwards tapped keys to the focused element:

void OnScreenKeyTapped(const String& key_text) {
view->editor()->InsertText(key_text);
}
Unicode string container with conversions for UTF-8, UTF-16, and UTF-32.
Definition String.h:31

Supporting Input Methods

AppCore windows run the OS input method automatically for their panels. When you host a View directly, you implement EditorListener and pass it to View::set_editor_listener() to coordinate the input method with the page.

Activating the Input Method

In EditorListener::OnChangeEditableState(), turn on the OS input method only while both view_has_focus and is_mutable are true in EditableState (turn it off whenever either property is false).

Composing Text

Pass in-progress composition text from the OS to SetComposition(). The initial call starts the composition and replaces any active selection on the page– later calls replace the previous in-progress text.

Placing the Candidate Window

Implement EditorListener::OnUpdateComposition() to reposition the candidate window whenever the composition updates.

Query GetCompositionCharacterBounds() at index 0 to anchor the candidate window to the composition's first character, or GetCaretBounds() when no composition is active. Anchoring to the first character prevents the candidate window from jumping as candidate words change length.

Both methods return rectangles in viewport CSS pixels. Multiply their coordinates by View::device_scale() to convert them to device pixels.

Ending a Composition

Call the matching editor method when the input method completes or cancels:

  • CommitComposition() applies final text. If no composition is active, it inserts the text at the caret.
  • FinishComposition() keeps the in-progress text as final text. Call this when the input method closes without committing (such as when focus moves away mid-composition).
  • CancelComposition() removes the in-progress text. Call this when the input method cancels without producing text.

When the page terminates an active composition on its own (such as during navigation or when a click focuses a different element), the library calls EditorListener::OnDiscardComposition(). The page keeps the in-progress text as final text, so cancel the OS input method without recommitting or inserting the text again.

Inspecting Surrounding Text

OS input methods sometimes inspect or replace text surrounding the caret, such as when showing an accent palette.

Call GetSelectionOffsets() to locate the selection. The editor's offset methods measure character positions in UTF-16 code units from the start of the focused editable element, matching the DOM selectionStart and selectionEnd properties.

See also
View::editor(), EditorListener, EditableState, EditorCommand

Public Member Functions

virtual bool Execute (EditorCommand command)=0
 Run an editing command.
virtual bool CanExecute (EditorCommand command) const =0
 Whether or not a command would do anything right now.
virtual bool InsertText (const String &text)=0
 Insert text at the caret, replacing the selection (the same as typing it).
virtual Rect GetCaretBounds ()=0
 Get the bounds of the caret.
virtual bool SetComposition (const String &text, const CompositionSegment *segments, size_t num_segments, const CompositionRange &selection)=0
 Set or update the in-progress text of an input method's composition.
virtual bool CommitComposition (const String &text)=0
 Replace the active composition with the input method's final text.
virtual bool FinishComposition ()=0
 Keep the active composition's in-progress text as final text.
virtual bool CancelComposition ()=0
 Cancel the active composition and remove its text.
virtual bool HasComposition () const =0
 Whether or not a composition is active.
virtual Rect GetCompositionBounds ()=0
 Get the bounds of the active composition's text, in viewport CSS pixels.
virtual uint32_t GetCompositionCharacterCount ()=0
 Get the length of the active composition's text, in UTF-16 code units (0 when none is active).
virtual Rect GetCompositionCharacterBounds (uint32_t index)=0
 Get the bounds of one character of the active composition's text, in viewport CSS pixels.
virtual bool GetSelectionOffsets (uint32_t &start, uint32_t &end)=0
 Get the selection's offsets within the focused element's text.
virtual String GetTextInRange (uint32_t start, uint32_t end)=0
 Get part of the focused element's text (see GetSelectionOffsets() for the offsets).
virtual bool ReplaceTextInRange (uint32_t start, uint32_t end, const String &text)=0
 Replace part of the focused element's text (see GetSelectionOffsets() for the offsets).
virtual bool GetCompositionOffsets (uint32_t &start, uint32_t &end)=0
 Get the active composition's offsets within the focused element's text (see GetSelectionOffsets() for the offsets).

Protected Member Functions

virtual ~Editor ()=default

Constructor & Destructor Documentation

◆ ~Editor()

virtual ~Editor ( )
protectedvirtualdefault

Member Function Documentation

◆ CancelComposition()

virtual bool CancelComposition ( )
pure virtual

Cancel the active composition and remove its text.

Returns
Returns whether a composition was cancelled (false when none was active).

◆ CanExecute()

virtual bool CanExecute ( EditorCommand command) const
nodiscardpure virtual

Whether or not a command would do anything right now.

You can use this to grey out items in a native menu.

Parameters
commandThe command to check.
Returns
Returns true if Execute() would run the command.

◆ CommitComposition()

virtual bool CommitComposition ( const String & text)
pure virtual

Replace the active composition with the input method's final text.

With no active composition, this inserts text at the caret.

Parameters
textThe final text.
Returns
Returns whether the text was inserted (false when there's no editable text).

◆ Execute()

virtual bool Execute ( EditorCommand command)
pure virtual

Run an editing command.

Parameters
commandThe command to run.
Returns
Returns whether the command ran (false whenever CanExecute() would return false).

◆ FinishComposition()

virtual bool FinishComposition ( )
pure virtual

Keep the active composition's in-progress text as final text.

Call this when the input method closes without committing or cancelling (eg, focus moves away mid-composition).

Returns
Returns whether a composition was finished (false when none was active).

◆ GetCaretBounds()

virtual Rect GetCaretBounds ( )
nodiscardpure virtual

Get the bounds of the caret.

The rect is in viewport CSS pixels (the same space as View::FireMouseEvent()). Multiply by View::device_scale() for device pixels.

Returns
Returns the caret bounds (an empty rect when there's no caret in editable text).
Note
This updates any pending layout first– query it when you need it (eg, when opening a menu) rather than every frame.

◆ GetCompositionBounds()

virtual Rect GetCompositionBounds ( )
nodiscardpure virtual

Get the bounds of the active composition's text, in viewport CSS pixels.

You can use this as the area a candidate window shouldn't cover.

Returns
Returns the bounds (all-zero when no composition is active).

◆ GetCompositionCharacterBounds()

virtual Rect GetCompositionCharacterBounds ( uint32_t index)
nodiscardpure virtual

Get the bounds of one character of the active composition's text, in viewport CSS pixels.

You can use this to place a candidate window. Anchor it on the composition's first character (index 0) so it doesn't move as the candidates change.

Parameters
indexThe character's offset within the composition's text, in UTF-16 code units.
Returns
Returns the character's bounds (all-zero when index is out of range or no composition is active).

◆ GetCompositionCharacterCount()

virtual uint32_t GetCompositionCharacterCount ( )
nodiscardpure virtual

Get the length of the active composition's text, in UTF-16 code units (0 when none is active).

◆ GetCompositionOffsets()

virtual bool GetCompositionOffsets ( uint32_t & start,
uint32_t & end )
nodiscardpure virtual

Get the active composition's offsets within the focused element's text (see GetSelectionOffsets() for the offsets).

You can use this to report the input method's marked range.

Parameters
startSet to the composition's start.
endSet to the composition's end (exclusive).
Returns
Returns whether the offsets were set (false when no composition is active in the focused element).

◆ GetSelectionOffsets()

virtual bool GetSelectionOffsets ( uint32_t & start,
uint32_t & end )
nodiscardpure virtual

Get the selection's offsets within the focused element's text.

The offset methods (this, GetTextInRange(), ReplaceTextInRange(), and GetCompositionOffsets()) use UTF-16 code units into the text of the focused text field or editable region. For <input> and <textarea>, they match the element's selectionStart and selectionEnd.

Parameters
startSet to the selection's start.
endSet to the selection's end (the same as start for a caret).
Returns
Returns whether the offsets were set (false when the focused element isn't editable text, or the selection is outside it).

◆ GetTextInRange()

virtual String GetTextInRange ( uint32_t start,
uint32_t end )
nodiscardpure virtual

Get part of the focused element's text (see GetSelectionOffsets() for the offsets).

Offsets past the end of the text are clamped to it.

Parameters
startThe start offset.
endThe end offset (exclusive).
Returns
Returns the text in the range (empty when the focused element isn't editable text).
Warning
This reads password fields too, so treat the result as sensitive.

◆ HasComposition()

virtual bool HasComposition ( ) const
nodiscardpure virtual

Whether or not a composition is active.

◆ InsertText()

virtual bool InsertText ( const String & text)
pure virtual

Insert text at the caret, replacing the selection (the same as typing it).

Parameters
textThe text to insert.
Returns
Returns whether the text was inserted (false when there's no editable text to insert into).

◆ ReplaceTextInRange()

virtual bool ReplaceTextInRange ( uint32_t start,
uint32_t end,
const String & text )
pure virtual

Replace part of the focused element's text (see GetSelectionOffsets() for the offsets).

This edits the same way typing does. The edit is one undo step, and the caret ends up after the new text. You can use this for an input method's replacement ranges (eg, the macOS accent picker replaces the character it targets).

Offsets past the end of the text are clamped to it.

Parameters
startThe start offset.
endThe end offset (exclusive).
textThe new text (an empty string deletes the range).
Returns
Returns whether the text was replaced (false when the focused element isn't editable text, or start is greater than end).
Note
An active composition is cancelled first, and the offsets apply to the text left after that.

◆ SetComposition()

virtual bool SetComposition ( const String & text,
const CompositionSegment * segments,
size_t num_segments,
const CompositionRange & selection )
pure virtual

Set or update the in-progress text of an input method's composition.

The first call starts a composition and replaces the selection. Later calls replace the previous in-progress text.

Parameters
textThe full in-progress text. Pass an empty string to remove it (the same as CancelComposition()).
segmentsUnderline styles for parts of the text (eg, one per clause). Pass a nullptr to underline all of it.
num_segmentsThe number of entries in segments.
selectionThe caret or selection within text, in UTF-16 code units.
Returns
Returns whether the composition was applied (false when there's no editable text).
Note
During a composition, the page gets the standard composition events. Every keydown reports key code 229 (the same as in a browser).

The documentation for this class was generated from the following file: