Textended Updates & Layout Engine Details
Textended-edit got improvements to it's layouting and rendering. 1-2 more short commits and it will support overlaying of documents over each other.
A programming tool remains incomplete if it never faces any use. For this reason I will write a computer game using textended-edit and python during the next February. The source code for the project will appear in this blog and in my github account.
It's starting to be relevant to document how the layout engine functions in my editor, so I'm doing it in this blogpost. The details may still change later on, but you'll get an idea of what it was today by reading on.
Compositor & Rendering layers
The rendering is carried out by OpenGL. GPU accelerated rendering is fast, but individual calls done by the driver are slow. I can render thousands of textured rectangles to the screen, as long as I'm doing it with a single draw call. Later on more optimizations are necessary, but first optimizations most likely affect the python scripts running layouting and not the rendering scheme.
I've organized this to Rendering Layers. Each one contains it's own texture atlas, shaders, vertex buffers to function. These layers are filled with rectangles and then rendered one layer at a time. I'm rendering fonts as rectangles using a signed distance field shader. For small graphical content I'm using rendering layer that combines a texture atlas and a vertex buffer. The different kind of layers can be added and removed as needed.
The layers are filled up by the compositor, which traverses a tree consisting of boxes. For every box it figures out the screen position and adds it to the respective layer.
The editor displays it's documents as a list of boxes, consisting of more boxes and some glue. Both concepts borrowed from TeX. Box is an any renderable element and has width, height, depth. Glue is used to space them apart and may stretch or shrink.
Any list of boxes and glue can be packed horizontally or vertically. During packing you may give to_dimen -parameter which adjusts the glue to fit the box to the given dimension. Once the box has been created, it's not resized or adjusted any more.
The glue can be configured to take priority during streching or shrinking. Such called 'fill' -glue can be used for aligning or repositioning elements.
Every box has a shift -parameter, which is recognised by the context. In horizontal boxes it shifts the box vertically. In vertical boxes it shifts them horizontally. This feature can be used for indenting or aligning elements.
Additionally there's a field for layout control, explained below.
Boxes, Glue are created by layouting functions and objects.
Configurable Layout Functions
The layouting functions take in a document node and an environment, and produce appropriate boxes and glue as a list considered as tokens. The tokens can be relayed to an another function to pack them up. The layouting functions are applied to nodes by mapping objects, which returns them to other layouting functions.
Layout functions determine the shape and appearance of every node on the screen.
Mappings take a node and maps it to a list of tokens. They're loosely invoked by the layouting functions themselves. Initially a mapping is generated for the whole document node, then passed to the layouting function.
The mappings can be cached for subsequent access. It allows partial rebuilding of the box model. Additionally the mappings are used for displaying selection.
The document consists of symbols, lists, strings and byte blobs. Everything except symbols are annotated with a string label that can be identified from an another document.
The editor represents a single scrollable frame for a document. If interaction spawns a minibuffer, it is associated to the editor the user was in. The editor contains everything to render and manipulate a document. It can also overlay other documents over the document it holds with bridges.
Bridges and Layers
Given a document and a function to read the document, bridges can be created over the given document and the document viewed by the editor.
A bridge is an object positioned inside the document, which contains a mapping and a rendered part of the overlayed document.
For clicking around in the document, leafmost boxes contain a source reference to where it's generated from in the document. This is sufficient because the navigation is bottom-up based. Larger, non-leaf selections are rendered with the help of mappings, which point out every box that was created to represent a node at a point.
Before the last update I had explicit objects for carets in my box mode. I switched to implicit representation of carets because the explicit carets appear too easily in the customizable part of the layouting. Unlike boxes and glue they were mostly invisible objects except in the structures. Many modifications would simply scramble them up, ceasing their proper function.
I have also studied the source code of TeXmacs, a text editor that shared similarities with my project, notably the TeX -inspired layouting. Some of the approaches and ideas seemed so good that I can apply them here.
Unfortunately I'm noticing the file format isn't stable. I will use it to test it this February. I may have to adjust it later to accomodate for variant uses of the editor.
I believe this project may get to something. But I'll know it only after I've developed programs in it.