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