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