Story Library
Home   Hierarchy   Classes   Files   Functions   Modules   Pages  

Glyph and Paragraph Attributes, and Styles

Glyphs and paragraphs uses parallel schemes to describe their formatting. What I say about glyph attributes here applies analogously to paragraph attributes.

Attributes

Glyph formatting information is represented by Story::CGlyphAtts, which is a collection of attributes. The attributes are indexed by C++ enums; each different type of attribute has its own enum type declared in GlyphAttsTypes.h. For example, Story::GlyphBool::IsItalic and Story::GlyphBool::IsStrikeOut are boolean attributes and Story::GlyphInt::Height is an integer attribute. This arrangement gives strong compile-time checking of indexes while allowing them to be manipulated in uniform ways.

The engine has reserved some space for the application to define attributes of its own. These go between ClientBegin and ClientEnd of the appropriate enum. The application is expected to define its own constants that map into this range, in one of its own header files, eg:

    // ApplicationTypes.h
    const Story::GlyphInt::Type MyFirstAtt = Story::GlyphInt::ClientBegin+0;
    const Story::GlyphInt::Type MySecondAtt = Story::GlyphInt::ClientBegin+1;

This makes MyFirstAtt a compile-time constant of the correct type and value, that can be used like Story::CGlyphAtts::Get(MyFirstAtt), etc.

The amount of space is set by some defines in Config. Changing config values, or adding new attributes outside of the ClientBegin/End ranges, would of course mean recompiling the text engine source. Little else is needed, though; the text engine should resize its data structures to fit.

Later versions of the text engine may change the number of built-in attributes, which will mean a change to the ClientBegin values. You probably won't need to store the index constants in a file, but if you do, you should be prepared to remap them when reading old files. The engine already does this for its own archive format. See CDeltas<Key,Value,end>::Serialize( CArchive &ar, int clientBegin, int clientEnd ).

During file import, the engine ignores unknown attributes and gives missing ones their default values, so adding or removing an attribute does not itself make old files unreadable. Changing the meaning of an attribute, however, will.

If you need an attribute more complex than bool, int, float or CString, you use the GlyphAtt enum and create a subclass of Story::CAtt. Story::CAtt is an abstract class which declares the comparison, hashing, sharing, cloning, immutability and serialization which the engine needs. Story::CListAtt is an example of a CAtt subclass for paragraphs.

Deltas

A collection of changes to a set of attributes is called a delta and represented by Story::CGlyphAttsDelta, and can be applied to the current selection with the Story::CCmdApplyGlyphDelta command. The function Delta() provides an easy way to make simple deltas, so

    new CCmdApplyGlyphDelta( Delta( GlyphBool::IsItalic, true ) );

creates a command which will make the selected text italic. You can make more complex deltas by creating a CGlyphAttsDelta explicitly and adding each change to it:

    CPtr<CGlyphAttsDelta> pDelta = new CGlyphAttsDelta; 
    pDelta->Add( GlyphBool::IsItalic, true ); 
    pDelta->Add( GlyphInt::Weight, 20 ); 
    new CCmdApplyGlyphDelta( pDelta );

creates a command which changes both weight and the italic style. You can also make a delta as the difference of two CGlyphAtts.

Styles, Flattened attributes

A Story::CStyle is essentially a named delta. Styles can be based on other styles, which means all their changes will be applied in turn, recursively. All the styles available to a document are stored in a Story::CStyleSheet object, in the Story::CRoot. Styles are referred to by name and looked up in the style sheet dynamically, so changing a style sheet can change all styles at once.

A Story::CGlyphAtts is actually a delta plus the name of a style. The style describes the base formatting and the delta describes any changes applied on top. The combined effect of all those deltas is represented by a Story::CGlyphFlat, which Story::CGlyphAtts also stores, and which provides a fast, simple, plain representation of the final glyph's attributes.

Ranges

Finally, a Story::CGlyphAttsRange represents the attributes of a range of text. It consists of the Story::CGlyphAtts for the glyph at the start of the range, plus a delta describing the attributes which differ across the range. These are mainly used for providing feedback in the user interface. To check a menu option you would use code like:

    enum { Unchecked, Checked, Indeterminate }; 
    void CPagePlusView::OnUpdateItalic( CCmdUI* pCmdUI )  
    { 
        GlyphBool::Type att = GlyphBool::IsItalic; 
        CSelection *pSelection = GetCurrentSelection(); 
        CPtr<CGlyphAttsRange> pRange = pSelection->GetGlyphAttsRange(); 
        int check = pRange->Contains( att ) ? Indeterminate : 
                pRange->Get( att ) ? Checked : Unchecked; 
        pCmdUI->SetCheck( check ); 
    }

Summary

These are the main attribute classes and files.
  1. GlyphAttsTypes.h - Defines attribute types and names.
  2. Story::CGlyphAttsFlat - Simple collection of all attributes.
  3. Story::CGlyphAttsDelta - Set of changes to glyph attributes.
  4. Story::CGlyphAtts - A style name and a delta, plus a Flat for speed.
  5. Story::CStyle - A named, user-defined delta.
  6. Story::CStyleSheet - Dictionary in which style names are looked up.
  7. Story::CAtt - base class for custom attributes.
See also Attribute Classes.


Serif Story Documentation.
This content last built on 30 Oct 2003.