]> git.lyx.org Git - lyx.git/blob - src/text.C
white-space changes, removed definitions.h several enum changes because of this,...
[lyx.git] / src / text.C
1 /* This file is part of
2 * ====================================================== 
3
4 *           LyX, The Document Processor
5 *        
6 *           Copyright (C) 1995 Matthias Ettrich
7 *           Copyright (C) 1995-1998 The LyX Team.
8 *
9 * ====================================================== */
10
11 #include <config.h>
12 #include <cstdlib>
13 #include <cctype>
14
15 #ifdef __GNUG__
16 #pragma implementation "table.h"
17 #endif
18
19 #include "layout.h"
20 #include "lyxparagraph.h"
21 #include "lyxtext.h"
22 #include "support/textutils.h"
23 #include "lyx_gui_misc.h"
24 #include "lyxdraw.h"
25 #include "gettext.h"
26 #include "bufferparams.h"
27 #include "buffer.h"
28 #include "lyxscreen.h"
29 #include "minibuffer.h"
30 #include "debug.h"
31
32 static const int LYX_PAPER_MARGIN = 20;
33
34 extern int mono_video;
35 extern int reverse_video;
36 extern int fast_selection;
37 extern BufferView * current_view;
38 extern int UnlockInset(UpdatableInset * inset);
39
40 // ale070405
41 extern int bibitemMaxWidth(LyXFont const &);
42
43 // dnaber 1999-02-02
44 extern MiniBuffer * minibuffer;
45
46 int LyXText::SingleWidth(LyXParagraph * par,
47                          LyXParagraph::size_type pos)
48 {
49         char c = par->GetChar(pos);
50         return SingleWidth(par, pos, c);
51 }
52
53
54 int LyXText::SingleWidth(LyXParagraph * par,
55                          LyXParagraph::size_type pos, char c)
56 {
57         LyXFont font = GetFont(par, pos);
58
59         // The most common case is handled first (Asger)
60         if (IsPrintable(c)) {
61                 return font.width(c);
62
63         } else if (IsHfillChar(c)) {
64                 return 3;       /* because of the representation
65                                  * as vertical lines */
66
67         } else if (c == LyXParagraph::META_FOOTNOTE ||
68                    c == LyXParagraph::META_MARGIN ||
69                    c == LyXParagraph::META_FIG ||
70                    c == LyXParagraph::META_TAB ||
71                    c == LyXParagraph::META_WIDE_FIG ||
72                    c == LyXParagraph::META_WIDE_TAB ||
73                    c == LyXParagraph::META_ALGORITHM) 
74         {
75                 string fs;
76                 switch (c) {
77                 case LyXParagraph::META_MARGIN:
78                         fs = "margin";
79                         break;
80                 case LyXParagraph::META_FIG:
81                         fs = "fig";
82                         break;
83                 case LyXParagraph::META_TAB:
84                         fs = "tab";
85                         break;
86                 case LyXParagraph::META_ALGORITHM:
87                         fs = "alg";
88                         break;
89                 case LyXParagraph::META_WIDE_FIG:
90                         fs = "wide-fig";
91                         break;
92                 case LyXParagraph::META_WIDE_TAB:
93                         fs = "wide-tab";
94                         break;
95                 case LyXParagraph::META_FOOTNOTE:
96                         fs = "foot";
97                         break;
98                 }
99                 font.decSize();
100                 font.decSize();
101                 return font.stringWidth(fs);
102         } 
103    
104         else if (c == LyXParagraph::META_INSET) {
105                 Inset *tmpinset= par->GetInset(pos);
106                 if (tmpinset)
107                         return par->GetInset(pos)->Width(font);
108                 else
109                         return 0;
110
111         } else if (IsSeparatorChar(c))
112                 c = ' ';
113         else if (IsNewlineChar(c))
114                 c = 'n';
115         return font.width(c);
116 }
117
118
119 /* returns the paragraph position of the last character in the 
120  * specified row */
121 LyXParagraph::size_type LyXText::RowLast(Row * row)
122 {
123         if (row->next == 0)
124                 return row->par->Last()-1;
125         else if (row->next->par != row->par) 
126                 return row->par->Last()-1;
127         else 
128                 return row->next->pos - 1;
129 }
130
131
132 void LyXText::Draw(Row * row, LyXParagraph::size_type & pos,
133                    LyXScreen & scr, int offset, float & x)
134 {
135         char c = row->par->GetChar(pos);
136
137         if (IsNewlineChar(c)) {
138                 pos++;
139                 // Draw end-of-line marker
140
141                 LyXFont font = GetFont(row->par, pos);
142                 int asc = font.maxAscent();
143                 int wid = font.width('n');
144                 int y = (offset + row->baseline);
145                 XPoint p[3];
146                 p[0].x = int(x + wid*0.375); p[0].y = int(y - 0.875*asc*0.75);
147                 p[1].x = int(x);             p[1].y = int(y - 0.500*asc*0.75);
148                 p[2].x = int(x + wid*0.375); p[2].y = int(y - 0.125*asc*0.75);
149                 scr.drawLines(::getGC(gc_new_line), p, 3);
150                 
151                 p[0].x = int(x);             p[0].y = int(y - 0.500*asc*0.75);
152                 p[1].x = int(x + wid);       p[1].y = int(y - 0.500*asc*0.75);
153                 p[2].x = int(x + wid);       p[2].y = int(y - asc*0.75);
154                 scr.drawLines(::getGC(gc_new_line), p, 3);
155                 return;
156         }
157
158         LyXFont font = GetFont(row->par, pos);
159         LyXFont font2 = font;
160
161         if (c == LyXParagraph::META_FOOTNOTE ||
162             c == LyXParagraph::META_MARGIN ||
163             c == LyXParagraph::META_FIG ||
164             c == LyXParagraph::META_TAB ||
165             c == LyXParagraph::META_WIDE_FIG ||
166             c == LyXParagraph::META_WIDE_TAB ||
167             c == LyXParagraph::META_ALGORITHM) {
168                 string fs;
169                 switch (c) {
170                 case LyXParagraph::META_MARGIN:
171                         fs = "margin";
172                         /* draw a sign at the left margin! */ 
173                         scr.drawText(font, "!", 1, offset + row->baseline,
174                                      (LYX_PAPER_MARGIN - font.width('!'))/2);
175                         break;
176                 case LyXParagraph::META_FIG:
177                         fs = "fig";
178                         break;
179                 case LyXParagraph::META_TAB:
180                         fs = "tab";
181                         break;
182                 case LyXParagraph::META_ALGORITHM:
183                         fs = "alg";
184                         break;
185                 case LyXParagraph::META_WIDE_FIG:
186                         fs = "wide-fig";
187                         break;
188                 case LyXParagraph::META_WIDE_TAB:
189                         fs = "wide-tab";
190                         break;
191                 case LyXParagraph::META_FOOTNOTE:
192                         fs = "foot";
193                         break;
194                 }
195                 font.decSize();
196                 font.decSize();
197           
198                 /* calculate the position of the footnotemark */
199                 int y = (row->baseline - font2.maxAscent() 
200                          + font.maxAscent());
201           
202                 font.setColor(LyXFont::INSET);
203
204                 float tmpx = x;
205
206                 /* draw it and set new x position */
207                 x += scr.drawString(font, fs, offset + y, int(x));
208
209                 scr.drawLine(gc_foot, offset + row->baseline,
210                              int(tmpx), int(x - tmpx));
211           
212                 pos++;
213                 return;
214         } else if (c == LyXParagraph::META_INSET) {
215                 Inset *tmpinset = row->par->GetInset(pos);
216                 if (tmpinset) 
217                         tmpinset->Draw(font, scr, offset + row->baseline, x);
218                 pos++;
219                 return;
220         }
221
222         /* usual characters, no insets */
223
224         // Collect character that we can draw in one command
225
226         // This is dirty, but fast. Notice that it will never be too small.
227         // For the record, I'll note that Microsoft Word has a limit
228         // of 768 here. We have none :-) (Asger)
229 #if 0
230         static char textstring[1024];
231 #else
232         // Ok. I am the first to admit that the use of std::string will be
233         // a tiny bit slower. However, I claim that this slowdown is so
234         // small that it is close to inperceptive. So IMHO we should go
235         // with the easier and clearer implementation. And even if 1024
236         // is a large number here it might overflow, string will only
237         // overflow if the machine is out of memory...
238         static string textstring;
239         textstring = c;
240         ++pos;
241 #endif
242
243         LyXParagraph::size_type last = RowLast(row);
244 #if 0
245         // Prevent crash in the extremely unlikely event
246         // that our array is too small
247         if (last > pos+1020) last = pos + 1020;
248
249         textstring[0] = c;
250         pos++;
251
252         int i = 1;
253 #endif
254         
255         while (pos <= last &&
256                static_cast<char>(c = row->par->GetChar(pos)) > ' ' &&
257                font2 == GetFont(row->par, pos)) {
258 #if 0
259                 textstring[i++] = c;
260 #else
261                 textstring += c;
262 #endif
263                 ++pos;
264         }
265 #if 0
266         textstring[i] = 0; 
267 #endif
268         float tmpx = x;
269
270         // If monochrome and LaTeX mode, provide reverse background
271         if (mono_video && font.latex() == LyXFont::ON) {
272                 int a= font.maxAscent(), d= font.maxDescent();
273 #if 0
274                 scr.fillRectangle(gc_copy, int(tmpx), offset + row->baseline-a,
275                                   font.textWidth(textstring, i), a+d);
276 #else
277                 scr.fillRectangle(gc_copy, int(tmpx), offset + row->baseline-a,
278                                   font.textWidth(textstring.c_str(),
279                                                  textstring.length()), a+d);
280 #endif
281         }
282 #if 0
283         /* Draw text and set the new x position */ 
284         x += scr.drawText(font, textstring, i, offset + row->baseline, 
285                           int(x));
286 #else
287         /* Draw text and set the new x position */ 
288         x += scr.drawText(font, textstring.c_str(), textstring.length(),
289                           offset + row->baseline, 
290                           int(x));
291 #endif
292         
293         /* what about underbars? */
294         if (font.underbar() == LyXFont::ON && font.latex() != LyXFont::ON) {
295                 scr.drawLine(gc_copy, offset + row->baseline + 2,
296                              int(tmpx), int(x - tmpx));
297         }
298
299         // If we want ulem.sty support, drawing
300         // routines should go here. (Asger)
301         // Why shouldn't LyXFont::drawText handle it internally?
302 }
303
304
305 /* Returns the left beginning of the text. 
306 * This information cannot be taken from the layouts-objekt, because in 
307 * LaTeX the beginning of the text fits in some cases (for example sections)
308 * exactly the label-width. */
309 int LyXText::LeftMargin(Row * row)
310 {
311    LyXFont labelfont;
312    LyXParagraph * newpar;
313    Row dummyrow;
314    LyXLayout const & layout = textclasslist.Style(parameters->textclass, row->par->GetLayout());
315    
316    string parindent = layout.parindent; 
317
318    /* table stuff -- begin*/ 
319    if (row->par->table)
320       parindent.clear();
321    /* table stuff -- end*/       
322
323    int x = LYX_PAPER_MARGIN;
324
325    x += textclasslist.TextClass(parameters->textclass).
326      defaultfont().signedStringWidth(textclasslist.TextClass(parameters->textclass).leftmargin());
327
328    if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)  {
329         LyXFont font(LyXFont::ALL_SANE);
330         font.setSize(LyXFont::SIZE_SMALL);
331         x += font.textWidth("Mwide-figM", 10) + LYX_PAPER_MARGIN/2;
332    }
333
334    /* this is the way, LyX handles the LaTeX-Environments.
335     * I have had this idea very late, so it seems to be a
336     * later added hack and this is true */ 
337    if (!row->par->GetDepth()) {
338       if (!row->par->GetLayout()) {
339          /* find the previous same level paragraph */
340          if (row->par->FirstPhysicalPar()->Previous()) {
341             newpar = row->par->DepthHook(row->par->GetDepth());
342             if (newpar && textclasslist.Style(parameters->textclass, newpar->GetLayout()).nextnoindent)
343                parindent.clear();
344          }
345       }
346    }
347    else {
348       /* find the next level paragraph */ 
349       
350       newpar = row->par->DepthHook(row->par->GetDepth()-1);
351
352       /* make a corresponding row. Needed to call LeftMargin() */
353       
354       /* check wether it is a sufficent paragraph */ 
355       if (newpar && newpar->footnoteflag == row->par->footnoteflag
356           && textclasslist.Style(parameters->textclass, 
357                             newpar->GetLayout()).isEnvironment()) {
358              dummyrow.par = newpar;
359              dummyrow.pos = newpar->Last();
360              x = LeftMargin(&dummyrow);
361       }
362       else {
363          /* this is no longer an error, because this function is used
364           * to clear impossible depths after changing a layout. Since there
365           * is always a redo, LeftMargin() is always called */ 
366          
367          /* printf("LYX_ERROR (text, LeftMargin()) impossible depth \n");*/ 
368          row->par->FirstPhysicalPar()->depth = 0;
369       }
370       
371       if (newpar && !row->par->GetLayout()) {
372          if (newpar->FirstPhysicalPar()->noindent)
373             parindent.clear();
374          else
375             parindent = textclasslist.Style(parameters->textclass, 
376                                        newpar->GetLayout()).parindent;
377       }
378       
379    }
380    
381    labelfont = GetFont(row->par, -2);
382    switch (layout.margintype) {
383     case MARGIN_DYNAMIC:
384       if (!layout.leftmargin.empty()) {
385         x += textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.leftmargin);
386       }
387       if (!row->par->GetLabestring().empty()) {
388             x += labelfont.signedStringWidth(layout.labelindent);
389             x += labelfont.stringWidth(row->par->GetLabestring());
390             x += labelfont.stringWidth(layout.labelsep);
391       }
392       break;
393     case MARGIN_MANUAL:
394       x += labelfont.signedStringWidth(layout.labelindent);
395       if (row->pos >= BeginningOfMainBody(row->par)) {
396          if (!row->par->GetLabelWidthString().empty()) {
397             x += labelfont.stringWidth(row->par->GetLabelWidthString());
398             x += labelfont.stringWidth(layout.labelsep);
399          }
400       }
401       break;
402     case MARGIN_STATIC:
403       x += ( textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.leftmargin) * 4
404              / (row->par->GetDepth() + 4));
405       break;
406     case MARGIN_FIRST_DYNAMIC:
407       if (layout.labeltype == LABEL_MANUAL) {
408          if (row->pos >= BeginningOfMainBody(row->par)) {
409             x += labelfont.signedStringWidth(layout.leftmargin);
410          } else {
411             x += labelfont.signedStringWidth(layout.labelindent);
412          }
413       } else {
414          if (row->pos
415              // Special case to fix problems with theorems (JMarc)
416              || (layout.labeltype == LABEL_STATIC
417                  && layout.latextype == LATEX_ENVIRONMENT
418                  && ! row->par->IsFirstInSequence())) {
419                  x += labelfont.signedStringWidth(layout.leftmargin);
420          } else if (layout.labeltype != LABEL_TOP_ENVIRONMENT
421                   && layout.labeltype != LABEL_BIBLIO
422                   && layout.labeltype != LABEL_CENTERED_TOP_ENVIRONMENT) {
423                  x += labelfont.signedStringWidth(layout.labelindent);
424                  x += labelfont.stringWidth(layout.labelsep);
425                  x += labelfont.stringWidth(row->par->GetLabestring());
426          } 
427       }
428       break;
429       
430     case MARGIN_RIGHT_ADDRESS_BOX:
431     {
432       /* ok, a terrible hack. The left margin depends on the widest row
433        * in this paragraph. Do not care about footnotes, they are *NOT*
434        * allowed in the LaTeX realisation of this layout. */ 
435       
436       /* find the first row of this paragraph */ 
437       Row * tmprow = row;
438       while (tmprow->previous && tmprow->previous->par == row->par)
439         tmprow = tmprow->previous;
440       
441       int minfill = tmprow->fill;
442       while (tmprow-> next && tmprow->next->par == row->par) {
443          tmprow = tmprow->next;
444          if (tmprow->fill < minfill)
445            minfill = tmprow->fill;
446       }
447       
448       x += textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.leftmargin);
449       x += minfill;
450     }
451       break;
452    }
453    if (row->par->pextra_type == LyXParagraph::PEXTRA_INDENT) {
454        if (!row->par->pextra_widthp.empty()) {
455            x += paperwidth * atoi(row->par->pextra_widthp.c_str()) / 100;
456        } else if (!row->par->pextra_width.empty()) {
457            int xx = VSpace(row->par->pextra_width).inPixels();
458
459            if (xx > paperwidth)
460                xx = paperwidth * 80 / 100;
461            x += xx;
462        } else { // should not happen
463            LyXFont font(LyXFont::ALL_SANE);
464            x += font.stringWidth("XXXXXX");
465        }
466    }
467    
468    int align;
469    if (row->par->FirstPhysicalPar()->align == LYX_ALIGN_LAYOUT)
470      align = layout.align;
471    else
472      align = row->par->FirstPhysicalPar()->align;
473    
474    /* set the correct parindent */
475    if (row->pos == 0) {
476        if ((layout.labeltype == LABEL_NO_LABEL 
477             || layout.labeltype == LABEL_TOP_ENVIRONMENT 
478             || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT
479             || (layout.labeltype == LABEL_STATIC
480                 && layout.latextype == LATEX_ENVIRONMENT
481                 && ! row->par->IsFirstInSequence()))
482            && row->par == row->par->FirstPhysicalPar()
483            && align == LYX_ALIGN_BLOCK
484            && !row->par->noindent
485            && (row->par->layout ||
486                parameters->paragraph_separation == BufferParams::PARSEP_INDENT))
487          x += textclasslist.TextClass(parameters->textclass).defaultfont().stringWidth(parindent);
488        else 
489          if (layout.labeltype == LABEL_BIBLIO) { // ale970405 Right width for bibitems
490              x += bibitemMaxWidth(textclasslist.TextClass(parameters->textclass).defaultfont());
491          }
492    }
493
494    return x;
495 }
496     
497    
498 int LyXText::RightMargin(Row *row)
499 {
500    LyXParagraph * newpar;
501    Row dummyrow;
502    LyXLayout const & layout = textclasslist.Style(parameters->textclass, row->par->GetLayout());
503
504    int x = LYX_PAPER_MARGIN;
505
506    x += textclasslist.TextClass(parameters->textclass).
507      defaultfont().signedStringWidth(textclasslist.TextClass(parameters->textclass).rightmargin());
508    if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)  {
509      x += LYX_PAPER_MARGIN/2;
510    }
511
512     /* this is the way, LyX handles the LaTeX-Environments.
513     * I have had this idea very late, so it seems to be a
514     * later added hack and this is true */ 
515    if (row->par->GetDepth()) {
516       /* find the next level paragraph */ 
517       
518       newpar = row->par;
519       
520       do {
521                 newpar = newpar->FirstPhysicalPar()->Previous();
522                 if (newpar) 
523                         newpar = newpar->FirstPhysicalPar();
524       } while (newpar && newpar->GetDepth() >= row->par->GetDepth()
525                && newpar->footnoteflag == row->par->footnoteflag);
526       
527       /* make a corresponding row. Needed to call LeftMargin() */
528
529       /* check wether it is a sufficent paragraph */ 
530       if (newpar && newpar->footnoteflag == row->par->footnoteflag
531           && textclasslist.Style(parameters->textclass,
532                             newpar->GetLayout()).isEnvironment()) {
533              dummyrow.par = newpar;
534              dummyrow.pos = 0;
535              x = RightMargin(&dummyrow);
536           }
537       else {
538          /* this is no longer an error, because this function is used
539           * to clear impossible depths after changing a layout. Since there
540           * is always a redo, LeftMargin() is always called */ 
541          
542          /* printf("LYX_ERROR (text, LeftMargin()) impossible depth \n");*/ 
543          row->par->FirstPhysicalPar()->depth = 0;
544       }
545    }
546
547    //lyxerr << "rightmargin: " << layout->rightmargin << endl;
548    x += (textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.rightmargin) * 4
549          / (row->par->GetDepth() + 4));
550    return x;
551    
552 }
553
554
555 int LyXText::LabelEnd (Row * row)
556 {
557    if (textclasslist.Style(parameters->textclass, row->par->GetLayout()).margintype == MARGIN_MANUAL) {
558       Row tmprow;
559       tmprow = *row;
560       tmprow.pos = row->par->Last();
561       return LeftMargin(&tmprow);      /* just the beginning 
562                                         * of the main body */
563    }
564    else
565      return 0;                         /* LabelEnd is only needed, if the  
566                                         * layout fills a flushleft
567                                         * label. */
568 }
569
570
571 /* table stuff -- begin*/
572 int LyXText::NumberOfCell(LyXParagraph * par,
573                           LyXParagraph::size_type pos)
574 {
575    int cell = 0;
576    LyXParagraph::size_type tmp_pos = 0;
577    while (tmp_pos < pos) {
578       if (par->IsNewline(tmp_pos))
579          cell++;
580       tmp_pos++;
581    }
582    return cell;
583 }
584
585
586 int LyXText::WidthOfCell(LyXParagraph * par, LyXParagraph::size_type & pos)
587 {
588    int w = 0;
589    while (pos < par->Last() && !par->IsNewline(pos)) {
590       w += SingleWidth(par, pos);
591       pos++;
592    }
593    if (par->IsNewline(pos))
594       pos++;
595    return w;
596 }
597
598
599 char LyXText::HitInTable(Row * row, int x)
600 {
601   float tmpx;
602   float fill_separator, fill_hfill, fill_label_hfill;
603   if (!row->par->table)
604     return 0;
605   PrepareToPrint(row, tmpx, fill_separator, fill_hfill, fill_label_hfill);
606   return (x > tmpx && x < tmpx + row->par->table->WidthOfTable());
607 }
608
609
610 bool LyXText::MouseHitInTable(int x, long y)
611 {
612         Row * row = GetRowNearY(y);
613         return HitInTable(row, x);
614 }
615
616
617 /* table stuff -- end*/
618
619
620 /* get the next breakpoint in a given paragraph */
621 LyXParagraph::size_type
622 LyXText::NextBreakPoint(Row * row, int width)
623 {
624         int x = 0;
625         LyXParagraph::size_type last_separator = -1;
626         /* position of the last possible breakpoint 
627          * -1 isn't a suitable value, but a flag */
628         int left_margin;
629         
630         LyXParagraph * par = row->par;
631         LyXParagraph::size_type i = 0;
632         LyXParagraph::size_type pos = row->pos;
633         
634         /* table stuff -- begin*/ 
635         if (par->table) {
636                 while (pos < par->size()
637                        && (!par->IsNewline(pos) 
638                            || !par->table->IsFirstCell(NumberOfCell(par, pos+1)))) {
639                         if (par->GetChar(pos) == LyXParagraph::META_INSET &&
640                             par->GetInset(pos) && par->GetInset(pos)->Display()){
641                                 par->GetInset(pos)->SetDisplay(false);
642                         }
643                         pos++;
644                 }
645                 return pos;
646         }
647         /* table stuff -- end*/ 
648         
649         left_margin = LabelEnd(row);
650         width -= RightMargin(row);
651         LyXParagraph::size_type main_body = 
652                 BeginningOfMainBody(par);
653         LyXLayout const & layout = textclasslist.Style(parameters->textclass, par->GetLayout());
654         i = pos;
655         char c;
656         
657         if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX) {
658                 /* special code for right address boxes, only newlines count */
659                 while (i < par->Last()) {
660                         if (par->IsNewline(i)) {
661                                 last_separator = i;
662                                 i = par->Last() - 1;/* this means break  */
663                                 x = width;
664                         } else if (par->GetChar(i) == LyXParagraph::META_INSET &&
665                                    par->GetInset(i) && par->GetInset(i)->Display()){
666                                 par->GetInset(i)->SetDisplay(false);
667                         }
668                         i++;
669                 }
670         } else {
671                 // Last position is an invariant
672                 LyXParagraph::size_type const last = 
673                         par->Last();
674                 /* this is the usual handling */ 
675                 x = LeftMargin(row);
676                 while (x < width && i < last) {
677                         c = par->GetChar(i);
678                         if (IsNewlineChar(c)) {
679                                 last_separator = i;
680                                 x = width;                     /* this means break  */
681                         } else if (c == LyXParagraph::META_INSET &&
682                                    par->GetInset(i) && par->GetInset(i)->Display()){
683                                 /* check wether a Display() inset is valid here .
684                                    if not, change it to non-display*/ 
685                                 if (layout.isCommand()
686                                     || (layout.labeltype == LABEL_MANUAL
687                                         && i < BeginningOfMainBody(par))){
688                                         /* display istn't allowd */ 
689                                         par->GetInset(i)->SetDisplay(false);
690                                         x += SingleWidth(par, i, c);
691                                 } else {
692                                         /* inset is display. So break the line here */ 
693                                         if (i == pos){
694                                                 if (pos < last-1) {
695                                                         last_separator = i;
696                                                         if (IsLineSeparatorChar(par->GetChar(i+1)))
697                                                                 last_separator++;
698                                                 } else
699                                                         last_separator = last; // to avoid extra rows
700                                         } else
701                                                 last_separator = i - 1;
702                                         x = width;                     /* this means break  */
703                                 }
704                         } else  {
705                                 if (IsLineSeparatorChar(c))
706                                         last_separator = i;
707                                 x += SingleWidth(par, i, c);
708                         }
709                         i++;
710                         if (i == main_body) {
711                                 x += GetFont(par, -2).stringWidth(layout.labelsep);
712                                 if (par->IsLineSeparator(i - 1))
713                                         x-= SingleWidth(par, i - 1);
714                                 if (x < left_margin)
715                                         x = left_margin;
716                         }
717                 }
718                 /* end of paragraph is always a suitable separator */
719                 if (i == last && x < width)
720                         last_separator = i;
721         }
722         
723         /* well, if last_separator is still 0, the line isn't breakable. 
724          * don't care and cut simply at the end */
725         if (last_separator < 0) {
726                 last_separator = i;
727         }
728         
729         /* manual labels cannot be broken in LaTeX, do not care  */
730         if (main_body && last_separator < main_body)
731                 last_separator = main_body - 1;
732         
733         return last_separator;
734 }
735
736
737 /* returns the minimum space a row needs on the screen in pixel */
738 int LyXText::Fill(Row * row, int paperwidth)
739 {
740    int w, fill;
741    /* get the pure distance */
742    LyXParagraph::size_type last = RowLast(row);
743    /* table stuff -- begin*/
744    if (row->par->table) {
745       /* for tables FILL does calculate the widthes of each cell in 
746        * the row */
747       LyXParagraph::size_type pos = row->pos;
748       int cell = NumberOfCell(row->par, pos);
749       w = 0;
750       do {
751          row->par->table->SetWidthOfCell(cell, WidthOfCell(row->par, pos));
752          cell++;
753       } while (pos <= last && !row->par->table->IsFirstCell(cell));
754       /* don't forget the very last table cell without characters */
755       if (cell == row->par->table->GetNumberOfCells()-1)
756           row->par->table->SetWidthOfCell(cell, WidthOfCell(row->par, pos));
757       
758       return 0; /* width of table cannot be returned since
759                  * we cannot guarantee its correct value at
760                  * this point. */ 
761    }
762    /* table stuff -- end*/ 
763
764    int left_margin = LabelEnd(row);
765
766      /* if the row ends with newline, this newline will not be relevant */ 
767      if (last >= 0 && row->par->IsNewline(last))
768        last--;
769      
770      /* if the row ends with a space, this space will not be relevant */ 
771      if (last >= 0 && row->par->IsLineSeparator(last))
772        last--;
773
774    /* special handling of the right address boxes */ 
775    if (textclasslist.Style(parameters->textclass,
776                            row->par->GetLayout()).margintype
777        == MARGIN_RIGHT_ADDRESS_BOX) {
778       int tmpfill = row->fill;
779       row->fill = 0;                   /* the minfill in MarginLeft()  */
780       w = LeftMargin(row);
781       row->fill = tmpfill;
782    }
783    else
784      w = LeftMargin(row);
785    
786    LyXLayout const & layout = textclasslist.Style(parameters->textclass,
787                                       row->par->GetLayout());
788    LyXParagraph::size_type main_body = 
789            BeginningOfMainBody(row->par);
790    LyXParagraph::size_type i = row->pos;
791    while (i <= last) {
792       w += SingleWidth(row->par, i);
793       ++i;
794       if (i == main_body) {
795          w += GetFont(row->par, -2).stringWidth(layout.labelsep);
796          if (row->par->IsLineSeparator(i - 1))
797            w -= SingleWidth(row->par, i - 1);
798          if (w < left_margin)
799            w = left_margin;
800       }
801    }
802    
803    fill = paperwidth - w - RightMargin(row);
804    return fill;
805 }
806
807
808 /* returns the minimum space a manual label needs on the screen in pixel */ 
809 int LyXText::LabelFill(Row * row)
810 {
811
812    LyXParagraph::size_type last = BeginningOfMainBody(row->par) - 1;
813    /* -1 because a label ends either with a space that is in the label, 
814     * or with the beginning of a footnote that is outside the label. */ 
815
816    // I don't understand this code in depth, but sometimes "last" is less than
817    // 0 and this causes a crash. This fix seems to work correctly, but I
818    // bet the real error is elsewhere.  The bug is triggered when you have an 
819    // open footnote in a paragraph environment with a manual label. (Asger)
820    if (last < 0) last = 0;
821
822    if (row->par->IsLineSeparator(last))    /* a sepearator at this end 
823                                         * does not count */
824      last--;
825    
826    int w = 0;
827    int i = row->pos;
828    while (i<= last) {
829       w += SingleWidth(row->par, i);
830       i++;
831    }
832    
833    int fill = 0;
834    if (!row->par->labelwidthstring.empty()) {
835       fill = GetFont(row->par, -2).stringWidth(row->par->labelwidthstring) - w;
836    }
837    
838    if (fill < 0)
839      fill = 0;
840    
841    return fill;
842 }
843
844
845 /* returns the number of separators in the specified row. The separator 
846 * on the very last column doesnt count */ 
847 int LyXText::NumberOfSeparators(Row *row)
848 {
849    int last = RowLast(row);
850    int n = 0;
851    int p = row->pos;
852    int main_body = BeginningOfMainBody(row->par);
853    if (p < main_body)
854      p = main_body;
855    for (; p < last; p++) {
856       if (row->par->IsSeparator(p)) {
857          n++;
858       }
859    }
860    return n;
861 }
862
863
864 /* returns the number of hfills in the specified row. The LyX-Hfill is
865 * a LaTeX \hfill so that the hfills at the beginning and at the end were 
866 * ignored. This is *MUCH* more usefull than not to ignore!  */
867 int LyXText::NumberOfHfills(Row * row)
868 {
869    int last = RowLast(row);
870    int first = row->pos;
871    if (first) {                        /* hfill *DO* count at the beginning 
872                                         * of paragraphs! */
873      while(first <= last && row->par->IsHfill(first))
874        first++;
875    }
876
877    int main_body = BeginningOfMainBody(row->par);
878    if (first < main_body)
879      first = main_body;
880    int n = 0;
881    for (int p = first; p <= last; p++) { // last, because the end is ignored!
882       if (row->par->IsHfill(p)) {
883          n++;
884       }
885    }
886    return n;
887 }
888
889
890 /* like NumberOfHfills, but only those in the manual label! */ 
891 int LyXText::NumberOfLabelHfills(Row * row)
892 {
893    LyXParagraph::size_type last = RowLast(row);
894    LyXParagraph::size_type first = row->pos;
895    if (first) {                        /* hfill *DO* count at the beginning 
896                                         * of paragraphs! */
897       while(first < last && row->par->IsHfill(first))
898         first++;
899    }
900    LyXParagraph::size_type main_body = 
901            BeginningOfMainBody(row->par);
902    if (last > main_body)
903      last = main_body;
904
905    int n = 0;
906    for (LyXParagraph::size_type p = first;
907         p < last; ++p) {  // last, because the end is ignored!
908       if (row->par->IsHfill(p)) {
909          ++n;
910       }
911    }
912    return n;
913 }
914
915
916 /* returns true, if a expansion is needed.
917  * Rules are given by LaTeX */
918 bool LyXText::HfillExpansion(Row * row_ptr,
919                              LyXParagraph::size_type pos)
920 {
921    /* by the way, is it a hfill? */ 
922    if (!row_ptr->par->IsHfill(pos))
923      return false;
924    
925    /* at the end of a row it does not count */ 
926    if (pos >= RowLast(row_ptr))
927      return false;
928    
929    /* at the beginning of a row it does not count, if it is not 
930     * the first row of a paragaph */ 
931    if (!row_ptr->pos)
932      return true;
933    
934    /* in some labels  it does not count */ 
935    if ( textclasslist.Style(parameters->textclass, row_ptr->par->GetLayout()).margintype != MARGIN_MANUAL &&
936        pos < BeginningOfMainBody(row_ptr->par))
937      return false; 
938    
939    /* if there is anything between the first char of the row and
940     * the sepcified position that is not a newline and not a hfill,
941     * the hfill will count, otherwise not */ 
942    LyXParagraph::size_type i = row_ptr->pos;
943    while (i < pos && (row_ptr->par->IsNewline(i)
944                       || row_ptr->par->IsHfill(i)))
945      i++;
946    
947    return (i != pos);
948 }
949
950
951 void LyXText::SetHeightOfRow(Row * row_ptr)
952 {
953     /* get the maximum ascent and the maximum descent */
954    int asc, maxasc, desc, maxdesc, pos_end, pos, labeladdon;
955    float layoutasc = 0;
956    float layoutdesc = 0;
957    float tmptop = 0;
958    LyXFont tmpfont;
959    Inset * tmpinset;
960
961    /* this must not happen before the currentrow for clear reasons.
962       so the trick is just to set the current row onto this row */
963    long unused_y;
964    GetRow(row_ptr->par, row_ptr->pos, unused_y);
965
966    /* ok , let us initialize the maxasc and maxdesc value. 
967     * This depends in LaTeX of the font of the last character
968     * in the paragraph. The hack below is necessary because
969     * of the possibility of open footnotes */
970
971    /* Correction: only the fontsize count. The other properties
972       are taken from the layoutfont. Nicer on the screen :) */
973    
974    LyXParagraph * par = row_ptr->par->LastPhysicalPar();
975    LyXParagraph * firstpar = row_ptr->par->FirstPhysicalPar();
976    
977    LyXLayout const & layout = textclasslist.Style(parameters->textclass, firstpar->GetLayout());
978    
979    LyXFont font = GetFont(par, par->Last()-1);
980    LyXFont::FONT_SIZE size = font.size();
981    font = GetFont(par, -1);
982    font.setSize(size);
983
984    LyXFont labelfont = GetFont(par, -2);
985
986    maxasc = int(font.maxAscent() *
987                    layout.spacing.getValue() *
988                    parameters->spacing.getValue());
989    maxdesc = int(font.maxDescent() *
990                     layout.spacing.getValue() *
991                     parameters->spacing.getValue());
992
993    pos_end = RowLast(row_ptr);
994    
995    labeladdon = 0;
996
997    // Check if any insets are larger
998    for (pos = row_ptr->pos; pos <= pos_end; pos++) {
999       if (row_ptr->par->GetChar(pos) == LyXParagraph::META_INSET) {
1000          tmpfont = GetFont(row_ptr->par, pos);
1001          tmpinset = row_ptr->par->GetInset(pos);
1002          if (tmpinset) {
1003             asc = tmpinset->Ascent(tmpfont);
1004             desc = tmpinset->Descent(tmpfont);
1005             if (asc > maxasc) 
1006               maxasc = asc;
1007             if (desc > maxdesc)
1008               maxdesc = desc;
1009          }
1010       }
1011    }
1012
1013    // Check if any custom fonts are larger (Asger)
1014    // This is not completely correct, but we can live with the small,
1015    // cosmetic error for now.
1016    LyXFont::FONT_SIZE maxsize = row_ptr->par->HighestFontInRange(row_ptr->pos, pos_end);
1017    if (maxsize > font.size()) {
1018         font.setSize(maxsize);
1019
1020         asc = font.maxAscent();
1021         desc = font.maxDescent();
1022         if (asc > maxasc) 
1023                 maxasc = asc;
1024         if (desc > maxdesc)
1025                 maxdesc = desc;
1026    }
1027
1028    /* table stuff -- begin*/
1029    if (row_ptr->par->table){
1030      // stretch the rows a bit
1031       maxasc += 1;
1032       maxdesc += 1;
1033    }
1034    /* table stuff -- end*/
1035
1036    // This is nicer with box insets:
1037    maxasc++;
1038    maxdesc++;
1039
1040    row_ptr->ascent_of_text = maxasc;
1041    
1042    /* is it a top line? */ 
1043    if (row_ptr->pos == 0
1044        && row_ptr->par == firstpar) {
1045       
1046       /* some parksips VERY EASY IMPLEMENTATION */ 
1047       if (parameters->paragraph_separation == BufferParams::PARSEP_SKIP) {
1048          if (layout.isParagraph()
1049              && firstpar->GetDepth() == 0
1050              && firstpar->Previous())
1051             maxasc += parameters->getDefSkip().inPixels();
1052          else if (firstpar->Previous()
1053                   && textclasslist.Style(parameters->textclass,
1054                            firstpar->Previous()->GetLayout()).isParagraph()
1055                   && firstpar->Previous()->GetDepth() == 0)
1056            // is it right to use defskip here too? (AS)
1057            maxasc += parameters->getDefSkip().inPixels();
1058       }
1059       
1060       /* the paper margins */ 
1061       if (!row_ptr->par->previous)
1062          maxasc += LYX_PAPER_MARGIN;
1063       
1064       /* add the vertical spaces, that the user added */
1065       if (firstpar->added_space_top.kind() != VSpace::NONE)
1066          maxasc += int(firstpar->added_space_top.inPixels());
1067       
1068       /* do not forget the DTP-lines! 
1069        * there height depends on the font of the nearest character */
1070       if (firstpar->line_top)
1071          maxasc += 2 * GetFont(firstpar, 0).ascent('x');
1072       
1073       /* and now the pagebreaks */ 
1074       if (firstpar->pagebreak_top)
1075          maxasc += 3 * DefaultHeight();
1076       
1077       /*  this is special code for the chapter, since the label of this
1078        * layout is printed in an extra row */ 
1079       if (layout.labeltype == LABEL_COUNTER_CHAPTER
1080           && parameters->secnumdepth>= 0) {
1081               labeladdon = int(labelfont.maxDescent() *
1082                                   layout.spacing.getValue() *
1083                                   parameters->spacing.getValue())
1084                       + int(labelfont.maxAscent() *
1085                                layout.spacing.getValue() *
1086                                parameters->spacing.getValue());
1087       }
1088       
1089       /* special code for the top label */ 
1090       if ((layout.labeltype == LABEL_TOP_ENVIRONMENT
1091            || layout.labeltype == LABEL_BIBLIO
1092            || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)
1093           && row_ptr->par->IsFirstInSequence()
1094           && !row_ptr->par->GetLabestring().empty()) {
1095          labeladdon = int(
1096                  (labelfont.maxAscent() *
1097                   layout.spacing.getValue() *
1098                   parameters->spacing.getValue())
1099                  +(labelfont.maxDescent() *
1100                    layout.spacing.getValue() *
1101                    parameters->spacing.getValue())
1102                  + layout.topsep * DefaultHeight()
1103                  + layout.labelbottomsep *  DefaultHeight());
1104       }
1105    
1106       /* and now the layout spaces, for example before and after a section, 
1107        * or between the items of a itemize or enumerate environment */ 
1108       
1109       if (!firstpar->pagebreak_top) {
1110          LyXParagraph *prev = row_ptr->par->Previous();
1111          if (prev)
1112             prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth());
1113          if (prev && prev->GetLayout() == firstpar->GetLayout()
1114              && prev->GetDepth() == firstpar->GetDepth()
1115              && prev->GetLabelWidthString() == firstpar->GetLabelWidthString())
1116            {
1117               layoutasc = (layout.itemsep * DefaultHeight());
1118            }
1119          else if (row_ptr->previous) {
1120             tmptop = layout.topsep;
1121             
1122             if (row_ptr->previous->par->GetDepth() >= row_ptr->par->GetDepth())
1123                tmptop-= textclasslist.Style(parameters->textclass, row_ptr->previous->par->GetLayout()).bottomsep;
1124             
1125             if (tmptop > 0)
1126                layoutasc = (tmptop * DefaultHeight());
1127          }
1128          else if (row_ptr->par->line_top){
1129             tmptop = layout.topsep;
1130             
1131             if (tmptop > 0)
1132                layoutasc = (tmptop * DefaultHeight());
1133          }
1134          
1135          prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth()-1);
1136          if (prev)  {
1137             maxasc += int(textclasslist.Style(parameters->textclass,
1138                                          prev->GetLayout()).parsep * DefaultHeight());
1139          }
1140          else {
1141                 if (firstpar->Previous()
1142                     && firstpar->Previous()->GetDepth() == 0
1143                     && firstpar->Previous()->GetLayout() != firstpar->GetLayout()) {
1144                    /* avoid parsep */ 
1145                 }
1146             else if (firstpar->Previous()){
1147                maxasc += int(layout.parsep * DefaultHeight());
1148             }
1149          }
1150       }
1151    }
1152    
1153    /* is it a bottom line? */ 
1154    if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
1155        && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {     
1156           
1157           /* the paper margins */ 
1158           if (!par->next)
1159             maxdesc += LYX_PAPER_MARGIN;
1160         
1161           /* add the vertical spaces, that the user added */
1162           if (firstpar->added_space_bottom.kind() != VSpace::NONE)
1163             maxdesc += int(firstpar->added_space_bottom.inPixels());
1164           
1165           /* do not forget the DTP-lines! 
1166            * there height depends on the font of the nearest character */
1167           if (firstpar->line_bottom)
1168             maxdesc += 2 * (GetFont(par, par->Last()-1).ascent('x'));
1169           
1170           /* and now the pagebreaks */
1171           if (firstpar->pagebreak_bottom)
1172             maxdesc += 3 * DefaultHeight();
1173           
1174           /* and now the layout spaces, for example before and after a section, 
1175            * or between the items of a itemize or enumerate environment */
1176           if (!firstpar->pagebreak_bottom && row_ptr->par->Next()) {
1177              LyXParagraph *nextpar = row_ptr->par->Next();
1178              LyXParagraph *comparepar = row_ptr->par;
1179              float usual = 0;
1180              float  unusual = 0;
1181              
1182              if (comparepar->GetDepth() > nextpar->GetDepth()) {
1183                 usual = (textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1184                 comparepar = comparepar->DepthHook(nextpar->GetDepth());
1185                 if (comparepar->GetLayout()!= nextpar->GetLayout()
1186                     || nextpar->GetLabelWidthString() != 
1187                         comparepar->GetLabelWidthString())
1188                   unusual = (textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1189                 
1190                 if (unusual > usual)
1191                   layoutdesc = unusual;
1192                 else
1193                   layoutdesc = usual;
1194              }
1195              else if (comparepar->GetDepth() ==  nextpar->GetDepth()) {
1196                 
1197                 if (comparepar->GetLayout()!= nextpar->GetLayout()
1198                     || nextpar->GetLabelWidthString() != 
1199                         comparepar->GetLabelWidthString())
1200                   layoutdesc = int(textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1201              }
1202           }
1203        }
1204    
1205    /* incalculate the layout spaces */ 
1206    maxasc += int(layoutasc * 2 / (2 + firstpar->GetDepth()));
1207    maxdesc += int(layoutdesc * 2 / (2 + firstpar->GetDepth()));
1208
1209    /* table stuff -- begin*/
1210    if (row_ptr->par->table){
1211       maxasc += row_ptr->par->table->
1212         AdditionalHeight(NumberOfCell(row_ptr->par, row_ptr->pos));
1213    }
1214    /* table stuff -- end*/
1215    
1216    /* calculate the new height of the text */ 
1217    height -= row_ptr->height;
1218    
1219    row_ptr->height= maxasc+maxdesc+labeladdon;
1220    row_ptr->baseline= maxasc+labeladdon;
1221    
1222    height += row_ptr->height;
1223 }
1224
1225
1226 /* Appends the implicit specified paragraph behind the specified row,
1227  * start at the implicit given position */
1228 void LyXText::AppendParagraph(Row * row)
1229 {
1230    bool not_ready = true;
1231    
1232    // The last character position of a paragraph is an invariant so we can 
1233    // safely get it here. (Asger)
1234    int lastposition = row->par->Last();
1235
1236    do {
1237       // Get the next breakpoint
1238       int z = NextBreakPoint(row, paperwidth);
1239       
1240       Row * tmprow = row;
1241
1242       // Insert the new row
1243       if (z < lastposition) {
1244          z++;
1245          InsertRow(row, row->par, z);
1246          row = row->next;
1247
1248          row->height = 0;
1249       } else
1250          not_ready = false;
1251       
1252       // Set the dimensions of the row
1253       tmprow->fill = Fill(tmprow, paperwidth);
1254       SetHeightOfRow(tmprow);
1255
1256    } while (not_ready);
1257 }
1258
1259
1260 void LyXText::BreakAgain(Row * row)
1261 {
1262    bool not_ready = true;
1263    
1264    do  {
1265       /* get the next breakpoint */
1266         LyXParagraph::size_type z = 
1267                 NextBreakPoint(row, paperwidth);
1268       Row * tmprow = row;
1269       
1270       if (z < row->par->Last() ) {
1271          if (!row->next || (row->next && row->next->par != row->par)) {
1272             /* insert a new row */ 
1273             z++;
1274             InsertRow(row, row->par, z);
1275             row = row->next;
1276             row->height = 0;
1277          } else  {
1278             row = row->next;
1279             z++;
1280             if (row->pos == z)
1281                     not_ready = false;     // the rest will not change
1282             else {
1283                row->pos = z;
1284             }
1285          }
1286       } else {
1287          /* if there are some rows too much, delete them */
1288          /* only if you broke the whole paragraph! */ 
1289          Row * tmprow2 = row;
1290          while (tmprow2->next && tmprow2->next->par == row->par) {
1291             tmprow2 = tmprow2->next;
1292          }
1293          while (tmprow2 != row) {
1294             tmprow2 = tmprow2->previous;
1295             RemoveRow(tmprow2->next);
1296          }
1297          not_ready = false;
1298       }
1299        
1300       /* set the dimensions of the row */ 
1301       tmprow->fill = Fill(tmprow, paperwidth);
1302       SetHeightOfRow(tmprow);
1303    } while (not_ready);
1304 }
1305
1306
1307 /* this is just a little changed version of break again */ 
1308 void LyXText::BreakAgainOneRow(Row * row)
1309 {
1310    /* get the next breakpoint */
1311    LyXParagraph::size_type z = NextBreakPoint(row, paperwidth);
1312    Row * tmprow = row;
1313    
1314    if (z < row->par->Last() ) {
1315       if (!row->next || (row->next && row->next->par != row->par)) {
1316          /* insert a new row */ 
1317          z++;
1318          InsertRow(row, row->par, z);
1319          row = row->next;
1320          row->height = 0;
1321       }
1322       else  {
1323          row= row->next;
1324          z++;
1325          if (row->pos != z)
1326             row->pos = z;
1327       }
1328    }
1329    else {
1330       /* if there are some rows too much, delete them */
1331       /* only if you broke the whole paragraph! */ 
1332       Row * tmprow2 = row;
1333       while (tmprow2->next && tmprow2->next->par == row->par) {
1334          tmprow2 = tmprow2->next;
1335       }
1336       while (tmprow2 != row) {
1337          tmprow2 = tmprow2->previous;
1338          RemoveRow(tmprow2->next);
1339       }
1340    }
1341    
1342    /* set the dimensions of the row */ 
1343    tmprow->fill = Fill(tmprow, paperwidth);
1344    SetHeightOfRow(tmprow);
1345 }
1346
1347
1348 void LyXText::BreakParagraph(char keep_layout)
1349 {
1350    LyXLayout const & layout = textclasslist.Style(parameters->textclass,
1351                                       cursor.par->GetLayout());
1352    
1353    /* table stuff -- begin*/
1354    if (cursor.par->table) {
1355        // breaking of tables is only allowed at the beginning or the end */
1356        if (cursor.pos && cursor.pos < cursor.par->size() &&
1357            !cursor.par->table->ShouldBeVeryLastCell(NumberOfCell(cursor.par, cursor.pos)))
1358            return; /* no breaking of tables allowed */ 
1359    }
1360    /* table stuff -- end*/
1361
1362    /* this is only allowed, if the current paragraph is not empty or caption*/ 
1363    if ((cursor.par->Last() <= 0 && !cursor.par->IsDummy())
1364        && 
1365        layout.labeltype!= LABEL_SENSITIVE)
1366      return;
1367
1368    SetUndo(Undo::INSERT, 
1369            cursor.par->ParFromPos(cursor.pos)->previous, 
1370            cursor.par->ParFromPos(cursor.pos)->next); 
1371
1372    /* table stuff -- begin*/
1373    if (cursor.par->table) {
1374        int cell = NumberOfCell(cursor.par, cursor.pos);
1375        if (cursor.par->table->ShouldBeVeryLastCell(cell))
1376            SetCursor(cursor.par, cursor.par->text.size());
1377    }
1378    /* table stuff -- end*/
1379    /* please break alway behind a space */ 
1380    if (cursor.pos < cursor.par->Last()
1381        && cursor.par->IsLineSeparator(cursor.pos))
1382      cursor.pos++;
1383    
1384    /* break the paragraph */
1385    if (keep_layout)
1386      keep_layout = 2;
1387    else 
1388      keep_layout = layout.isEnvironment();
1389    cursor.par->BreakParagraph(cursor.pos, keep_layout);
1390
1391    /* table stuff -- begin*/
1392    if (cursor.par->table){
1393      // the table should stay with the contents
1394      if (!cursor.pos){
1395        cursor.par->Next()->table = cursor.par->table;
1396        cursor.par->table = 0;
1397      }
1398    }
1399    /* table stuff -- end*/
1400
1401    /* well this is the caption hack since one caption is really enough */
1402    if (layout.labeltype == LABEL_SENSITIVE){
1403      if (!cursor.pos)
1404        cursor.par->SetLayout(0); /* set the new paragraph to standard-layout */
1405      else
1406        cursor.par->Next()->SetLayout(0); /* set the new paragraph to standard-layout */
1407          
1408    }
1409    
1410    /* if the cursor is at the beginning of a row without prior newline, 
1411     *  move one row up! 
1412     * This touches only the screen-update. Otherwise we would may have
1413     * an empty row on the screen */
1414    if (cursor.pos && !cursor.row->par->IsNewline(cursor.row->pos -1) &&
1415        cursor.row->pos == cursor.pos) {
1416      CursorLeft();
1417    } 
1418    
1419    status = LyXText::NEED_MORE_REFRESH;
1420    refresh_row = cursor.row;
1421    refresh_y = cursor.y - cursor.row->baseline;
1422    
1423    /* Do not forget the special right address boxes */
1424    if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX) {
1425       while (refresh_row->previous &&
1426              refresh_row->previous->par == refresh_row->par) {
1427                 refresh_row = refresh_row->previous;
1428                 refresh_y -= refresh_row->height;
1429              }
1430    }
1431    RemoveParagraph(cursor.row);
1432    
1433    /* set the dimensions of the cursor row */
1434    cursor.row->fill = Fill(cursor.row, paperwidth);
1435
1436    SetHeightOfRow(cursor.row);
1437    
1438    while (!cursor.par->Next()->table && cursor.par->Next()->Last()
1439           && cursor.par->Next()->IsNewline(0))
1440      cursor.par->Next()->Erase(0);
1441    
1442    InsertParagraph(cursor.par->Next(), cursor.row);
1443
1444    UpdateCounters(cursor.row->previous);
1445    
1446    /* this check is necessary. Otherwise the new empty paragraph will
1447     * be deleted automatically. And it is more friendly for the user! */ 
1448    if (cursor.pos)
1449      SetCursor(cursor.par->Next(), 0);
1450    else
1451      SetCursor(cursor.par, 0);
1452    
1453    if (cursor.row->next)
1454      BreakAgain(cursor.row->next);
1455
1456    need_break_row = 0;
1457 }
1458
1459
1460 void LyXText::OpenFootnote()
1461 {
1462    LyXParagraph * endpar,* tmppar;
1463    Row * row;
1464    
1465    LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
1466    
1467    /* if there is no footnote in this paragraph, just return. */ 
1468    if (!par->next
1469        || par->next->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1470      return;
1471    
1472    /* ok, move the cursor right before the footnote */ 
1473    
1474    /* just a little faster than using CursorRight() */
1475    for (cursor.pos= 0; cursor.par->ParFromPos(cursor.pos)!= par; cursor.pos++);
1476    /* now the cursor is at the beginning of the physical par */
1477    SetCursor(cursor.par,
1478              cursor.pos + cursor.par->ParFromPos(cursor.pos)->text.size());
1479    
1480    /* the cursor must be exactly before the footnote */ 
1481    par = cursor.par->ParFromPos(cursor.pos);
1482    
1483    status = LyXText::NEED_MORE_REFRESH;
1484    refresh_row = cursor.row;
1485    refresh_y = cursor.y - cursor.row->baseline;
1486    
1487    tmppar = cursor.par;
1488    endpar = cursor.par->Next();
1489    row = cursor.row;
1490    
1491    tmppar->OpenFootnote(cursor.pos);
1492    RemoveParagraph(row);
1493    /* set the dimensions of the cursor row */
1494    row->fill = Fill(row, paperwidth);
1495    SetHeightOfRow(row);
1496    tmppar = tmppar->Next();
1497    
1498    while (tmppar != endpar) {
1499       if (tmppar) {
1500          InsertParagraph(tmppar, row);
1501          while (row->next && row->next->par == tmppar)
1502            row = row->next;
1503          tmppar = tmppar->Next();
1504       }
1505    }
1506    SetCursor(par->next, 0);
1507    sel_cursor = cursor;
1508 }
1509    
1510
1511 /* table stuff -- begin*/
1512
1513 void LyXText::TableFeatures(int feature, string val)
1514 {
1515     if (!cursor.par->table)
1516         return; /* this should never happen */
1517   
1518     int actCell = NumberOfCell(cursor.par, cursor.pos);
1519     SetUndo(Undo::FINISH, 
1520             cursor.par->ParFromPos(cursor.pos)->previous, 
1521             cursor.par->ParFromPos(cursor.pos)->next); 
1522
1523     switch (feature){
1524       case LyXTable::SET_PWIDTH:
1525           cursor.par->table->SetPWidth(actCell, val);
1526           break;
1527       case LyXTable::SET_SPECIAL_COLUMN:
1528       case LyXTable::SET_SPECIAL_MULTI:
1529           cursor.par->table->SetAlignSpecial(actCell, val, feature);
1530           break;
1531       default:
1532           break;
1533     }
1534     RedoParagraph();
1535 }
1536
1537
1538 void LyXText::TableFeatures(int feature)
1539 {
1540         int setLines = 0;
1541         int setAlign = LYX_ALIGN_LEFT;
1542         int lineSet;
1543         bool what;
1544     
1545     if (!cursor.par->table)
1546         return; /* this should never happen */
1547   
1548     int actCell = NumberOfCell(cursor.par, cursor.pos);
1549     SetUndo(Undo::FINISH, 
1550             cursor.par->ParFromPos(cursor.pos)->previous, 
1551             cursor.par->ParFromPos(cursor.pos)->next); 
1552
1553     switch (feature){
1554       case LyXTable::ALIGN_LEFT:
1555           setAlign= LYX_ALIGN_LEFT;
1556           break;
1557       case LyXTable::ALIGN_RIGHT:
1558           setAlign= LYX_ALIGN_RIGHT;
1559           break;
1560       case LyXTable::ALIGN_CENTER:
1561           setAlign= LYX_ALIGN_CENTER;
1562           break;
1563       default:
1564           break;
1565     }
1566     switch (feature){
1567       case LyXTable::APPEND_ROW: {
1568               LyXParagraph::size_type pos = cursor.pos;
1569
1570               /* move to the next row */
1571           int cell_org = actCell;
1572           int cell = cell_org;
1573
1574           // if there is a ContRow following this row I have to add
1575           // the row after the ContRow's
1576           if ((pos < cursor.par->Last()) &&
1577               cursor.par->table->RowHasContRow(cell_org)) {
1578               while((pos < cursor.par->Last()) &&
1579                     !cursor.par->table->IsContRow(cell)) {
1580                   while (pos < cursor.par->Last() &&
1581                          !cursor.par->IsNewline(pos))
1582                       pos++;
1583                   if (pos < cursor.par->Last())
1584                       pos++;
1585                   cell++;
1586               }
1587               while((pos < cursor.par->Last()) &&
1588                     cursor.par->table->IsContRow(cell)) {
1589                   while (pos < cursor.par->Last() &&
1590                          !cursor.par->IsNewline(pos))
1591                       pos++;
1592                   if (pos < cursor.par->Last())
1593                       pos++;
1594                   cell++;
1595               }
1596               cell_org = --cell;
1597               if (pos < cursor.par->Last())
1598                   pos--;
1599           }
1600           while (pos < cursor.par->Last() && 
1601                  (cell == cell_org || !cursor.par->table->IsFirstCell(cell))){
1602               while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1603                   pos++;
1604               if (pos < cursor.par->Last())
1605                   pos++;
1606               cell++;
1607           }
1608                 
1609           /* insert the new cells */ 
1610           int number = cursor.par->table->NumberOfCellsInRow(cell_org);
1611           for (int i = 0; i < number; ++i)
1612               cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1613                 
1614           /* append the row into the table */
1615           cursor.par->table->AppendRow(cell_org);
1616           RedoParagraph();
1617           return;
1618       }
1619       case LyXTable::APPEND_CONT_ROW: {
1620               LyXParagraph::size_type pos = cursor.pos;
1621           /* move to the next row */
1622           int cell_org = actCell;
1623           int cell = cell_org;
1624
1625           // if there is already a controw but not for this cell
1626           // the AppendContRow sets only the right values but does
1627           // not actually add a row
1628           if (cursor.par->table->RowHasContRow(cell_org) &&
1629               (cursor.par->table->CellHasContRow(cell_org)<0)) {
1630               cursor.par->table->AppendContRow(cell_org);
1631               RedoParagraph();
1632               return;
1633           }
1634           while (pos < cursor.par->Last() && 
1635                  (cell == cell_org
1636                   || !cursor.par->table->IsFirstCell(cell))){
1637               while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1638                   pos++;
1639               if (pos < cursor.par->Last())
1640                   pos++;
1641               cell++;
1642           }
1643                 
1644           /* insert the new cells */ 
1645           int number = cursor.par->table->NumberOfCellsInRow(cell_org);
1646           int i;
1647           for (i= 0; i<number; i++)
1648               cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1649                 
1650           /* append the row into the table */
1651           cursor.par->table->AppendContRow(cell_org);
1652           RedoParagraph();
1653           return;
1654       }
1655       case LyXTable::APPEND_COLUMN: {
1656               LyXParagraph::size_type pos = 0;
1657           int cell_org = actCell;
1658           int cell = 0;
1659           do{
1660               if (pos && (cursor.par->IsNewline(pos-1))){
1661                   if (cursor.par->table->AppendCellAfterCell(cell_org, cell)){
1662                       cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1663                       if (pos <= cursor.pos)
1664                           cursor.pos++;
1665                       ++pos;
1666                   }
1667                   ++cell;
1668               }
1669               ++pos;
1670           } while (pos <= cursor.par->Last());
1671           /* remember that the very last cell doesn't end with a newline.
1672              This saves one byte memory per table ;-) */ 
1673           if (cursor.par->table->AppendCellAfterCell(cell_org, cell))
1674               cursor.par->InsertChar(cursor.par->Last(), LyXParagraph::META_NEWLINE);
1675                 
1676           /* append the column into the table */ 
1677           cursor.par->table->AppendColumn(cell_org);
1678                 
1679           RedoParagraph();
1680           return;
1681       }
1682       case LyXTable::DELETE_ROW:
1683           if (current_view->buffer()->the_locking_inset)
1684               UnlockInset(current_view->buffer()->the_locking_inset);
1685           RemoveTableRow(&cursor);
1686           RedoParagraph();
1687           return;
1688         
1689       case LyXTable::DELETE_COLUMN: {
1690               LyXParagraph::size_type pos = 0;
1691           int cell_org = actCell;
1692           int cell = 0;
1693           if (current_view->buffer()->the_locking_inset)
1694               UnlockInset(current_view->buffer()->the_locking_inset);
1695           do {
1696               if (!pos || (cursor.par->IsNewline(pos-1))){
1697                   if (cursor.par->table->DeleteCellIfColumnIsDeleted(cell, cell_org)){
1698                       // delete one cell
1699                       while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1700                           cursor.par->Erase(pos);
1701                       if (pos < cursor.par->Last())
1702                           cursor.par->Erase(pos);
1703                       else 
1704                           cursor.par->Erase(pos - 1); // the missing newline at the end of a table
1705                       --pos; // because of pos++ below
1706                   }   
1707                   ++cell;
1708               }
1709               ++pos;
1710           } while (pos <= cursor.par->Last());
1711                 
1712           /* delete the column from the table */ 
1713           cursor.par->table->DeleteColumn(cell_org);
1714                 
1715           /* set the cursor to the beginning of the table, where else? */ 
1716           cursor.pos = 0;
1717           RedoParagraph();
1718           return;
1719       }
1720       case LyXTable::TOGGLE_LINE_TOP:
1721           lineSet = !cursor.par->table->TopLine(actCell);
1722           if (!selection){
1723               cursor.par->table->SetTopLine(actCell, lineSet);
1724           } else {
1725                   LyXParagraph::size_type i;
1726                   int n = -1, m = -2;
1727               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
1728                   if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1729                       cursor.par->table->SetTopLine(n, lineSet);
1730                       m = n;
1731                   }
1732               }
1733           }
1734           RedoParagraph();
1735           return;
1736     
1737       case LyXTable::TOGGLE_LINE_BOTTOM:
1738           lineSet = !cursor.par->table->BottomLine(actCell);
1739           if (!selection){
1740               cursor.par->table->SetBottomLine(actCell, lineSet);
1741           } else {
1742                   LyXParagraph::size_type i;
1743                   int n = -1, m = -2;
1744               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
1745                   if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1746                       cursor.par->table->SetBottomLine(n, lineSet);
1747                       m = n;
1748                   }
1749               }
1750           }
1751           RedoParagraph();
1752           return;
1753                 
1754       case LyXTable::TOGGLE_LINE_LEFT:
1755           lineSet = !cursor.par->table->LeftLine(actCell);
1756           if (!selection){
1757               cursor.par->table->SetLeftLine(actCell, lineSet);
1758           } else {
1759                   LyXParagraph::size_type i;
1760                   int n = -1, m = -2;
1761               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
1762                   if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1763                       cursor.par->table->SetLeftLine(n, lineSet);
1764                       m = n;
1765                   }
1766               }
1767           }
1768           RedoParagraph();
1769           return;
1770
1771       case LyXTable::TOGGLE_LINE_RIGHT:
1772           lineSet = !cursor.par->table->RightLine(actCell);
1773           if (!selection){
1774               cursor.par->table->SetRightLine(actCell, lineSet);
1775           } else {
1776                   LyXParagraph::size_type i;
1777                   int n = -1, m = -2;
1778               for (i= sel_start_cursor.pos; i<= sel_end_cursor.pos; i++){
1779                   if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1780                       cursor.par->table->SetRightLine(n, lineSet);
1781                       m = n;
1782                   }
1783               }
1784           }
1785           RedoParagraph();
1786           return;
1787     
1788       case LyXTable::ALIGN_LEFT:
1789       case LyXTable::ALIGN_RIGHT:
1790       case LyXTable::ALIGN_CENTER:
1791           if (!selection){
1792               cursor.par->table->SetAlignment(actCell, setAlign);
1793           } else {
1794                   LyXParagraph::size_type i;
1795               int n = -1, m = -2;
1796               for (i= sel_start_cursor.pos; i<= sel_end_cursor.pos; i++){
1797                   if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1798                       cursor.par->table->SetAlignment(n, setAlign);
1799                       m = n;
1800                   }
1801               }
1802           }
1803           RedoParagraph();
1804           return;
1805                 
1806       case LyXTable::DELETE_TABLE:
1807           SetCursorIntern(cursor.par, 0);
1808           delete cursor.par->table;
1809           cursor.par->table = 0;
1810           // temporary: Should put table in simple_cut_buffer (with before and after
1811           // dummy-paragraph !! 
1812           // not necessar anymore with UNDO :)
1813           for (LyXParagraph::size_type i = 
1814                        cursor.par->text.size() - 1; i >= 0; --i)
1815               cursor.par->Erase(i);
1816           RedoParagraph();
1817           return;
1818                 
1819       case LyXTable::MULTICOLUMN: {
1820           int number = 0;
1821           // check wether we are completly in a multicol
1822           int multicol = cursor.par->table->IsMultiColumn(actCell);
1823           if (multicol && selection && sel_start_cursor.row == sel_end_cursor.row){
1824               multicol = NumberOfCell(sel_start_cursor.par, sel_start_cursor.pos)
1825                   == NumberOfCell(sel_end_cursor.par, sel_end_cursor.pos);
1826           }
1827
1828           if (multicol){
1829               int newlines = cursor.par->table->UnsetMultiColumn(actCell);
1830               LyXParagraph::size_type pos = cursor.pos;
1831               while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1832                   pos++;
1833               for (;newlines;newlines--)
1834                   cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1835               RedoParagraph();
1836               return;
1837           }
1838           else {
1839               // selection must be in one row (or no selection)
1840               if (!selection){
1841                   cursor.par->table->SetMultiColumn(NumberOfCell(cursor.par,
1842                                                                  cursor.pos),
1843                                                     1);
1844                   RedoParagraph();
1845                   return;
1846               }
1847               else {
1848                   if (sel_start_cursor.row == sel_end_cursor.row){
1849                       LyXParagraph::size_type i;
1850                       number = 1;
1851                       for (i = sel_start_cursor.pos;
1852                            i < sel_end_cursor.pos; ++i){
1853                           if (sel_start_cursor.par->IsNewline(i)){
1854                               sel_start_cursor.par->Erase(i);
1855                               // check for double-blanks
1856                               if ((i && !sel_start_cursor.par->IsLineSeparator(i-1))
1857                                   &&
1858                                   (i < sel_start_cursor.par->Last() 
1859                                    && !sel_start_cursor.par->IsLineSeparator(i)))
1860                                   sel_start_cursor.par->InsertChar(i, ' ');
1861                               else {
1862                                   sel_end_cursor.pos--;
1863                                   i--;
1864                               }
1865                               number++;
1866                           }
1867                       }
1868                       cursor.par->table->
1869                           SetMultiColumn(NumberOfCell(sel_start_cursor.par,
1870                                                       sel_start_cursor.pos),
1871                                          number);
1872                       cursor.pos = sel_start_cursor.pos;
1873                       RedoParagraph();
1874                       return;
1875                   }
1876                   else {
1877                       WriteAlert(_("Impossible Operation!"), 
1878                                  _("Multicolumns can only be horizontally."), 
1879                                  _("Sorry."));
1880                   }
1881               }
1882           }
1883           break;
1884       }
1885       case LyXTable::SET_ALL_LINES:
1886           setLines = 1;
1887       case LyXTable::UNSET_ALL_LINES:
1888           if (!selection){
1889               cursor.par->table->SetAllLines(NumberOfCell(cursor.par,
1890                                                           cursor.pos),
1891                                              setLines);
1892           } else {
1893                   LyXParagraph::size_type i;
1894                   int n = -1, m = -2;
1895               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
1896                   if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1897                       cursor.par->table->SetAllLines(n, setLines);
1898                       m = n;
1899                   }
1900               }
1901           }
1902           RedoParagraph();
1903           return;
1904       case LyXTable::SET_LONGTABLE:
1905           cursor.par->table->SetLongTable(true);
1906           return;
1907       case LyXTable::UNSET_LONGTABLE:
1908           cursor.par->table->SetLongTable(false);
1909           return;
1910       case LyXTable::SET_ROTATE_TABLE:
1911           cursor.par->table->SetRotateTable(true);
1912           return;
1913       case LyXTable::UNSET_ROTATE_TABLE:
1914           cursor.par->table->SetRotateTable(false);
1915           return;
1916       case LyXTable::SET_ROTATE_CELL:
1917           if (!selection){
1918               cursor.par->table->SetRotateCell(actCell, true);
1919           } else {
1920                   LyXParagraph::size_type i;
1921                   int n = -1, m = -2;
1922               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
1923                   if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1924                       cursor.par->table->SetRotateCell(n, true);
1925                       m = n;
1926                   }
1927               }
1928           }
1929           return;
1930       case LyXTable::UNSET_ROTATE_CELL:
1931           if (!selection){
1932               cursor.par->table->SetRotateCell(actCell, false);
1933           } else {
1934                   LyXParagraph::size_type i;
1935                   int n = -1, m = -2;
1936               for (i= sel_start_cursor.pos; i<= sel_end_cursor.pos; i++){
1937                   if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1938                       cursor.par->table->SetRotateCell(n, false);
1939                       m = n;
1940                   }
1941               }
1942           }
1943           return;
1944       case LyXTable::SET_LINEBREAKS:
1945           what = !cursor.par->table->Linebreaks(cursor.par->table->FirstVirtualCell(actCell));
1946           if (!selection){
1947               cursor.par->table->SetLinebreaks(actCell, what);
1948           } else {
1949                   LyXParagraph::size_type i;
1950                   int n = -1, m = -2;
1951               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
1952                   if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1953                       cursor.par->table->SetLinebreaks(n, what);
1954                       m = n;
1955                   }
1956               }
1957           }
1958           return;
1959       case LyXTable::SET_LTFIRSTHEAD:
1960           cursor.par->table->SetLTHead(actCell, true);
1961           return;
1962       case LyXTable::SET_LTHEAD:
1963           cursor.par->table->SetLTHead(actCell, false);
1964           return;
1965       case LyXTable::SET_LTFOOT:
1966           cursor.par->table->SetLTFoot(actCell, false);
1967           return;
1968       case LyXTable::SET_LTLASTFOOT:
1969           cursor.par->table->SetLTFoot(actCell, true);
1970           return;
1971       case LyXTable::SET_LTNEWPAGE:
1972           what = !cursor.par->table->LTNewPage(actCell);
1973           cursor.par->table->SetLTNewPage(actCell, what);
1974           return;
1975     }
1976 }
1977         
1978
1979 void LyXText::InsertCharInTable(char c)
1980 {
1981         Row * row;
1982         Row * tmprow;
1983         long y;
1984         bool jumped_over_space;
1985         
1986         /* first check, if there will be two blanks together or a blank at 
1987          * the beginning of a paragraph. 
1988          * I decided to handle blanks like normal characters, the main 
1989          * difference are the special checks when calculating the row.fill
1990          * (blank does not count at the end of a row) and the check here */ 
1991         
1992         LyXFont realtmpfont = real_current_font;
1993         LyXFont rawtmpfont = current_font; /* store the current font.
1994                                             * This is because of the use
1995                                             * of cursor movements. The moving
1996                                             * cursor would refresh the 
1997                                             * current font */
1998
1999         // Get the font that is used to calculate the baselineskip
2000         LyXParagraph::size_type const lastpos = 
2001                 cursor.par->Last();
2002         LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2003
2004         jumped_over_space = false;
2005         if (IsLineSeparatorChar(c)) {
2006                 
2007                 /* avoid double blanks but insert the new blank because
2008                  * of a possible font change */
2009                 if (cursor.pos < lastpos &&
2010                     cursor.par->IsLineSeparator(cursor.pos))
2011                 {
2012                         cursor.par->Erase(cursor.pos);
2013                         jumped_over_space = true;
2014                 }
2015                 else if ((cursor.pos > 0 && 
2016                           cursor.par->IsLineSeparator(cursor.pos - 1))
2017                          || (cursor.pos > 0 && cursor.par->IsNewline(cursor.pos - 1))
2018                           || (cursor.pos == 0 &&
2019                               !(cursor.par->Previous()
2020                               && cursor.par->Previous()->footnoteflag
2021                               == LyXParagraph::OPEN_FOOTNOTE)))
2022                         return;
2023         }
2024         else if (IsNewlineChar(c)) {
2025             if (!IsEmptyTableCell()) {
2026                 TableFeatures(LyXTable::APPEND_CONT_ROW);
2027                 CursorDown();
2028             }
2029           return;
2030         }
2031    
2032         row = cursor.row;
2033         y = cursor.y - row->baseline;
2034         if (c != LyXParagraph::META_INSET)      /* in this case LyXText::InsertInset 
2035                                          * already inserted the character */
2036                 cursor.par->InsertChar(cursor.pos, c);
2037         SetCharFont(cursor.par, cursor.pos, rawtmpfont);
2038
2039         if (!jumped_over_space) {
2040                 /* refresh the positions */
2041                 tmprow = row;
2042                 while (tmprow->next && tmprow->next->par == row->par) {
2043                         tmprow = tmprow->next;
2044                         tmprow->pos++;
2045                 }
2046         }
2047
2048         cursor.pos++;
2049
2050         CheckParagraphInTable(cursor.par, cursor.pos);
2051         
2052         current_font = rawtmpfont;
2053         real_current_font = realtmpfont;
2054         
2055         /* check, whether the last character's font has changed. */
2056         if (cursor.pos && cursor.pos == cursor.par->Last()
2057             && rawparfont != rawtmpfont)
2058                 RedoHeightOfParagraph(cursor);
2059 }
2060
2061
2062 void LyXText::CheckParagraphInTable(LyXParagraph * par,
2063                                     LyXParagraph::size_type pos)
2064 {
2065         
2066         if (par->GetChar(pos) == LyXParagraph::META_INSET &&
2067             par->GetInset(pos) && par->GetInset(pos)->Display()){
2068           par->GetInset(pos)->SetDisplay(false);
2069         }
2070
2071         long y;
2072         Row * row = GetRow(par, pos, y);
2073         
2074         int tmpheight = row->height;
2075         SetHeightOfRow(row);
2076
2077         LyXParagraph::size_type tmp_pos = pos;
2078         /* update the table information */
2079         while (tmp_pos && !par->IsNewline(tmp_pos - 1))
2080                 tmp_pos--;
2081         if (par->table->SetWidthOfCell(NumberOfCell(par, pos),
2082                                        WidthOfCell(par, tmp_pos))) {
2083                 LyXCursor tmpcursor = cursor;
2084                 SetCursorIntern(par, pos);
2085                 /* make a complete redraw */
2086                 RedoDrawingOfParagraph(cursor);
2087                 cursor = tmpcursor;
2088         }
2089         else {
2090                 /* redraw only the row */
2091                 LyXCursor tmpcursor = cursor;
2092                 SetCursorIntern(par, pos);
2093                 refresh_y = y;
2094                 refresh_x = cursor.x;
2095                 refresh_row = row;
2096                 refresh_pos = cursor.pos;
2097                 cursor = tmpcursor;
2098                 
2099                 if (tmpheight == row->height)
2100                         status = LyXText::NEED_VERY_LITTLE_REFRESH;
2101                 else
2102                         status = LyXText::NEED_MORE_REFRESH;
2103         }
2104         SetCursorIntern(cursor.par, cursor.pos);
2105 }
2106
2107
2108 void LyXText::BackspaceInTable()
2109 {
2110         Row * tmprow, * row;
2111         long y;
2112         
2113         LyXFont rawtmpfont = current_font;
2114         LyXFont realtmpfont = real_current_font;
2115
2116         // Get the font that is used to calculate the baselineskip
2117         int const lastpos = cursor.par->Last();
2118         LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2119         
2120         if (cursor.pos == 0) {
2121                 /* no pasting of table paragraphs */
2122                 
2123                 CursorLeft();
2124         }
2125         else {
2126                 /* this is the code for a normal backspace, not pasting
2127                  * any paragraphs */ 
2128           SetUndo(Undo::DELETE, 
2129                   cursor.par->ParFromPos(cursor.pos)->previous, 
2130                   cursor.par->ParFromPos(cursor.pos)->next); 
2131           
2132                 CursorLeftIntern();
2133                 
2134                 /* some insets are undeletable here */
2135                 if (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
2136                         if (!cursor.par->GetInset(cursor.pos)->Deletable())
2137                                 return;
2138                 }
2139                 
2140                 row = cursor.row;
2141                 y = cursor.y - row->baseline;
2142                 
2143                 /* some special code when deleting a newline. */
2144                 if (cursor.par->IsNewline(cursor.pos)) {
2145                         /* nothing :-) */
2146                         return;
2147                 }
2148                 else {
2149                         cursor.par->Erase(cursor.pos);
2150                         
2151                         /* refresh the positions */
2152                         tmprow = row;
2153                         while (tmprow->next && tmprow->next->par == row->par) {
2154                                 tmprow = tmprow->next;
2155                                 tmprow->pos--;
2156                         }
2157                         
2158                         /* delete superfluous blanks */ 
2159                         if (cursor.pos < cursor.par->Last() - 1 &&
2160                         (cursor.par->IsLineSeparator(cursor.pos))) {
2161                                 
2162                                 if (cursor.pos == BeginningOfMainBody(cursor.par)
2163                                 || !cursor.pos 
2164                                 || cursor.par->IsLineSeparator(cursor.pos - 1)) {
2165                                         cursor.par->Erase(cursor.pos);
2166                                         /* refresh the positions */
2167                                         tmprow = row;
2168                                         while (tmprow->next && 
2169                                                tmprow->next->par == row->par) {
2170                                                 tmprow = tmprow->next;
2171                                                 tmprow->pos--;
2172                                         }
2173                                         if (cursor.pos)   /* move one character left */
2174                                                 cursor.pos--;
2175                                 }
2176                         }
2177                 }
2178       
2179                 CheckParagraphInTable(cursor.par, cursor.pos);
2180       
2181                 /* check, wether the last characters font has changed. */ 
2182                 if (cursor.pos && cursor.pos == cursor.par->Last()
2183                     && rawparfont != rawtmpfont)
2184                         RedoHeightOfParagraph(cursor);
2185
2186                 /* restore the current font 
2187                  * That is what a user expects! */
2188                 current_font = rawtmpfont;
2189                 real_current_font = realtmpfont;
2190         }
2191         SetCursorIntern(cursor.par, cursor.pos);
2192 }
2193
2194 /* table stuff -- end*/
2195
2196
2197 /* just a macro to make some thing easier. */ 
2198 void LyXText::RedoParagraph()
2199 {
2200   LyXCursor tmpcursor = cursor;
2201   ClearSelection();
2202   RedoParagraphs(cursor, cursor.par->Next());;
2203   SetCursorIntern(tmpcursor.par, tmpcursor.pos);
2204 }
2205
2206
2207 /* insert a character, moves all the following breaks in the 
2208  * same Paragraph one to the right and make a rebreak */
2209 void  LyXText::InsertChar(char c)
2210 {
2211         Row * row;
2212         Row * tmprow;
2213         long y;
2214         bool jumped_over_space;
2215         LyXFont realtmpfont;
2216         LyXFont rawtmpfont;
2217         LyXParagraph::size_type z;
2218         LyXParagraph::size_type lastpos;
2219         LyXFont rawparfont;
2220    
2221         SetUndo(Undo::INSERT, 
2222                 cursor.par->ParFromPos(cursor.pos)->previous, 
2223                 cursor.par->ParFromPos(cursor.pos)->next);
2224
2225         /* When the free-spacing option is set for the current layout,
2226          * all spaces are converted to protected spaces. */
2227         bool freeSpacingBo = 
2228                 textclasslist.Style(parameters->textclass,
2229                                cursor.row->par->GetLayout()).free_spacing;
2230    
2231         if (freeSpacingBo && IsLineSeparatorChar(c) 
2232             && (!cursor.pos || cursor.par->IsLineSeparator(cursor.pos-1))) 
2233                 c = LyXParagraph::META_PROTECTED_SEPARATOR;
2234    
2235         /* table stuff -- begin*/
2236         if (cursor.par->table) {
2237                 InsertCharInTable(c);
2238                 goto out;
2239         }
2240         /* table stuff -- end*/
2241    
2242         /* first check, if there will be two blanks together or a blank at 
2243          * the beginning of a paragraph. 
2244          * I decided to handle blanks like normal characters, the main 
2245          * difference are the special checks when calculating the row.fill
2246          * (blank does not count at the end of a row) and the check here */ 
2247
2248         // The bug is triggered when we type in a description environment:
2249         // The current_font is not changed when we go from label to main text
2250         // and it should (along with realtmpfont) when we type the space.
2251 #ifdef WITH_WARNINGS
2252 #warning There is a bug here! (Asger)
2253 #endif
2254         
2255         realtmpfont = real_current_font;
2256         rawtmpfont = current_font;  /* store the current font.
2257                                      * This is because of the use
2258                                      * of cursor movements. The moving
2259                                      * cursor would refresh the 
2260                                      * current font */
2261
2262         // Get the font that is used to calculate the baselineskip
2263         lastpos = cursor.par->Last();
2264         rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2265
2266         jumped_over_space = false;
2267    
2268         if (IsLineSeparatorChar(c)) {
2269            
2270                 if (cursor.pos < lastpos
2271                     && cursor.par->IsLineSeparator(cursor.pos)) {
2272                         /* the user inserted a space before a space. So we
2273                          * will just make a CursorRight. BUT: The font of this
2274                          * space should be set to current font. That is why
2275                          * we need to rebreak perhaps. If there is a protected
2276                          * blank at the end of a row we have to force
2277                          * a rebreak.*/ 
2278            
2279                         minibuffer->Set(_("You cannot type two spaces this way.  Please read the Tutorial."));
2280                         if (cursor.pos == RowLast(cursor.row)
2281                             && !IsLineSeparatorChar(c))
2282                                 cursor.row->fill = -1;    /* force rebreak  */
2283            
2284                         cursor.par->Erase(cursor.pos);
2285                         jumped_over_space = true;
2286            
2287                 } else if ((cursor.pos > 0 
2288                             && cursor.par->IsLineSeparator(cursor.pos - 1))
2289                            || (cursor.pos > 0
2290                                && cursor.par->IsNewline(cursor.pos - 1))
2291                            || (cursor.pos == 0
2292                                && !(cursor.par->Previous()
2293                                     && cursor.par->Previous()->footnoteflag
2294                                     == LyXParagraph::OPEN_FOOTNOTE))) {
2295                         if (cursor.pos == 0 )
2296                                 minibuffer->Set(_("You cannot insert a space at the beginning of a paragraph.  Please read the Tutorial."));
2297                         else
2298                                 minibuffer->Set(_("You cannot type two spaces this way.  Please read the Tutorial."));
2299                         goto out;
2300                 }
2301         } else if (IsNewlineChar(c)) {
2302                 if (cursor.par->FirstPhysicalPar() == cursor.par
2303                     && cursor.pos <= BeginningOfMainBody(cursor.par))
2304                         goto out;
2305                 /* no newline at first position 
2306                  * of a paragraph or behind labels. 
2307                  * TeX does not allow that. */
2308                 
2309                 if (cursor.pos < cursor.par->Last() &&
2310                     cursor.par->IsLineSeparator(cursor.pos))
2311                         CursorRightIntern(); // newline always after a blank!
2312                 cursor.row->fill = -1;         // to force a new break
2313         }
2314    
2315         /* the display inset stuff */ 
2316         if (cursor.row->par->GetChar(cursor.row->pos) == LyXParagraph::META_INSET
2317             && cursor.row->par->GetInset(cursor.row->pos)
2318             && cursor.row->par->GetInset(cursor.row->pos)->Display())
2319                 cursor.row->fill = -1; // to force a new break  
2320
2321         /* get the cursor row fist */
2322         /* this is a dumb solution, i will try to hold the cursor.row
2323            in future */ 
2324         /* row = GetRow(cursor.par, cursor.pos, y);*/
2325         /* ok, heres a better way: */ 
2326         row = cursor.row;
2327         y = cursor.y - row->baseline;
2328         if (c != LyXParagraph::META_INSET)  /* in this case LyXText::InsertInset 
2329                                    * already insertet the character */
2330                 cursor.par->InsertChar(cursor.pos, c);
2331         SetCharFont(cursor.par, cursor.pos, rawtmpfont);
2332
2333         if (!jumped_over_space) {
2334                 /* refresh the positions */
2335                 tmprow = row;
2336                 while (tmprow->next && tmprow->next->par == row->par) {
2337                         tmprow = tmprow->next;
2338                         tmprow->pos++;
2339                 }
2340         }
2341    
2342         /* Is there a break one row above */ 
2343         if ((cursor.par->IsLineSeparator(cursor.pos)
2344              || cursor.par->IsNewline(cursor.pos)
2345              || cursor.row->fill == -1)
2346             && row->previous && row->previous->par == row->par) {
2347                 z = NextBreakPoint(row->previous, paperwidth);
2348                 if ( z >= row->pos) {
2349                         row->pos = z + 1;
2350                         
2351                         /* set the dimensions of the row above  */ 
2352                         row->previous->fill = Fill(row->previous, paperwidth);
2353
2354                         SetHeightOfRow(row->previous);
2355              
2356                         y -= row->previous->height;
2357                         refresh_y = y;
2358                         refresh_row = row->previous;
2359                         status = LyXText::NEED_MORE_REFRESH;
2360              
2361                         BreakAgainOneRow(row);
2362                         SetCursor(cursor.par, cursor.pos + 1);
2363                         /* cursor MUST be in row now */
2364              
2365                         if (row->next && row->next->par == row->par)
2366                                 need_break_row = row->next;
2367                         else
2368                                 need_break_row = 0;
2369
2370                         current_font = rawtmpfont;
2371                         real_current_font = realtmpfont;
2372              
2373                         // check, wether the last characters font has changed. 
2374                         if (cursor.pos && cursor.pos == cursor.par->Last()
2375                             && rawparfont != rawtmpfont)
2376                                 RedoHeightOfParagraph(cursor);
2377                         
2378                         goto out;
2379                 }
2380         }
2381    
2382         /* recalculate the fill of the row */ 
2383         if (row->fill >= 0)  /* needed because a newline
2384                               * will set fill to -1. Otherwise
2385                               * we would not get a rebreak! */
2386                 row->fill = Fill(row, paperwidth);
2387         if (row->fill < 0 ) {
2388                 refresh_y = y;
2389                 refresh_row = row; 
2390                 refresh_x = cursor.x;
2391                 refresh_pos = cursor.pos;
2392                 status = LyXText::NEED_MORE_REFRESH;
2393                 BreakAgainOneRow(row); 
2394                 /* will the cursor be in another row now? */ 
2395                 if (RowLast(row) <= cursor.pos + 1 && row->next) {
2396                         if (row->next && row->next->par == row->par)
2397                                 /* this should
2398                                  * always be true */
2399                                 row = row->next;
2400                         BreakAgainOneRow(row);
2401                 }
2402                 SetCursor(cursor.par, cursor.pos + 1);
2403                 if (row->next && row->next->par == row->par)
2404                         need_break_row = row->next;
2405                 else
2406                         need_break_row = 0;
2407                 
2408                 current_font = rawtmpfont;
2409                 real_current_font = realtmpfont;
2410         } else {
2411                 refresh_y = y;
2412                 refresh_x = cursor.x;
2413                 refresh_row = row;
2414                 refresh_pos = cursor.pos;
2415                 
2416                 int tmpheight = row->height;
2417                 SetHeightOfRow(row);
2418                 if (tmpheight == row->height)
2419                         status = LyXText::NEED_VERY_LITTLE_REFRESH;
2420                 else
2421                         status = LyXText::NEED_MORE_REFRESH;
2422             
2423                 SetCursor(cursor.par, cursor.pos + 1);
2424                 current_font = rawtmpfont;
2425                 real_current_font = realtmpfont;
2426         }
2427
2428         /* check, wether the last characters font has changed. */ 
2429         if (cursor.pos && cursor.pos == cursor.par->Last()
2430             && rawparfont != rawtmpfont) {
2431                 RedoHeightOfParagraph(cursor);
2432         } else {
2433                 /* now the special right address boxes */
2434                 if (textclasslist.Style(parameters->textclass,
2435                                    cursor.par->GetLayout()).margintype
2436                     == MARGIN_RIGHT_ADDRESS_BOX) {
2437                         RedoDrawingOfParagraph(cursor); 
2438                 }
2439         }
2440   out:
2441
2442         // Here we could call FinishUndo for every 20 characters inserted.
2443         // This is from my experience how emacs does it.
2444         static unsigned short counter = 0;
2445         if (counter < 20) {
2446                 ++counter;
2447         } else {
2448                 FinishUndo();
2449                 counter = 0;
2450         }
2451         return;
2452 }
2453    
2454    
2455 void LyXText::PrepareToPrint(Row * row, float & x, float & fill_separator, 
2456                              float & fill_hfill, float & fill_label_hfill)
2457 {
2458         float nh, nlh, ns;
2459         
2460         float w = row->fill;
2461         fill_hfill = 0;
2462         fill_label_hfill = 0;
2463         fill_separator = 0;
2464         fill_label_hfill = 0;
2465         
2466         x = LeftMargin(row);
2467         
2468         /* is there a manual margin with a manual label */ 
2469         if (textclasslist.Style(parameters->textclass,
2470                            row->par->GetLayout()).margintype == MARGIN_MANUAL
2471             && textclasslist.Style(parameters->textclass,
2472                               row->par->GetLayout()).labeltype == LABEL_MANUAL) {
2473                
2474                 nlh = NumberOfLabelHfills(row) + 1; /* one more since labels 
2475                                                     * are left aligned*/ 
2476                 if (nlh && !row->par->GetLabelWidthString().empty()) {
2477                         fill_label_hfill = LabelFill(row) / nlh;
2478                 }
2479         }
2480                 
2481         /* are there any hfills in the row? */ 
2482         nh = NumberOfHfills(row);
2483         
2484 /* table stuff -- begin*/
2485         if (row->par->table) {
2486            w = paperwidth - row->par->table->WidthOfTable()
2487            - x - RightMargin(row);
2488            nh = 0; /* ignore hfills in tables */ 
2489         }
2490 /* table stuff -- end*/
2491
2492         if (nh)
2493           fill_hfill = w /nh;
2494         else  {
2495            /* is it block, flushleft or flushright? 
2496             * set x how you need it */
2497            int align;
2498            if (row->par->FirstPhysicalPar()->align == LYX_ALIGN_LAYOUT)
2499              align = textclasslist.Style(parameters->textclass, row->par->GetLayout()).align;
2500            else
2501              align = row->par->FirstPhysicalPar()->align;
2502            
2503            /* center displayed insets */ 
2504            if (row->par->GetChar(row->pos) == LyXParagraph::META_INSET
2505                && row->par->GetInset(row->pos)
2506                && row->par->GetInset(row->pos)->Display())
2507              align = LYX_ALIGN_CENTER;
2508
2509            switch (align) {
2510             case LYX_ALIGN_BLOCK:
2511               ns = NumberOfSeparators(row);
2512               if (ns && row->next && row->next->par == row->par &&
2513                   !(row->next->par->IsNewline(row->next->pos-1))
2514                   && !(row->next->par->GetChar(row->next->pos) == LyXParagraph::META_INSET
2515                        && row->next->par->GetInset(row->next->pos)
2516                        && row->next->par->GetInset(row->next->pos)->Display())
2517                   )
2518                 fill_separator = w / ns;
2519               break;
2520             case LYX_ALIGN_RIGHT:
2521               x += w;
2522               break;
2523             case LYX_ALIGN_CENTER:
2524               x += w / 2;
2525               break;
2526            }
2527         }
2528      }
2529
2530       
2531 /* important for the screen */
2532
2533
2534 /* the cursor set functions have a special mechanism. When they
2535 * realize, that you left an empty paragraph, they will delete it.
2536 * They also delete the corresponding row */
2537
2538 void LyXText::CursorRightOneWord()
2539 {
2540         // treat floats, HFills and Insets as words
2541         LyXCursor tmpcursor = cursor;
2542
2543         if (tmpcursor.pos == tmpcursor.par->Last()
2544             && tmpcursor.par->Next())
2545         {
2546                         tmpcursor.par = tmpcursor.par->Next();
2547                         tmpcursor.pos = 0;
2548         } else {
2549                 int steps = 0;
2550
2551                 // Skip through initial nonword stuff.
2552                 while ( tmpcursor.pos < tmpcursor.par->Last() &&
2553                         ! tmpcursor.par->IsWord( tmpcursor.pos ) ) 
2554                 {
2555                   //    printf("Current pos1 %d", tmpcursor.pos) ;
2556                         tmpcursor.pos++;
2557                         steps++;
2558                 }
2559                 // Advance through word.
2560                 while ( tmpcursor.pos < tmpcursor.par->Last() &&
2561                         tmpcursor.par->IsWord( tmpcursor.pos ) )
2562                 {
2563                   //     printf("Current pos2 %d", tmpcursor.pos) ;
2564                         tmpcursor.pos++;
2565                         steps++;
2566                 }
2567         }
2568         SetCursor(tmpcursor.par, tmpcursor.pos);
2569 }
2570
2571
2572 void LyXText::CursorTab()
2573 {
2574     if (cursor.par->table) {
2575         int cell = NumberOfCell(cursor.par, cursor.pos);
2576         while(cursor.par->table->IsContRow(cell)) {
2577             CursorUp();
2578             cell = NumberOfCell(cursor.par, cursor.pos);
2579         }
2580         if (cursor.par->table->ShouldBeVeryLastCell(cell))
2581             TableFeatures(LyXTable::APPEND_ROW);
2582     }
2583     LyXCursor tmpcursor = cursor;
2584     while (tmpcursor.pos < tmpcursor.par->Last()
2585            && !tmpcursor.par->IsNewline(tmpcursor.pos))
2586         tmpcursor.pos++;
2587    
2588     if (tmpcursor.pos == tmpcursor.par->Last()){
2589         if (tmpcursor.par->Next()) {
2590             tmpcursor.par = tmpcursor.par->Next();
2591             tmpcursor.pos = 0;
2592         }
2593     }
2594     else
2595         tmpcursor.pos++;
2596     SetCursor(tmpcursor.par, tmpcursor.pos);
2597     if (cursor.par->table) {
2598         int cell = NumberOfCell(cursor.par, cursor.pos);
2599         while (cursor.par->table->IsContRow(cell) &&
2600                !cursor.par->table->ShouldBeVeryLastCell(cell)) {
2601             tmpcursor = cursor;
2602             while (tmpcursor.pos < tmpcursor.par->Last()
2603                    && !tmpcursor.par->IsNewline(tmpcursor.pos))
2604                 tmpcursor.pos++;
2605    
2606             if (tmpcursor.pos == tmpcursor.par->Last()){
2607                 if (tmpcursor.par->Next()) {
2608                     tmpcursor.par = tmpcursor.par->Next();
2609                     tmpcursor.pos = 0;
2610                 }
2611             }
2612             else
2613                 tmpcursor.pos++;
2614             SetCursor(tmpcursor.par, tmpcursor.pos);
2615             cell = NumberOfCell(cursor.par, cursor.pos);
2616         }
2617     }
2618 }
2619
2620
2621 /* -------> Skip initial whitespace at end of word and move cursor to *start*
2622             of prior word, not to end of next prior word. */
2623
2624 void LyXText::CursorLeftOneWord() 
2625 {
2626         // treat HFills, floats and Insets as words
2627         LyXCursor tmpcursor = cursor;
2628         while (tmpcursor.pos 
2629                && (tmpcursor.par->IsSeparator(tmpcursor.pos - 1) 
2630                    || tmpcursor.par->IsKomma(tmpcursor.pos - 1))
2631                && !(tmpcursor.par->IsHfill(tmpcursor.pos - 1)
2632                     || tmpcursor.par->IsFloat(tmpcursor.pos - 1)
2633                     || tmpcursor.par->IsInset(tmpcursor.pos - 1)))
2634                 tmpcursor.pos--;
2635
2636         if (tmpcursor.pos
2637             && (tmpcursor.par->IsInset(tmpcursor.pos - 1)
2638                 || tmpcursor.par->IsFloat(tmpcursor.pos - 1)
2639                 || tmpcursor.par->IsHfill(tmpcursor.pos - 1))) {
2640                 tmpcursor.pos--;
2641         } else if (!tmpcursor.pos) {
2642                 if (tmpcursor.par->Previous()){
2643                         tmpcursor.par = tmpcursor.par->Previous();
2644                         tmpcursor.pos = tmpcursor.par->Last();
2645                 }
2646         } else {                // Here, tmpcursor != 0 
2647                 while (tmpcursor.pos > 0 &&
2648                        tmpcursor.par->IsWord(tmpcursor.pos-1) )
2649                         tmpcursor.pos-- ;
2650         }
2651         SetCursor(tmpcursor.par, tmpcursor.pos);
2652 }
2653
2654 /* -------> Select current word. This depends on behaviour of CursorLeftOneWord(), so it is
2655                         patched as well. */
2656
2657 void LyXText::SelectWord() 
2658 {
2659         /* Move cursor to the beginning, when not already there. */
2660         if ( cursor.pos
2661              && !cursor.par->IsSeparator(cursor.pos-1)
2662              && !cursor.par->IsKomma(cursor.pos-1) )
2663                 CursorLeftOneWord();
2664
2665         /* set the sel cursor */
2666         sel_cursor = cursor;
2667
2668         while ( cursor.pos < cursor.par->Last()
2669                         && !cursor.par->IsSeparator(cursor.pos)
2670                         && !cursor.par->IsKomma(cursor.pos) )
2671                 cursor.pos++;
2672         SetCursor( cursor.par, cursor.pos );
2673         
2674         /* finally set the selection */ 
2675         SetSelection();
2676 }
2677
2678
2679 /* -------> Select the word currently under the cursor when:
2680                         1: no selection is currently set,
2681                         2: the cursor is not at the borders of the word. */
2682
2683 int LyXText::SelectWordWhenUnderCursor() 
2684 {
2685         if ( selection ) return 0;
2686         if ( cursor.pos < cursor.par->Last()
2687                  && !cursor.par->IsSeparator(cursor.pos)
2688                  && !cursor.par->IsKomma(cursor.pos)
2689                  && cursor.pos 
2690                  && !cursor.par->IsSeparator(cursor.pos -1)
2691                  && !cursor.par->IsKomma(cursor.pos -1) ) {
2692                 SelectWord();
2693                 return 1;
2694         }
2695         return 0;
2696 }
2697
2698
2699 // This function is only used by the spellchecker for NextWord().
2700 // It doesn't handle LYX_ACCENTs and probably never will.
2701 char * LyXText::SelectNextWord(float & value)
2702 {
2703         LyXParagraph * tmppar = cursor.par;
2704         
2705         // If this is not the very first word, skip rest of
2706         // current word because we are probably in the middle
2707         // of a word if there is text here.
2708         if (cursor.pos || cursor.par->previous) {
2709                 while (cursor.pos < cursor.par->Last()
2710                        && cursor.par->IsLetter(cursor.pos))
2711                         cursor.pos++;
2712         }
2713         // Now, skip until we have real text (will jump paragraphs)
2714         while ((cursor.par->Last() > cursor.pos
2715                 && (!cursor.par->IsLetter(cursor.pos)
2716                     || cursor.par->getFont(cursor.pos).latex() == LyXFont::ON))
2717                || (cursor.par->Last() == cursor.pos
2718                    && cursor.par->Next())){
2719                 if (cursor.pos == cursor.par->Last()) {
2720                         cursor.par = cursor.par->Next();
2721                         cursor.pos = 0;
2722                 }
2723                 else
2724                         cursor.pos++;
2725         }
2726   
2727         // Update the value if we changed paragraphs
2728         if (cursor.par != tmppar){
2729                 SetCursor(cursor.par, cursor.pos);
2730                 value = float(cursor.y)/float(height);
2731         }
2732
2733         /* Start the selection from here */
2734         sel_cursor = cursor;
2735
2736         string latex;
2737    
2738         /* and find the end of the word 
2739            (optional hyphens are part of a word) */
2740         while (cursor.pos < cursor.par->Last()
2741                && (cursor.par->IsLetter(cursor.pos)) 
2742                    || (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET &&
2743                        cursor.par->GetInset(cursor.pos) != 0 &&
2744                        cursor.par->GetInset(cursor.pos)->Latex(latex, 0) == 0 &&
2745                        latex == "\\-"))
2746                 cursor.pos++;
2747
2748         // Finally, we copy the word to a string and return it
2749         char * str = 0;
2750
2751         if (sel_cursor.pos < cursor.pos) {
2752                 str = new char [cursor.pos - sel_cursor.pos + 2];
2753                 LyXParagraph::size_type i, j;
2754                 for (i = sel_cursor.pos, j = 0; i < cursor.pos; ++i) {
2755                         if (cursor.par->GetChar(i) != LyXParagraph::META_INSET)
2756                                 str[j++] = cursor.par->GetChar(i);
2757                 }
2758                 str[j] = '\0';
2759         }
2760         return str;
2761 }
2762
2763
2764 // This one is also only for the spellchecker
2765 void LyXText::SelectSelectedWord()
2766 {
2767         /* move cursor to the beginning */
2768         SetCursor(sel_cursor.par, sel_cursor.pos);
2769         
2770         /* set the sel cursor */
2771         sel_cursor = cursor;
2772
2773         string latex;
2774         
2775         /* now find the end of the word */
2776         while (cursor.pos < cursor.par->Last()
2777                && (cursor.par->IsLetter(cursor.pos)
2778                    || (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET &&
2779                        cursor.par->GetInset(cursor.pos) != 0 &&
2780                        cursor.par->GetInset(cursor.pos)->Latex(latex, 0) == 0 &&
2781                        latex == "\\-")))
2782                 cursor.pos++;
2783         
2784         SetCursor(cursor.par, cursor.pos);
2785         
2786         /* finally set the selection */ 
2787         SetSelection();
2788 }
2789
2790
2791 /* -------> Delete from cursor up to the end of the current or next word. */
2792 void LyXText::DeleteWordForward()
2793 {
2794         LyXCursor tmpcursor = cursor;
2795         
2796         if (!cursor.par->Last())
2797                 CursorRight();
2798         else {
2799                 /* -------> Skip initial non-word stuff. */
2800                 while ( cursor.pos < cursor.par->Last() 
2801                         && (cursor.par->IsSeparator(cursor.pos)
2802                             || cursor.par->IsKomma(cursor.pos)) )
2803                         cursor.pos++;
2804                 
2805                 SetCursorIntern(cursor.par, cursor.pos);
2806                 selection = True; // to avoid deletion 
2807                 CursorRightOneWord();
2808                 sel_cursor = cursor;
2809                 cursor = tmpcursor;
2810                 SetSelection(); 
2811                 
2812                 /* -----> Great, CutSelection() gets rid of multiple spaces. */
2813                 CutSelection();
2814         }
2815 }
2816
2817
2818 /* -------> Delete from cursor to start of current or prior word. */
2819 void LyXText::DeleteWordBackward()
2820 {
2821        LyXCursor tmpcursor = cursor;
2822        if (!cursor.par->Last())
2823          CursorLeft();
2824        else{
2825          selection = true; // to avoid deletion 
2826          CursorLeftOneWord();
2827          sel_cursor = cursor;
2828          cursor = tmpcursor;
2829          SetSelection();
2830          CutSelection();
2831        }
2832 }
2833
2834
2835 /* -------> Kill to end of line. */
2836 void LyXText::DeleteLineForward()
2837 {
2838         LyXCursor tmpcursor = cursor;
2839         if (!cursor.par->Last())
2840                 CursorRight();
2841         else {
2842                 CursorEnd();
2843                 sel_cursor = cursor;
2844                 cursor = tmpcursor;
2845                 SetSelection();
2846                 if (selection == false) {
2847                         DeleteWordForward();
2848                 } else {
2849                         CutSelection();
2850                 }
2851         }
2852 }
2853
2854
2855 // Change the case of a word at cursor position. The meaning of action
2856 // is:
2857 // 0  change to lowercase
2858 // 1  capitalize word
2859 // 2  change to uppercase
2860 // This function directly manipulates LyXParagraph::text because there
2861 // is no LyXParagraph::SetChar currently. I did what I could to ensure
2862 // that it is correct. I guess part of it should be moved to
2863 // LyXParagraph, but it will have to change for 1.1 anyway. At least
2864 // it does not access outside of the allocated array as the older
2865 // version did. (JMarc) 
2866 void LyXText::ChangeWordCase(LyXText::TextCase action) 
2867 {
2868         LyXParagraph * tmppar = cursor.par->ParFromPos(cursor.pos);
2869
2870         SetUndo(Undo::FINISH, tmppar->previous, tmppar->next); 
2871
2872         LyXParagraph::size_type tmppos = 
2873                 cursor.par->PositionInParFromPos(cursor.pos);
2874         while (tmppos < tmppar->size()) {
2875                 unsigned char c = tmppar->text[tmppos];
2876                 if (IsKommaChar(c) || IsLineSeparatorChar(c))
2877                         break;
2878                 if (c != LyXParagraph::META_INSET) {
2879                         switch (action) {
2880                         case text_lowercase:
2881                                 c = tolower(c);
2882                                 break;
2883                         case text_capitalization:
2884                                 c = toupper(c);
2885                                 action = text_lowercase;
2886                                 break;
2887                         case text_uppercase:
2888                                 c = toupper(c);
2889                                 break;
2890                         }
2891                 }
2892                 
2893                 tmppar->text[tmppos] = c;
2894                 ++tmppos;
2895         }
2896         CheckParagraph(tmppar, tmppos);
2897         CursorRightOneWord();
2898 }
2899
2900
2901 void  LyXText::Delete()
2902 {
2903    LyXCursor old_cursor = cursor;
2904    /* this is a very easy implementation*/ 
2905    
2906    /* just move to the right */ 
2907    CursorRightIntern();
2908    
2909    if (cursor.par->previous == old_cursor.par->previous
2910        && cursor.par != old_cursor.par)
2911      return; // delete-emty-paragraph-mechanism has done it
2912    
2913    /* if you had success make a backspace */ 
2914    if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) {
2915      LyXCursor tmpcursor = cursor;
2916      cursor = old_cursor; // to make sure undo gets the right cursor position
2917      SetUndo(Undo::DELETE, 
2918              cursor.par->ParFromPos(cursor.pos)->previous, 
2919              cursor.par->ParFromPos(cursor.pos)->next); 
2920      cursor = tmpcursor;
2921      Backspace();
2922    }
2923 }
2924
2925
2926 void  LyXText::Backspace()
2927 {
2928         LyXParagraph * tmppar;
2929         Row * tmprow, * row;
2930         long y;
2931         int tmpheight;
2932
2933         /* table stuff -- begin*/
2934    
2935         if (cursor.par->table) {
2936                 BackspaceInTable();
2937                 return;
2938         }
2939         /* table stuff -- end*/
2940         
2941         LyXFont rawtmpfont = current_font;
2942         LyXFont realtmpfont = real_current_font;
2943    
2944         // Get the font that is used to calculate the baselineskip
2945         int const lastpos = cursor.par->Last();
2946         LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2947
2948         if (cursor.pos == 0) {
2949                 /* we may paste some paragraphs */
2950       
2951                 /* is it an empty paragraph? */
2952       
2953                 if ((lastpos == 0
2954                      || (lastpos == 1 && cursor.par->IsSeparator(0)))
2955                     && !(cursor.par->Next() 
2956                          && cursor.par->footnoteflag == 
2957                          LyXParagraph::NO_FOOTNOTE
2958                          && cursor.par->Next()->footnoteflag == 
2959                          LyXParagraph::OPEN_FOOTNOTE)) {
2960                         
2961                         if (cursor.par->previous) {
2962                                 tmppar = cursor.par->previous->FirstPhysicalPar();
2963                                 if (cursor.par->GetLayout() == tmppar->GetLayout()
2964                                     && cursor.par->footnoteflag == tmppar->footnoteflag
2965                                     && cursor.par->GetAlign() == tmppar->GetAlign()) {
2966                                         
2967                                         tmppar->line_bottom = cursor.par->line_bottom;
2968                                         tmppar->added_space_bottom = cursor.par->added_space_bottom;
2969                                         tmppar->pagebreak_bottom = cursor.par->pagebreak_bottom;
2970                                 }
2971                                 
2972                                 CursorLeftIntern();
2973                      
2974                                 /* the layout things can change the height of a row ! */ 
2975                                 tmpheight = cursor.row->height;
2976                                 SetHeightOfRow(cursor.row);
2977                                 if (cursor.row->height != tmpheight) {
2978                                         refresh_y = cursor.y - cursor.row->baseline;
2979                                         refresh_row = cursor.row;
2980                                         status = LyXText::NEED_MORE_REFRESH;
2981                                 }
2982                                 return;
2983                         }
2984                 }
2985                 if (cursor.par->ParFromPos(cursor.pos)->previous){
2986                         SetUndo(Undo::DELETE, 
2987                                 cursor.par->ParFromPos(cursor.pos)->previous->previous, 
2988                                 cursor.par->ParFromPos(cursor.pos)->next); 
2989                 }
2990                 tmppar = cursor.par;
2991                 tmprow = cursor.row;
2992                 CursorLeftIntern();
2993                 /* Pasting is not allowed, if the paragraphs have different
2994                    layout. I think it is a real bug of all other
2995                    word processors to allow it. It confuses the user.
2996                    Even so with a footnote paragraph and a non-footnote
2997                    paragraph. I will not allow pasting in this case, 
2998                    because the user would be confused if the footnote behaves 
2999                    different wether it is open or closed.
3000                   
3001                    Correction: Pasting is always allowed with standard-layout
3002                 */
3003                 if (cursor.par != tmppar
3004                     && (cursor.par->GetLayout() == tmppar->GetLayout()
3005                         || !tmppar->GetLayout())
3006                     && cursor.par->footnoteflag == tmppar->footnoteflag
3007                     /* table stuff -- begin*/
3008                     && !cursor.par->table /* no pasting of tables */ 
3009                     /* table stuff -- end*/
3010                     && cursor.par->GetAlign() == tmppar->GetAlign()) {
3011                         
3012                         cursor.par->PasteParagraph();
3013                         
3014                         if (!(cursor.pos &&
3015                               cursor.par->IsSeparator(cursor.pos - 1)))
3016                                 cursor.par->InsertChar(cursor.pos, ' ');
3017                         else
3018                                 if (cursor.pos)
3019                                         cursor.pos--;
3020                         
3021                         status = LyXText::NEED_MORE_REFRESH;
3022                         refresh_row = cursor.row;
3023                         refresh_y = cursor.y - cursor.row->baseline;
3024                         
3025                         /* remove the lost paragraph */
3026                         RemoveParagraph(tmprow);
3027                         RemoveRow(tmprow);  
3028                         
3029                         AppendParagraph(cursor.row);
3030                         UpdateCounters(cursor.row);
3031                         
3032                         /* the row may have changed, block, hfills etc. */ 
3033                         SetCursor(cursor.par, cursor.pos);
3034                 }
3035         } else  {
3036                 /* this is the code for a normal backspace, not pasting
3037                  * any paragraphs */ 
3038                 SetUndo(Undo::DELETE, 
3039                         cursor.par->ParFromPos(cursor.pos)->previous, 
3040                         cursor.par->ParFromPos(cursor.pos)->next); 
3041                 CursorLeftIntern();
3042                 
3043                 /* some insets are undeletable here */
3044                 if (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
3045                         if (!cursor.par->GetInset(cursor.pos)->Deletable())
3046                                 return; 
3047                         /* force complete redo when erasing display insets */ 
3048                         /* this is a cruel mathod but save..... Matthias */ 
3049                         if (cursor.par->GetInset(cursor.pos)->Display()){
3050                                 cursor.par->Erase(cursor.pos);
3051                                 RedoParagraph();
3052                                 return;
3053                         }
3054                 }
3055                 
3056                 row = cursor.row;
3057                 y = cursor.y - row->baseline;
3058                 LyXParagraph::size_type z;
3059                 /* remember that a space at the end of a row doesnt count
3060                  * when calculating the fill */ 
3061                 if (cursor.pos < RowLast(row) ||
3062                     !cursor.par->IsLineSeparator(cursor.pos)) {
3063                         row->fill += SingleWidth(cursor.par, cursor.pos);
3064                 }
3065                 
3066                 /* some special code when deleting a newline. This is similar
3067                  * to the behavior when pasting paragraphs */ 
3068                 if (cursor.pos && cursor.par->IsNewline(cursor.pos)) {
3069                         cursor.par->Erase(cursor.pos);
3070                         /* refresh the positions */
3071                         tmprow = row;
3072                         while (tmprow->next && tmprow->next->par == row->par) {
3073                                 tmprow = tmprow->next;
3074                                 tmprow->pos--;
3075                         }
3076                         if (cursor.par->IsLineSeparator(cursor.pos - 1))
3077                                 cursor.pos--;
3078                         
3079                         if (cursor.pos < cursor.par->Last() && !cursor.par->IsSeparator(cursor.pos)) {
3080                                 cursor.par->InsertChar(cursor.pos, ' ');
3081                                 /* refresh the positions */
3082                                 tmprow = row;
3083                                 while (tmprow->next && tmprow->next->par == row->par) {
3084                                         tmprow = tmprow->next;
3085                                         tmprow->pos++;
3086                                 }
3087                         }
3088                 } else {
3089                         cursor.par->Erase(cursor.pos);
3090                         
3091                         /* refresh the positions */
3092                         tmprow = row;
3093                         while (tmprow->next && tmprow->next->par == row->par) {
3094                                 tmprow = tmprow->next;
3095                                 tmprow->pos--;
3096                         }
3097                         
3098                         /* delete superfluous blanks */ 
3099                         if (cursor.pos < cursor.par->Last() - 1 &&
3100                             (cursor.par->IsLineSeparator(cursor.pos))) {
3101                                 
3102                                 if (cursor.pos == BeginningOfMainBody(cursor.par)
3103                                     || !cursor.pos 
3104                                     || cursor.par->IsLineSeparator(cursor.pos - 1)) {
3105                                         cursor.par->Erase(cursor.pos);
3106                                         /* refresh the positions */
3107                                         tmprow = row;
3108                                         while (tmprow->next && 
3109                                                tmprow->next->par == row->par) {
3110                                                 tmprow = tmprow->next;
3111                                                 tmprow->pos--;
3112                                         }
3113                                         if (cursor.pos)   /* move one character left */
3114                                                 cursor.pos--;
3115                                 }
3116                         }
3117                         
3118                         /* delete newlines at the beginning of paragraphs */ 
3119                         while (cursor.par->Last() &&
3120                                cursor.par->IsNewline(cursor.pos) &&
3121                                cursor.pos == BeginningOfMainBody(cursor.par)) {
3122                                 cursor.par->Erase(cursor.pos);
3123                                 /* refresh the positions */
3124                                 tmprow = row;
3125                                 while (tmprow->next && 
3126                                        tmprow->next->par == row->par) {
3127                                         tmprow = tmprow->next;
3128                                         tmprow->pos--;
3129                                 }
3130                         }
3131                 }
3132                 
3133                 /* is there a break one row above */ 
3134                 if (row->previous && row->previous->par == row->par) {
3135                         z = NextBreakPoint(row->previous, paperwidth);
3136                         if ( z >= row->pos) {
3137                                 row->pos = z + 1;
3138                                 
3139                                 tmprow = row->previous;
3140                                 
3141                                 /* maybe the current row is now empty */ 
3142                                 if (row->pos >= row->par->Last()) {
3143                                         /* remove it */ 
3144                                         RemoveRow(row);
3145                                         need_break_row = 0;
3146                                 }
3147                                 else  {
3148                                         BreakAgainOneRow(row);
3149                                         if (row->next && row->next->par == row->par)
3150                                                 need_break_row = row->next;
3151                                         else
3152                                                 need_break_row = 0;
3153                                 }
3154                                 
3155                                 /* set the dimensions of the row above  */ 
3156                                 y -= tmprow->height;
3157                                 tmprow->fill = Fill(tmprow, paperwidth);
3158                                 SetHeightOfRow(tmprow);
3159                                 
3160                                 refresh_y = y;
3161                                 refresh_row = tmprow;
3162                                 status = LyXText::NEED_MORE_REFRESH;
3163                                 SetCursor(cursor.par, cursor.pos);
3164                                 current_font = rawtmpfont;
3165                                 real_current_font = realtmpfont;
3166                                 /* check, whether the last character's font has changed. */
3167                                 rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
3168                                 if (rawparfont != rawtmpfont)
3169                                         RedoHeightOfParagraph(cursor);
3170                                 return;
3171                         }
3172                 }
3173                 
3174                 /* break the cursor row again */ 
3175                 z = NextBreakPoint(row, paperwidth);
3176                 
3177                 if ( z != RowLast(row) || 
3178                      (row->next && row->next->par == row->par &&
3179                       RowLast(row) == row->par->Last() - 1)){
3180                         
3181                         /* it can happen that a paragraph loses one row
3182                          * without a real breakup. This is when a word
3183                          * is to long to be broken. Well, I don t care this 
3184                          * hack ;-) */ 
3185                         if (row->next && row->next->par == row->par &&
3186                             RowLast(row) == row->par->Last() - 1)
3187                                 RemoveRow(row->next);
3188                         
3189                         refresh_y = y;
3190                         refresh_row = row;
3191                         status = LyXText::NEED_MORE_REFRESH;
3192                         
3193                         BreakAgainOneRow(row);
3194                         
3195                         SetCursor(cursor.par, cursor.pos);
3196                         /* cursor MUST be in row now */
3197                         
3198                         if (row->next && row->next->par == row->par)
3199                                 need_break_row = row->next;
3200                         else
3201                                 need_break_row = 0;
3202                 } else  {
3203                         /* set the dimensions of the row */ 
3204                         row->fill = Fill(row, paperwidth);
3205                         int tmpheight = row->height;
3206                         SetHeightOfRow(row);
3207                         if (tmpheight == row->height)
3208                                 status = LyXText::NEED_VERY_LITTLE_REFRESH;
3209                         else
3210                                 status = LyXText::NEED_MORE_REFRESH;
3211                         refresh_y = y;
3212                         refresh_row = row;
3213                         SetCursor(cursor.par, cursor.pos);
3214                 }
3215         }
3216    
3217         /* restore the current font 
3218          * That is what a user expects! */
3219         current_font = rawtmpfont; 
3220         real_current_font = realtmpfont;
3221         
3222         /* check, wether the last characters font has changed. */
3223         rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
3224         if (rawparfont != rawtmpfont) {
3225                 RedoHeightOfParagraph(cursor);
3226         } else {
3227                 /* now the special right address boxes */
3228                 if (textclasslist.Style(parameters->textclass,
3229                                    cursor.par->GetLayout()).margintype == MARGIN_RIGHT_ADDRESS_BOX) {
3230                         RedoDrawingOfParagraph(cursor); 
3231                 }
3232         }
3233 }
3234
3235
3236 void LyXText::GetVisibleRow(LyXScreen & scr, int offset, 
3237                             Row * row_ptr, long y)
3238 {
3239         /* returns a printed row */
3240         LyXParagraph::size_type pos, pos_end;
3241         float x, tmpx;
3242         int y_top, y_bottom;
3243         float fill_separator, fill_hfill, fill_label_hfill;
3244         LyXParagraph * par, * firstpar;
3245         int left_margin;
3246         LyXFont font;
3247         int maxdesc;
3248         if (row_ptr->height <= 0) {
3249                 lyxerr << "LYX_ERROR: row.height: " << row_ptr->height << endl;
3250                 return;
3251         }
3252         left_margin = LabelEnd(row_ptr);
3253         PrepareToPrint(row_ptr, x, fill_separator,
3254                        fill_hfill, fill_label_hfill);
3255
3256         LyXParagraph::size_type main_body = 
3257                 BeginningOfMainBody(row_ptr->par);
3258         /* initialize the pixmap */
3259         
3260         scr.fillRectangle(gc_clear,
3261                           0, offset, paperwidth, row_ptr->height);
3262         // check for NOT FAST SELECTION
3263         if (!fast_selection && !mono_video && selection) {
3264                 /* selection code */ 
3265                 if (sel_start_cursor.row == row_ptr &&
3266                     sel_end_cursor.row == row_ptr) {
3267                         scr.fillRectangle(gc_selection, sel_start_cursor.x,
3268                                           offset,
3269                                           sel_end_cursor.x -
3270                                           sel_start_cursor.x,
3271                                           row_ptr->height);
3272                 }
3273                 else if (sel_start_cursor.row == row_ptr) {
3274                         scr.fillRectangle(gc_selection, sel_start_cursor.x,
3275                                           offset,
3276                                           paperwidth - sel_start_cursor.x,
3277                                           row_ptr->height);
3278                 } else if (sel_end_cursor.row == row_ptr) {
3279                         scr.fillRectangle(gc_selection, 0, offset,
3280                                           sel_end_cursor.x, row_ptr->height);
3281                 } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
3282                         scr.fillRectangle(gc_selection, 0, offset,
3283                                           paperwidth, row_ptr->height);
3284                         
3285                 }
3286         } // end of NOT FAST SELECTION code
3287         
3288         if (row_ptr->par->appendix){
3289           scr.drawVerticalLine(gc_math, 1, offset, offset+row_ptr->height);
3290           scr.drawVerticalLine(gc_math, paperwidth-2 , offset, offset+row_ptr->height);
3291         }
3292
3293         if (row_ptr->par->pextra_type == LyXParagraph::PEXTRA_MINIPAGE) {
3294                 /* draw a marker at the left margin! */ 
3295                 LyXFont font = GetFont(row_ptr->par, 0);
3296                 int asc = font.maxAscent();
3297                 int x = (LYX_PAPER_MARGIN - font.width('|')) / 2;
3298                 int y1 = (offset + row_ptr->baseline);
3299                 int y2 = (offset + row_ptr->baseline) - asc;
3300
3301                 scr.drawVerticalLine(gc_minipage, x, y1, y2);
3302         }       
3303         if (row_ptr->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3304                 LyXFont font(LyXFont::ALL_SANE);
3305                 font.setSize(LyXFont::SIZE_FOOTNOTE);
3306                 font.setColor(LyXFont::RED);
3307                 
3308                 int box_x = LYX_PAPER_MARGIN;
3309                 box_x += font.textWidth(" wide-tab ", 10);
3310                 if (row_ptr->previous && 
3311                     row_ptr->previous->par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
3312                         string fs;
3313                         switch (row_ptr->par->footnotekind) {
3314                         case LyXParagraph::MARGIN:
3315                                 fs = " margin";
3316                                 break;
3317                         case LyXParagraph::FIG:
3318                                 fs = " fig";
3319                                 break;
3320                         case LyXParagraph::TAB:
3321                                 fs = " tab";
3322                                 break;
3323                         case LyXParagraph::WIDE_FIG:
3324                                 fs = " wide-fig";
3325                                 break;
3326                         case LyXParagraph::WIDE_TAB:
3327                                 fs = " wide-tab";
3328                                 break;
3329                         case LyXParagraph::ALGORITHM:
3330                                 fs = " alg";
3331                                 break;
3332                         case LyXParagraph::FOOTNOTE:
3333                                 fs = " foot";
3334                                 break;
3335                         }
3336                         
3337                         // Determine background color.
3338                         gc_type back = gc_lighted;
3339                         if (mono_video) {
3340                                 back = gc_clear;
3341                         }
3342                         scr.fillRectangle(back, LYX_PAPER_MARGIN, offset+1,
3343                                           box_x - LYX_PAPER_MARGIN, 
3344                                           int(font.maxAscent())+
3345                                           int(font.maxDescent()));
3346                         
3347                         scr.drawLine(gc_foot,
3348                                      offset,
3349                                      LYX_PAPER_MARGIN,
3350                                      paperwidth - 2*LYX_PAPER_MARGIN);
3351                         
3352                         scr.drawString(font, fs,
3353                                        offset + int(font.maxAscent())+1,
3354                                        LYX_PAPER_MARGIN);
3355                         scr.drawVerticalLine(gc_foot,
3356                                              LYX_PAPER_MARGIN,
3357                                              offset,
3358                                              offset
3359                                              + int(font.maxAscent())+
3360                                              int(font.maxDescent()));
3361                         
3362                         scr.drawLine(gc_foot,
3363                                      offset
3364                                      + int(font.maxAscent())
3365                                      + int(font.maxDescent()) + 1,
3366                                      LYX_PAPER_MARGIN, box_x - LYX_PAPER_MARGIN); 
3367                 }
3368                 
3369                 /* draw the open floats in a red box */
3370                 scr.drawVerticalLine(gc_foot,
3371                                      box_x,
3372                                      offset,  offset + row_ptr->height);
3373                 
3374                 scr.drawVerticalLine(gc_foot,
3375                                      paperwidth - LYX_PAPER_MARGIN,
3376                                      offset,
3377                                      offset + row_ptr->height);
3378                         
3379                 
3380         } else  {
3381                 if (row_ptr->previous &&
3382                     row_ptr->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3383                         LyXFont font(LyXFont::ALL_SANE);
3384                         font.setSize(LyXFont::SIZE_FOOTNOTE);
3385                         
3386                         int box_x = LYX_PAPER_MARGIN;
3387                         box_x += font.textWidth(" wide-tab ", 10);
3388                         
3389                         scr.drawLine(gc_foot,
3390                                      offset,
3391                                      box_x,
3392                                      paperwidth - LYX_PAPER_MARGIN - box_x);
3393                 }
3394         }
3395         
3396         LyXLayout const & layout = textclasslist.Style(parameters->textclass,
3397                                            row_ptr->par->GetLayout());
3398         firstpar = row_ptr->par->FirstPhysicalPar();
3399         
3400         y_top = 0;
3401         y_bottom = row_ptr->height;
3402         
3403         /* is it a first row? */ 
3404         if (row_ptr->pos == 0
3405             && row_ptr->par == firstpar) {
3406                 
3407                  /* start of appendix? */
3408                 if (row_ptr->par->start_of_appendix){
3409                   scr.drawLine(gc_math, 
3410                                offset,
3411                                1, paperwidth-2);
3412                 }
3413
3414                 /* think about the margins */ 
3415                 if (!row_ptr->previous)
3416                         y_top += LYX_PAPER_MARGIN;
3417                 
3418                 if (row_ptr->par->pagebreak_top){ /* draw a top pagebreak  */
3419                         scr.drawOnOffLine(offset + y_top + 2 * DefaultHeight(),
3420                                           0, paperwidth);
3421                         y_top += 3 * DefaultHeight();
3422                 }
3423                 
3424                 if (row_ptr->par->added_space_top.kind() == VSpace::VFILL) {
3425                         /* draw a vfill top  */
3426                         scr.drawLine(gc_fill, 
3427                                      offset + 2 + y_top,
3428                                      0, LYX_PAPER_MARGIN);
3429                         scr.drawLine(gc_fill,
3430                                      offset + y_top + 3 * DefaultHeight(),
3431                                      0, LYX_PAPER_MARGIN);
3432                         scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2, 
3433                                                   offset + 2 + y_top,
3434                                                   offset + y_top + 3 *
3435                                                   DefaultHeight());
3436                         
3437                         y_top += 3 * DefaultHeight();
3438                 }
3439                 
3440                 /* think about user added space */ 
3441                 y_top += int(row_ptr->par->added_space_top.inPixels());
3442                 
3443                 /* think about the parskip */ 
3444                 /* some parskips VERY EASY IMPLEMENTATION */ 
3445                 if (parameters->paragraph_separation == BufferParams::PARSEP_SKIP) {
3446                         if (layout.latextype == LATEX_PARAGRAPH
3447                             && firstpar->GetDepth() == 0
3448                             && firstpar->Previous())
3449                                 y_top += parameters->getDefSkip().inPixels();
3450                         else if (firstpar->Previous()
3451                                  && textclasslist.Style(parameters->textclass,
3452                                                    firstpar->Previous()->GetLayout()).latextype == LATEX_PARAGRAPH
3453                                  && firstpar->Previous()->GetDepth() == 0)
3454                                 // is it right to use defskip here, too? (AS) 
3455                                 y_top += parameters->getDefSkip().inPixels();
3456                 }
3457                 
3458                 if (row_ptr->par->line_top) {      /* draw a top line  */
3459                         y_top +=  GetFont(row_ptr->par, 0).ascent('x');
3460
3461                         scr.drawThickLine(offset + y_top,
3462                                           0, paperwidth);
3463                         y_top +=  GetFont(row_ptr->par, 0).ascent('x');
3464                 }
3465                 
3466                 /* should we print a label? */ 
3467                 if (layout.labeltype >= LABEL_STATIC
3468                     && (layout.labeltype != LABEL_STATIC
3469                         || layout.latextype != LATEX_ENVIRONMENT
3470                         || row_ptr->par->IsFirstInSequence())) {
3471                         font = GetFont(row_ptr->par, -2);
3472                         if (!row_ptr->par->GetLabestring().empty()) {
3473                                 tmpx = x;
3474                                 string tmpstring = row_ptr->par->GetLabestring();
3475                                 
3476                                 if (layout.labeltype == LABEL_COUNTER_CHAPTER) {
3477                                         if (parameters->secnumdepth >= 0){
3478                                                 /* this is special code for the chapter layout. This is printed in
3479                                                  * an extra row and has a pagebreak at the top. */
3480                                                 maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue())
3481                                                         + int(layout.parsep) * DefaultHeight();
3482                                                 scr.drawString(font, tmpstring,
3483                                                                offset + row_ptr->baseline
3484                                                                - row_ptr->ascent_of_text - maxdesc,
3485                                                                int(x));
3486                                         }
3487                                 } else {
3488                                         x -= font.stringWidth( layout.labelsep);
3489                                         x -= font.stringWidth( tmpstring);
3490                                         /* draw it! */
3491                                         scr.drawString(font, tmpstring,
3492                                                        offset + row_ptr->baseline, int(x));
3493                                 }
3494                                 x = tmpx;
3495                         }
3496                         /* the labels at the top of an environment. More or less for bibliography */ 
3497                 } else if (layout.labeltype == LABEL_TOP_ENVIRONMENT ||
3498                            layout.labeltype == LABEL_BIBLIO ||
3499                            layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) {
3500                         if (row_ptr->par->IsFirstInSequence()) {
3501                                 font = GetFont(row_ptr->par, -2);
3502                                 if (!row_ptr->par->GetLabestring().empty()) {
3503                                         string tmpstring = row_ptr->par->GetLabestring();
3504                                         
3505                                         maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue()
3506                                                          + (layout.labelbottomsep * DefaultHeight()));
3507                                         
3508                                         int top_label_x = int(x);
3509                                         if (layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT){
3510                                                 top_label_x = int(x + (paperwidth - RightMargin(row_ptr) - x) / 2); 
3511                                                 top_label_x -= (font.stringWidth( tmpstring)/2);
3512                                         }
3513                                         
3514                                         scr.drawString(font, tmpstring,
3515                                                        offset + row_ptr->baseline
3516                                                        - row_ptr->ascent_of_text - maxdesc,  
3517                                                        top_label_x);                
3518                                 }
3519                         }
3520                 }
3521                 if (layout.labeltype == LABEL_BIBLIO) { // ale970302
3522                         if (row_ptr->par->bibkey) {
3523                                 tmpx = x;
3524                                 x -= font.stringWidth(layout.labelsep);
3525                                 font = GetFont(row_ptr->par, -1);
3526                                 x -= row_ptr->par->bibkey->Width(font);
3527                                 row_ptr->par->bibkey->Draw(font, scr,
3528                                                            offset + row_ptr->baseline, 
3529                                                            x);
3530                                 x = tmpx;
3531                         }
3532                 } 
3533         }
3534         
3535         /* is it a last row? */
3536         par = row_ptr->par->LastPhysicalPar();
3537         if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
3538             && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {     
3539                 
3540                 /* think about the margins */ 
3541                 if (!row_ptr->next)
3542                         y_bottom -= LYX_PAPER_MARGIN;
3543                 
3544                 /* draw a bottom pagebreak */ 
3545                 if (firstpar->pagebreak_bottom) {
3546                         scr.drawOnOffLine(offset + y_bottom - 2 *
3547                                           DefaultHeight(),
3548                                           0, paperwidth);
3549                         y_bottom -= 3 * DefaultHeight();
3550                 }
3551                 
3552                 if (firstpar->added_space_bottom.kind() == VSpace::VFILL) {
3553                         /* draw a vfill bottom  */
3554                         scr.drawLine(gc_fill,
3555                                      offset + y_bottom - 3 * DefaultHeight(),
3556                                      0, LYX_PAPER_MARGIN);
3557                         scr.drawLine(gc_fill, offset + y_bottom - 2,
3558                                      0, LYX_PAPER_MARGIN);
3559                         scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2, 
3560                                                   offset + y_bottom - 3 * DefaultHeight(),
3561                                                   offset + y_bottom - 2
3562                                 );          
3563                         y_bottom -= 3* DefaultHeight();
3564                 }
3565                 
3566                 /* think about user added space */ 
3567                 y_bottom -= int(firstpar->added_space_bottom.inPixels());
3568                 
3569                 if (firstpar->line_bottom) {
3570                         /* draw a bottom line */
3571                         y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
3572
3573                         scr.drawThickLine(offset + y_bottom,
3574                                           0, paperwidth);           
3575                         y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
3576                 }
3577         }
3578         
3579         /* draw the text in the pixmap */  
3580         pos_end = RowLast(row_ptr);
3581         
3582         pos = row_ptr->pos;
3583         /* table stuff -- begin*/
3584         if (row_ptr->par->table) {
3585                 bool on_off;
3586                 int cell = NumberOfCell(row_ptr->par, row_ptr->pos);
3587                 float x_old = x;
3588                 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
3589                 
3590                 while (pos <= pos_end)  {
3591                         if (row_ptr->par->IsNewline(pos)) {
3592                                 
3593                                 x = x_old + row_ptr->par->table->WidthOfColumn(cell);
3594                                 /* draw the table lines, still very simple */
3595                                 on_off = !row_ptr->par->table->TopLine(cell);
3596                                 if ((!on_off ||
3597                                      !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
3598                                     !row_ptr->par->table->IsContRow(cell))
3599                                         scr.drawTableLine(offset + row_ptr->baseline -
3600                                                           row_ptr->ascent_of_text,
3601                                                           int(x_old), int(x - x_old), on_off);
3602                                 on_off = !row_ptr->par->table->BottomLine(cell);
3603                                 if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
3604                                     row_ptr->par->table->VeryLastRow(cell))
3605                                         scr.drawTableLine(offset + y_bottom - 1,
3606                                                           int(x_old), int(x - x_old), on_off);
3607                                 on_off = !row_ptr->par->table->LeftLine(cell);
3608                                 
3609                                 scr.drawVerticalTableLine(int(x_old), 
3610                                                           offset + row_ptr->baseline -
3611                                                           row_ptr->ascent_of_text,
3612                                                           offset + y_bottom - 1,
3613                                                           on_off);
3614                                 on_off = !row_ptr->par->table->RightLine(cell);
3615                                 
3616                                 scr.drawVerticalTableLine(int(x) -
3617                                                           row_ptr->par->table->AdditionalWidth(cell),
3618                                                           offset + row_ptr->baseline -
3619                                                           row_ptr->ascent_of_text,
3620                                                           offset + y_bottom - 1,
3621                                                           on_off);
3622                                 x_old = x;
3623                 /* take care about the alignment and other spaces */
3624                                 cell++;
3625                                 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
3626                                 if (row_ptr->par->table->IsFirstCell(cell))
3627                                         cell--; // little hack, sorry
3628                                 pos++;
3629                         } else if (row_ptr->par->IsHfill(pos)) {
3630                                 x += 1;
3631                                 
3632                                 scr.drawVerticalLine(gc_fill, int(x),  
3633                                                      offset + row_ptr->baseline - DefaultHeight()/2, 
3634                                                      offset + row_ptr->baseline);               
3635                                 x += 2;
3636                                 pos++;
3637                         } else {
3638                                 if (row_ptr->par->IsSeparator(pos)) {
3639                                         tmpx = x;
3640                                         x+= SingleWidth(row_ptr->par, pos);
3641                                         /* -------> Only draw protected spaces when not in
3642                                          * free-spacing mode. */
3643                                         if (row_ptr->par->GetChar(pos) == LyXParagraph::META_PROTECTED_SEPARATOR && !layout.free_spacing) {
3644                                                 scr.drawVerticalLine(gc_fill, int(tmpx),
3645                                                                      offset + row_ptr->baseline - 3,
3646                                                                      offset + row_ptr->baseline - 1);
3647                                                 scr.drawLine(gc_fill,
3648                                                              offset + row_ptr->baseline - 1,
3649                                                              int(tmpx),
3650                                                              int(x-tmpx-2));
3651                                                 scr.drawVerticalLine(gc_fill, int(x-2),
3652                                                                      offset + row_ptr->baseline - 3,
3653                                                                      offset + row_ptr->baseline - 1);                   
3654                                                 /* what about underbars? */
3655                                                 font = GetFont(row_ptr->par, pos); 
3656                                                 if (font.underbar() == LyXFont::ON
3657                                                     && font.latex() != LyXFont::ON) {
3658                                                         scr.drawLine(gc_copy,
3659                                                                      offset +
3660                                                                      row_ptr->baseline + 2,
3661                                                                      int(tmpx),
3662                                                                      int(x - tmpx));                        
3663                                                 }
3664                                         }
3665                                         pos++;
3666                                 } else
3667                                         Draw(row_ptr, pos, scr, offset, x);
3668                         }
3669                 }
3670                 
3671                 /* do not forget the very last cell. This has no NEWLINE so 
3672                  * ignored by the code above*/ 
3673                 if (cell == row_ptr->par->table->GetNumberOfCells()-1){
3674                         x = x_old + row_ptr->par->table->WidthOfColumn(cell);
3675                         on_off = !row_ptr->par->table->TopLine(cell);
3676                         if ((!on_off ||
3677                              !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
3678                             !row_ptr->par->table->IsContRow(cell))
3679                                 
3680                                 scr.drawTableLine(offset + row_ptr->baseline -
3681                                                   row_ptr->ascent_of_text,
3682                                                   int(x_old), int(x - x_old), on_off);      
3683                         on_off = !row_ptr->par->table->BottomLine(cell);
3684                         if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
3685                             row_ptr->par->table->VeryLastRow(cell))
3686                                 
3687                                 scr.drawTableLine(offset + y_bottom - 1,
3688                                                   int(x_old), int(x - x_old), on_off);      
3689                         on_off = !row_ptr->par->table->LeftLine(cell);
3690                         
3691                         scr.drawVerticalTableLine(int(x_old), 
3692                                                   offset + row_ptr->baseline -
3693                                                   row_ptr->ascent_of_text,
3694                                                   offset + y_bottom - 1,
3695                                                   on_off);          
3696                         on_off = !row_ptr->par->table->RightLine(cell);
3697                         
3698                         scr.drawVerticalTableLine(int(x) -
3699                                                   row_ptr->par->table->AdditionalWidth(cell),
3700                                                   offset + row_ptr->baseline -
3701                                                   row_ptr->ascent_of_text,
3702                                                   offset + y_bottom - 1,
3703                                                   on_off);          
3704                 }
3705         } else {
3706                 /* table stuff -- end*/
3707                 
3708                 while (pos <= pos_end)  {
3709                         
3710                         if (row_ptr->par->IsHfill(pos)) {
3711                                 x += 1;
3712                                 scr.drawVerticalLine(gc_fill, int(x),  
3713                                                      offset + row_ptr->baseline - DefaultHeight()/2, 
3714                                                      offset + row_ptr->baseline);               
3715                                 if (HfillExpansion(row_ptr, pos)) {
3716                                         if (pos >= main_body) {
3717                                                 scr.drawOnOffLine(offset + row_ptr->baseline -
3718                                                                   DefaultHeight()/4,
3719                                                                   int(x),
3720                                                                   int(fill_hfill));                     
3721                                                 x += fill_hfill;
3722                     } else {
3723                             scr.drawOnOffLine(offset + row_ptr->baseline -
3724                                               DefaultHeight()/4,
3725                                               int(x),
3726                                               int(fill_label_hfill));
3727                             x += fill_label_hfill;
3728                     }
3729                                         scr.drawVerticalLine(gc_fill, int(x),
3730                                                              offset + row_ptr->baseline -
3731                                                              DefaultHeight()/2, 
3732                                                              offset + row_ptr->baseline);
3733                                 }
3734                                 x += 2;
3735                                 pos++;
3736                         } else {
3737                                 if (row_ptr->par->IsSeparator(pos)) {
3738                                         tmpx = x;
3739                                         x+= SingleWidth(row_ptr->par, pos);
3740                                         if (pos >= main_body)
3741                                                 x+= fill_separator;
3742                                         /* -------> Only draw protected spaces when not in
3743                                          * free-spacing mode. */
3744                                         if (row_ptr->par->GetChar(pos) == LyXParagraph::META_PROTECTED_SEPARATOR && !layout.free_spacing) {
3745                                                 
3746                                                 scr.drawVerticalLine(gc_fill, int(tmpx),
3747                                                                      offset + row_ptr->baseline - 3,
3748                                                                      offset + row_ptr->baseline - 1);
3749                                                 scr.drawLine(gc_fill,
3750                                                              offset + row_ptr->baseline - 1,
3751                                                              int(tmpx),
3752                                                              int(x-tmpx-2));
3753                                                 scr.drawVerticalLine(gc_fill, int(x-2),
3754                                                                      offset + row_ptr->baseline - 3,
3755                                                                      offset + row_ptr->baseline - 1);                   
3756                                                 /* what about underbars? */
3757                                                 font = GetFont(row_ptr->par, pos); 
3758                                                 if (font.underbar() == LyXFont::ON
3759                                                     && font.latex() != LyXFont::ON) {
3760                                                         scr.drawLine(gc_copy,
3761                                              offset + row_ptr->baseline + 2,
3762                                                                      int(tmpx),
3763                                                                      int(x - tmpx));
3764                                                 }
3765                                         }
3766                                         pos++;
3767                                 } else
3768                                         Draw(row_ptr, pos, scr, offset, x);
3769                         }
3770                         if (pos == main_body) {
3771                                 x += GetFont(row_ptr->par, -2).stringWidth(
3772                                         layout.labelsep);
3773                                 if (row_ptr->par->IsLineSeparator(pos - 1))
3774                                         x-= SingleWidth(row_ptr->par, pos - 1);
3775                                 if (x < left_margin)
3776                                         x = left_margin;
3777                         }
3778                 }
3779         }
3780         // check for FAST SELECTION
3781         if (fast_selection || mono_video){
3782                 if (selection) {
3783                         
3784                         /* selection code */ 
3785                         if (sel_start_cursor.row == row_ptr && sel_end_cursor.row == row_ptr) {
3786                                 scr.fillRectangle(gc_select, sel_start_cursor.x, offset,
3787                                                   sel_end_cursor.x - sel_start_cursor.x,
3788                                                   row_ptr->height); 
3789                         } else if (sel_start_cursor.row == row_ptr) {
3790                                 scr.fillRectangle(gc_select, sel_start_cursor.x, offset,
3791                                                   paperwidth - sel_start_cursor.x,
3792                                                   row_ptr->height);
3793                         } else if (sel_end_cursor.row == row_ptr) {
3794                                 scr.fillRectangle(gc_select, 0, offset,
3795                                                   sel_end_cursor.x,
3796                                                   row_ptr->height);
3797                         } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
3798                                 scr.fillRectangle(gc_select, 0, offset,
3799                                                   paperwidth, row_ptr->height);
3800                                 
3801                         }
3802                 }
3803         }
3804 // end of FAST SELECTION code
3805         /* thats it */ 
3806 }
3807
3808
3809 int LyXText::DefaultHeight()
3810 {
3811         LyXFont font(LyXFont::ALL_SANE);
3812         return int(font.maxAscent() + font.maxDescent() * 1.5);
3813 }
3814
3815    
3816 /* returns the column near the specified x-coordinate of the row 
3817 * x is set to the real beginning of this column  */ 
3818 int  LyXText::GetColumnNearX(Row * row, int& x)
3819 {
3820         float tmpx = 0.0;
3821         float fill_separator, fill_hfill, fill_label_hfill;
3822    
3823         int left_margin = LabelEnd(row);
3824         PrepareToPrint(row, tmpx, fill_separator,
3825                        fill_hfill, fill_label_hfill);
3826         int main_body = BeginningOfMainBody(row->par);
3827    
3828         int c = row->pos;
3829
3830         int last = RowLast(row);
3831         if (row->par->IsNewline(last))
3832                 last--;
3833    
3834         LyXLayout const & layout = textclasslist.Style(parameters->textclass,
3835                                            row->par->GetLayout());
3836         /* table stuff -- begin */
3837         if (row->par->table) {
3838                 if (!row->next || row->next->par != row->par)
3839                         last = RowLast(row); /* the last row doesn't need a newline at the end*/
3840                 int cell = NumberOfCell(row->par, row->pos);
3841                 float x_old = tmpx;
3842                 bool ready = false;
3843                 tmpx += row->par->table->GetBeginningOfTextInCell(cell);
3844                 while (c <= last
3845                        && tmpx + (SingleWidth(row->par, c)/2) <= x
3846                        && !ready){
3847                         if (row->par->IsNewline(c)) {
3848                                 if (x_old + row->par->table->WidthOfColumn(cell) <= x){
3849                                         tmpx = x_old + row->par->table->WidthOfColumn(cell);
3850                                         x_old = tmpx;
3851                                         cell++;
3852                                         tmpx += row->par->table->GetBeginningOfTextInCell(cell);
3853                                         c++;
3854                                 } else
3855                                         ready = true;
3856                         } else {
3857                                 tmpx += SingleWidth(row->par, c);
3858                                 c++;
3859                         }
3860                 }
3861         } else
3862                 /* table stuff -- end*/
3863
3864                 while (c <= last
3865                        && tmpx + (SingleWidth(row->par, c)/2)  <= x) {
3866                         
3867                         if (c && c == main_body
3868                             && !row->par->IsLineSeparator(c - 1)) {
3869                                 tmpx += GetFont(row->par, -2)
3870                                         .stringWidth(layout.labelsep);
3871                                 if (tmpx < left_margin)
3872                                         tmpx = left_margin;
3873                         }
3874              
3875                         tmpx += SingleWidth(row->par, c);
3876                         if (HfillExpansion(row, c)) {
3877                                 if (c >= main_body)
3878                                         tmpx += fill_hfill;
3879                                 else
3880                                         tmpx += fill_label_hfill;
3881                         }
3882                         else if (c >= main_body
3883                                  && row->par->IsSeparator(c)) {
3884                                 tmpx+= fill_separator;  
3885                         }
3886                         c++;
3887                         if (c == main_body
3888                             && row->par->IsLineSeparator(c - 1)) {
3889                                 tmpx += GetFont(row->par, -2)
3890                                         .stringWidth(layout.labelsep);
3891                                 tmpx-= SingleWidth(row->par, c - 1);
3892                                 if (tmpx < left_margin)
3893                                         tmpx = left_margin;
3894                         }
3895                 }
3896         /* make sure that a last space in a row doesnt count */
3897         if (c > 0 && c >= last
3898             && row->par->IsLineSeparator(c - 1)
3899             && !(!row->next || row->next->par != row->par)) {
3900                 tmpx -= SingleWidth(row->par, c - 1);
3901                 tmpx -= fill_separator;
3902         }
3903         c-= row->pos;
3904         
3905         x = int(tmpx);
3906         return c;
3907 }
3908
3909    
3910 /* turn the selection into a new environment. If there is no selection,
3911 * create an empty environment */ 
3912 void LyXText::InsertFootnoteEnvironment(LyXParagraph::footnote_kind kind)
3913 {
3914    /* no footnoteenvironment in a footnoteenvironment */ 
3915    if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3916       WriteAlert(_("Impossible operation"), 
3917                  _("You can't insert a float in a float!"), 
3918                  _("Sorry."));
3919      return;
3920    }
3921    /* no marginpars in minipages */
3922    if (kind == LyXParagraph::MARGIN 
3923       && cursor.par->pextra_type == LyXParagraph::PEXTRA_MINIPAGE) {
3924       WriteAlert(_("Impossible operation"), 
3925                  _("You can't insert a marginpar in a minipage!"), 
3926                  _("Sorry."));
3927       return;
3928    }
3929    
3930    /* this doesnt make sense, if there is no selection */ 
3931    bool dummy_selection = false;
3932    if (!selection) {
3933       sel_start_cursor = cursor;       /* dummy selection  */
3934       sel_end_cursor = cursor;
3935       dummy_selection = true;
3936    }
3937    
3938    LyXParagraph *tmppar;
3939
3940    if (sel_start_cursor.par->table || sel_end_cursor.par->table){
3941       WriteAlert(_("Impossible operation"), _("Cannot cut table."), _("Sorry."));
3942       return;
3943    }
3944      
3945    /* a test to make sure there is not already a footnote
3946     * in the selection. */
3947    
3948    tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
3949    
3950    while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos) && 
3951           tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
3952      tmppar = tmppar->next;
3953    
3954    if (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
3955        || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3956       WriteAlert(_("Impossible operation"), 
3957                  _("Float would include float!"), 
3958                  _("Sorry."));
3959       return;
3960    }
3961    
3962    /* ok we have a selection. This is always between sel_start_cursor
3963     * and sel_end cursor */
3964
3965    SetUndo(Undo::FINISH, 
3966            sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
3967            sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next); 
3968    
3969    if (sel_end_cursor.pos > 0 
3970        && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1))
3971      sel_end_cursor.pos--;             /* please break before a space at
3972                                         * the end */
3973    if (sel_start_cursor.par == sel_end_cursor.par
3974        && sel_start_cursor.pos > sel_end_cursor.pos)
3975      sel_start_cursor.pos--;
3976
3977    sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
3978    
3979    sel_end_cursor.par = sel_end_cursor.par->Next();
3980    sel_end_cursor.pos = 0;
3981    
3982    // don't forget to insert a dummy layout paragraph if necessary
3983    if (sel_start_cursor.par->GetLayout() != sel_end_cursor.par->layout){
3984      sel_end_cursor.par->BreakParagraphConservative(0);
3985      sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
3986      sel_end_cursor.par = sel_end_cursor.par->next;
3987    }
3988    else
3989      sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
3990
3991    cursor = sel_end_cursor;
3992
3993    /* please break behind a space, if there is one. The space should
3994     * be erased too */ 
3995    if (sel_start_cursor.pos > 0 
3996        && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1))
3997      sel_start_cursor.pos--;
3998    if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)) {
3999       sel_start_cursor.par->Erase(sel_start_cursor.pos);
4000    }
4001    
4002    sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
4003    tmppar = sel_start_cursor.par->Next();
4004    
4005    if (dummy_selection) {
4006            tmppar->Clear();
4007            if (kind == LyXParagraph::TAB
4008                || kind == LyXParagraph::FIG 
4009                || kind == LyXParagraph::WIDE_TAB
4010                || kind == LyXParagraph::WIDE_FIG 
4011                || kind == LyXParagraph::ALGORITHM) {
4012                    int lay = textclasslist.NumberOfLayout(parameters->textclass,
4013                                                      "Caption").second;
4014                    if (lay == -1) // layout not found
4015                            // use default layout "Standard" (0)
4016                            lay = 0;
4017                    tmppar->SetLayout(lay);
4018            }
4019    }
4020    else {
4021      if (sel_start_cursor.pos > 0) {
4022        /* the footnote-environment should begin with a standard layout.
4023         * Imagine you insert a footnote within an enumeration, you 
4024         * certainly do not want an enumerated footnote! */ 
4025        tmppar->Clear();
4026      }
4027      else {
4028        /* this is a exception the user would sometimes expect, I hope */
4029        sel_start_cursor.par->Clear();
4030      }
4031    }
4032    
4033    while (tmppar != sel_end_cursor.par) {
4034       tmppar->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
4035       tmppar->footnotekind = kind;
4036       tmppar = tmppar->Next();
4037    } 
4038
4039    RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
4040    
4041    SetCursor(sel_start_cursor.par->Next(), 0);
4042
4043    ClearSelection();
4044 }
4045    
4046
4047 /* returns pointer to a specified row */
4048 Row * LyXText::GetRow(LyXParagraph * par, LyXParagraph::size_type pos, long &y)
4049 {
4050    Row * tmprow;
4051
4052    if (currentrow){
4053      if (par == currentrow->par || par == currentrow->par->Previous()){
4054              // do not dereference par, it may have been deleted
4055              // already! (Matthias) 
4056              while (currentrow->previous && currentrow->previous->par != par){
4057                      currentrow = currentrow->previous;
4058                      currentrow_y -= currentrow->height;
4059              }
4060              while (currentrow->previous && currentrow->previous->par == par){
4061                      currentrow = currentrow->previous;
4062                      currentrow_y -= currentrow->height;
4063              }
4064      }
4065      tmprow = currentrow;
4066      y = currentrow_y;
4067      /* find the first row of the specified paragraph */ 
4068      while (tmprow->next && (tmprow->par != par)) {
4069        y += tmprow->height;
4070        tmprow = tmprow->next;
4071      }
4072
4073      if (tmprow->par == par){
4074        /* now find the wanted row */ 
4075        while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par && 
4076               tmprow->next->pos <= pos) {
4077          y += tmprow->height;
4078        tmprow = tmprow->next;
4079        }
4080        currentrow = tmprow;
4081        currentrow_y = y;
4082        return tmprow;
4083      }
4084    }
4085    tmprow = firstrow;
4086    y = 0;
4087    /* find the first row of the specified paragraph */ 
4088    while (tmprow->next && (tmprow->par != par)) {
4089       y += tmprow->height;
4090       tmprow = tmprow->next;
4091    }
4092  
4093    /* now find the wanted row */ 
4094    while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par && 
4095           tmprow->next->pos <= pos) {
4096              y += tmprow->height;
4097              tmprow = tmprow->next;
4098    }
4099    
4100    currentrow = tmprow;
4101    currentrow_y = y;
4102
4103    return tmprow;
4104 }