000

What you should know first

This is about EnFrame's class layoutstream and its default plain-text renderer.

The layout is composed as you write certain template function identifiers or else class constructors if arguments are needed. Of course instance references will work too. Inbetween them, you write data to the stream that will first be formatted by std::basic_ostream.

UTF-8 is supported, and neither multibyte character sequences nor ANSI codes add to line width character counts. More use-case-specific input encodings can be added.

Go to the reference manual.

The class layoutstream

The stream objects used to define a layout while you stream output, are of class layoutstream. Layoutstream is a template class with a single template parameter which poses no trouble for autodeduction when the constructor is called with a single argument, which should be, well, the actual stream object that represents the destination of the output after performing the layout. What happens is this: a reference to the destined stream is kept in the layoutstream object, which acts as a layer on top of the stream object to which it holds a reference. But when you stream to a ‘layoutstream’ object, you do stream to a stream object. Only, this layoutstream stream object performs layouting of the textual data it is sent or that it produces after formatting input. The text actually ends up in a hierarchy of stream buffers, which get composited later on, at the time the layoutstream object receives a std::flush iomanipulator.

001

Blocks

The stream buffers are actually the base classes of layout elements. There are different layout element classes for each of the manipulators of the layout, sometimes there are even multiple different element classes needed to represent one layout concept. You shouldn’t worry too much about them, as they are only an implementation detail. But what you should know is to differentiate between two important distinct types of element classes: an element is either a block-element or else a flow-element. Block elements are always representative of a rectangular region of layout. They can have box-model padding/border/margin values set for each side of their bounding rectangle independently, just like you can with CSS in a webbrowser. In the default plain-text rendering, block-elements that aren’t empty can be flooded with fill characters (whitespace) to make them take up the place they represent in the final, composited output. Wherever the insert position is in the visualisation of the intended output to render, inserting a block-element there makes the upper-left corner be at that precise position, and the block is guaranteed to extend rightward first and then downward vertically. After a block-element is rendered, the new insert position is adjacent to the right of the bottom-right corner of the bounding rectangle.

Not blocks

Imagine you are positioned after insertion of a block-element. A flow-element then, is most easily comprehended as an element that, whenever following a block, will have a part to the right of the block and, after a newline within the flow-element, a part underneath that same block. Flow-elements have carriage return margins equal to the position following the left-sided padding of the nearest block parent. So, the last block element that hasn’t yet been closed always provides your left margin. Inside block elements, it’s safe to assume are always flow elements, except when specifically requesting to nest another block element. Which layout elements are which is found in the reference.