| Story Library |
The engine generally separates the logical story content - the characters of the text together with formatting such as italic attributes and paragraph indents - from the physical layout - the series of columns the story flows into. Each story can have any number of layouts. For example, you might have a "Page" layout with frames and columns edited by the users, and a "Word Processing" layout with a single fixed, infinitely high scrolling column. Both layouts would share the same logical content.
The compositor pours the logical story into each layout, adding extra information, such as character widths and hyphenation, as it does so. This means there are two kinds of text stream - the original logical text for each story and composed text for each layout. The logical text is the "master" to which editing commands are applied.
The division between logical and layout data occurs through out the engine code.
The engine data is structured as a series of nested containers all ultimately owned by a root. Here's the logical content view: the root has a collection of stories. A story has a collection of (logical) paragraphs. A paragraph has a collection of glyphs.
Here's the layout view: each story has a collection of layouts. A layout has a collection of columns. A column has a collection of the (physical) lines. A line has a collection of formatted glyphs.
A Story::CLogPos represents an arbitrary position in the logical text stream of a story. A Story::CLayPos is the same thing but specific to a particular layout. Each layout has a current selection, which is a range of glyphs nominally described by a pair of CLayPos, and which is used by most editing commands.
See also Story::CRoot, Layout Overview, Page Geometry, Navigation Overview, Logical Classes, Layout Classes.
All user events come first to the application. The text engine has no direct user interface of its own. The application translates operating system user events into engine command objects, which inherit from Story::CCmd. For keyboard events (OnKeyDown() etc) the engine provides Story::CControllerKey which will return an appropriate command, and the application can just forward keyboard messages to it. For mouse events (OnLButtonDown() etc) the engine provides a Story::CVHitTest visitor to help translate mouse coordinates into text positions. For menu events, the application creates the commands directly. Once a command is created, the application adds it to its undo/redo stack and then executes the command on the current selection of the current layout.
The command uses the selection to figure out what text to effect. For example, some commands implement the basic text entry that adds paragraphs and glyphs to a story. Others apply formatting to the selected text using a visitor. Changes to the text content are always made to the logical story/paragraph structures.
The engine recomposes affected text automatically. Each layout has its own Story::CCompositor object, which pours paragraphs into columns one at a time. For each paragraph, it creates a new line object and copies all the glyphs from the paragraph into it, adding layout information, expanding powerfields, bulleted lists etc as it goes. It works out the glyph widths and breaks the line into several shorter lines to fit the width of its current column. Then it adds the lines to the columns. Most of the reflow work is done incrementally, managed by the scheduler object held by the root. the application calls the scheduler when it has some idle time or when it needs an update done immediately. As the engine progresses it creates redraw events, which are sent through an Observer interface which the application provides. The application typically responds by invalidating the window and waits for a normal operating system "paint" request.
Finally, the application redraws in response to "paint" by iterating over the layout a line at a time using another visitor. It requests positioning and font information from the layout as needed.
See also Commands Overview, Composition Overview