Go to page:

Search:   Help

Developers' side bar

Selected categories


Shared groups



Categories: Development, Misc
<< | Page list | >>

LyX's internal representation and iterators

Inset structure.

The following image is intended to understand how data in LyX is internally represented:

Inset Structure

[Note: this pictures a somewhat simple situation (It doesn't have multiple paragraphs nor nor multiple idx inside one inset, but one could say that these are details ;-)]

On top we have a snapshot showing the normal LyX editing window with a series of nested "Note" insets and some text. On bottom we have a representation of LyX's internal data structure: it is an ordered tree. square nodes represent insets, circle nodes represent normal chars, and parallelograms represent paragraph "end positions".

There is a root InsetText (Inset0 in the bottom image), that contains everything else. It is a member of Buffer::Impl (you can find it in Buffer.cpp). Inset0 node is sort of an exception and *not* a valid cursor position, the first valid one is "A".


DocIterator is a class that serves to point to a specific node in the LyX tree, along with the stack of parents up to the root node.

For example, the stack of greyed nodes in the figure form a DocIterator pointing to the cursor position (before the D)

DocIterator::forwardPos should move "logically" between nodes in the tree exactly as cursor-right in the lyx window, in this order:

A, Inset1, B, Inset3, C, END3, END1, Inset2, Inset4, D, Inset5, E, END5, F, END4, END2, G, END0


InsetIterator is a "proxy class" derived from DocIterator and implementing operator++ as DocIterator::forwardInset. This action jumps between valid cursor positions that happend to be insets, in this order in the example:

Inset1, Inset3, Inset2, Inset4, Inset5


ParIterator is another "proxy class" derived from DocIterator and implementing operator++ as DocIterator::forwardPar. This action jumps between valid cursor positions that happend to be the first position of a paragraph. In the example it follows this order:

A, B, C, Inset4, D, E

There are 6 positions because there are 6 paragraphs: One for each one of the 5 Note insets plus one for the root inset.

Unfortunately operator!=(ParIterator &, ParIterator &) is implemented with operator!=(DocIterator &, DocIterator &) that gives false if the positions are different, even if the pars are the same. So ultimately it's a bug in operator!=(ParIterator &, ParIterator &) I'd say (nevertheless, I would be reluctant to change it, because I fear that some part of the code could rely on this "bug").


If the <---> means a refernce or a pointer then it's more something like this:

BufferList (N Buffer)


Application (this is the frontend really, should probably be renamed).

   LyXView-1 (M1 WorkAreas, M1 <= N)
   |  |
   |  <tab-widget>
   |     | (many)
   |     WorkArea-1
   |       |
   |       BufferView <-----------> Buffer-c
   |         |
   |         Cursor
   LyXView-2 (M2 WorkAreas, M2 <= N, M2 independent of M1)

(see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg125246.html)


The anchor_ref_ is really the anchor paragraph of the BufferView from which all other paragraphs are positioned.

The offset_ref_ is basically the offset position of the anchor paragraph from the top screen (and that is 0). In effect, offset_ref_ is just the opposite of the paragraph position on screen and I am really tempted to rename that.

(see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg127460.html)

ParagraphMetrics.position_, ascent and discent

>Ok, they're y coords, they represent the paragraph vertical >dimension and position, but I couldn't really figure out what >are they relative to,

All inset and paragraph coords are absolute WRT the screen. (0,0) is the top left corner.

>and why I always see in the code >*) position()-ascent() >*) position()+descent()

  • Position of a paragraph is the baseline of its first row.
  • position()-ascent() is the where the paragraph drawing effectively start.
  • position()+descent() is the where the paragraph drawing effectively end.
position()-ascent()  ________________________
position()           XXXXXXXXXXXXXXXXXXXXXXXX       
position()+descent() ^^^^^^^^^^^^^^^^^^^^^^^^    


Mailer Interface

The connection lies in the Mailer interface: Every inset that needs to pass data between kernel and frontend has a mailer, and this mailer exchanges the data in the same format that is used in .lyx files and naturally uses the same classes to read and write this data (in this case InsetCommandParams). (http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg127904.html)

Getting to the containing paragraph

I have a cursor inside an inset. How can I easily get to the paragraph containing this inset? What I really want is to get to the character which represents the inset I'm in, so that I can get its font.

If you have access to the Cursor this information is in the previous CursorSlice. That is:

        int current_slice_index = cur.depth() - 1;
        CursorSlice const & previous_slice = cur[current_slice_index - 1];

        pos_type char_previous_to_inset_pos = previous_slice.pos() - 1;

Just to make sure I understand: the current_slice_index depth is "cur.depth() - 1" (and not cur.depth()) because the depth is 1-based, whereas I need a 0-based index?

Yes, depth() is just size() actually, look at DocIterator.h:

        /// how many nested insets do we have?
        size_t depth() const { return slices_.size(); }


latex_language variable


paragraph control

 p. width - http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg131650.html
 Detecting paragraphs structure changes - http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg131652.html

Update and dispatch


Rowpainter width

http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg134832.html > So, for my own education: width_ is the width of the row, counting the > margins or not counting them?

width_ is the width of the Text including the margins. I was wrong when I said that leftMargin() should be taken into account. It is instead because of TEXT_TO_INSET_OFFSET.

TextClass handling

http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg135140.html ...It reflects a change in TextClass handling that is important to understand.

The point, as Stefan says, is that anything that belongs to a text class needs to be "preserved" by keeping a TextClassPtr around. These are boost:shared_ptr's. The need for this is a consequence of the modules code. TextClass objects do not now represent layout files but rather the result of incorporating whatever modules the user loads. So they are unique to documents and can even change if the user loads a new module. So you cannot just represent a TextClass by an index into a list of layout files, as we used to. Rather, a TextClass is just an object, and it is inclined to disappear when the document that created it disappears. Now the problem is that, if you cut something, the cut material needs to know about its TextClass, since that is what defines its layout, etc. So the TextClass needs to "stay with" what's cut, since the document itself may be closed. And all references to layout-related stuff in, say, an inset need to go via the corresponding TextClassPtr.

There may be an argument here for doing things differently, a way Abdel suggested a while ago, namely, that we keep every TextClass we ever generate in (say) a std::vector and refer to them via indices into this vector. This change would not be terribly hard to make: It's just a matter of redefining TextClassPtr. The downside to this is that you could end up with a lot of TextClass's in memory that don't need to be there. But it would prevent this kind of problem.

InsetCommandParams design


Category: Development, Misc

Edit - History - Print - Recent Changes - All Recent Changes - Search
Page last modified on 2012-03-15 00:11 CET