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 stylesTextRenderer
- 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 Clone
d 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:
- Run
let topmost_text_box =
Text::find_topmost_text_box()
to find out which text box would have received the event, if it wasn’t for other objects. - Run some custom code to find out which other object would have received the event, if it wasn’t for text boxes.
- Compare the depth of the two candidates. For the text box, use
Text::get_text_box_depth()
. - If the text box is on top, run
Text::handle_event_with_topmost()
(Some(topmost_text_box))
, which will handle the event normally, but avoid looking for the topmost box again. - If the text box, is occluded, run
Text::handle_event_with_topmost()
(None)
.
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§
- Alignment
Options - Additional options to fine tune alignment
- Color
Brush - RGBA color value for text rendering.
- Event
Result - Result of handling a window event, providing hints to the user about what actions they should take.
- Font
Weight - Visual weight class of a font, typically on a scale from 1.0 to 1000.0.
- Parley
Text Style - Unresolved styles.
- Rect
- A rectangle.
- Scroll
Animation - 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.
- Split
String - A string that may be split into two parts (used for IME composition).
- Style
Handle - Handle for a text style. Use with Text methods to apply styles to text.
- Text
- Centralized struct that holds collections of
TextBox
es,TextEdit
s,TextStyle2
s. - TextBox
- A struct that refers to a text box stored inside a
Text
struct. - Text
BoxHandle - Handle for a text box.
- Text
BoxMut - A struct that refers to a text box stored inside a
Text
struct. - Text
Edit - A non-mutable text edit with access to both inner data and style.
- Text
Edit Handle - Handle for a text edit box.
- Text
Edit Mut - A text edit with access to both inner data and style.
- Text
Edit Style - Style configuration for text edit boxes.
- Text
Event Result - Result of handling a window event.
- Text
Renderer - A struct for rendering text and text edit boxes on the GPU.
- Text
Renderer Params - 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).
- Atlas
Page Size - Determines the size of texture atlas pages for glyph storage.
- Focus
Update - Font
Stack - Prioritized sequence of font families.
- Font
Style - Visual style or ‘slope’ of a font.
- Line
Height - The height that this text takes up. The default is
MetricsRelative(1.0)
, which is the given font’s preferred line height. - Newline
Mode - Defines how newlines are entered in a text edit box.
- Overflow
Wrap - Control over “emergency” line-breaking.
- Scroll
Direction
Constants§
- DEFAULT_
STYLE_ HANDLE - Pre-defined handle for the default text style.
Traits§
Functions§
Type Aliases§
- Text
Style2 - Text style.