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