Led 3.0 Class Library Design Overview

Led is a C++-based class library designed to support the flexible rendering, display, and editing of text. Led isn't merely intended to support traditional text editors. Nor word-processors. Nor even their union. Led is designed to support a far wider array of applications where different sorts of underlying data which contain text are being displayed, and edited, and the desired model for this display/editing is text-editor-like - though quite possibly different in interesting ways.

Led takes full advantage of C++'s expressiveness and flexibility, to achieve both cross-platform capability, and this aforementioned flexibility of having different representations of the underlying text, and for allowing widely varying rendering techniques for that text. Led's flexible, object-oriented design allows the easy separation of event-driven actions, associated with editing, from graphics-oriented, and possibly data-oriented imaging techniques. Which in turn, are separated from the more database-oriented storage of text and embedded information.

Organization of Led

Basics

At the lowest level are some simple utility classes, like a stack buffer class, assertion support, etc. Also, within this LedSupport module are definitions like Led_tChar, and character navigation routines, which support low level infrastructure to allow Led to easily deal with UNICODE, wide character sets, ASCII, and multibyte character sets.

The real crux of the Led class library is organized around a few abstract classes. First, there is the TextStore. A TextStore is an abstraction of something that contains text, and special objects called Markers, which can be used to represent embedded data, or hypertext links, or font style runs. Markers have a left and right edge (named by indexes into the text buffer), and conceptually stick to the text they wrap as the text is modified (edited).

Then there are TextImagers. TextImagers are responsable for imaging to a graphics device the contents of a particular TextStore. A TextImager (except in the degenerate case) is always associated with one TextStore (though a single TextStore can have multiple TextImagers displaying its contents). This long-term relationship allows the TextImagers to keep track of cached data like word wrapping information etc. TextStores have a flexible notification mechanism so that TextImagers get notified when 'interesting' modifications are made to the text (or markers) in the TextStore a TextImager is pointing to.

Next we come to the TextInteractors. TextInteractors are (subclass from) TextImagers which respond to events, and are designed to work with some sort of windowing system. They have a concept of Update events, and having their content data out of sync with that which is displayed in the window (inval/validate region). They also provide support for things like a selection, and cursoring through the selection, and word selection, etc.

Note that TextInteractors are still abstract classes, and know nothing about particular windowing systems, or other windowing class libraries (like MFC). TextInteractors do what can be done generically, without having yet made a choice about these things. TextInteractor mainly serves to collect common code/functionality which can be shared across (for example) MFC/PowerPlant, etc. See the section on Integration with other class libraries/frameworks for more information about support for integrated Led with other class libraries and frameworks like MFC, PowerPlant, Gtk, etc.

PartitioningTextImager is a subclass of TextImager which implements the concept of partitioning of the text into stable regions. Stable regions are those which can be laid out independently of other regions. They cover the text (span all characters in the text), and don't overlap (except at the edges). This class uses Markers to maintain the partition.

Typically you don't need to worry about this class, as the handling of the Partition object and its creation are handled automatically by the TextImager subclasses you will typically using already. The default is to use the LinedBasedPartition

That covers the basic Led concepts/classes. Of course there is much more. Features like support for styled text, and for word-wrapping are special TextImager subclasses. These then get mixed into whichever class-library, or interactor classes you chose to build from. Programming with Led is like working with a super-flexible Erector set. You pick the pieces, and features you want, and can stick them together in typical, or unusual ways. Then (and here's the super part) - you can subclass, and refine the behavior of any of the parts. You can build from scratch various components (TextImagers maybe), and plug them in just like the parts that came with Led.

Feature Oriented subclasses



SimpleTextImager

SimpleTextImager is a very simple, speedy, and light-weight implementation of text imaging. It is ideally suited to situations where very large amounts of text need to be edited (tens of megabytes work fine on ordinary commodity PCs). This is the imager used by the LedLintIt! text editor.

MultiRowTextImager

MultiRowTextImager is a subclass of PartitioningTextImager which allows for its partition elements (typically thought of as paragraphs) to be displayed as multiple rows. This is the basis class for word-wrapping (WordWrappedTextImager), but other sorts of multi-row partitions could easily be supported (broken up be some consideration other than word-wrapping - such as some other kind of syntactic analysis).

WordWrappedTextImager

WordWrappedTextImager is a subclass of MultiRowTextImager which breaks the partition elements at word boundaries. This is typically used in word-processing type applications, and not used in line-editing applications.

StyledTextImager

StyledTextImager is a subclass of TextImager which implements support for styled text (i.e.style runs). This implementation is VERY DIFFERENT, and far more powerful than is typical in text engines. And yet this class's implementation is rather simple, built on top of the powerful marker mechanism. It simply defines a special marker subclass - StyledTextMarker - which is used to do special font setup / and special display, and layout of the text. This can be used to alter the display of text (say making it bold), or to completely ignore the text it bounds in its display (e.g. by drawing a picture embedding). Note that these StyledTextMarkers can overlap arbitrarily. And they can be subclassed.

For example, you could implement an HTML editor by defining special marker objects (subclasses of StyledTextMarker) to keep track of the tag information, and keep it associated with a region of text. And then override the draw/layout methods of the StyledTextMarker to display an arbitrary picture, or to highlight the text in an unusual (say underlining or coloring) way.

StandardStyledTextImager

StandardStyledTextImager is a subclass of StyledTextImager. This is the class which provides a more traditional API for handling styled text. You can specify ranges of text, and apply font styles to them. And there are routines (like GetContinguousFontSelection etc) to help find/identify font style runs, etc. This class is built trivially on top of the StyledTextImager. The rendering of styles and layout issues are all taken care of. This class is merely responsible for preserving a disjoint cover (partition) of styles (StandardStyleMarkers), and coalescing adjacent ones that have the same font info.

WordProcessor

WordProcessor is a subclass of StandardStyledWordWrappedTextInteractor which itself indirectly mixes in ( StandardStyledTextImager, WordWrappedTextImager, and TextInteractor ).

This is one of the more common Led classes you might use. It is what you would subclass from to create a view (or widget) with word-processing capabilities.

Integration with other class libraries

TextImagers and TextInteractors are abstract classes, and know nothing about particular windowing systems, or framework class libraries. In fact, none of the feature-oriented, or other classes mentioned so far have platform specific (except LedGDI's implementation - but not its API) or class library specific code in them. They do what can be done generically, without having yet made a choice about these things. TextInteractor mainly serves to collect common code/functionality which can be shared across (for example) ATL/OWL/MFC/PowerPlant/Gtk/TCL, etc.

Then we have the actual class library wrapper classes. Led must somehow know about the event system, and windowing system, etc, in order to display text, in the right place, and in order to receive mouse (and other) events, and to react to them. You can provide this connection between the OS/Windowing system yourself. Or you can use these pre-packaged integration classes which are provided for a few common application class libraries. In Led 3.0 - we explicitly support:

In addition to providing this hooking into the display/event system, these class-library-integration classes also provide hooks/APIs to make Led appear most naturally within the context of that class library.

In some class libraries that don't utilize any abstract-class mechanism, like MFC, Led mimics the API the CEdit, and CEditView classes provide, so that it is still fairly easy to recompile MFC code built to use one of these text engines, and instead use Led.




Return to Led Page Return to Led Class Library Design Index
Last Updated 2001-10-19