]> git.lyx.org Git - features.git/blob - src/text.C
merge from the string-switch branch and ready for a prelease.
[features.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
31 static const int LYX_PAPER_MARGIN = 20;
32
33 extern int mono_video;
34 extern int reverse_video;
35 extern int fast_selection;
36 extern BufferView *current_view;
37 extern int UnlockInset(UpdatableInset* inset);
38
39 // ale070405
40 extern int bibitemMaxWidth(const class LyXFont &);
41
42 // dnaber 1999-02-02
43 extern MiniBuffer *minibuffer;
44
45 int LyXText::SingleWidth(LyXParagraph *par, int pos)
46 {
47         char c = par->GetChar(pos);
48         return SingleWidth(par, pos, c);
49 }
50
51
52 int LyXText::SingleWidth(LyXParagraph *par, int pos, char c)
53 {
54         LyXFont font = GetFont(par, pos);
55
56         // The most common case is handled first (Asger)
57         if (IsPrintable(c)) {
58                 return font.width(c);
59
60         } else if (IsHfillChar(c)) {
61                 return 3;       /* because of the representation
62                                  * as vertical lines */
63
64         } else if (c == LYX_META_FOOTNOTE ||
65                    c == LYX_META_MARGIN ||
66                    c == LYX_META_FIG ||
67                    c == LYX_META_TAB ||
68                    c == LYX_META_WIDE_FIG ||
69                    c == LYX_META_WIDE_TAB ||
70                    c == LYX_META_ALGORITHM) 
71         {
72                 string fs;
73                 switch (c) {
74                 case LYX_META_MARGIN:
75                         fs = "margin";
76                         break;
77                 case LYX_META_FIG:
78                         fs = "fig";
79                         break;
80                 case LYX_META_TAB:
81                         fs = "tab";
82                         break;
83                 case LYX_META_ALGORITHM:
84                         fs = "alg";
85                         break;
86                 case LYX_META_WIDE_FIG:
87                         fs = "wide-fig";
88                         break;
89                 case LYX_META_WIDE_TAB:
90                         fs = "wide-tab";
91                         break;
92                 case LYX_META_FOOTNOTE:
93                         fs = "foot";
94                         break;
95                 }
96                 font.decSize();
97                 font.decSize();
98                 return font.stringWidth(fs);
99         } 
100    
101         else if (c == LYX_META_INSET) {
102                 Inset *tmpinset=par->GetInset(pos);
103                 if (tmpinset)
104                         return par->GetInset(pos)->Width(font);
105                 else
106                         return 0;
107
108         } else if (IsSeparatorChar(c))
109                 c = ' ';
110         else if (IsNewlineChar(c))
111                 c = 'n';
112         return font.width(c);
113 }
114
115
116 /* returns the paragraph position of the last character in the 
117  * specified row */
118 int LyXText::RowLast(Row *row)
119 {
120         if (row->next == 0)
121                 return row->par->Last()-1;
122         else if (row->next->par != row->par) 
123                 return row->par->Last()-1;
124         else 
125                 return row->next->pos - 1;
126 }
127
128
129 void LyXText::Draw(Row *row, int &pos, LyXScreen &scr, int offset, float &x)
130 {
131         char c = row->par->GetChar(pos);
132
133         if (IsNewlineChar(c)) {
134                 pos++;
135                 // Draw end-of-line marker
136
137                 LyXFont font = GetFont(row->par, pos);
138                 int asc = font.maxAscent();
139                 int wid = font.width('n');
140                 int y = (offset + row->baseline);
141                 XPoint p[3];
142                 p[0].x = int(x + wid*0.375); p[0].y = int(y - 0.875*asc*0.75);
143                 p[1].x = int(x);             p[1].y = int(y - 0.500*asc*0.75);
144                 p[2].x = int(x + wid*0.375); p[2].y = int(y - 0.125*asc*0.75);
145                 scr.drawLines(::getGC(gc_new_line),p, 3);
146                 
147                 p[0].x = int(x);             p[0].y = int(y - 0.500*asc*0.75);
148                 p[1].x = int(x + wid);       p[1].y = int(y - 0.500*asc*0.75);
149                 p[2].x = int(x + wid);       p[2].y = int(y - asc*0.75);
150                 scr.drawLines(::getGC(gc_new_line),p, 3);
151                 return;
152         }
153
154         LyXFont font = GetFont(row->par, pos);
155         LyXFont font2 = font;
156
157         if (c == LYX_META_FOOTNOTE ||
158             c == LYX_META_MARGIN ||
159             c == LYX_META_FIG ||
160             c == LYX_META_TAB ||
161             c == LYX_META_WIDE_FIG ||
162             c == LYX_META_WIDE_TAB ||
163             c == LYX_META_ALGORITHM) {
164                 string fs;
165                 switch (c) {
166                 case LYX_META_MARGIN:
167                         fs = "margin";
168                         /* draw a sign at the left margin! */ 
169                         scr.drawText(font, "!", 1, offset + row->baseline,
170                                      (LYX_PAPER_MARGIN - font.width('!'))/2);
171                         break;
172                 case LYX_META_FIG:
173                         fs = "fig";
174                         break;
175                 case LYX_META_TAB:
176                         fs = "tab";
177                         break;
178                 case LYX_META_ALGORITHM:
179                         fs = "alg";
180                         break;
181                 case LYX_META_WIDE_FIG:
182                         fs = "wide-fig";
183                         break;
184                 case LYX_META_WIDE_TAB:
185                         fs = "wide-tab";
186                         break;
187                 case LYX_META_FOOTNOTE:
188                         fs = "foot";
189                         break;
190                 }
191                 font.decSize();
192                 font.decSize();
193           
194                 /* calculate the position of the footnotemark */
195                 int y = (row->baseline - font2.maxAscent() 
196                          + font.maxAscent());
197           
198                 font.setColor(LyXFont::INSET);
199
200                 float tmpx = x;
201
202                 /* draw it and set new x position */
203                 x += scr.drawString(font, fs, offset + y, int(x));
204
205                 scr.drawLine(gc_foot, offset + row->baseline,
206                              int(tmpx), int(x - tmpx));
207           
208                 pos++;
209                 return;
210         } else if (c == LYX_META_INSET) {
211                 Inset *tmpinset = row->par->GetInset(pos);
212                 if (tmpinset) 
213                         tmpinset->Draw(font, scr, offset + row->baseline, x);
214                 pos++;
215                 return;
216         }
217
218         /* usual characters, no insets */
219
220         // Collect character that we can draw in one command
221
222         // This is dirty, but fast. Notice that it will never be too small.
223         // For the record, I'll note that Microsoft Word has a limit
224         // of 768 here. We have none :-) (Asger)
225         static char textstring[1024];
226
227         int last = RowLast(row);
228         // Prevent crash in the extremely unlikely event
229         // that our array is too small
230         if (last > pos+1020) last = pos + 1020;
231
232         textstring[0] = c;
233         pos++;
234
235         int i = 1;
236
237         while (pos <= last &&
238                (unsigned char) (c = row->par->GetChar(pos)) > ' ' &&
239                font2 == GetFont(row->par, pos)) {
240                 textstring[i++] = c;
241                 pos++;
242         }
243         textstring[i] = 0; 
244
245         float tmpx = x;
246
247         // If monochrome and LaTeX mode, provide reverse background
248         if (mono_video && font.latex() == LyXFont::ON) {
249                 int a=font.maxAscent(), d=font.maxDescent();
250                 scr.fillRectangle(gc_copy, int(tmpx), offset + row->baseline-a,
251                                   font.textWidth(textstring, i), a+d);
252         }
253
254         /* Draw text and set the new x position */ 
255         x += scr.drawText(font, textstring, i, offset + row->baseline, 
256                           int(x));
257         /* what about underbars? */
258         if (font.underbar() == LyXFont::ON && font.latex() != LyXFont::ON) {
259                 scr.drawLine(gc_copy, offset + row->baseline + 2,
260                              int(tmpx), int(x - tmpx));
261         }
262
263         // If we want ulem.sty support, drawing
264         // routines should go here. (Asger)
265         // Why shouldn't LyXFont::drawText handle it internally?
266 }
267
268
269 /* Returns the left beginning of the text. 
270 * This information cannot be taken from the layouts-objekt, because in 
271 * LaTeX the beginning of the text fits in some cases (for example sections)
272 * exactly the label-width. */
273 int LyXText::LeftMargin(Row* row)
274 {
275    int x;
276    LyXLayout *layout;
277    LyXFont labelfont;
278    LyXParagraph *newpar;
279    Row dummyrow;
280    layout = lyxstyle.Style(parameters->textclass, row->par->GetLayout());
281    
282    string parindent = layout->parindent; 
283
284    /* table stuff -- begin*/ 
285    if (row->par->table)
286       parindent.erase();
287    /* table stuff -- end*/       
288
289    x = LYX_PAPER_MARGIN;
290
291    x += lyxstyle.TextClass(parameters->textclass)->
292      defaultfont.signedStringWidth(lyxstyle.TextClass(parameters->textclass)->leftmargin);
293
294    if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)  {
295         LyXFont font(LyXFont::ALL_SANE);
296         font.setSize(LyXFont::SIZE_SMALL);
297         x += font.textWidth("Mwide-figM", 10) + LYX_PAPER_MARGIN/2;
298    }
299
300    /* this is the way, LyX handles the LaTeX-Environments.
301     * I have had this idea very late, so it seems to be a
302     * later added hack and this is true */ 
303    if (!row->par->GetDepth()) {
304       if (!row->par->GetLayout()) {
305          /* find the previous same level paragraph */
306          if (row->par->FirstPhysicalPar()->Previous()) {
307             newpar = row->par->DepthHook(row->par->GetDepth());
308             if (newpar && lyxstyle.Style(parameters->textclass, newpar->GetLayout())->nextnoindent)
309                parindent.erase();
310          }
311       }
312    }
313    else {
314       /* find the next level paragraph */ 
315       
316       newpar = row->par->DepthHook(row->par->GetDepth()-1);
317
318       /* make a corresponding row. Needed to call LeftMargin() */
319       
320       /* check wether it is a sufficent paragraph */ 
321       if (newpar && newpar->footnoteflag == row->par->footnoteflag
322           && lyxstyle.Style(parameters->textclass, 
323                             newpar->GetLayout())->isEnvironment()) {
324              dummyrow.par = newpar;
325              dummyrow.pos = newpar->Last();
326              x = LeftMargin(&dummyrow);
327       }
328       else {
329          /* this is no longer an error, because this function is used
330           * to clear impossible depths after changing a layout. Since there
331           * is always a redo, LeftMargin() is always called */ 
332          
333          /* printf("LYX_ERROR (text, LeftMargin()) impossible depth \n");*/ 
334          row->par->FirstPhysicalPar()->depth = 0;
335       }
336       
337       if (newpar && !row->par->GetLayout()) {
338          if (newpar->FirstPhysicalPar()->noindent)
339             parindent.erase();
340          else
341             parindent = lyxstyle.Style(parameters->textclass, 
342                                        newpar->GetLayout())->parindent;
343       }
344       
345    }
346    
347    labelfont = GetFont(row->par, -2);
348    switch (layout->margintype) {
349     case MARGIN_DYNAMIC:
350       if (!layout->leftmargin.empty()) {
351         x += lyxstyle.TextClass(parameters->textclass)->defaultfont.signedStringWidth(layout->leftmargin);
352       }
353       if (!row->par->GetLabestring().empty()) {
354             x += labelfont.signedStringWidth(layout->labelindent);
355             x += labelfont.stringWidth(row->par->GetLabestring());
356             x += labelfont.stringWidth(layout->labelsep);
357       }
358       break;
359     case MARGIN_MANUAL:
360       x += labelfont.signedStringWidth(layout->labelindent);
361       if (row->pos >= BeginningOfMainBody(row->par)) {
362          if (!row->par->GetLabelWidthString().empty()) {
363             x += labelfont.stringWidth(row->par->GetLabelWidthString());
364             x += labelfont.stringWidth(layout->labelsep);
365          }
366       }
367       break;
368     case MARGIN_STATIC:
369       x += ( lyxstyle.TextClass(parameters->textclass)->defaultfont.signedStringWidth(layout->leftmargin) * 4
370              / (row->par->GetDepth() + 4));
371       break;
372     case MARGIN_FIRST_DYNAMIC:
373       if (layout->labeltype == LABEL_MANUAL) {
374          if (row->pos >= BeginningOfMainBody(row->par)) {
375             x += labelfont.signedStringWidth(layout->leftmargin);
376          } else {
377             x += labelfont.signedStringWidth(layout->labelindent);
378          }
379       } else {
380          if (row->pos
381              // Special case to fix problems with theorems (JMarc)
382              || (layout->labeltype == LABEL_STATIC
383                  && layout->latextype == LATEX_ENVIRONMENT
384                  && ! row->par->IsFirstInSequence())) {
385                  x += labelfont.signedStringWidth(layout->leftmargin);
386          } else if (layout->labeltype != LABEL_TOP_ENVIRONMENT
387                   && layout->labeltype != LABEL_BIBLIO
388                   && layout->labeltype != LABEL_CENTERED_TOP_ENVIRONMENT) {
389                  x += labelfont.signedStringWidth(layout->labelindent);
390                  x += labelfont.stringWidth(layout->labelsep);
391                  x += labelfont.stringWidth(row->par->GetLabestring());
392          } 
393       }
394       break;
395       
396     case MARGIN_RIGHT_ADDRESS_BOX:
397     {
398       /* ok, a terrible hack. The left margin depends on the widest row
399        * in this paragraph. Do not care about footnotes, they are *NOT*
400        * allowed in the LaTeX realisation of this layout. */ 
401       
402       /* find the first row of this paragraph */ 
403       Row *tmprow = row;
404       while (tmprow->previous && tmprow->previous->par == row->par)
405         tmprow = tmprow->previous;
406       
407       int minfill = tmprow->fill;
408       while (tmprow-> next && tmprow->next->par == row->par) {
409          tmprow = tmprow->next;
410          if (tmprow->fill < minfill)
411            minfill = tmprow->fill;
412       }
413       
414       x += lyxstyle.TextClass(parameters->textclass)->defaultfont.signedStringWidth(layout->leftmargin);
415       x += minfill;
416     }
417       break;
418    }
419    if (row->par->pextra_type == PEXTRA_INDENT) {
420        if (!row->par->pextra_widthp.empty()) {
421            x += paperwidth * atoi(row->par->pextra_widthp.c_str()) / 100;
422        } else if (!row->par->pextra_width.empty()) {
423            int xx = VSpace(row->par->pextra_width).inPixels();
424
425            if (xx > paperwidth)
426                xx = paperwidth * 80 / 100;
427            x += xx;
428        } else { // should not happen
429            LyXFont font(LyXFont::ALL_SANE);
430            x += font.stringWidth("XXXXXX");
431        }
432    }
433    
434    int align;
435    if (row->par->FirstPhysicalPar()->align == LYX_ALIGN_LAYOUT)
436      align = layout->align;
437    else
438      align = row->par->FirstPhysicalPar()->align;
439    
440    /* set the correct parindent */
441    if (row->pos == 0) {
442        if ((layout->labeltype == LABEL_NO_LABEL 
443             || layout->labeltype == LABEL_TOP_ENVIRONMENT 
444             || layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT
445             || (layout->labeltype == LABEL_STATIC
446                 && layout->latextype == LATEX_ENVIRONMENT
447                 && ! row->par->IsFirstInSequence()))
448            && row->par == row->par->FirstPhysicalPar()
449            && align == LYX_ALIGN_BLOCK
450            && !row->par->noindent
451            && (row->par->layout ||
452                parameters->paragraph_separation == LYX_PARSEP_INDENT))
453          x += lyxstyle.TextClass(parameters->textclass)->defaultfont.stringWidth(parindent);
454        else 
455          if (layout->labeltype==LABEL_BIBLIO) { // ale970405 Right width for bibitems
456              x += bibitemMaxWidth(lyxstyle.TextClass(parameters->textclass)->defaultfont);
457          }
458    }
459
460    return x;
461 }
462     
463    
464 int LyXText::RightMargin(Row *row)
465 {
466    int  x;
467    LyXLayout* layout;
468    
469    LyXParagraph *newpar;
470    Row dummyrow;
471    layout = lyxstyle.Style(parameters->textclass, row->par->GetLayout());
472
473    x = LYX_PAPER_MARGIN;
474
475    x += lyxstyle.TextClass(parameters->textclass)->
476      defaultfont.signedStringWidth(lyxstyle.TextClass(parameters->textclass)->rightmargin);
477    if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)  {
478      x += LYX_PAPER_MARGIN/2;
479    }
480
481     /* this is the way, LyX handles the LaTeX-Environments.
482     * I have had this idea very late, so it seems to be a
483     * later added hack and this is true */ 
484    if (row->par->GetDepth()) {
485       /* find the next level paragraph */ 
486       
487       newpar = row->par;
488       
489       do {
490                 newpar = newpar->FirstPhysicalPar()->Previous();
491                 if (newpar) 
492                         newpar = newpar->FirstPhysicalPar();
493       } while (newpar && newpar->GetDepth() >= row->par->GetDepth()
494                && newpar->footnoteflag == row->par->footnoteflag);
495       
496       /* make a corresponding row. Needed to call LeftMargin() */
497
498       /* check wether it is a sufficent paragraph */ 
499       if (newpar && newpar->footnoteflag == row->par->footnoteflag
500           && lyxstyle.Style(parameters->textclass,
501                             newpar->GetLayout())->isEnvironment()) {
502              dummyrow.par = newpar;
503              dummyrow.pos = 0;
504              x = RightMargin(&dummyrow);
505           }
506       else {
507          /* this is no longer an error, because this function is used
508           * to clear impossible depths after changing a layout. Since there
509           * is always a redo, LeftMargin() is always called */ 
510          
511          /* printf("LYX_ERROR (text, LeftMargin()) impossible depth \n");*/ 
512          row->par->FirstPhysicalPar()->depth = 0;
513       }
514    }
515
516    //fprintf(stderr,"rightmargin: %s\n", layout->rightmargin.c_str());
517    //fflush(stderr);
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                 fprintf(stderr, "LYX_ERROR: row.height: %d \n",
3259                         row_ptr->height);
3260                 return;
3261         }
3262         left_margin = LabelEnd(row_ptr);
3263         PrepareToPrint(row_ptr, x, fill_separator,
3264                        fill_hfill, fill_label_hfill);
3265         
3266         int main_body = BeginningOfMainBody(row_ptr->par);
3267         
3268         /* initialize the pixmap */
3269         
3270         scr.fillRectangle(gc_clear,
3271                           0, offset, paperwidth, row_ptr->height);
3272         // check for NOT FAST SELECTION
3273         if (!fast_selection && !mono_video && selection) {
3274                 /* selection code */ 
3275                 if (sel_start_cursor.row == row_ptr &&
3276                     sel_end_cursor.row == row_ptr) {
3277                         scr.fillRectangle(gc_selection, sel_start_cursor.x,
3278                                           offset,
3279                                           sel_end_cursor.x -
3280                                           sel_start_cursor.x,
3281                                           row_ptr->height);
3282                 }
3283                 else if (sel_start_cursor.row == row_ptr) {
3284                         scr.fillRectangle(gc_selection, sel_start_cursor.x,
3285                                           offset,
3286                                           paperwidth - sel_start_cursor.x,
3287                                           row_ptr->height);
3288                 } else if (sel_end_cursor.row == row_ptr) {
3289                         scr.fillRectangle(gc_selection,0, offset,
3290                                           sel_end_cursor.x, row_ptr->height);
3291                 } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
3292                         scr.fillRectangle(gc_selection, 0, offset,
3293                                           paperwidth, row_ptr->height);
3294                         
3295                 }
3296         } // end of NOT FAST SELECTION code
3297         
3298         if (row_ptr->par->appendix){
3299           scr.drawVerticalLine(gc_math, 1, offset, offset+row_ptr->height);
3300           scr.drawVerticalLine(gc_math, paperwidth-2 , offset, offset+row_ptr->height);
3301         }
3302
3303         if (row_ptr->par->pextra_type == PEXTRA_MINIPAGE) {
3304                 /* draw a marker at the left margin! */ 
3305                 LyXFont font = GetFont(row_ptr->par, 0);
3306                 int asc = font.maxAscent();
3307                 int x = (LYX_PAPER_MARGIN - font.width('|')) / 2;
3308                 int y1 = (offset + row_ptr->baseline);
3309                 int y2 = (offset + row_ptr->baseline) - asc;
3310
3311                 scr.drawVerticalLine(gc_minipage, x, y1, y2);
3312         }       
3313         if (row_ptr->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3314                 LyXFont font(LyXFont::ALL_SANE);
3315                 font.setSize(LyXFont::SIZE_FOOTNOTE);
3316                 font.setColor(LyXFont::RED);
3317                 
3318                 int box_x = LYX_PAPER_MARGIN;
3319                 box_x += font.textWidth(" wide-tab ", 10);
3320                 if (row_ptr->previous && 
3321                     row_ptr->previous->par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
3322                         string fs;
3323                         switch (row_ptr->par->footnotekind) {
3324                         case LyXParagraph::MARGIN:
3325                                 fs = " margin";
3326                                 break;
3327                         case LyXParagraph::FIG:
3328                                 fs = " fig";
3329                                 break;
3330                         case LyXParagraph::TAB:
3331                                 fs = " tab";
3332                                 break;
3333                         case LyXParagraph::WIDE_FIG:
3334                                 fs = " wide-fig";
3335                                 break;
3336                         case LyXParagraph::WIDE_TAB:
3337                                 fs = " wide-tab";
3338                                 break;
3339                         case LyXParagraph::ALGORITHM:
3340                                 fs = " alg";
3341                                 break;
3342                         case LyXParagraph::FOOTNOTE:
3343                                 fs = " foot";
3344                                 break;
3345                         }
3346                         
3347                         // Determine background color.
3348                         gc_type back = gc_lighted;
3349                         if (mono_video) {
3350                                 back = gc_clear;
3351                         }
3352                         scr.fillRectangle(back,LYX_PAPER_MARGIN, offset+1,
3353                                           box_x - LYX_PAPER_MARGIN, 
3354                                           int(font.maxAscent())+
3355                                           int(font.maxDescent()));
3356                         
3357                         scr.drawLine(gc_foot,
3358                                      offset,
3359                                      LYX_PAPER_MARGIN,
3360                                      paperwidth - 2*LYX_PAPER_MARGIN);
3361                         
3362                         scr.drawString(font, fs,
3363                                        offset + int(font.maxAscent())+1,
3364                                        LYX_PAPER_MARGIN);
3365                         scr.drawVerticalLine(gc_foot,
3366                                              LYX_PAPER_MARGIN,
3367                                              offset,
3368                                              offset
3369                                              + int(font.maxAscent())+
3370                                              int(font.maxDescent()));
3371                         
3372                         scr.drawLine(gc_foot,
3373                                      offset
3374                                      + int(font.maxAscent())
3375                                      + int(font.maxDescent()) + 1,
3376                                      LYX_PAPER_MARGIN, box_x - LYX_PAPER_MARGIN); 
3377                 }
3378                 
3379                 /* draw the open floats in a red box */
3380                 scr.drawVerticalLine(gc_foot,
3381                                      box_x,
3382                                      offset,  offset + row_ptr->height);
3383                 
3384                 scr.drawVerticalLine(gc_foot,
3385                                      paperwidth - LYX_PAPER_MARGIN,
3386                                      offset,
3387                                      offset + row_ptr->height);
3388                         
3389                 
3390         } else  {
3391                 if (row_ptr->previous &&
3392                     row_ptr->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3393                         LyXFont font(LyXFont::ALL_SANE);
3394                         font.setSize(LyXFont::SIZE_FOOTNOTE);
3395                         
3396                         int box_x = LYX_PAPER_MARGIN;
3397                         box_x += font.textWidth(" wide-tab ", 10);
3398                         
3399                         scr.drawLine(gc_foot,
3400                                      offset,
3401                                      box_x,
3402                                      paperwidth - LYX_PAPER_MARGIN - box_x);
3403                 }
3404         }
3405         
3406         LyXLayout* layout = lyxstyle.Style(parameters->textclass,
3407                                            row_ptr->par->GetLayout());
3408         firstpar = row_ptr->par->FirstPhysicalPar();
3409         
3410         y_top = 0;
3411         y_bottom = row_ptr->height;
3412         
3413         /* is it a first row? */ 
3414         if (row_ptr->pos == 0
3415             && row_ptr->par == firstpar) {
3416                 
3417                  /* start of appendix? */
3418                 if (row_ptr->par->start_of_appendix){
3419                   scr.drawLine(gc_math, 
3420                                offset,
3421                                1, paperwidth-2);
3422                 }
3423
3424                 /* think about the margins */ 
3425                 if (!row_ptr->previous)
3426                         y_top += LYX_PAPER_MARGIN;
3427                 
3428                 if (row_ptr->par->pagebreak_top){ /* draw a top pagebreak  */
3429                         scr.drawOnOffLine(offset + y_top + 2 * DefaultHeight(),
3430                                           0, paperwidth);
3431                         y_top += 3 * DefaultHeight();
3432                 }
3433                 
3434                 if (row_ptr->par->added_space_top.kind() == VSpace::VFILL) {
3435                         /* draw a vfill top  */
3436                         scr.drawLine(gc_fill, 
3437                                      offset + 2 + y_top,
3438                                      0, LYX_PAPER_MARGIN);
3439                         scr.drawLine(gc_fill,
3440                                      offset + y_top + 3 * DefaultHeight(),
3441                                      0, LYX_PAPER_MARGIN);
3442                         scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2, 
3443                                                   offset + 2 + y_top,
3444                                                   offset + y_top + 3 *
3445                                                   DefaultHeight());
3446                         
3447                         y_top += 3 * DefaultHeight();
3448                 }
3449                 
3450                 /* think about user added space */ 
3451                 y_top += int(row_ptr->par->added_space_top.inPixels());
3452                 
3453                 /* think about the parskip */ 
3454                 /* some parskips VERY EASY IMPLEMENTATION */ 
3455                 if (parameters->paragraph_separation == LYX_PARSEP_SKIP) {
3456                         if (layout->latextype == LATEX_PARAGRAPH
3457                             && firstpar->GetDepth() == 0
3458                             && firstpar->Previous())
3459                                 y_top += parameters->getDefSkip().inPixels();
3460                         else if (firstpar->Previous()
3461                                  && lyxstyle.Style(parameters->textclass,
3462                                                    firstpar->Previous()->GetLayout())->latextype == LATEX_PARAGRAPH
3463                                  && firstpar->Previous()->GetDepth() == 0)
3464                                 // is it right to use defskip here, too? (AS) 
3465                                 y_top += parameters->getDefSkip().inPixels();
3466                 }
3467                 
3468                 if (row_ptr->par->line_top) {      /* draw a top line  */
3469                         y_top +=  GetFont(row_ptr->par, 0).ascent('x');
3470
3471                         scr.drawThickLine(offset + y_top,
3472                                           0, paperwidth);
3473                         y_top +=  GetFont(row_ptr->par, 0).ascent('x');
3474                 }
3475                 
3476                 /* should we print a label? */ 
3477                 if (layout->labeltype >= LABEL_STATIC
3478                     && (layout->labeltype != LABEL_STATIC
3479                         || layout->latextype != LATEX_ENVIRONMENT
3480                         || row_ptr->par->IsFirstInSequence())) {
3481                         font = GetFont(row_ptr->par, -2);
3482                         if (!row_ptr->par->GetLabestring().empty()) {
3483                                 tmpx = x;
3484                                 string tmpstring = row_ptr->par->GetLabestring();
3485                                 
3486                                 if (layout->labeltype == LABEL_COUNTER_CHAPTER) {
3487                                         if (parameters->secnumdepth >=0){
3488                                                 /* this is special code for the chapter layout. This is printed in
3489                                                  * an extra row and has a pagebreak at the top. */
3490                                                 maxdesc = int(font.maxDescent() * layout->spacing.getValue() * parameters->spacing.getValue())
3491                                                         + int(layout->parsep) * DefaultHeight();
3492                                                 scr.drawString(font, tmpstring,
3493                                                                offset + row_ptr->baseline
3494                                                                - row_ptr->ascent_of_text - maxdesc,
3495                                                                int(x));
3496                                         }
3497                                 } else {
3498                                         x -= font.stringWidth( layout->labelsep);
3499                                         x -= font.stringWidth( tmpstring);
3500                                         /* draw it! */
3501                                         scr.drawString(font, tmpstring,
3502                                                        offset + row_ptr->baseline, int(x));
3503                                 }
3504                                 x = tmpx;
3505                         }
3506                         /* the labels at the top of an environment. More or less for bibliography */ 
3507                 } else if (layout->labeltype == LABEL_TOP_ENVIRONMENT ||
3508                            layout->labeltype == LABEL_BIBLIO ||
3509                            layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) {
3510                         if (row_ptr->par->IsFirstInSequence()) {
3511                                 font = GetFont(row_ptr->par, -2);
3512                                 if (!row_ptr->par->GetLabestring().empty()) {
3513                                         string tmpstring = row_ptr->par->GetLabestring();
3514                                         
3515                                         maxdesc = int(font.maxDescent() * layout->spacing.getValue() * parameters->spacing.getValue()
3516                                                          + (layout->labelbottomsep * DefaultHeight()));
3517                                         
3518                                         int top_label_x = int(x);
3519                                         if (layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT){
3520                                                 top_label_x = int(x + (paperwidth - RightMargin(row_ptr) - x) / 2); 
3521                                                 top_label_x -= (font.stringWidth( tmpstring)/2);
3522                                         }
3523                                         
3524                                         scr.drawString(font, tmpstring,
3525                                                        offset + row_ptr->baseline
3526                                                        - row_ptr->ascent_of_text - maxdesc,  
3527                                                        top_label_x);                
3528                                 }
3529                         }
3530                 }
3531                 if (layout->labeltype==LABEL_BIBLIO) { // ale970302
3532                         if (row_ptr->par->bibkey) {
3533                                 tmpx = x;
3534                                 x -= font.stringWidth(layout->labelsep);
3535                                 font = GetFont(row_ptr->par, -1);
3536                                 x -= row_ptr->par->bibkey->Width(font);
3537                                 row_ptr->par->bibkey->Draw(font, scr,
3538                                                            offset + row_ptr->baseline, 
3539                                                            x);
3540                                 x = tmpx;
3541                         }
3542                 } 
3543         }
3544         
3545         /* is it a last row? */
3546         par = row_ptr->par->LastPhysicalPar();
3547         if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
3548             && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {     
3549                 
3550                 /* think about the margins */ 
3551                 if (!row_ptr->next)
3552                         y_bottom -= LYX_PAPER_MARGIN;
3553                 
3554                 /* draw a bottom pagebreak */ 
3555                 if (firstpar->pagebreak_bottom) {
3556                         scr.drawOnOffLine(offset + y_bottom - 2 *
3557                                           DefaultHeight(),
3558                                           0, paperwidth);
3559                         y_bottom -= 3 * DefaultHeight();
3560                 }
3561                 
3562                 if (firstpar->added_space_bottom.kind() == VSpace::VFILL) {
3563                         /* draw a vfill bottom  */
3564                         scr.drawLine(gc_fill,
3565                                      offset + y_bottom - 3 * DefaultHeight(),
3566                                      0, LYX_PAPER_MARGIN);
3567                         scr.drawLine(gc_fill, offset + y_bottom - 2,
3568                                      0, LYX_PAPER_MARGIN);
3569                         scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2, 
3570                                                   offset + y_bottom - 3 * DefaultHeight(),
3571                                                   offset + y_bottom - 2
3572                                 );          
3573                         y_bottom -= 3* DefaultHeight();
3574                 }
3575                 
3576                 /* think about user added space */ 
3577                 y_bottom -= int(firstpar->added_space_bottom.inPixels());
3578                 
3579                 if (firstpar->line_bottom) {
3580                         /* draw a bottom line */
3581                         y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
3582
3583                         scr.drawThickLine(offset + y_bottom,
3584                                           0, paperwidth);           
3585                         y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
3586                 }
3587         }
3588         
3589         /* draw the text in the pixmap */  
3590         pos_end = RowLast(row_ptr);
3591         
3592         pos = row_ptr->pos;
3593         /* table stuff -- begin*/
3594         if (row_ptr->par->table) {
3595                 bool on_off;
3596                 int cell = NumberOfCell(row_ptr->par, row_ptr->pos);
3597                 float x_old = x;
3598                 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
3599                 
3600                 while (pos <= pos_end)  {
3601                         if (row_ptr->par->IsNewline(pos)) {
3602                                 
3603                                 x = x_old + row_ptr->par->table->WidthOfColumn(cell);
3604                                 /* draw the table lines, still very simple */
3605                                 on_off = !row_ptr->par->table->TopLine(cell);
3606                                 if ((!on_off ||
3607                                      !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
3608                                     !row_ptr->par->table->IsContRow(cell))
3609                                         scr.drawTableLine(offset + row_ptr->baseline -
3610                                                           row_ptr->ascent_of_text,
3611                                                           int(x_old), int(x - x_old), on_off);
3612                                 on_off = !row_ptr->par->table->BottomLine(cell);
3613                                 if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
3614                                     row_ptr->par->table->VeryLastRow(cell))
3615                                         scr.drawTableLine(offset + y_bottom - 1,
3616                                                           int(x_old), int(x - x_old), on_off);
3617                                 on_off = !row_ptr->par->table->LeftLine(cell);
3618                                 
3619                                 scr.drawVerticalTableLine(int(x_old), 
3620                                                           offset + row_ptr->baseline -
3621                                                           row_ptr->ascent_of_text,
3622                                                           offset + y_bottom - 1,
3623                                                           on_off);
3624                                 on_off = !row_ptr->par->table->RightLine(cell);
3625                                 
3626                                 scr.drawVerticalTableLine(int(x) -
3627                                                           row_ptr->par->table->AdditionalWidth(cell),
3628                                                           offset + row_ptr->baseline -
3629                                                           row_ptr->ascent_of_text,
3630                                                           offset + y_bottom - 1,
3631                                                           on_off);
3632                                 x_old = x;
3633                 /* take care about the alignment and other spaces */
3634                                 cell++;
3635                                 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
3636                                 if (row_ptr->par->table->IsFirstCell(cell))
3637                                         cell--; // little hack, sorry
3638                                 pos++;
3639                         } else if (row_ptr->par->IsHfill(pos)) {
3640                                 x += 1;
3641                                 
3642                                 scr.drawVerticalLine(gc_fill, int(x),  
3643                                                      offset + row_ptr->baseline - DefaultHeight()/2, 
3644                                                      offset + row_ptr->baseline);               
3645                                 x += 2;
3646                                 pos++;
3647                         } else {
3648                                 if (row_ptr->par->IsSeparator(pos)) {
3649                                         tmpx = x;
3650                                         x+=SingleWidth(row_ptr->par, pos);
3651                                         /* -------> Only draw protected spaces when not in
3652                                          * free-spacing mode. */
3653                                         if (row_ptr->par->GetChar(pos)==LYX_META_PROTECTED_SEPARATOR && !layout->free_spacing) {
3654                                                 scr.drawVerticalLine(gc_fill, int(tmpx),
3655                                                                      offset + row_ptr->baseline - 3,
3656                                                                      offset + row_ptr->baseline - 1);
3657                                                 scr.drawLine(gc_fill,
3658                                                              offset + row_ptr->baseline - 1,
3659                                                              int(tmpx),
3660                                                              int(x-tmpx-2));
3661                                                 scr.drawVerticalLine(gc_fill, int(x-2),
3662                                                                      offset + row_ptr->baseline - 3,
3663                                                                      offset + row_ptr->baseline - 1);                   
3664                                                 /* what about underbars? */
3665                                                 font = GetFont(row_ptr->par, pos); 
3666                                                 if (font.underbar() == LyXFont::ON
3667                                                     && font.latex() != LyXFont::ON) {
3668                                                         scr.drawLine(gc_copy,
3669                                                                      offset +
3670                                                                      row_ptr->baseline + 2,
3671                                                                      int(tmpx),
3672                                                                      int(x - tmpx));                        
3673                                                 }
3674                                         }
3675                                         pos++;
3676                                 } else
3677                                         Draw(row_ptr, pos, scr, offset, x);
3678                         }
3679                 }
3680                 
3681                 /* do not forget the very last cell. This has no NEWLINE so 
3682                  * ignored by the code above*/ 
3683                 if (cell == row_ptr->par->table->GetNumberOfCells()-1){
3684                         x = x_old + row_ptr->par->table->WidthOfColumn(cell);
3685                         on_off = !row_ptr->par->table->TopLine(cell);
3686                         if ((!on_off ||
3687                              !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
3688                             !row_ptr->par->table->IsContRow(cell))
3689                                 
3690                                 scr.drawTableLine(offset + row_ptr->baseline -
3691                                                   row_ptr->ascent_of_text,
3692                                                   int(x_old), int(x - x_old), on_off);      
3693                         on_off = !row_ptr->par->table->BottomLine(cell);
3694                         if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
3695                             row_ptr->par->table->VeryLastRow(cell))
3696                                 
3697                                 scr.drawTableLine(offset + y_bottom - 1,
3698                                                   int(x_old), int(x - x_old), on_off);      
3699                         on_off = !row_ptr->par->table->LeftLine(cell);
3700                         
3701                         scr.drawVerticalTableLine(int(x_old), 
3702                                                   offset + row_ptr->baseline -
3703                                                   row_ptr->ascent_of_text,
3704                                                   offset + y_bottom - 1,
3705                                                   on_off);          
3706                         on_off = !row_ptr->par->table->RightLine(cell);
3707                         
3708                         scr.drawVerticalTableLine(int(x) -
3709                                                   row_ptr->par->table->AdditionalWidth(cell),
3710                                                   offset + row_ptr->baseline -
3711                                                   row_ptr->ascent_of_text,
3712                                                   offset + y_bottom - 1,
3713                                                   on_off);          
3714                 }
3715         } else {
3716                 /* table stuff -- end*/
3717                 
3718                 while (pos <= pos_end)  {
3719                         
3720                         if (row_ptr->par->IsHfill(pos)) {
3721                                 x += 1;
3722                                 scr.drawVerticalLine(gc_fill, int(x),  
3723                                                      offset + row_ptr->baseline - DefaultHeight()/2, 
3724                                                      offset + row_ptr->baseline);               
3725                                 if (HfillExpansion(row_ptr,pos)) {
3726                                         if (pos >= main_body) {
3727                                                 scr.drawOnOffLine(offset + row_ptr->baseline -
3728                                                                   DefaultHeight()/4,
3729                                                                   int(x),
3730                                                                   int(fill_hfill));                     
3731                                                 x += fill_hfill;
3732                     } else {
3733                             scr.drawOnOffLine(offset + row_ptr->baseline -
3734                                               DefaultHeight()/4,
3735                                               int(x),
3736                                               int(fill_label_hfill));
3737                             x += fill_label_hfill;
3738                     }
3739                                         scr.drawVerticalLine(gc_fill, int(x),
3740                                                              offset + row_ptr->baseline -
3741                                                              DefaultHeight()/2, 
3742                                                              offset + row_ptr->baseline);
3743                                 }
3744                                 x += 2;
3745                                 pos++;
3746                         } else {
3747                                 if (row_ptr->par->IsSeparator(pos)) {
3748                                         tmpx = x;
3749                                         x+=SingleWidth(row_ptr->par, pos);
3750                                         if (pos >= main_body)
3751                                                 x+= fill_separator;
3752                                         /* -------> Only draw protected spaces when not in
3753                                          * free-spacing mode. */
3754                                         if (row_ptr->par->GetChar(pos)==LYX_META_PROTECTED_SEPARATOR && !layout->free_spacing) {
3755                                                 
3756                                                 scr.drawVerticalLine(gc_fill, int(tmpx),
3757                                                                      offset + row_ptr->baseline - 3,
3758                                                                      offset + row_ptr->baseline - 1);
3759                                                 scr.drawLine(gc_fill,
3760                                                              offset + row_ptr->baseline - 1,
3761                                                              int(tmpx),
3762                                                              int(x-tmpx-2));
3763                                                 scr.drawVerticalLine(gc_fill, int(x-2),
3764                                                                      offset + row_ptr->baseline - 3,
3765                                                                      offset + row_ptr->baseline - 1);                   
3766                                                 /* what about underbars? */
3767                                                 font = GetFont(row_ptr->par, pos); 
3768                                                 if (font.underbar() == LyXFont::ON
3769                                                     && font.latex() != LyXFont::ON) {
3770                                                         scr.drawLine(gc_copy,
3771                                              offset + row_ptr->baseline + 2,
3772                                                                      int(tmpx),
3773                                                                      int(x - tmpx));
3774                                                 }
3775                                         }
3776                                         pos++;
3777                                 } else
3778                                         Draw(row_ptr, pos, scr, offset, x);
3779                         }
3780                         if (pos == main_body) {
3781                                 x += GetFont(row_ptr->par, -2).stringWidth(
3782                                         layout->labelsep);
3783                                 if (row_ptr->par->IsLineSeparator(pos - 1))
3784                                         x-= SingleWidth(row_ptr->par, pos - 1);
3785                                 if (x < left_margin)
3786                                         x = left_margin;
3787                         }
3788                 }
3789         }
3790         // check for FAST SELECTION
3791         if (fast_selection || mono_video){
3792                 if (selection) {
3793                         
3794                         /* selection code */ 
3795                         if (sel_start_cursor.row == row_ptr && sel_end_cursor.row == row_ptr) {
3796                                 scr.fillRectangle(gc_select,sel_start_cursor.x, offset,
3797                                                   sel_end_cursor.x - sel_start_cursor.x,
3798                                                   row_ptr->height); 
3799                         } else if (sel_start_cursor.row == row_ptr) {
3800                                 scr.fillRectangle(gc_select, sel_start_cursor.x, offset,
3801                                                   paperwidth - sel_start_cursor.x,
3802                                                   row_ptr->height);
3803                         } else if (sel_end_cursor.row == row_ptr) {
3804                                 scr.fillRectangle(gc_select, 0, offset,
3805                                                   sel_end_cursor.x,
3806                                                   row_ptr->height);
3807                         } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
3808                                 scr.fillRectangle(gc_select, 0, offset,
3809                                                   paperwidth, row_ptr->height);
3810                                 
3811                         }
3812                 }
3813         }
3814 // end of FAST SELECTION code
3815         /* thats it */ 
3816 }
3817
3818
3819 int LyXText::DefaultHeight()
3820 {
3821         LyXFont font(LyXFont::ALL_SANE);
3822         return int(font.maxAscent() + font.maxDescent() * 1.5);
3823 }
3824
3825    
3826 /* returns the column near the specified x-coordinate of the row 
3827 * x is set to the real beginning of this column  */ 
3828 int  LyXText::GetColumnNearX(Row *row, int& x)
3829 {
3830         int c; 
3831         float tmpx = 0.0;
3832         float fill_separator, fill_hfill, fill_label_hfill;
3833         int left_margin;
3834    
3835         left_margin = LabelEnd(row);
3836         PrepareToPrint(row, tmpx, fill_separator,
3837                        fill_hfill, fill_label_hfill);
3838         int main_body = BeginningOfMainBody(row->par);
3839    
3840         c = row->pos;
3841
3842         int last = RowLast(row);
3843         if (row->par->IsNewline(last))
3844                 last--;
3845    
3846         LyXLayout *layout = lyxstyle.Style(parameters->textclass,
3847                                            row->par->GetLayout());
3848         /* table stuff -- begin*/
3849         if (row->par->table) {
3850                 if (!row->next || row->next->par != row->par)
3851                         last = RowLast(row); /* the last row doesn't need a newline at the end*/
3852                 int cell = NumberOfCell(row->par, row->pos);
3853                 float x_old = tmpx;
3854                 bool ready = false;
3855                 tmpx += row->par->table->GetBeginningOfTextInCell(cell);
3856                 while (c <= last
3857                        && tmpx + (SingleWidth(row->par, c)/2) <= x
3858                        && !ready){
3859                         if (row->par->IsNewline(c)) {
3860                                 if (x_old + row->par->table->WidthOfColumn(cell) <= x){
3861                                         tmpx = x_old + row->par->table->WidthOfColumn(cell);
3862                                         x_old = tmpx;
3863                                         cell++;
3864                                         tmpx += row->par->table->GetBeginningOfTextInCell(cell);
3865                                         c++;
3866                                 } else
3867                                         ready = true;
3868                         } else {
3869                                 tmpx += SingleWidth(row->par, c);
3870                                 c++;
3871                         }
3872                 }
3873         } else
3874                 /* table stuff -- end*/
3875
3876                 while (c <= last
3877                        && tmpx + (SingleWidth(row->par, c)/2)  <= x) {
3878                         
3879                         if (c && c == main_body
3880                             && !row->par->IsLineSeparator(c - 1)) {
3881                                 tmpx += GetFont(row->par, -2)
3882                                         .stringWidth(layout->labelsep);
3883                                 if (tmpx < left_margin)
3884                                         tmpx = left_margin;
3885                         }
3886              
3887                         tmpx += SingleWidth(row->par, c);
3888                         if (HfillExpansion(row, c)) {
3889                                 if (c >= main_body)
3890                                         tmpx += fill_hfill;
3891                                 else
3892                                         tmpx += fill_label_hfill;
3893                         }
3894                         else if (c >= main_body
3895                                  && row->par->IsSeparator(c)) {
3896                                 tmpx+= fill_separator;  
3897                         }
3898                         c++;
3899                         if (c == main_body
3900                             && row->par->IsLineSeparator(c - 1)) {
3901                                 tmpx += GetFont(row->par, -2)
3902                                         .stringWidth(layout->labelsep);
3903                                 tmpx-= SingleWidth(row->par, c - 1);
3904                                 if (tmpx < left_margin)
3905                                         tmpx = left_margin;
3906                         }
3907                 }
3908         /* make sure that a last space in a row doesnt count */
3909         if (c > 0 && c >= last
3910             && row->par->IsLineSeparator(c - 1)
3911             && !(!row->next || row->next->par != row->par)) {
3912                 tmpx -= SingleWidth(row->par, c - 1);
3913                 tmpx -= fill_separator;
3914         }
3915         c-=row->pos;
3916         
3917         x = int(tmpx);
3918         return c;
3919 }
3920
3921    
3922 /* turn the selection into a new environment. If there is no selection,
3923 * create an empty environment */ 
3924 void LyXText::InsertFootnoteEnvironment(LyXParagraph::footnote_kind kind)
3925 {
3926    /* no footnoteenvironment in a footnoteenvironment */ 
3927    if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3928       WriteAlert(_("Impossible operation"), 
3929                  _("You can't insert a float in a float!"), 
3930                  _("Sorry."));
3931      return;
3932    }
3933    /* no marginpars in minipages */
3934    if (kind == LyXParagraph::MARGIN 
3935       && cursor.par->pextra_type == PEXTRA_MINIPAGE) {
3936       WriteAlert(_("Impossible operation"), 
3937                  _("You can't insert a marginpar in a minipage!"), 
3938                  _("Sorry."));
3939       return;
3940    }
3941    
3942    /* this doesnt make sense, if there is no selection */ 
3943    bool dummy_selection = false;
3944    if (!selection) {
3945       sel_start_cursor = cursor;       /* dummy selection  */
3946       sel_end_cursor = cursor;
3947       dummy_selection = true;
3948    }
3949    
3950    LyXParagraph *tmppar;
3951
3952    if (sel_start_cursor.par->table || sel_end_cursor.par->table){
3953       WriteAlert(_("Impossible operation"), _("Cannot cut table."), _("Sorry."));
3954       return;
3955    }
3956      
3957    /* a test to make sure there is not already a footnote
3958     * in the selection. */
3959    
3960    tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
3961    
3962    while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos) && 
3963           tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
3964      tmppar = tmppar->next;
3965    
3966    if (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
3967        || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3968       WriteAlert(_("Impossible operation"), 
3969                  _("Float would include float!"), 
3970                  _("Sorry."));
3971       return;
3972    }
3973    
3974    /* ok we have a selection. This is always between sel_start_cursor
3975     * and sel_end cursor */
3976
3977    SetUndo(Undo::FINISH, 
3978            sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
3979            sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next); 
3980    
3981    if (sel_end_cursor.pos > 0 
3982        && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1))
3983      sel_end_cursor.pos--;             /* please break before a space at
3984                                         * the end */
3985    if (sel_start_cursor.par == sel_end_cursor.par
3986        && sel_start_cursor.pos > sel_end_cursor.pos)
3987      sel_start_cursor.pos--;
3988
3989    sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
3990    
3991    sel_end_cursor.par = sel_end_cursor.par->Next();
3992    sel_end_cursor.pos = 0;
3993    
3994    // don't forget to insert a dummy layout paragraph if necessary
3995    if (sel_start_cursor.par->GetLayout() != sel_end_cursor.par->layout){
3996      sel_end_cursor.par->BreakParagraphConservative(0);
3997      sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
3998      sel_end_cursor.par = sel_end_cursor.par->next;
3999    }
4000    else
4001      sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
4002
4003    cursor = sel_end_cursor;
4004
4005    /* please break behind a space, if there is one. The space should
4006     * be erased too */ 
4007    if (sel_start_cursor.pos > 0 
4008        && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1))
4009      sel_start_cursor.pos--;
4010    if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)) {
4011       sel_start_cursor.par->Erase(sel_start_cursor.pos);
4012    }
4013    
4014    sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
4015    tmppar = sel_start_cursor.par->Next();
4016    
4017    if (dummy_selection) {
4018            tmppar->Clear();
4019            if (kind == LyXParagraph::TAB
4020                || kind == LyXParagraph::FIG 
4021                || kind == LyXParagraph::WIDE_TAB
4022                || kind == LyXParagraph::WIDE_FIG 
4023                || kind == LyXParagraph::ALGORITHM) {
4024                    int lay = lyxstyle.NumberOfLayout(parameters->textclass,
4025                                                      "Caption");
4026                    if (lay == -1) // layout not found
4027                            // use default layout "Standard" (0)
4028                            lay = 0;
4029                    tmppar->SetLayout(lay);
4030            }
4031    }
4032    else {
4033      if (sel_start_cursor.pos > 0) {
4034        /* the footnote-environment should begin with a standard layout.
4035         * Imagine you insert a footnote within an enumeration, you 
4036         * certainly do not want an enumerated footnote! */ 
4037        tmppar->Clear();
4038      }
4039      else {
4040        /* this is a exception the user would sometimes expect, I hope */
4041        sel_start_cursor.par->Clear();
4042      }
4043    }
4044    
4045    while (tmppar != sel_end_cursor.par) {
4046       tmppar->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
4047       tmppar->footnotekind = kind;
4048       tmppar = tmppar->Next();
4049    } 
4050
4051    RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
4052    
4053    SetCursor(sel_start_cursor.par->Next(), 0);
4054
4055    ClearSelection();
4056 }
4057    
4058
4059 /* returns pointer to a specified row */
4060 Row* LyXText::GetRow(LyXParagraph *par, int pos, long &y)
4061 {
4062    Row* tmprow;
4063
4064    if (currentrow){
4065      if (par == currentrow->par || par == currentrow->par->Previous()){
4066              // do not dereference par, it may have been deleted
4067              // already! (Matthias) 
4068              while (currentrow->previous && currentrow->previous->par != par){
4069                      currentrow = currentrow->previous;
4070                      currentrow_y -= currentrow->height;
4071              }
4072              while (currentrow->previous && currentrow->previous->par == par){
4073                      currentrow = currentrow->previous;
4074                      currentrow_y -= currentrow->height;
4075              }
4076      }
4077      tmprow = currentrow;
4078      y = currentrow_y;
4079      /* find the first row of the specified paragraph */ 
4080      while (tmprow->next && (tmprow->par != par)) {
4081        y += tmprow->height;
4082        tmprow = tmprow->next;
4083      }
4084
4085      if (tmprow->par == par){
4086        /* now find the wanted row */ 
4087        while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par && 
4088               tmprow->next->pos <= pos) {
4089          y += tmprow->height;
4090        tmprow = tmprow->next;
4091        }
4092        currentrow = tmprow;
4093        currentrow_y = y;
4094        return tmprow;
4095      }
4096    }
4097    tmprow = firstrow;
4098    y = 0;
4099    /* find the first row of the specified paragraph */ 
4100    while (tmprow->next && (tmprow->par != par)) {
4101       y += tmprow->height;
4102       tmprow = tmprow->next;
4103    }
4104  
4105    /* now find the wanted row */ 
4106    while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par && 
4107           tmprow->next->pos <= pos) {
4108              y += tmprow->height;
4109              tmprow = tmprow->next;
4110    }
4111    
4112    currentrow = tmprow;
4113    currentrow_y = y;
4114
4115    return tmprow;
4116 }