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