
I. TERMS AND CONCEPTS
~~~~~~~~~~~~~~~~~~~~~
Index Space:
 
Each text element occupies a certain range in index space. There is
exactly one cursor position per indexnumber. A string object of length
10 therefore occupies an interval of length 10 in index space. Indices
are not non-ambiguous, since elements are nested. A paragraph which
spans the interval 0..30, might contain a HBox which ranges from 5 to
9.  The index at which an object begins is always denoted by
i0. Intervals relative to i0 are usually denoted i1..i2, j1..j2 or
k1..k2.

Locality:
 
The text elements form a nested tree structure. All elements except
the root have a parent element and most elements contain child
elements. An element is only responsible for laying out its direct
childs. It has no information about its parents. Elements containing
other elements are usually derived from the class Container, and
elements without childs from Glyph.

Context:
Global informations as font, color and alignment are stored in the
context. Each object has a reference to context.

Glyphs:
Are special text elements which must have length 1. 

Partial typesetting:
I am lazy and so should be every good program. After a local change,
for example by insertion or removal, it is not necessary to redraw the
whole text. Instead it is sufficient to redraw those parts which did
change. Since drawing text in sketch is a bit slow, partial
typesetting gives a great improvement of speed. Changed regions are
collected in area1 and area2. In area1 the regions with their old
positions are stored and in area2 the new ones. The total area which
has to be updated can than be restricted to the area given by the
union of area1.bbox() and area2.bbox().
 
I have been a bit reluctant to implement partial typesetting because
it complicates the code considerably. For many methods additional
arguments area1 and area2 now have to be given. 

Boxes:
The essential concept of TeX and also of MyWord are boxes. A box
describes an area in screen coordinates which is used for type-
setting. Elements have a method GetBoxes() which returns an intmap
describing the boxes as ((i1, i2, box1), (i3, i4, box2), ...). For
example a "String" element breaks its content into words and returns a
box for each word. A 'word' is the smallest substring which is typeset
in a uniform style and does not contain spaces (only at the end).

The entries in the box map and the content map do not have to match!
It is therefore possible that len(elem) > len(elem.boxes). On the
other hand, len(elem) == len(elem.GetBoxes()) must be fullfilled.

Currently, boxes are decribed by the tuple of five numbers:

        (width, height, depth, penalty, delta)


     (0,h)___________________(w,h)_______HEIGHT
         |                   |
         |                   |
         |                   |
         |                   |
     (0,0)-------------------(w,0)_____BASELINE
         |                   |
    (0,-d)-------------------(w,-d)_______DEPTH


         |-WIDTH-------------|


    - Penalty is the badness of breaking after the box. Can be
      positive (avoid breaking) or negative (favor breaking).
    - Delta denotes how the width shrinks if the line is broken
      after the box. It can be positive (e.g. when the last char
      is a space) or negative (a hyphen sign has to be drawn).
    - Future extensions might contain the line height and a break
      function.  

Method conventions:
Most methods have the parameters i0, i1, i2, meaning that the method
should be applied from i0+i1 to i0+i2. i0 is the beginning of the text
element in absolute coordinates.

The return value of all methods which can change an element is always
a tuple (stuff, area1, area2), where stuff is an intmap. The parent
object replaces the element by stuff.values().

Indentation:
The concept for indentation is taken from Abiword. The indent level is
determined by the number of tab-glyphs at the beginning of a line.
Changing the level is done by inserting or removing tabs.

Virtual Elements:
A virtual is similar to a text element. The difference is that virtuals 
do not contain any data, or occupy any region in index space. They 
usually represent stuff which is not user editable, e.g. line numbers, 
data fields, ...

II. RULES
~~~~~~~~~

Elements in the hierarchy must fulfill the following rules.

1. Conservation of index numbers. For example, this means that
   elem.Insert(i,e) increases len(elem) exactly by len(e).

   n1 = len(elem)
   n2 = len(e)
   len(elem.Insert(i,e)) == n1+n2

2. Boxes are not allowed to have holes:

   boxes = elem.GetBoxes(i0)
   assert boxes.cum_width() == len(boxes) 

   and of the same length as the element:
   assert len(boxes)== len(elem)

3. Reversibility of Fillin and Takeout. 

   elem is preserved here:
   elem.Fillin(i1, elem.Takeout(i1, i2))

   and also here:
   n = len(e)
   elem.Insert(i, e)
   elem.Takeout(i, i+n)

4. Elements which are returned by Takeout or Copy have to be
   updated. They are not updated upon insert.

5. Each element can be only once in the hierarchy. This could be
   changed in later versions. For now it is convenient, and I do not
   care about memory consumption.
   


III. CONVENTIONS
~~~~~~~~~~~~~~~~

- Methods which are called from outside of the object are in
  CapitalLetters. lower_case or _lower_case names are only used
  internally.

- Debugging text elements turned out be quite a pain. Therefor each
  element must have a Method 'Check' which performs a test. If the
  check succeeds the element must be 100 % o.k. The check must be
  performed and the end of a change, i.e. at the end of Copy, Takeout
  and Fillin. Returned elements must be checked. The check can be
  turned off by setting _debug to 0 in MyWord.__init__.py .

IV. ALGORITHMS
~~~~~~~~~~~~~~
1. Finding the next word / the previous word

   next(i): 
     - set last_is_space to None
     - start at j=i
     - loop:
         - if last_is_space == 1 and at j is no space and j>i, return j
         - set last_is_space to 0 or 1
         - increment j

   prev(i): 
     - set last_is_space to None
     - start at j=i
     - loop:
         - if last_is_space == 0 and at i is a space, return j+1
         - set last_is_space to 0 or 1
         - decrement j

2. Takeout
For the Takeout operation there are two absolute index positions, the
index in the old space which is denoted as i0, and the one in the new
space, k0. Using i1 and i2 for the interval which is to be cut out (in
local coordinates), we assign the following variables prior the cutting:

k0 = i0+min(0, i1)      --- the elements origin in new coordinates
k1 = max(0, i1)         --- the local start of the cut in new coordinates
k2 = min(len(self), i2) --- the local end of the cut in new coordinates

It has to be notes, that i1, i2 are only allowed to be shifted,
i.e. something as i1 = max(0, i1) is not allowed. Passing i1, i2 to
childs in th econventional way as child.Takeout(i0+j1, i1-j1, i2-j1,
... ) would be wrong.

The cutout gets its own context and therefore its own coordinate
system having the origin at i0+i1 of the old system.

The cutout part of an element starts at the absolute index
max(0, -i1) in the index space of the cutout context.

