Crate textslabs

Source
Expand description

Textslabs is an experimental high level text library based on Parley.

The goal is to allow any winit/wgpu program to have full-featured text and text editing with minimal integration effort.

Most GUI programs or toolkits, games, etc. don’t have any advanced requirements for text: they just want basic text boxes that “work the same way as everywhere else” (browsers, native operating system GUIs, etc.).

If all that is available is a relatively low level library such as Parley, all these projects will have to do a large amount of repeated work, needlessly raising the barrier of entry to GUI programming.

§Limitations

This library is not ready for use. It currently does not reach its own goal of “full featured text”.

  • Accessibility is supported in Parley itself but not in Textslabs, because of my personal lack of familiarity with the subject.

  • Textslabs currently uses the built-in Swash CPU rasterizer and a basic homemade atlas renderer to actually show the text on screen. The performance is acceptable but it is not as good as it could be. This might eventually be fixed by switching to the new “Vello Hybrid” renderer, or by solving the performance problems in Swash.

  • Parley itself has some limitations, but they will be probably fixed soon.

§Usage

See the basic.rs example in the repository to see how the library can be used.

The two main structs are:

  • Text - manages collections of text boxes and styles
  • TextRenderer - renders the text on the GPU

§Imperative Mode

The main way to use the library is imperative with a handle-based system:

use textslabs::*;
let mut text = Text::new_without_blink_wakeup();
 
// Add text boxes and get handles
let handle = text.add_text_box("Hello", (10.0, 10.0), (200.0, 50.0), 0.0);
let edit_handle = text.add_text_edit("Type here".to_string(), (10.0, 70.0), (200.0, 30.0), 0.0);
 
// Use handles to access and modify the boxes
// text.get_text_box_mut(&handle).set_style(&my_style);
text.get_text_box_mut(&handle).text_mut().push_str("... World");
 
// Manually remove text boxes
text.remove_text_box(handle);
text.remove_text_edit(edit_handle);

This interface is ideal for retained-mode GUI libraries, but declarative GUI libraries that diff their node trees can still use the imperative interface, calling the Text::remove_* functions when the nodes holding the handles are removed.

Handles can’t be Cloned or constructed manually, so they are unique references that can never be “dangling”.

Text uses slabs internally, so get_text_box_mut() and all similar functions are basically as fast as an array lookup. There is no hashing involved.

§Declarative Mode

There is an optional declarative interface for hiding and removing text boxes. For hiding text boxes declaratively:

// Each frame, advance an internal frame counter,
// and implicitly mark all text boxes as "outdated"
text.advance_frame_and_hide_boxes();
 
// "Refresh" only the nodes that should remain visible
for node in current_nodes {
    text.refresh_text_box(&node.text_box_handle);
}
 
// Text boxes that were not refreshed will be remain hidden,
// and they will be skipped when rendering or handling events.

There’s also an experimental function for removing text boxes declaratively: Text::remove_old_nodes().

This library was written for use in Keru. Keru is a declarative library that diffs node trees, so it uses imperative-mode calls to remove widgets. However, it uses the declarative interface for hiding text boxes that need to be kept hidden in the background.

§Interaction

Text boxes and text edit boxes are fully interactive. In simple situations, this requires a single function call: Text::handle_event(). This function takes a winit::WindowEvent and updates all the text boxes accordingly.

As great as this sounds, sometimes text boxes are occluded by other objects, such as an opaque panel. In this case, handling a mouse click event requires information that the Text struct doesn’t have, so the integration needs to be a bit more complex. The process is this:

For any winit::WindowEvent other than a winit::WindowEvent::MouseInput, this process can be skipped, and you can just call Text::handle_event().

The occlusion.rs example shows how this works.

Structs§

AlignmentOptions
Additional options to fine tune alignment
ColorBrush
RGBA color value for text rendering.
EventResult
Result of handling a window event, providing hints to the user about what actions they should take.
FontWeight
Visual weight class of a font, typically on a scale from 1.0 to 1000.0.
ParleyTextStyle
Unresolved styles.
Rect
A rectangle.
ScrollAnimation
Shared
Data that TextBoxMut and similar things need to have a reference to. Kept all together so that TextBoxMut and similar things can hold a single pointer to all of it.
SplitString
A string that may be split into two parts (used for IME composition).
StyleHandle
Handle for a text style. Use with Text methods to apply styles to text.
Text
Centralized struct that holds collections of TextBoxes, TextEdits, TextStyle2s.
TextBox
A struct that refers to a text box stored inside a Text struct.
TextBoxHandle
Handle for a text box.
TextBoxMut
A struct that refers to a text box stored inside a Text struct.
TextEdit
A non-mutable text edit with access to both inner data and style.
TextEditHandle
Handle for a text edit box.
TextEditMut
A text edit with access to both inner data and style.
TextEditStyle
Style configuration for text edit boxes.
TextEventResult
Result of handling a window event.
TextRenderer
A struct for rendering text and text edit boxes on the GPU.
TextRendererParams
Configuration parameters for the text renderer.

Enums§

Alignment
Alignment of a layout.
AnyBox
Enum that can represent any type of text box (text box or text edit).
AtlasPageSize
Determines the size of texture atlas pages for glyph storage.
FocusUpdate
FontStack
Prioritized sequence of font families.
FontStyle
Visual style or ‘slope’ of a font.
LineHeight
The height that this text takes up. The default is MetricsRelative(1.0), which is the given font’s preferred line height.
NewlineMode
Defines how newlines are entered in a text edit box.
OverflowWrap
Control over “emergency” line-breaking.
ScrollDirection

Constants§

DEFAULT_STYLE_HANDLE
Pre-defined handle for the default text style.

Traits§

IntoAnyBox

Functions§

with_clipboard

Type Aliases§

TextStyle2
Text style.