]> git.lyx.org Git - lyx.git/blob - src/text.C
fix some of the bugs reported, should hopefully be a bit better now.
[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, pos_end);
1028    if (maxsize > font.size()) {
1029         font.setSize(maxsize);
1030
1031         asc = font.maxAscent();
1032         desc = font.maxDescent();
1033         if (asc > maxasc) 
1034                 maxasc = asc;
1035         if (desc > maxdesc)
1036                 maxdesc = desc;
1037    }
1038
1039    /* table stuff -- begin*/
1040    if (row_ptr->par->table){
1041      // stretch the rows a bit
1042       maxasc += 1;
1043       maxdesc += 1;
1044    }
1045    /* table stuff -- end*/
1046
1047    // This is nicer with box insets:
1048    maxasc++;
1049    maxdesc++;
1050
1051    row_ptr->ascent_of_text = maxasc;
1052    
1053    /* is it a top line? */ 
1054    if (row_ptr->pos == 0
1055        && row_ptr->par == firstpar) {
1056       
1057       /* some parksips VERY EASY IMPLEMENTATION */ 
1058       if (parameters->paragraph_separation == BufferParams::PARSEP_SKIP) {
1059          if (layout.isParagraph()
1060              && firstpar->GetDepth() == 0
1061              && firstpar->Previous())
1062             maxasc += parameters->getDefSkip().inPixels();
1063          else if (firstpar->Previous()
1064                   && textclasslist.Style(parameters->textclass,
1065                            firstpar->Previous()->GetLayout()).isParagraph()
1066                   && firstpar->Previous()->GetDepth() == 0)
1067            // is it right to use defskip here too? (AS)
1068            maxasc += parameters->getDefSkip().inPixels();
1069       }
1070       
1071       /* the paper margins */ 
1072       if (!row_ptr->par->previous)
1073          maxasc += LYX_PAPER_MARGIN;
1074       
1075       /* add the vertical spaces, that the user added */
1076       if (firstpar->added_space_top.kind() != VSpace::NONE)
1077          maxasc += int(firstpar->added_space_top.inPixels());
1078       
1079       /* do not forget the DTP-lines! 
1080        * there height depends on the font of the nearest character */
1081       if (firstpar->line_top)
1082          maxasc += 2 * GetFont(firstpar, 0).ascent('x');
1083       
1084       /* and now the pagebreaks */ 
1085       if (firstpar->pagebreak_top)
1086          maxasc += 3 * DefaultHeight();
1087       
1088       /*  this is special code for the chapter, since the label of this
1089        * layout is printed in an extra row */ 
1090       if (layout.labeltype == LABEL_COUNTER_CHAPTER
1091           && parameters->secnumdepth>= 0) {
1092               labeladdon = int(labelfont.maxDescent() *
1093                                   layout.spacing.getValue() *
1094                                   parameters->spacing.getValue())
1095                       + int(labelfont.maxAscent() *
1096                                layout.spacing.getValue() *
1097                                parameters->spacing.getValue());
1098       }
1099       
1100       /* special code for the top label */ 
1101       if ((layout.labeltype == LABEL_TOP_ENVIRONMENT
1102            || layout.labeltype == LABEL_BIBLIO
1103            || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)
1104           && row_ptr->par->IsFirstInSequence()
1105           && !row_ptr->par->GetLabestring().empty()) {
1106          labeladdon = int(
1107                  (labelfont.maxAscent() *
1108                   layout.spacing.getValue() *
1109                   parameters->spacing.getValue())
1110                  +(labelfont.maxDescent() *
1111                    layout.spacing.getValue() *
1112                    parameters->spacing.getValue())
1113                  + layout.topsep * DefaultHeight()
1114                  + layout.labelbottomsep *  DefaultHeight());
1115       }
1116    
1117       /* and now the layout spaces, for example before and after a section, 
1118        * or between the items of a itemize or enumerate environment */ 
1119       
1120       if (!firstpar->pagebreak_top) {
1121          LyXParagraph *prev = row_ptr->par->Previous();
1122          if (prev)
1123             prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth());
1124          if (prev && prev->GetLayout() == firstpar->GetLayout()
1125              && prev->GetDepth() == firstpar->GetDepth()
1126              && prev->GetLabelWidthString() == firstpar->GetLabelWidthString())
1127            {
1128               layoutasc = (layout.itemsep * DefaultHeight());
1129            }
1130          else if (row_ptr->previous) {
1131             tmptop = layout.topsep;
1132             
1133             if (row_ptr->previous->par->GetDepth() >= row_ptr->par->GetDepth())
1134                tmptop-= textclasslist.Style(parameters->textclass, row_ptr->previous->par->GetLayout()).bottomsep;
1135             
1136             if (tmptop > 0)
1137                layoutasc = (tmptop * DefaultHeight());
1138          }
1139          else if (row_ptr->par->line_top){
1140             tmptop = layout.topsep;
1141             
1142             if (tmptop > 0)
1143                layoutasc = (tmptop * DefaultHeight());
1144          }
1145          
1146          prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth()-1);
1147          if (prev)  {
1148             maxasc += int(textclasslist.Style(parameters->textclass,
1149                                          prev->GetLayout()).parsep * DefaultHeight());
1150          }
1151          else {
1152                 if (firstpar->Previous()
1153                     && firstpar->Previous()->GetDepth() == 0
1154                     && firstpar->Previous()->GetLayout() != firstpar->GetLayout()) {
1155                    /* avoid parsep */ 
1156                 }
1157             else if (firstpar->Previous()){
1158                maxasc += int(layout.parsep * DefaultHeight());
1159             }
1160          }
1161       }
1162    }
1163    
1164    /* is it a bottom line? */ 
1165    if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
1166        && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {     
1167           
1168           /* the paper margins */ 
1169           if (!par->next)
1170             maxdesc += LYX_PAPER_MARGIN;
1171         
1172           /* add the vertical spaces, that the user added */
1173           if (firstpar->added_space_bottom.kind() != VSpace::NONE)
1174             maxdesc += int(firstpar->added_space_bottom.inPixels());
1175           
1176           /* do not forget the DTP-lines! 
1177            * there height depends on the font of the nearest character */
1178           if (firstpar->line_bottom)
1179             maxdesc += 2 * (GetFont(par, par->Last()-1).ascent('x'));
1180           
1181           /* and now the pagebreaks */
1182           if (firstpar->pagebreak_bottom)
1183             maxdesc += 3 * DefaultHeight();
1184           
1185           /* and now the layout spaces, for example before and after a section, 
1186            * or between the items of a itemize or enumerate environment */
1187           if (!firstpar->pagebreak_bottom && row_ptr->par->Next()) {
1188              LyXParagraph *nextpar = row_ptr->par->Next();
1189              LyXParagraph *comparepar = row_ptr->par;
1190              float usual = 0;
1191              float  unusual = 0;
1192              
1193              if (comparepar->GetDepth() > nextpar->GetDepth()) {
1194                 usual = (textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1195                 comparepar = comparepar->DepthHook(nextpar->GetDepth());
1196                 if (comparepar->GetLayout()!= nextpar->GetLayout()
1197                     || nextpar->GetLabelWidthString() != 
1198                         comparepar->GetLabelWidthString())
1199                   unusual = (textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1200                 
1201                 if (unusual > usual)
1202                   layoutdesc = unusual;
1203                 else
1204                   layoutdesc = usual;
1205              }
1206              else if (comparepar->GetDepth() ==  nextpar->GetDepth()) {
1207                 
1208                 if (comparepar->GetLayout()!= nextpar->GetLayout()
1209                     || nextpar->GetLabelWidthString() != 
1210                         comparepar->GetLabelWidthString())
1211                   layoutdesc = int(textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1212              }
1213           }
1214        }
1215    
1216    /* incalculate the layout spaces */ 
1217    maxasc += int(layoutasc * 2 / (2 + firstpar->GetDepth()));
1218    maxdesc += int(layoutdesc * 2 / (2 + firstpar->GetDepth()));
1219
1220    /* table stuff -- begin*/
1221    if (row_ptr->par->table){
1222       maxasc += row_ptr->par->table->
1223         AdditionalHeight(NumberOfCell(row_ptr->par, row_ptr->pos));
1224    }
1225    /* table stuff -- end*/
1226    
1227    /* calculate the new height of the text */ 
1228    height -= row_ptr->height;
1229    
1230    row_ptr->height= maxasc+maxdesc+labeladdon;
1231    row_ptr->baseline= maxasc+labeladdon;
1232    
1233    height += row_ptr->height;
1234 }
1235
1236
1237 /* Appends the implicit specified paragraph behind the specified row,
1238  * start at the implicit given position */
1239 void LyXText::AppendParagraph(Row * row) const
1240 {
1241    bool not_ready = true;
1242    
1243    // The last character position of a paragraph is an invariant so we can 
1244    // safely get it here. (Asger)
1245    int lastposition = row->par->Last();
1246
1247    do {
1248       // Get the next breakpoint
1249       int z = NextBreakPoint(row, paperwidth);
1250       
1251       Row * tmprow = row;
1252
1253       // Insert the new row
1254       if (z < lastposition) {
1255          z++;
1256          InsertRow(row, row->par, z);
1257          row = row->next;
1258
1259          row->height = 0;
1260       } else
1261          not_ready = false;
1262       
1263       // Set the dimensions of the row
1264       tmprow->fill = Fill(tmprow, paperwidth);
1265       SetHeightOfRow(tmprow);
1266
1267    } while (not_ready);
1268 }
1269
1270
1271 void LyXText::BreakAgain(Row * row) const
1272 {
1273    bool not_ready = true;
1274    
1275    do  {
1276       /* get the next breakpoint */
1277         LyXParagraph::size_type z = 
1278                 NextBreakPoint(row, paperwidth);
1279       Row * tmprow = row;
1280       
1281       if (z < row->par->Last() ) {
1282          if (!row->next || (row->next && row->next->par != row->par)) {
1283                  // insert a new row
1284             ++z;
1285             InsertRow(row, row->par, z);
1286             row = row->next;
1287             row->height = 0;
1288          } else  {
1289             row = row->next;
1290             z++;
1291             if (row->pos == z)
1292                     not_ready = false;     // the rest will not change
1293             else {
1294                row->pos = z;
1295             }
1296          }
1297       } else {
1298          /* if there are some rows too much, delete them */
1299          /* only if you broke the whole paragraph! */ 
1300          Row * tmprow2 = row;
1301          while (tmprow2->next && tmprow2->next->par == row->par) {
1302             tmprow2 = tmprow2->next;
1303          }
1304          while (tmprow2 != row) {
1305             tmprow2 = tmprow2->previous;
1306             RemoveRow(tmprow2->next);
1307          }
1308          not_ready = false;
1309       }
1310        
1311       /* set the dimensions of the row */ 
1312       tmprow->fill = Fill(tmprow, paperwidth);
1313       SetHeightOfRow(tmprow);
1314    } while (not_ready);
1315 }
1316
1317
1318 /* this is just a little changed version of break again */ 
1319 void LyXText::BreakAgainOneRow(Row * row)
1320 {
1321    /* get the next breakpoint */
1322    LyXParagraph::size_type z = NextBreakPoint(row, paperwidth);
1323    Row * tmprow = row;
1324    
1325    if (z < row->par->Last() ) {
1326       if (!row->next || (row->next && row->next->par != row->par)) {
1327          /* insert a new row */ 
1328          z++;
1329          InsertRow(row, row->par, z);
1330          row = row->next;
1331          row->height = 0;
1332       }
1333       else  {
1334          row= row->next;
1335          z++;
1336          if (row->pos != z)
1337             row->pos = z;
1338       }
1339    }
1340    else {
1341       /* if there are some rows too much, delete them */
1342       /* only if you broke the whole paragraph! */ 
1343       Row * tmprow2 = row;
1344       while (tmprow2->next && tmprow2->next->par == row->par) {
1345          tmprow2 = tmprow2->next;
1346       }
1347       while (tmprow2 != row) {
1348          tmprow2 = tmprow2->previous;
1349          RemoveRow(tmprow2->next);
1350       }
1351    }
1352    
1353    /* set the dimensions of the row */ 
1354    tmprow->fill = Fill(tmprow, paperwidth);
1355    SetHeightOfRow(tmprow);
1356 }
1357
1358
1359 void LyXText::BreakParagraph(char keep_layout)
1360 {
1361    LyXLayout const & layout = textclasslist.Style(parameters->textclass,
1362                                       cursor.par->GetLayout());
1363    
1364    /* table stuff -- begin */
1365    if (cursor.par->table) {
1366        // breaking of tables is only allowed at the beginning or the end */
1367        if (cursor.pos && cursor.pos < cursor.par->size() &&
1368            !cursor.par->table->ShouldBeVeryLastCell(NumberOfCell(cursor.par, cursor.pos)))
1369                return; // no breaking of tables allowed
1370    }
1371    /* table stuff -- end */
1372
1373    // this is only allowed, if the current paragraph is not empty or caption
1374    if ((cursor.par->Last() <= 0 && !cursor.par->IsDummy())
1375        && 
1376        layout.labeltype!= LABEL_SENSITIVE)
1377      return;
1378
1379    SetUndo(Undo::INSERT, 
1380            cursor.par->ParFromPos(cursor.pos)->previous, 
1381            cursor.par->ParFromPos(cursor.pos)->next); 
1382
1383    /* table stuff -- begin */
1384    if (cursor.par->table) {
1385        int cell = NumberOfCell(cursor.par, cursor.pos);
1386        if (cursor.par->table->ShouldBeVeryLastCell(cell))
1387            SetCursor(cursor.par, cursor.par->text.size());
1388    }
1389    /* table stuff -- end */
1390    
1391    // please break always behind a space
1392    if (cursor.pos < cursor.par->Last()
1393        && cursor.par->IsLineSeparator(cursor.pos))
1394      cursor.pos++;
1395    
1396    // break the paragraph
1397    if (keep_layout)
1398      keep_layout = 2;
1399    else 
1400      keep_layout = layout.isEnvironment();
1401    cursor.par->BreakParagraph(cursor.pos, keep_layout);
1402
1403    /* table stuff -- begin */
1404    if (cursor.par->table){
1405      // the table should stay with the contents
1406      if (!cursor.pos){
1407        cursor.par->Next()->table = cursor.par->table;
1408        cursor.par->table = 0;
1409      }
1410    }
1411    /* table stuff -- end */
1412
1413    // well this is the caption hack since one caption is really enough
1414    if (layout.labeltype == LABEL_SENSITIVE){
1415      if (!cursor.pos)
1416              cursor.par->SetLayout(0); // set to standard-layout
1417      else
1418              cursor.par->Next()->SetLayout(0); // set to standard-layout
1419    }
1420    
1421    /* if the cursor is at the beginning of a row without prior newline, 
1422     * move one row up! 
1423     * This touches only the screen-update. Otherwise we would may have
1424     * an empty row on the screen */
1425    if (cursor.pos && !cursor.row->par->IsNewline(cursor.row->pos -1) &&
1426        cursor.row->pos == cursor.pos) {
1427      CursorLeft();
1428    } 
1429    
1430    status = LyXText::NEED_MORE_REFRESH;
1431    refresh_row = cursor.row;
1432    refresh_y = cursor.y - cursor.row->baseline;
1433    
1434    // Do not forget the special right address boxes
1435    if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX) {
1436       while (refresh_row->previous &&
1437              refresh_row->previous->par == refresh_row->par) {
1438                 refresh_row = refresh_row->previous;
1439                 refresh_y -= refresh_row->height;
1440              }
1441    }
1442    RemoveParagraph(cursor.row);
1443    
1444    // set the dimensions of the cursor row
1445    cursor.row->fill = Fill(cursor.row, paperwidth);
1446
1447    SetHeightOfRow(cursor.row);
1448    
1449    while (!cursor.par->Next()->table && cursor.par->Next()->Last()
1450           && cursor.par->Next()->IsNewline(0))
1451      cursor.par->Next()->Erase(0);
1452    
1453    InsertParagraph(cursor.par->Next(), cursor.row);
1454
1455    UpdateCounters(cursor.row->previous);
1456    
1457    /* This check is necessary. Otherwise the new empty paragraph will
1458     * be deleted automatically. And it is more friendly for the user! */ 
1459    if (cursor.pos)
1460      SetCursor(cursor.par->Next(), 0);
1461    else
1462      SetCursor(cursor.par, 0);
1463    
1464    if (cursor.row->next)
1465      BreakAgain(cursor.row->next);
1466
1467    need_break_row = 0;
1468 }
1469
1470
1471 void LyXText::OpenFootnote()
1472 {
1473    LyXParagraph * endpar,* tmppar;
1474    Row * row;
1475    
1476    LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
1477    
1478    /* if there is no footnote in this paragraph, just return. */ 
1479    if (!par->next
1480        || par->next->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1481      return;
1482    
1483    /* ok, move the cursor right before the footnote */ 
1484    
1485    /* just a little faster than using CursorRight() */
1486    for (cursor.pos= 0; cursor.par->ParFromPos(cursor.pos)!= par; cursor.pos++);
1487    /* now the cursor is at the beginning of the physical par */
1488    SetCursor(cursor.par,
1489              cursor.pos + cursor.par->ParFromPos(cursor.pos)->text.size());
1490    
1491    /* the cursor must be exactly before the footnote */ 
1492    par = cursor.par->ParFromPos(cursor.pos);
1493    
1494    status = LyXText::NEED_MORE_REFRESH;
1495    refresh_row = cursor.row;
1496    refresh_y = cursor.y - cursor.row->baseline;
1497    
1498    tmppar = cursor.par;
1499    endpar = cursor.par->Next();
1500    row = cursor.row;
1501    
1502    tmppar->OpenFootnote(cursor.pos);
1503    RemoveParagraph(row);
1504    /* set the dimensions of the cursor row */
1505    row->fill = Fill(row, paperwidth);
1506    SetHeightOfRow(row);
1507    tmppar = tmppar->Next();
1508    
1509    while (tmppar != endpar) {
1510       if (tmppar) {
1511          InsertParagraph(tmppar, row);
1512          while (row->next && row->next->par == tmppar)
1513            row = row->next;
1514          tmppar = tmppar->Next();
1515       }
1516    }
1517    SetCursor(par->next, 0);
1518    sel_cursor = cursor;
1519 }
1520    
1521
1522 /* table stuff -- begin*/
1523
1524 void LyXText::TableFeatures(int feature, string const & val) const
1525 {
1526         if (!cursor.par->table)
1527                 return; /* this should never happen */
1528   
1529         int actCell = NumberOfCell(cursor.par, cursor.pos);
1530         SetUndo(Undo::FINISH, 
1531                 cursor.par->ParFromPos(cursor.pos)->previous, 
1532                 cursor.par->ParFromPos(cursor.pos)->next); 
1533         
1534         switch (feature){
1535         case LyXTable::SET_PWIDTH:
1536                 cursor.par->table->SetPWidth(actCell, val);
1537                 break;
1538         case LyXTable::SET_SPECIAL_COLUMN:
1539         case LyXTable::SET_SPECIAL_MULTI:
1540                 cursor.par->table->SetAlignSpecial(actCell, val, feature);
1541                 break;
1542         default:
1543                 break;
1544         }
1545         RedoParagraph();
1546 }
1547
1548
1549 void LyXText::TableFeatures(int feature) const
1550 {
1551         int setLines = 0;
1552         int setAlign = LYX_ALIGN_LEFT;
1553         int lineSet;
1554         bool what;
1555     
1556     if (!cursor.par->table)
1557         return; /* this should never happen */
1558   
1559     int actCell = NumberOfCell(cursor.par, cursor.pos);
1560     SetUndo(Undo::FINISH, 
1561             cursor.par->ParFromPos(cursor.pos)->previous, 
1562             cursor.par->ParFromPos(cursor.pos)->next); 
1563
1564     switch (feature){
1565       case LyXTable::ALIGN_LEFT:
1566           setAlign= LYX_ALIGN_LEFT;
1567           break;
1568       case LyXTable::ALIGN_RIGHT:
1569           setAlign= LYX_ALIGN_RIGHT;
1570           break;
1571       case LyXTable::ALIGN_CENTER:
1572           setAlign= LYX_ALIGN_CENTER;
1573           break;
1574       default:
1575           break;
1576     }
1577     switch (feature){
1578       case LyXTable::APPEND_ROW: {
1579               LyXParagraph::size_type pos = cursor.pos;
1580
1581               /* move to the next row */
1582           int cell_org = actCell;
1583           int cell = cell_org;
1584
1585           // if there is a ContRow following this row I have to add
1586           // the row after the ContRow's
1587           if ((pos < cursor.par->Last()) &&
1588               cursor.par->table->RowHasContRow(cell_org)) {
1589               while((pos < cursor.par->Last()) &&
1590                     !cursor.par->table->IsContRow(cell)) {
1591                   while (pos < cursor.par->Last() &&
1592                          !cursor.par->IsNewline(pos))
1593                       pos++;
1594                   if (pos < cursor.par->Last())
1595                       pos++;
1596                   cell++;
1597               }
1598               while((pos < cursor.par->Last()) &&
1599                     cursor.par->table->IsContRow(cell)) {
1600                   while (pos < cursor.par->Last() &&
1601                          !cursor.par->IsNewline(pos))
1602                       pos++;
1603                   if (pos < cursor.par->Last())
1604                       pos++;
1605                   cell++;
1606               }
1607               cell_org = --cell;
1608               if (pos < cursor.par->Last())
1609                   pos--;
1610           }
1611           while (pos < cursor.par->Last() && 
1612                  (cell == cell_org || !cursor.par->table->IsFirstCell(cell))){
1613               while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1614                   pos++;
1615               if (pos < cursor.par->Last())
1616                   pos++;
1617               cell++;
1618           }
1619                 
1620           /* insert the new cells */ 
1621           int number = cursor.par->table->NumberOfCellsInRow(cell_org);
1622           for (int i = 0; i < number; ++i)
1623               cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1624                 
1625           /* append the row into the table */
1626           cursor.par->table->AppendRow(cell_org);
1627           RedoParagraph();
1628           return;
1629       }
1630       case LyXTable::APPEND_CONT_ROW: {
1631               LyXParagraph::size_type pos = cursor.pos;
1632           /* move to the next row */
1633           int cell_org = actCell;
1634           int cell = cell_org;
1635
1636           // if there is already a controw but not for this cell
1637           // the AppendContRow sets only the right values but does
1638           // not actually add a row
1639           if (cursor.par->table->RowHasContRow(cell_org) &&
1640               (cursor.par->table->CellHasContRow(cell_org)<0)) {
1641               cursor.par->table->AppendContRow(cell_org);
1642               RedoParagraph();
1643               return;
1644           }
1645           while (pos < cursor.par->Last() && 
1646                  (cell == cell_org
1647                   || !cursor.par->table->IsFirstCell(cell))){
1648               while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1649                   pos++;
1650               if (pos < cursor.par->Last())
1651                   pos++;
1652               cell++;
1653           }
1654                 
1655           /* insert the new cells */ 
1656           int number = cursor.par->table->NumberOfCellsInRow(cell_org);
1657           int i;
1658           for (i= 0; i<number; i++)
1659               cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1660                 
1661           /* append the row into the table */
1662           cursor.par->table->AppendContRow(cell_org);
1663           RedoParagraph();
1664           return;
1665       }
1666       case LyXTable::APPEND_COLUMN: {
1667               LyXParagraph::size_type pos = 0;
1668           int cell_org = actCell;
1669           int cell = 0;
1670           do{
1671               if (pos && (cursor.par->IsNewline(pos-1))){
1672                   if (cursor.par->table->AppendCellAfterCell(cell_org, cell)){
1673                       cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1674                       if (pos <= cursor.pos)
1675                           cursor.pos++;
1676                       ++pos;
1677                   }
1678                   ++cell;
1679               }
1680               ++pos;
1681           } while (pos <= cursor.par->Last());
1682           /* remember that the very last cell doesn't end with a newline.
1683              This saves one byte memory per table ;-) */ 
1684           if (cursor.par->table->AppendCellAfterCell(cell_org, cell))
1685               cursor.par->InsertChar(cursor.par->Last(), LyXParagraph::META_NEWLINE);
1686                 
1687           /* append the column into the table */ 
1688           cursor.par->table->AppendColumn(cell_org);
1689                 
1690           RedoParagraph();
1691           return;
1692       }
1693       case LyXTable::DELETE_ROW:
1694           if (current_view->the_locking_inset)
1695               current_view->unlockInset(current_view->the_locking_inset);
1696           RemoveTableRow(&cursor);
1697           RedoParagraph();
1698           return;
1699         
1700       case LyXTable::DELETE_COLUMN: {
1701               LyXParagraph::size_type pos = 0;
1702           int cell_org = actCell;
1703           int cell = 0;
1704           if (current_view->the_locking_inset)
1705               current_view->unlockInset(current_view->the_locking_inset);
1706           do {
1707               if (!pos || (cursor.par->IsNewline(pos-1))){
1708                   if (cursor.par->table->DeleteCellIfColumnIsDeleted(cell, cell_org)){
1709                       // delete one cell
1710                       while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1711                           cursor.par->Erase(pos);
1712                       if (pos < cursor.par->Last())
1713                           cursor.par->Erase(pos);
1714                       else 
1715                           cursor.par->Erase(pos - 1); // the missing newline at the end of a table
1716                       --pos; // because of pos++ below
1717                   }   
1718                   ++cell;
1719               }
1720               ++pos;
1721           } while (pos <= cursor.par->Last());
1722                 
1723           /* delete the column from the table */ 
1724           cursor.par->table->DeleteColumn(cell_org);
1725                 
1726           /* set the cursor to the beginning of the table, where else? */ 
1727           cursor.pos = 0;
1728           RedoParagraph();
1729           return;
1730       }
1731       case LyXTable::TOGGLE_LINE_TOP:
1732           lineSet = !cursor.par->table->TopLine(actCell);
1733           if (!selection){
1734               cursor.par->table->SetTopLine(actCell, lineSet);
1735           } else {
1736                   LyXParagraph::size_type i;
1737                   int n = -1, m = -2;
1738               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
1739                   if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1740                       cursor.par->table->SetTopLine(n, lineSet);
1741                       m = n;
1742                   }
1743               }
1744           }
1745           RedoParagraph();
1746           return;
1747     
1748       case LyXTable::TOGGLE_LINE_BOTTOM:
1749           lineSet = !cursor.par->table->BottomLine(actCell);
1750           if (!selection){
1751               cursor.par->table->SetBottomLine(actCell, lineSet);
1752           } else {
1753                   LyXParagraph::size_type i;
1754                   int n = -1, m = -2;
1755               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
1756                   if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1757                       cursor.par->table->SetBottomLine(n, lineSet);
1758                       m = n;
1759                   }
1760               }
1761           }
1762           RedoParagraph();
1763           return;
1764                 
1765       case LyXTable::TOGGLE_LINE_LEFT:
1766           lineSet = !cursor.par->table->LeftLine(actCell);
1767           if (!selection){
1768               cursor.par->table->SetLeftLine(actCell, lineSet);
1769           } else {
1770                   LyXParagraph::size_type i;
1771                   int n = -1, m = -2;
1772               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
1773                   if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1774                       cursor.par->table->SetLeftLine(n, lineSet);
1775                       m = n;
1776                   }
1777               }
1778           }
1779           RedoParagraph();
1780           return;
1781
1782       case LyXTable::TOGGLE_LINE_RIGHT:
1783           lineSet = !cursor.par->table->RightLine(actCell);
1784           if (!selection){
1785               cursor.par->table->SetRightLine(actCell, lineSet);
1786           } else {
1787                   LyXParagraph::size_type i;
1788                   int n = -1, m = -2;
1789               for (i= sel_start_cursor.pos; i<= sel_end_cursor.pos; i++){
1790                   if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1791                       cursor.par->table->SetRightLine(n, lineSet);
1792                       m = n;
1793                   }
1794               }
1795           }
1796           RedoParagraph();
1797           return;
1798     
1799       case LyXTable::ALIGN_LEFT:
1800       case LyXTable::ALIGN_RIGHT:
1801       case LyXTable::ALIGN_CENTER:
1802           if (!selection){
1803               cursor.par->table->SetAlignment(actCell, setAlign);
1804           } else {
1805                   LyXParagraph::size_type i;
1806               int n = -1, m = -2;
1807               for (i= sel_start_cursor.pos; i<= sel_end_cursor.pos; i++){
1808                   if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1809                       cursor.par->table->SetAlignment(n, setAlign);
1810                       m = n;
1811                   }
1812               }
1813           }
1814           RedoParagraph();
1815           return;
1816                 
1817       case LyXTable::DELETE_TABLE:
1818           SetCursorIntern(cursor.par, 0);
1819           delete cursor.par->table;
1820           cursor.par->table = 0;
1821           // temporary: Should put table in simple_cut_buffer (with before and after
1822           // dummy-paragraph !! 
1823           // not necessar anymore with UNDO :)
1824           for (LyXParagraph::size_type i = 
1825                        cursor.par->text.size() - 1; i >= 0; --i)
1826               cursor.par->Erase(i);
1827           RedoParagraph();
1828           return;
1829                 
1830       case LyXTable::MULTICOLUMN: {
1831           int number = 0;
1832           // check wether we are completly in a multicol
1833           int multicol = cursor.par->table->IsMultiColumn(actCell);
1834           if (multicol && selection && sel_start_cursor.row == sel_end_cursor.row){
1835               multicol = NumberOfCell(sel_start_cursor.par, sel_start_cursor.pos)
1836                   == NumberOfCell(sel_end_cursor.par, sel_end_cursor.pos);
1837           }
1838
1839           if (multicol){
1840               int newlines = cursor.par->table->UnsetMultiColumn(actCell);
1841               LyXParagraph::size_type pos = cursor.pos;
1842               while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1843                   pos++;
1844               for (;newlines;newlines--)
1845                   cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1846               RedoParagraph();
1847               return;
1848           }
1849           else {
1850               // selection must be in one row (or no selection)
1851               if (!selection){
1852                   cursor.par->table->SetMultiColumn(NumberOfCell(cursor.par,
1853                                                                  cursor.pos),
1854                                                     1);
1855                   RedoParagraph();
1856                   return;
1857               }
1858               else {
1859                   if (sel_start_cursor.row == sel_end_cursor.row){
1860                       LyXParagraph::size_type i;
1861                       number = 1;
1862                       for (i = sel_start_cursor.pos;
1863                            i < sel_end_cursor.pos; ++i){
1864                           if (sel_start_cursor.par->IsNewline(i)){
1865                               sel_start_cursor.par->Erase(i);
1866                               // check for double-blanks
1867                               if ((i && !sel_start_cursor.par->IsLineSeparator(i-1))
1868                                   &&
1869                                   (i < sel_start_cursor.par->Last() 
1870                                    && !sel_start_cursor.par->IsLineSeparator(i)))
1871                                   sel_start_cursor.par->InsertChar(i, ' ');
1872                               else {
1873                                   sel_end_cursor.pos--;
1874                                   i--;
1875                               }
1876                               number++;
1877                           }
1878                       }
1879                       cursor.par->table->
1880                           SetMultiColumn(NumberOfCell(sel_start_cursor.par,
1881                                                       sel_start_cursor.pos),
1882                                          number);
1883                       cursor.pos = sel_start_cursor.pos;
1884                       RedoParagraph();
1885                       return;
1886                   }
1887                   else {
1888                       WriteAlert(_("Impossible Operation!"), 
1889                                  _("Multicolumns can only be horizontally."), 
1890                                  _("Sorry."));
1891                   }
1892               }
1893           }
1894           break;
1895       }
1896       case LyXTable::SET_ALL_LINES:
1897           setLines = 1;
1898       case LyXTable::UNSET_ALL_LINES:
1899           if (!selection){
1900               cursor.par->table->SetAllLines(NumberOfCell(cursor.par,
1901                                                           cursor.pos),
1902                                              setLines);
1903           } else {
1904                   LyXParagraph::size_type i;
1905                   int n = -1, m = -2;
1906               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
1907                   if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1908                       cursor.par->table->SetAllLines(n, setLines);
1909                       m = n;
1910                   }
1911               }
1912           }
1913           RedoParagraph();
1914           return;
1915       case LyXTable::SET_LONGTABLE:
1916           cursor.par->table->SetLongTable(true);
1917           return;
1918       case LyXTable::UNSET_LONGTABLE:
1919           cursor.par->table->SetLongTable(false);
1920           return;
1921       case LyXTable::SET_ROTATE_TABLE:
1922           cursor.par->table->SetRotateTable(true);
1923           return;
1924       case LyXTable::UNSET_ROTATE_TABLE:
1925           cursor.par->table->SetRotateTable(false);
1926           return;
1927       case LyXTable::SET_ROTATE_CELL:
1928           if (!selection){
1929               cursor.par->table->SetRotateCell(actCell, true);
1930           } else {
1931                   LyXParagraph::size_type i;
1932                   int n = -1, m = -2;
1933               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
1934                   if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1935                       cursor.par->table->SetRotateCell(n, true);
1936                       m = n;
1937                   }
1938               }
1939           }
1940           return;
1941       case LyXTable::UNSET_ROTATE_CELL:
1942           if (!selection){
1943               cursor.par->table->SetRotateCell(actCell, false);
1944           } else {
1945                   LyXParagraph::size_type i;
1946                   int n = -1, m = -2;
1947               for (i= sel_start_cursor.pos; i<= sel_end_cursor.pos; i++){
1948                   if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1949                       cursor.par->table->SetRotateCell(n, false);
1950                       m = n;
1951                   }
1952               }
1953           }
1954           return;
1955       case LyXTable::SET_LINEBREAKS:
1956           what = !cursor.par->table->Linebreaks(cursor.par->table->FirstVirtualCell(actCell));
1957           if (!selection){
1958               cursor.par->table->SetLinebreaks(actCell, what);
1959           } else {
1960                   LyXParagraph::size_type i;
1961                   int n = -1, m = -2;
1962               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
1963                   if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1964                       cursor.par->table->SetLinebreaks(n, what);
1965                       m = n;
1966                   }
1967               }
1968           }
1969           return;
1970       case LyXTable::SET_LTFIRSTHEAD:
1971           cursor.par->table->SetLTHead(actCell, true);
1972           return;
1973       case LyXTable::SET_LTHEAD:
1974           cursor.par->table->SetLTHead(actCell, false);
1975           return;
1976       case LyXTable::SET_LTFOOT:
1977           cursor.par->table->SetLTFoot(actCell, false);
1978           return;
1979       case LyXTable::SET_LTLASTFOOT:
1980           cursor.par->table->SetLTFoot(actCell, true);
1981           return;
1982       case LyXTable::SET_LTNEWPAGE:
1983           what = !cursor.par->table->LTNewPage(actCell);
1984           cursor.par->table->SetLTNewPage(actCell, what);
1985           return;
1986     }
1987 }
1988         
1989
1990 void LyXText::InsertCharInTable(char c)
1991 {
1992         Row * row;
1993         Row * tmprow;
1994         long y;
1995         bool jumped_over_space;
1996         
1997         /* first check, if there will be two blanks together or a blank at 
1998          * the beginning of a paragraph. 
1999          * I decided to handle blanks like normal characters, the main 
2000          * difference are the special checks when calculating the row.fill
2001          * (blank does not count at the end of a row) and the check here */ 
2002         
2003         LyXFont realtmpfont = real_current_font;
2004         LyXFont rawtmpfont = current_font; /* store the current font.
2005                                             * This is because of the use
2006                                             * of cursor movements. The moving
2007                                             * cursor would refresh the 
2008                                             * current font */
2009
2010         // Get the font that is used to calculate the baselineskip
2011         LyXParagraph::size_type const lastpos = 
2012                 cursor.par->Last();
2013         LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2014
2015         jumped_over_space = false;
2016         if (IsLineSeparatorChar(c)) {
2017                 
2018                 /* avoid double blanks but insert the new blank because
2019                  * of a possible font change */
2020                 if (cursor.pos < lastpos &&
2021                     cursor.par->IsLineSeparator(cursor.pos))
2022                 {
2023                         cursor.par->Erase(cursor.pos);
2024                         jumped_over_space = true;
2025                 }
2026                 else if ((cursor.pos > 0 && 
2027                           cursor.par->IsLineSeparator(cursor.pos - 1))
2028                          || (cursor.pos > 0 && cursor.par->IsNewline(cursor.pos - 1))
2029                           || (cursor.pos == 0 &&
2030                               !(cursor.par->Previous()
2031                               && cursor.par->Previous()->footnoteflag
2032                               == LyXParagraph::OPEN_FOOTNOTE)))
2033                         return;
2034         }
2035         else if (IsNewlineChar(c)) {
2036             if (!IsEmptyTableCell()) {
2037                 TableFeatures(LyXTable::APPEND_CONT_ROW);
2038                 CursorDown();
2039             }
2040           return;
2041         }
2042    
2043         row = cursor.row;
2044         y = cursor.y - row->baseline;
2045         if (c != LyXParagraph::META_INSET)      /* in this case LyXText::InsertInset 
2046                                          * already inserted the character */
2047                 cursor.par->InsertChar(cursor.pos, c);
2048         SetCharFont(cursor.par, cursor.pos, rawtmpfont);
2049
2050         if (!jumped_over_space) {
2051                 /* refresh the positions */
2052                 tmprow = row;
2053                 while (tmprow->next && tmprow->next->par == row->par) {
2054                         tmprow = tmprow->next;
2055                         tmprow->pos++;
2056                 }
2057         }
2058
2059         cursor.pos++;
2060
2061         CheckParagraphInTable(cursor.par, cursor.pos);
2062         
2063         current_font = rawtmpfont;
2064         real_current_font = realtmpfont;
2065         
2066         /* check, whether the last character's font has changed. */
2067         if (cursor.pos && cursor.pos == cursor.par->Last()
2068             && rawparfont != rawtmpfont)
2069                 RedoHeightOfParagraph(cursor);
2070 }
2071
2072
2073 void LyXText::CheckParagraphInTable(LyXParagraph * par,
2074                                     LyXParagraph::size_type pos)
2075 {
2076         
2077         if (par->GetChar(pos) == LyXParagraph::META_INSET &&
2078             par->GetInset(pos) && par->GetInset(pos)->display()){
2079           par->GetInset(pos)->display(false);
2080         }
2081
2082         long y;
2083         Row * row = GetRow(par, pos, y);
2084         
2085         int tmpheight = row->height;
2086         SetHeightOfRow(row);
2087
2088         LyXParagraph::size_type tmp_pos = pos;
2089         /* update the table information */
2090         while (tmp_pos && !par->IsNewline(tmp_pos - 1))
2091                 tmp_pos--;
2092         if (par->table->SetWidthOfCell(NumberOfCell(par, pos),
2093                                        WidthOfCell(par, tmp_pos))) {
2094                 LyXCursor tmpcursor = cursor;
2095                 SetCursorIntern(par, pos);
2096                 /* make a complete redraw */
2097                 RedoDrawingOfParagraph(cursor);
2098                 cursor = tmpcursor;
2099         }
2100         else {
2101                 /* redraw only the row */
2102                 LyXCursor tmpcursor = cursor;
2103                 SetCursorIntern(par, pos);
2104                 refresh_y = y;
2105                 refresh_x = cursor.x;
2106                 refresh_row = row;
2107                 refresh_pos = cursor.pos;
2108                 cursor = tmpcursor;
2109                 
2110                 if (tmpheight == row->height)
2111                         status = LyXText::NEED_VERY_LITTLE_REFRESH;
2112                 else
2113                         status = LyXText::NEED_MORE_REFRESH;
2114         }
2115         SetCursorIntern(cursor.par, cursor.pos);
2116 }
2117
2118
2119 void LyXText::BackspaceInTable()
2120 {
2121         Row * tmprow, * row;
2122         long y;
2123         
2124         LyXFont rawtmpfont = current_font;
2125         LyXFont realtmpfont = real_current_font;
2126
2127         // Get the font that is used to calculate the baselineskip
2128         int const lastpos = cursor.par->Last();
2129         LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2130         
2131         if (cursor.pos == 0) {
2132                 /* no pasting of table paragraphs */
2133                 
2134                 CursorLeft();
2135         }
2136         else {
2137                 /* this is the code for a normal backspace, not pasting
2138                  * any paragraphs */ 
2139           SetUndo(Undo::DELETE, 
2140                   cursor.par->ParFromPos(cursor.pos)->previous, 
2141                   cursor.par->ParFromPos(cursor.pos)->next); 
2142           
2143                 CursorLeftIntern();
2144                 
2145                 /* some insets are undeletable here */
2146                 if (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
2147                         if (!cursor.par->GetInset(cursor.pos)->Deletable())
2148                                 return;
2149                 }
2150                 
2151                 row = cursor.row;
2152                 y = cursor.y - row->baseline;
2153                 
2154                 /* some special code when deleting a newline. */
2155                 if (cursor.par->IsNewline(cursor.pos)) {
2156                         /* nothing :-) */
2157                         return;
2158                 }
2159                 else {
2160                         cursor.par->Erase(cursor.pos);
2161                         
2162                         /* refresh the positions */
2163                         tmprow = row;
2164                         while (tmprow->next && tmprow->next->par == row->par) {
2165                                 tmprow = tmprow->next;
2166                                 tmprow->pos--;
2167                         }
2168                         
2169                         /* delete superfluous blanks */ 
2170                         if (cursor.pos < cursor.par->Last() - 1 &&
2171                         (cursor.par->IsLineSeparator(cursor.pos))) {
2172                                 
2173                                 if (cursor.pos == BeginningOfMainBody(cursor.par)
2174                                 || !cursor.pos 
2175                                 || cursor.par->IsLineSeparator(cursor.pos - 1)) {
2176                                         cursor.par->Erase(cursor.pos);
2177                                         /* refresh the positions */
2178                                         tmprow = row;
2179                                         while (tmprow->next && 
2180                                                tmprow->next->par == row->par) {
2181                                                 tmprow = tmprow->next;
2182                                                 tmprow->pos--;
2183                                         }
2184                                         if (cursor.pos)   /* move one character left */
2185                                                 cursor.pos--;
2186                                 }
2187                         }
2188                 }
2189       
2190                 CheckParagraphInTable(cursor.par, cursor.pos);
2191       
2192                 /* check, wether the last characters font has changed. */ 
2193                 if (cursor.pos && cursor.pos == cursor.par->Last()
2194                     && rawparfont != rawtmpfont)
2195                         RedoHeightOfParagraph(cursor);
2196
2197                 /* restore the current font 
2198                  * That is what a user expects! */
2199                 current_font = rawtmpfont;
2200                 real_current_font = realtmpfont;
2201         }
2202         SetCursorIntern(cursor.par, cursor.pos);
2203 }
2204
2205 /* table stuff -- end*/
2206
2207
2208 /* just a macro to make some thing easier. */ 
2209 void LyXText::RedoParagraph() const
2210 {
2211 #if 1
2212         // I suspect this version will work
2213         // also.
2214         ClearSelection();
2215         RedoParagraphs(cursor, cursor.par->Next());
2216         SetCursorIntern(cursor.par, cursor.pos);
2217 #else
2218         LyXCursor tmpcursor = cursor;
2219         ClearSelection();
2220         RedoParagraphs(cursor, cursor.par->Next());
2221         SetCursorIntern(tmpcursor.par, tmpcursor.pos);
2222 #endif
2223 }
2224
2225
2226 /* insert a character, moves all the following breaks in the 
2227  * same Paragraph one to the right and make a rebreak */
2228 void  LyXText::InsertChar(char c)
2229 {
2230         SetUndo(Undo::INSERT, 
2231                 cursor.par->ParFromPos(cursor.pos)->previous, 
2232                 cursor.par->ParFromPos(cursor.pos)->next);
2233
2234         /* When the free-spacing option is set for the current layout,
2235          * all spaces are converted to protected spaces. */
2236         bool freeSpacingBo = 
2237                 textclasslist.Style(parameters->textclass,
2238                                cursor.row->par->GetLayout()).free_spacing;
2239    
2240         if (freeSpacingBo && IsLineSeparatorChar(c) 
2241             && (!cursor.pos || cursor.par->IsLineSeparator(cursor.pos - 1))) 
2242                 c = LyXParagraph::META_PROTECTED_SEPARATOR;
2243    
2244         /* table stuff -- begin*/
2245         if (cursor.par->table) {
2246                 InsertCharInTable(c);
2247                 charInserted();
2248                 return;
2249         }
2250         /* table stuff -- end*/
2251    
2252         /* First check, if there will be two blanks together or a blank at 
2253           the beginning of a paragraph. 
2254           I decided to handle blanks like normal characters, the main 
2255           difference are the special checks when calculating the row.fill
2256           (blank does not count at the end of a row) and the check here */ 
2257
2258         // The bug is triggered when we type in a description environment:
2259         // The current_font is not changed when we go from label to main text
2260         // and it should (along with realtmpfont) when we type the space.
2261 #ifdef WITH_WARNINGS
2262 #warning There is a bug here! (Asger)
2263 #endif
2264         
2265         LyXFont realtmpfont = real_current_font;
2266         LyXFont rawtmpfont = current_font;  /* store the current font.
2267                                      * This is because of the use
2268                                      * of cursor movements. The moving
2269                                      * cursor would refresh the 
2270                                      * current font */
2271
2272         // Get the font that is used to calculate the baselineskip
2273         LyXParagraph::size_type lastpos = cursor.par->Last();
2274         LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2275
2276         bool jumped_over_space = false;
2277    
2278         if (IsLineSeparatorChar(c)) {
2279 #ifndef FIX_DOUBLE_SPACE
2280                 if (cursor.pos < lastpos
2281                     && cursor.par->IsLineSeparator(cursor.pos)) {
2282                         /* the user inserted a space before a space. So we
2283                          * will just make a CursorRight. BUT: The font of this
2284                          * space should be set to current font. That is why
2285                          * we need to rebreak perhaps. If there is a protected
2286                          * blank at the end of a row we have to force
2287                          * a rebreak.*/ 
2288            
2289                         current_view->owner()->getMiniBuffer()
2290                                 ->Set(_("You cannot type two spaces this way. "
2291                                         " Please read the Tutorial."));
2292 #if 1
2293                         // How can this ever happen?
2294                         if (cursor.pos == RowLast(cursor.row)
2295                             && !IsLineSeparatorChar(c))
2296                                 cursor.row->fill = -1;  // force rebreak
2297                         cursor.par->Erase(cursor.pos);
2298                         jumped_over_space = true;
2299 #else
2300                         // Seems to me that this works just as well.
2301                         CursorRight();
2302                         charInserted();
2303                         return;
2304 #endif
2305                 } else
2306 #endif   
2307                 if ((cursor.pos > 0 
2308                      && cursor.par->IsLineSeparator(cursor.pos - 1))
2309                     || (cursor.pos > 0
2310                         && cursor.par->IsNewline(cursor.pos - 1))
2311                     || (cursor.pos == 0
2312                         && !(cursor.par->Previous()
2313                              && cursor.par->Previous()->footnoteflag
2314                              == LyXParagraph::OPEN_FOOTNOTE))) {
2315                         if (cursor.pos == 0 )
2316                                 current_view->owner()->getMiniBuffer()->Set(_("You cannot insert a space at the beginning of a paragraph.  Please read the Tutorial."));
2317                         else
2318                                 current_view->owner()->getMiniBuffer()->Set(_("You cannot type two spaces this way.  Please read the Tutorial."));
2319                         charInserted();
2320                         return;
2321                 }
2322         } else if (IsNewlineChar(c)) {
2323                 if (cursor.par->FirstPhysicalPar() == cursor.par
2324                     && cursor.pos <= BeginningOfMainBody(cursor.par)) {
2325                         charInserted();
2326                         return;
2327                 }
2328                 /* No newline at first position 
2329                  * of a paragraph or behind labels. 
2330                  * TeX does not allow that. */
2331                 
2332                 if (cursor.pos < cursor.par->Last() &&
2333                     cursor.par->IsLineSeparator(cursor.pos))
2334                         CursorRightIntern(); // newline always after a blank!
2335                 cursor.row->fill = -1;         // to force a new break
2336         }
2337    
2338         // the display inset stuff
2339         if (cursor.row->par->GetChar(cursor.row->pos) == LyXParagraph::META_INSET
2340             && cursor.row->par->GetInset(cursor.row->pos)
2341             && cursor.row->par->GetInset(cursor.row->pos)->display())
2342                 cursor.row->fill = -1; // to force a new break  
2343
2344         // get the cursor row fist
2345         Row * row = cursor.row;
2346         long y = cursor.y - row->baseline;
2347         if (c != LyXParagraph::META_INSET) /* Here case LyXText::InsertInset 
2348                                             * already insertet the character */
2349                 cursor.par->InsertChar(cursor.pos, c);
2350         SetCharFont(cursor.par, cursor.pos, rawtmpfont);
2351
2352         if (!jumped_over_space) {
2353                 // refresh the positions
2354                 Row * tmprow = row;
2355                 while (tmprow->next && tmprow->next->par == row->par) {
2356                         tmprow = tmprow->next;
2357                         tmprow->pos++;
2358                 }
2359         }
2360    
2361         // Is there a break one row above
2362         if ((cursor.par->IsLineSeparator(cursor.pos)
2363              || cursor.par->IsNewline(cursor.pos)
2364              || cursor.row->fill == -1)
2365             && row->previous && row->previous->par == row->par) {
2366                 LyXParagraph::size_type z = NextBreakPoint(row->previous,
2367                                                            paperwidth);
2368                 if ( z >= row->pos) {
2369                         row->pos = z + 1;
2370                         
2371                         // set the dimensions of the row above
2372                         row->previous->fill = Fill(row->previous, paperwidth);
2373
2374                         SetHeightOfRow(row->previous);
2375              
2376                         y -= row->previous->height;
2377                         refresh_y = y;
2378                         refresh_row = row->previous;
2379                         status = LyXText::NEED_MORE_REFRESH;
2380              
2381                         BreakAgainOneRow(row);
2382                         SetCursor(cursor.par, cursor.pos + 1);
2383                         /* cursor MUST be in row now */
2384              
2385                         if (row->next && row->next->par == row->par)
2386                                 need_break_row = row->next;
2387                         else
2388                                 need_break_row = 0;
2389
2390                         current_font = rawtmpfont;
2391                         real_current_font = realtmpfont;
2392              
2393                         // check, wether the last characters font has changed. 
2394                         if (cursor.pos && cursor.pos == cursor.par->Last()
2395                             && rawparfont != rawtmpfont)
2396                                 RedoHeightOfParagraph(cursor);
2397                         
2398                         charInserted();
2399                         return;
2400                 }
2401         }
2402    
2403         /* recalculate the fill of the row */ 
2404         if (row->fill >= 0)  /* needed because a newline
2405                               * will set fill to -1. Otherwise
2406                               * we would not get a rebreak! */
2407                 row->fill = Fill(row, paperwidth);
2408         if (row->fill < 0 ) {
2409                 refresh_y = y;
2410                 refresh_row = row; 
2411                 refresh_x = cursor.x;
2412                 refresh_pos = cursor.pos;
2413                 status = LyXText::NEED_MORE_REFRESH;
2414                 BreakAgainOneRow(row); 
2415                 /* will the cursor be in another row now? */ 
2416                 if (RowLast(row) <= cursor.pos + 1 && row->next) {
2417                         if (row->next && row->next->par == row->par)
2418                                 /* this should
2419                                  * always be true */
2420                                 row = row->next;
2421                         BreakAgainOneRow(row);
2422                 }
2423                 SetCursor(cursor.par, cursor.pos + 1);
2424                 if (row->next && row->next->par == row->par)
2425                         need_break_row = row->next;
2426                 else
2427                         need_break_row = 0;
2428                 
2429                 current_font = rawtmpfont;
2430                 real_current_font = realtmpfont;
2431         } else {
2432                 refresh_y = y;
2433                 refresh_x = cursor.x;
2434                 refresh_row = row;
2435                 refresh_pos = cursor.pos;
2436                 
2437                 int tmpheight = row->height;
2438                 SetHeightOfRow(row);
2439                 if (tmpheight == row->height)
2440                         status = LyXText::NEED_VERY_LITTLE_REFRESH;
2441                 else
2442                         status = LyXText::NEED_MORE_REFRESH;
2443             
2444                 SetCursor(cursor.par, cursor.pos + 1);
2445                 current_font = rawtmpfont;
2446                 real_current_font = realtmpfont;
2447         }
2448
2449         /* check, wether the last characters font has changed. */ 
2450         if (cursor.pos && cursor.pos == cursor.par->Last()
2451             && rawparfont != rawtmpfont) {
2452                 RedoHeightOfParagraph(cursor);
2453         } else {
2454                 /* now the special right address boxes */
2455                 if (textclasslist.Style(parameters->textclass,
2456                                    cursor.par->GetLayout()).margintype
2457                     == MARGIN_RIGHT_ADDRESS_BOX) {
2458                         RedoDrawingOfParagraph(cursor); 
2459                 }
2460         }
2461
2462         charInserted();
2463 }
2464    
2465
2466 void LyXText::charInserted()
2467 {
2468         // Here we could call FinishUndo for every 20 characters inserted.
2469         // This is from my experience how emacs does it.
2470         static unsigned int counter = 0;
2471         if (counter < 20) {
2472                 ++counter;
2473         } else {
2474                 FinishUndo();
2475                 counter = 0;
2476         }
2477 }
2478
2479
2480 void LyXText::PrepareToPrint(Row * row, float & x,
2481                              float & fill_separator, 
2482                              float & fill_hfill,
2483                              float & fill_label_hfill) const
2484 {
2485         float nh, nlh, ns;
2486         
2487         float w = row->fill;
2488         fill_hfill = 0;
2489         fill_label_hfill = 0;
2490         fill_separator = 0;
2491         fill_label_hfill = 0;
2492         
2493         x = LeftMargin(row);
2494         
2495         /* is there a manual margin with a manual label */ 
2496         if (textclasslist.Style(parameters->textclass,
2497                            row->par->GetLayout()).margintype == MARGIN_MANUAL
2498             && textclasslist.Style(parameters->textclass,
2499                               row->par->GetLayout()).labeltype == LABEL_MANUAL) {
2500                
2501                 nlh = NumberOfLabelHfills(row) + 1; /* one more since labels 
2502                                                     * are left aligned*/ 
2503                 if (nlh && !row->par->GetLabelWidthString().empty()) {
2504                         fill_label_hfill = LabelFill(row) / nlh;
2505                 }
2506         }
2507                 
2508         /* are there any hfills in the row? */ 
2509         nh = NumberOfHfills(row);
2510         
2511 /* table stuff -- begin*/
2512         if (row->par->table) {
2513            w = paperwidth - row->par->table->WidthOfTable()
2514            - x - RightMargin(row);
2515            nh = 0; /* ignore hfills in tables */ 
2516         }
2517 /* table stuff -- end*/
2518
2519         if (nh)
2520           fill_hfill = w /nh;
2521         else  {
2522            /* is it block, flushleft or flushright? 
2523             * set x how you need it */
2524            int align;
2525            if (row->par->FirstPhysicalPar()->align == LYX_ALIGN_LAYOUT)
2526              align = textclasslist.Style(parameters->textclass, row->par->GetLayout()).align;
2527            else
2528              align = row->par->FirstPhysicalPar()->align;
2529            
2530            /* center displayed insets */ 
2531            if (row->par->GetChar(row->pos) == LyXParagraph::META_INSET
2532                && row->par->GetInset(row->pos)
2533                && row->par->GetInset(row->pos)->display())
2534              align = LYX_ALIGN_CENTER;
2535
2536            switch (align) {
2537             case LYX_ALIGN_BLOCK:
2538               ns = NumberOfSeparators(row);
2539               if (ns && row->next && row->next->par == row->par &&
2540                   !(row->next->par->IsNewline(row->next->pos-1))
2541                   && !(row->next->par->GetChar(row->next->pos) == LyXParagraph::META_INSET
2542                        && row->next->par->GetInset(row->next->pos)
2543                        && row->next->par->GetInset(row->next->pos)->display())
2544                   )
2545                 fill_separator = w / ns;
2546               break;
2547             case LYX_ALIGN_RIGHT:
2548               x += w;
2549               break;
2550             case LYX_ALIGN_CENTER:
2551               x += w / 2;
2552               break;
2553            }
2554         }
2555      }
2556
2557       
2558 /* important for the screen */
2559
2560
2561 /* the cursor set functions have a special mechanism. When they
2562 * realize, that you left an empty paragraph, they will delete it.
2563 * They also delete the corresponding row */
2564
2565 void LyXText::CursorRightOneWord() const
2566 {
2567         // treat floats, HFills and Insets as words
2568         LyXCursor tmpcursor = cursor;
2569
2570         if (tmpcursor.pos == tmpcursor.par->Last()
2571             && tmpcursor.par->Next())
2572         {
2573                         tmpcursor.par = tmpcursor.par->Next();
2574                         tmpcursor.pos = 0;
2575         } else {
2576                 int steps = 0;
2577
2578                 // Skip through initial nonword stuff.
2579                 while ( tmpcursor.pos < tmpcursor.par->Last() &&
2580                         ! tmpcursor.par->IsWord( tmpcursor.pos ) ) 
2581                 {
2582                   //    printf("Current pos1 %d", tmpcursor.pos) ;
2583                         tmpcursor.pos++;
2584                         steps++;
2585                 }
2586                 // Advance through word.
2587                 while ( tmpcursor.pos < tmpcursor.par->Last() &&
2588                         tmpcursor.par->IsWord( tmpcursor.pos ) )
2589                 {
2590                   //     printf("Current pos2 %d", tmpcursor.pos) ;
2591                         tmpcursor.pos++;
2592                         steps++;
2593                 }
2594         }
2595         SetCursor(tmpcursor.par, tmpcursor.pos);
2596 }
2597
2598
2599 void LyXText::CursorTab() const
2600 {
2601     if (cursor.par->table) {
2602         int cell = NumberOfCell(cursor.par, cursor.pos);
2603         while(cursor.par->table->IsContRow(cell)) {
2604             CursorUp();
2605             cell = NumberOfCell(cursor.par, cursor.pos);
2606         }
2607         if (cursor.par->table->ShouldBeVeryLastCell(cell))
2608             TableFeatures(LyXTable::APPEND_ROW);
2609     }
2610     LyXCursor tmpcursor = cursor;
2611     while (tmpcursor.pos < tmpcursor.par->Last()
2612            && !tmpcursor.par->IsNewline(tmpcursor.pos))
2613         tmpcursor.pos++;
2614    
2615     if (tmpcursor.pos == tmpcursor.par->Last()){
2616         if (tmpcursor.par->Next()) {
2617             tmpcursor.par = tmpcursor.par->Next();
2618             tmpcursor.pos = 0;
2619         }
2620     }
2621     else
2622         tmpcursor.pos++;
2623     SetCursor(tmpcursor.par, tmpcursor.pos);
2624     if (cursor.par->table) {
2625         int cell = NumberOfCell(cursor.par, cursor.pos);
2626         while (cursor.par->table->IsContRow(cell) &&
2627                !cursor.par->table->ShouldBeVeryLastCell(cell)) {
2628             tmpcursor = cursor;
2629             while (tmpcursor.pos < tmpcursor.par->Last()
2630                    && !tmpcursor.par->IsNewline(tmpcursor.pos))
2631                 tmpcursor.pos++;
2632    
2633             if (tmpcursor.pos == tmpcursor.par->Last()){
2634                 if (tmpcursor.par->Next()) {
2635                     tmpcursor.par = tmpcursor.par->Next();
2636                     tmpcursor.pos = 0;
2637                 }
2638             }
2639             else
2640                 tmpcursor.pos++;
2641             SetCursor(tmpcursor.par, tmpcursor.pos);
2642             cell = NumberOfCell(cursor.par, cursor.pos);
2643         }
2644     }
2645 }
2646
2647
2648 /* -------> Skip initial whitespace at end of word and move cursor to *start*
2649             of prior word, not to end of next prior word. */
2650
2651 void LyXText::CursorLeftOneWord()  const
2652 {
2653         // treat HFills, floats and Insets as words
2654         LyXCursor tmpcursor = cursor;
2655         while (tmpcursor.pos 
2656                && (tmpcursor.par->IsSeparator(tmpcursor.pos - 1) 
2657                    || tmpcursor.par->IsKomma(tmpcursor.pos - 1))
2658                && !(tmpcursor.par->IsHfill(tmpcursor.pos - 1)
2659                     || tmpcursor.par->IsFloat(tmpcursor.pos - 1)
2660                     || tmpcursor.par->IsInset(tmpcursor.pos - 1)))
2661                 tmpcursor.pos--;
2662
2663         if (tmpcursor.pos
2664             && (tmpcursor.par->IsInset(tmpcursor.pos - 1)
2665                 || tmpcursor.par->IsFloat(tmpcursor.pos - 1)
2666                 || tmpcursor.par->IsHfill(tmpcursor.pos - 1))) {
2667                 tmpcursor.pos--;
2668         } else if (!tmpcursor.pos) {
2669                 if (tmpcursor.par->Previous()){
2670                         tmpcursor.par = tmpcursor.par->Previous();
2671                         tmpcursor.pos = tmpcursor.par->Last();
2672                 }
2673         } else {                // Here, tmpcursor != 0 
2674                 while (tmpcursor.pos > 0 &&
2675                        tmpcursor.par->IsWord(tmpcursor.pos-1) )
2676                         tmpcursor.pos-- ;
2677         }
2678         SetCursor(tmpcursor.par, tmpcursor.pos);
2679 }
2680
2681 /* -------> Select current word. This depends on behaviour of CursorLeftOneWord(), so it is
2682                         patched as well. */
2683
2684 void LyXText::SelectWord() 
2685 {
2686         /* Move cursor to the beginning, when not already there. */
2687         if ( cursor.pos
2688              && !cursor.par->IsSeparator(cursor.pos-1)
2689              && !cursor.par->IsKomma(cursor.pos-1) )
2690                 CursorLeftOneWord();
2691
2692         /* set the sel cursor */
2693         sel_cursor = cursor;
2694
2695         while ( cursor.pos < cursor.par->Last()
2696                         && !cursor.par->IsSeparator(cursor.pos)
2697                         && !cursor.par->IsKomma(cursor.pos) )
2698                 cursor.pos++;
2699         SetCursor( cursor.par, cursor.pos );
2700         
2701         /* finally set the selection */ 
2702         SetSelection();
2703 }
2704
2705
2706 /* -------> Select the word currently under the cursor when:
2707                         1: no selection is currently set,
2708                         2: the cursor is not at the borders of the word. */
2709
2710 int LyXText::SelectWordWhenUnderCursor() 
2711 {
2712         if ( selection ) return 0;
2713         if ( cursor.pos < cursor.par->Last()
2714                  && !cursor.par->IsSeparator(cursor.pos)
2715                  && !cursor.par->IsKomma(cursor.pos)
2716                  && cursor.pos 
2717                  && !cursor.par->IsSeparator(cursor.pos -1)
2718                  && !cursor.par->IsKomma(cursor.pos -1) ) {
2719                 SelectWord();
2720                 return 1;
2721         }
2722         return 0;
2723 }
2724
2725
2726 // This function is only used by the spellchecker for NextWord().
2727 // It doesn't handle LYX_ACCENTs and probably never will.
2728 char * LyXText::SelectNextWord(float & value)
2729 {
2730         LyXParagraph * tmppar = cursor.par;
2731         
2732         // If this is not the very first word, skip rest of
2733         // current word because we are probably in the middle
2734         // of a word if there is text here.
2735         if (cursor.pos || cursor.par->previous) {
2736                 while (cursor.pos < cursor.par->Last()
2737                        && cursor.par->IsLetter(cursor.pos))
2738                         cursor.pos++;
2739         }
2740         // Now, skip until we have real text (will jump paragraphs)
2741         while ((cursor.par->Last() > cursor.pos
2742                 && (!cursor.par->IsLetter(cursor.pos)
2743                     || cursor.par->getFont(cursor.pos).latex() == LyXFont::ON))
2744                || (cursor.par->Last() == cursor.pos
2745                    && cursor.par->Next())){
2746                 if (cursor.pos == cursor.par->Last()) {
2747                         cursor.par = cursor.par->Next();
2748                         cursor.pos = 0;
2749                 }
2750                 else
2751                         cursor.pos++;
2752         }
2753   
2754         // Update the value if we changed paragraphs
2755         if (cursor.par != tmppar){
2756                 SetCursor(cursor.par, cursor.pos);
2757                 value = float(cursor.y)/float(height);
2758         }
2759
2760         /* Start the selection from here */
2761         sel_cursor = cursor;
2762
2763         string latex;
2764    
2765         /* and find the end of the word 
2766            (optional hyphens are part of a word) */
2767         while (cursor.pos < cursor.par->Last()
2768                && (cursor.par->IsLetter(cursor.pos)) 
2769                    || (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET &&
2770                        cursor.par->GetInset(cursor.pos) != 0 &&
2771                        cursor.par->GetInset(cursor.pos)->Latex(latex, 0) == 0 &&
2772                        latex == "\\-"))
2773                 cursor.pos++;
2774
2775         // Finally, we copy the word to a string and return it
2776         char * str = 0;
2777
2778         if (sel_cursor.pos < cursor.pos) {
2779                 str = new char [cursor.pos - sel_cursor.pos + 2];
2780                 LyXParagraph::size_type i, j;
2781                 for (i = sel_cursor.pos, j = 0; i < cursor.pos; ++i) {
2782                         if (cursor.par->GetChar(i) != LyXParagraph::META_INSET)
2783                                 str[j++] = cursor.par->GetChar(i);
2784                 }
2785                 str[j] = '\0';
2786         }
2787         return str;
2788 }
2789
2790
2791 // This one is also only for the spellchecker
2792 void LyXText::SelectSelectedWord()
2793 {
2794         /* move cursor to the beginning */
2795         SetCursor(sel_cursor.par, sel_cursor.pos);
2796         
2797         /* set the sel cursor */
2798         sel_cursor = cursor;
2799
2800         string latex;
2801         
2802         /* now find the end of the word */
2803         while (cursor.pos < cursor.par->Last()
2804                && (cursor.par->IsLetter(cursor.pos)
2805                    || (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET &&
2806                        cursor.par->GetInset(cursor.pos) != 0 &&
2807                        cursor.par->GetInset(cursor.pos)->Latex(latex, 0) == 0 &&
2808                        latex == "\\-")))
2809                 cursor.pos++;
2810         
2811         SetCursor(cursor.par, cursor.pos);
2812         
2813         /* finally set the selection */ 
2814         SetSelection();
2815 }
2816
2817
2818 /* -------> Delete from cursor up to the end of the current or next word. */
2819 void LyXText::DeleteWordForward()
2820 {
2821         LyXCursor tmpcursor = cursor;
2822         
2823         if (!cursor.par->Last())
2824                 CursorRight();
2825         else {
2826                 /* -------> Skip initial non-word stuff. */
2827                 while ( cursor.pos < cursor.par->Last() 
2828                         && (cursor.par->IsSeparator(cursor.pos)
2829                             || cursor.par->IsKomma(cursor.pos)) )
2830                         cursor.pos++;
2831                 
2832                 SetCursorIntern(cursor.par, cursor.pos);
2833                 selection = True; // to avoid deletion 
2834                 CursorRightOneWord();
2835                 sel_cursor = cursor;
2836                 cursor = tmpcursor;
2837                 SetSelection(); 
2838                 
2839                 /* -----> Great, CutSelection() gets rid of multiple spaces. */
2840                 CutSelection();
2841         }
2842 }
2843
2844
2845 /* -------> Delete from cursor to start of current or prior word. */
2846 void LyXText::DeleteWordBackward()
2847 {
2848        LyXCursor tmpcursor = cursor;
2849        if (!cursor.par->Last())
2850          CursorLeft();
2851        else{
2852          selection = true; // to avoid deletion 
2853          CursorLeftOneWord();
2854          sel_cursor = cursor;
2855          cursor = tmpcursor;
2856          SetSelection();
2857          CutSelection();
2858        }
2859 }
2860
2861
2862 /* -------> Kill to end of line. */
2863 void LyXText::DeleteLineForward()
2864 {
2865         LyXCursor tmpcursor = cursor;
2866         if (!cursor.par->Last())
2867                 CursorRight();
2868         else {
2869                 CursorEnd();
2870                 sel_cursor = cursor;
2871                 cursor = tmpcursor;
2872                 SetSelection();
2873                 if (selection == false) {
2874                         DeleteWordForward();
2875                 } else {
2876                         CutSelection();
2877                 }
2878         }
2879 }
2880
2881
2882 // Change the case of a word at cursor position. The meaning of action
2883 // is:
2884 // 0  change to lowercase
2885 // 1  capitalize word
2886 // 2  change to uppercase
2887 // This function directly manipulates LyXParagraph::text because there
2888 // is no LyXParagraph::SetChar currently. I did what I could to ensure
2889 // that it is correct. I guess part of it should be moved to
2890 // LyXParagraph, but it will have to change for 1.1 anyway. At least
2891 // it does not access outside of the allocated array as the older
2892 // version did. (JMarc) 
2893 void LyXText::ChangeWordCase(LyXText::TextCase action) 
2894 {
2895         LyXParagraph * tmppar = cursor.par->ParFromPos(cursor.pos);
2896
2897         SetUndo(Undo::FINISH, tmppar->previous, tmppar->next); 
2898
2899         LyXParagraph::size_type tmppos = 
2900                 cursor.par->PositionInParFromPos(cursor.pos);
2901         while (tmppos < tmppar->size()) {
2902                 unsigned char c = tmppar->text[tmppos];
2903                 if (IsKommaChar(c) || IsLineSeparatorChar(c))
2904                         break;
2905                 if (c != LyXParagraph::META_INSET) {
2906                         switch (action) {
2907                         case text_lowercase:
2908                                 c = tolower(c);
2909                                 break;
2910                         case text_capitalization:
2911                                 c = toupper(c);
2912                                 action = text_lowercase;
2913                                 break;
2914                         case text_uppercase:
2915                                 c = toupper(c);
2916                                 break;
2917                         }
2918                 }
2919                 
2920                 tmppar->text[tmppos] = c;
2921                 ++tmppos;
2922         }
2923         CheckParagraph(tmppar, tmppos);
2924         CursorRightOneWord();
2925 }
2926
2927
2928 void LyXText::Delete()
2929 {
2930         // this is a very easy implementation
2931
2932         LyXCursor old_cursor = cursor;
2933         int old_cur_par_id = old_cursor.par->id();
2934         int old_cur_par_prev_id = old_cursor.par->previous->id();
2935         
2936         // just move to the right
2937         CursorRightIntern();
2938
2939         // This check is not very good...
2940         // The CursorRightIntern calls DeleteEmptyParagrapgMechanism
2941         // and that can very well delete the par or par->previous in
2942         // old_cursor. Will a solution where we compare paragraph id's
2943         //work better?
2944 #if 1
2945         if (cursor.par->previous->id() == old_cur_par_prev_id
2946             && cursor.par->id() != old_cur_par_id)
2947                 return; // delete-empty-paragraph-mechanism has done it
2948 #else
2949         if (cursor.par->previous == old_cursor.par->previous
2950             && cursor.par != old_cursor.par)
2951                 return; // delete-empty-paragraph-mechanism has done it
2952 #endif
2953         // if you had success make a backspace
2954         if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) {
2955                 LyXCursor tmpcursor = cursor;
2956                 cursor = old_cursor; // to make sure undo gets the right cursor position
2957                 SetUndo(Undo::DELETE, 
2958                         cursor.par->ParFromPos(cursor.pos)->previous, 
2959                         cursor.par->ParFromPos(cursor.pos)->next); 
2960                 cursor = tmpcursor;
2961                 Backspace();
2962         }
2963 }
2964
2965
2966 void  LyXText::Backspace()
2967 {
2968         LyXParagraph * tmppar;
2969         Row * tmprow, * row;
2970         long y;
2971         int tmpheight;
2972
2973         /* table stuff -- begin */
2974         if (cursor.par->table) {
2975                 BackspaceInTable();
2976                 return;
2977         }
2978         /* table stuff -- end */
2979         
2980         LyXFont rawtmpfont = current_font;
2981         LyXFont realtmpfont = real_current_font;
2982    
2983         // Get the font that is used to calculate the baselineskip
2984         int const lastpos = cursor.par->Last();
2985         LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2986
2987         if (cursor.pos == 0) {
2988                 // we may paste some paragraphs
2989       
2990                 // is it an empty paragraph?
2991       
2992                 if ((lastpos == 0
2993                      || (lastpos == 1 && cursor.par->IsSeparator(0)))
2994                     && !(cursor.par->Next() 
2995                          && cursor.par->footnoteflag == 
2996                          LyXParagraph::NO_FOOTNOTE
2997                          && cursor.par->Next()->footnoteflag == 
2998                          LyXParagraph::OPEN_FOOTNOTE)) {
2999                         
3000                         if (cursor.par->previous) {
3001                                 tmppar = cursor.par->previous->FirstPhysicalPar();
3002                                 if (cursor.par->GetLayout() == tmppar->GetLayout()
3003                                     && cursor.par->footnoteflag == tmppar->footnoteflag
3004                                     && cursor.par->GetAlign() == tmppar->GetAlign()) {
3005                                         
3006                                         tmppar->line_bottom = cursor.par->line_bottom;
3007                                         tmppar->added_space_bottom = cursor.par->added_space_bottom;
3008                                         tmppar->pagebreak_bottom = cursor.par->pagebreak_bottom;
3009                                 }
3010                                 
3011                                 CursorLeftIntern();
3012                      
3013                                 // the layout things can change the height of a row !
3014                                 tmpheight = cursor.row->height;
3015                                 SetHeightOfRow(cursor.row);
3016                                 if (cursor.row->height != tmpheight) {
3017                                         refresh_y = cursor.y - cursor.row->baseline;
3018                                         refresh_row = cursor.row;
3019                                         status = LyXText::NEED_MORE_REFRESH;
3020                                 }
3021                                 return;
3022                         }
3023                 }
3024                 if (cursor.par->ParFromPos(cursor.pos)->previous){
3025                         SetUndo(Undo::DELETE,
3026                                 cursor.par->ParFromPos(cursor.pos)->previous->previous,
3027                                 cursor.par->ParFromPos(cursor.pos)->next);
3028                 }
3029                 tmppar = cursor.par;
3030                 tmprow = cursor.row;
3031                 CursorLeftIntern();
3032                 /* Pasting is not allowed, if the paragraphs have different
3033                    layout. I think it is a real bug of all other
3034                    word processors to allow it. It confuses the user.
3035                    Even so with a footnote paragraph and a non-footnote
3036                    paragraph. I will not allow pasting in this case, 
3037                    because the user would be confused if the footnote behaves 
3038                    different wether it is open or closed.
3039                   
3040                    Correction: Pasting is always allowed with standard-layout
3041                 */
3042                 if (cursor.par != tmppar
3043                     && (cursor.par->GetLayout() == tmppar->GetLayout()
3044                         || !tmppar->GetLayout())
3045                     && cursor.par->footnoteflag == tmppar->footnoteflag
3046                     /* table stuff -- begin*/
3047                     && !cursor.par->table /* no pasting of tables */ 
3048                     /* table stuff -- end*/
3049                     && cursor.par->GetAlign() == tmppar->GetAlign()) {
3050                         
3051                         cursor.par->PasteParagraph();
3052                         
3053                         if (!(cursor.pos &&
3054                               cursor.par->IsSeparator(cursor.pos - 1)))
3055                                 cursor.par->InsertChar(cursor.pos, ' ');
3056                         else
3057                                 if (cursor.pos)
3058                                         cursor.pos--;
3059                         
3060                         status = LyXText::NEED_MORE_REFRESH;
3061                         refresh_row = cursor.row;
3062                         refresh_y = cursor.y - cursor.row->baseline;
3063                         
3064                         // remove the lost paragraph
3065                         RemoveParagraph(tmprow);
3066                         RemoveRow(tmprow);  
3067                         
3068                         AppendParagraph(cursor.row);
3069                         UpdateCounters(cursor.row);
3070                         
3071                         // the row may have changed, block, hfills etc.
3072                         SetCursor(cursor.par, cursor.pos);
3073                 }
3074         } else {
3075                 /* this is the code for a normal backspace, not pasting
3076                  * any paragraphs */ 
3077                 SetUndo(Undo::DELETE, 
3078                         cursor.par->ParFromPos(cursor.pos)->previous, 
3079                         cursor.par->ParFromPos(cursor.pos)->next); 
3080                 CursorLeftIntern();
3081                 
3082                 // some insets are undeletable here
3083                 if (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
3084                         if (!cursor.par->GetInset(cursor.pos)->Deletable())
3085                                 return; 
3086                         // force complete redo when erasing display insets
3087                         // this is a cruel mathod but save..... Matthias 
3088                         if (cursor.par->GetInset(cursor.pos)->display()){
3089                                 cursor.par->Erase(cursor.pos);
3090                                 RedoParagraph();
3091                                 return;
3092                         }
3093                 }
3094                 
3095                 row = cursor.row;
3096                 y = cursor.y - row->baseline;
3097                 LyXParagraph::size_type z;
3098                 /* remember that a space at the end of a row doesnt count
3099                  * when calculating the fill */ 
3100                 if (cursor.pos < RowLast(row) ||
3101                     !cursor.par->IsLineSeparator(cursor.pos)) {
3102                         row->fill += SingleWidth(cursor.par, cursor.pos);
3103                 }
3104                 
3105                 /* some special code when deleting a newline. This is similar
3106                  * to the behavior when pasting paragraphs */ 
3107                 if (cursor.pos && cursor.par->IsNewline(cursor.pos)) {
3108                         cursor.par->Erase(cursor.pos);
3109                         // refresh the positions
3110                         tmprow = row;
3111                         while (tmprow->next && tmprow->next->par == row->par) {
3112                                 tmprow = tmprow->next;
3113                                 tmprow->pos--;
3114                         }
3115                         if (cursor.par->IsLineSeparator(cursor.pos - 1))
3116                                 cursor.pos--;
3117                         
3118                         if (cursor.pos < cursor.par->Last() && !cursor.par->IsSeparator(cursor.pos)) {
3119                                 cursor.par->InsertChar(cursor.pos, ' ');
3120                                 // refresh the positions
3121                                 tmprow = row;
3122                                 while (tmprow->next && tmprow->next->par == row->par) {
3123                                         tmprow = tmprow->next;
3124                                         tmprow->pos++;
3125                                 }
3126                         }
3127                 } else {
3128                         cursor.par->Erase(cursor.pos);
3129                         
3130                         // refresh the positions
3131                         tmprow = row;
3132                         while (tmprow->next && tmprow->next->par == row->par) {
3133                                 tmprow = tmprow->next;
3134                                 tmprow->pos--;
3135                         }
3136
3137 #ifndef FIX_DOUBLE_SPACE
3138                         // delete superfluous blanks 
3139                         if (cursor.pos < cursor.par->Last() - 1 &&
3140                             (cursor.par->IsLineSeparator(cursor.pos))) {
3141                                 
3142                                 if (cursor.pos == BeginningOfMainBody(cursor.par)
3143                                     || !cursor.pos 
3144                                     || cursor.par->IsLineSeparator(cursor.pos - 1)) {
3145                                         cursor.par->Erase(cursor.pos);
3146                                         // refresh the positions
3147                                         tmprow = row;
3148                                         while (tmprow->next && 
3149                                                tmprow->next->par == row->par) {
3150                                                 tmprow = tmprow->next;
3151                                                 tmprow->pos--;
3152                                         }
3153                                         if (cursor.pos)   // move one character left
3154                                                 cursor.pos--;
3155                                 }
3156                         }
3157 #endif
3158                         
3159                         // delete newlines at the beginning of paragraphs
3160                         while (cursor.par->Last() &&
3161                                cursor.par->IsNewline(cursor.pos) &&
3162                                cursor.pos == BeginningOfMainBody(cursor.par)) {
3163                                 cursor.par->Erase(cursor.pos);
3164                                 // refresh the positions
3165                                 tmprow = row;
3166                                 while (tmprow->next && 
3167                                        tmprow->next->par == row->par) {
3168                                         tmprow = tmprow->next;
3169                                         tmprow->pos--;
3170                                 }
3171                         }
3172                 }
3173                 
3174                 // is there a break one row above
3175                 if (row->previous && row->previous->par == row->par) {
3176                         z = NextBreakPoint(row->previous, paperwidth);
3177                         if ( z >= row->pos) {
3178                                 row->pos = z + 1;
3179                                 
3180                                 tmprow = row->previous;
3181                                 
3182                                 // maybe the current row is now empty
3183                                 if (row->pos >= row->par->Last()) {
3184                                         // remove it
3185                                         RemoveRow(row);
3186                                         need_break_row = 0;
3187                                 } else {
3188                                         BreakAgainOneRow(row);
3189                                         if (row->next && row->next->par == row->par)
3190                                                 need_break_row = row->next;
3191                                         else
3192                                                 need_break_row = 0;
3193                                 }
3194                                 
3195                                 // set the dimensions of the row above
3196                                 y -= tmprow->height;
3197                                 tmprow->fill = Fill(tmprow, paperwidth);
3198                                 SetHeightOfRow(tmprow);
3199                                 
3200                                 refresh_y = y;
3201                                 refresh_row = tmprow;
3202                                 status = LyXText::NEED_MORE_REFRESH;
3203                                 SetCursor(cursor.par, cursor.pos);
3204                                 current_font = rawtmpfont;
3205                                 real_current_font = realtmpfont;
3206                                 // check, whether the last character's font has changed.
3207                                 rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
3208                                 if (rawparfont != rawtmpfont)
3209                                         RedoHeightOfParagraph(cursor);
3210                                 return;
3211                         }
3212                 }
3213                 
3214                 // break the cursor row again
3215                 z = NextBreakPoint(row, paperwidth);
3216                 
3217                 if (z != RowLast(row) || 
3218                     (row->next && row->next->par == row->par &&
3219                      RowLast(row) == row->par->Last() - 1)){
3220                         
3221                         /* it can happen that a paragraph loses one row
3222                          * without a real breakup. This is when a word
3223                          * is to long to be broken. Well, I don t care this 
3224                          * hack ;-) */ 
3225                         if (row->next && row->next->par == row->par &&
3226                             RowLast(row) == row->par->Last() - 1)
3227                                 RemoveRow(row->next);
3228                         
3229                         refresh_y = y;
3230                         refresh_row = row;
3231                         status = LyXText::NEED_MORE_REFRESH;
3232                         
3233                         BreakAgainOneRow(row);
3234                         
3235                         SetCursor(cursor.par, cursor.pos);
3236                         // cursor MUST be in row now
3237                         
3238                         if (row->next && row->next->par == row->par)
3239                                 need_break_row = row->next;
3240                         else
3241                                 need_break_row = 0;
3242                 } else  {
3243                         // set the dimensions of the row
3244                         row->fill = Fill(row, paperwidth);
3245                         int tmpheight = row->height;
3246                         SetHeightOfRow(row);
3247                         if (tmpheight == row->height)
3248                                 status = LyXText::NEED_VERY_LITTLE_REFRESH;
3249                         else
3250                                 status = LyXText::NEED_MORE_REFRESH;
3251                         refresh_y = y;
3252                         refresh_row = row;
3253                         SetCursor(cursor.par, cursor.pos);
3254                 }
3255         }
3256    
3257         // restore the current font
3258         // That is what a user expects!
3259         current_font = rawtmpfont; 
3260         real_current_font = realtmpfont;
3261         
3262         // check, wether the last characters font has changed.
3263         rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
3264         if (rawparfont != rawtmpfont) {
3265                 RedoHeightOfParagraph(cursor);
3266         } else {
3267                 // now the special right address boxes
3268                 if (textclasslist.Style(parameters->textclass,
3269                                         cursor.par->GetLayout()).margintype == MARGIN_RIGHT_ADDRESS_BOX) {
3270                         RedoDrawingOfParagraph(cursor); 
3271                 }
3272         }
3273 }
3274
3275
3276 void LyXText::GetVisibleRow(LyXScreen & scr, int offset, 
3277                             Row * row_ptr, long y)
3278 {
3279         /* returns a printed row */
3280         LyXParagraph::size_type pos, pos_end;
3281         float x, tmpx;
3282         int y_top, y_bottom;
3283         float fill_separator, fill_hfill, fill_label_hfill;
3284         LyXParagraph * par, * firstpar;
3285         int left_margin;
3286         LyXFont font;
3287         int maxdesc;
3288         if (row_ptr->height <= 0) {
3289                 lyxerr << "LYX_ERROR: row.height: " << row_ptr->height << endl;
3290                 return;
3291         }
3292         left_margin = LabelEnd(row_ptr);
3293         PrepareToPrint(row_ptr, x, fill_separator,
3294                        fill_hfill, fill_label_hfill);
3295
3296         LyXParagraph::size_type main_body = 
3297                 BeginningOfMainBody(row_ptr->par);
3298         /* initialize the pixmap */
3299         
3300         scr.fillRectangle(gc_clear,
3301                           0, offset, paperwidth, row_ptr->height);
3302         // check for NOT FAST SELECTION
3303         if (!fast_selection && !mono_video && selection) {
3304                 /* selection code */ 
3305                 if (sel_start_cursor.row == row_ptr &&
3306                     sel_end_cursor.row == row_ptr) {
3307                         scr.fillRectangle(gc_selection, sel_start_cursor.x,
3308                                           offset,
3309                                           sel_end_cursor.x -
3310                                           sel_start_cursor.x,
3311                                           row_ptr->height);
3312                 }
3313                 else if (sel_start_cursor.row == row_ptr) {
3314                         scr.fillRectangle(gc_selection, sel_start_cursor.x,
3315                                           offset,
3316                                           paperwidth - sel_start_cursor.x,
3317                                           row_ptr->height);
3318                 } else if (sel_end_cursor.row == row_ptr) {
3319                         scr.fillRectangle(gc_selection, 0, offset,
3320                                           sel_end_cursor.x, row_ptr->height);
3321                 } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
3322                         scr.fillRectangle(gc_selection, 0, offset,
3323                                           paperwidth, row_ptr->height);
3324                         
3325                 }
3326         } // end of NOT FAST SELECTION code
3327         
3328         if (row_ptr->par->appendix){
3329           scr.drawVerticalLine(gc_math, 1, offset, offset+row_ptr->height);
3330           scr.drawVerticalLine(gc_math, paperwidth-2 , offset, offset+row_ptr->height);
3331         }
3332
3333         if (row_ptr->par->pextra_type == LyXParagraph::PEXTRA_MINIPAGE) {
3334                 /* draw a marker at the left margin! */ 
3335                 LyXFont font = GetFont(row_ptr->par, 0);
3336                 int asc = font.maxAscent();
3337                 int x = (LYX_PAPER_MARGIN - font.width('|')) / 2;
3338                 int y1 = (offset + row_ptr->baseline);
3339                 int y2 = (offset + row_ptr->baseline) - asc;
3340
3341                 scr.drawVerticalLine(gc_minipage, x, y1, y2);
3342         }       
3343         if (row_ptr->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3344                 LyXFont font(LyXFont::ALL_SANE);
3345                 font.setSize(LyXFont::SIZE_FOOTNOTE);
3346                 font.setColor(LyXFont::RED);
3347                 
3348                 int box_x = LYX_PAPER_MARGIN;
3349                 box_x += font.textWidth(" wide-tab ", 10);
3350                 if (row_ptr->previous && 
3351                     row_ptr->previous->par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
3352                         string fs;
3353                         switch (row_ptr->par->footnotekind) {
3354                         case LyXParagraph::MARGIN:
3355                                 fs = " margin";
3356                                 break;
3357                         case LyXParagraph::FIG:
3358                                 fs = " fig";
3359                                 break;
3360                         case LyXParagraph::TAB:
3361                                 fs = " tab";
3362                                 break;
3363                         case LyXParagraph::WIDE_FIG:
3364                                 fs = " wide-fig";
3365                                 break;
3366                         case LyXParagraph::WIDE_TAB:
3367                                 fs = " wide-tab";
3368                                 break;
3369                         case LyXParagraph::ALGORITHM:
3370                                 fs = " alg";
3371                                 break;
3372                         case LyXParagraph::FOOTNOTE:
3373                                 fs = " foot";
3374                                 break;
3375                         }
3376                         
3377                         // Determine background color.
3378                         gc_type back = gc_lighted;
3379                         if (mono_video) {
3380                                 back = gc_clear;
3381                         }
3382                         scr.fillRectangle(back, LYX_PAPER_MARGIN, offset+1,
3383                                           box_x - LYX_PAPER_MARGIN, 
3384                                           int(font.maxAscent())+
3385                                           int(font.maxDescent()));
3386                         
3387                         scr.drawLine(gc_foot,
3388                                      offset,
3389                                      LYX_PAPER_MARGIN,
3390                                      paperwidth - 2*LYX_PAPER_MARGIN);
3391                         
3392                         scr.drawString(font, fs,
3393                                        offset + int(font.maxAscent())+1,
3394                                        LYX_PAPER_MARGIN);
3395                         scr.drawVerticalLine(gc_foot,
3396                                              LYX_PAPER_MARGIN,
3397                                              offset,
3398                                              offset
3399                                              + int(font.maxAscent())+
3400                                              int(font.maxDescent()));
3401                         
3402                         scr.drawLine(gc_foot,
3403                                      offset
3404                                      + int(font.maxAscent())
3405                                      + int(font.maxDescent()) + 1,
3406                                      LYX_PAPER_MARGIN, box_x - LYX_PAPER_MARGIN); 
3407                 }
3408                 
3409                 /* draw the open floats in a red box */
3410                 scr.drawVerticalLine(gc_foot,
3411                                      box_x,
3412                                      offset,  offset + row_ptr->height);
3413                 
3414                 scr.drawVerticalLine(gc_foot,
3415                                      paperwidth - LYX_PAPER_MARGIN,
3416                                      offset,
3417                                      offset + row_ptr->height);
3418                         
3419                 
3420         } else  {
3421                 if (row_ptr->previous &&
3422                     row_ptr->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3423                         LyXFont font(LyXFont::ALL_SANE);
3424                         font.setSize(LyXFont::SIZE_FOOTNOTE);
3425                         
3426                         int box_x = LYX_PAPER_MARGIN;
3427                         box_x += font.textWidth(" wide-tab ", 10);
3428                         
3429                         scr.drawLine(gc_foot,
3430                                      offset,
3431                                      box_x,
3432                                      paperwidth - LYX_PAPER_MARGIN - box_x);
3433                 }
3434         }
3435         
3436         LyXLayout const & layout = textclasslist.Style(parameters->textclass,
3437                                            row_ptr->par->GetLayout());
3438         firstpar = row_ptr->par->FirstPhysicalPar();
3439         
3440         y_top = 0;
3441         y_bottom = row_ptr->height;
3442         
3443         /* is it a first row? */ 
3444         if (row_ptr->pos == 0
3445             && row_ptr->par == firstpar) {
3446                 
3447                  /* start of appendix? */
3448                 if (row_ptr->par->start_of_appendix){
3449                   scr.drawLine(gc_math, 
3450                                offset,
3451                                1, paperwidth-2);
3452                 }
3453
3454                 /* think about the margins */ 
3455                 if (!row_ptr->previous)
3456                         y_top += LYX_PAPER_MARGIN;
3457                 
3458                 if (row_ptr->par->pagebreak_top){ /* draw a top pagebreak  */
3459                         scr.drawOnOffLine(offset + y_top + 2 * DefaultHeight(),
3460                                           0, paperwidth);
3461                         y_top += 3 * DefaultHeight();
3462                 }
3463                 
3464                 if (row_ptr->par->added_space_top.kind() == VSpace::VFILL) {
3465                         /* draw a vfill top  */
3466                         scr.drawLine(gc_fill, 
3467                                      offset + 2 + y_top,
3468                                      0, LYX_PAPER_MARGIN);
3469                         scr.drawLine(gc_fill,
3470                                      offset + y_top + 3 * DefaultHeight(),
3471                                      0, LYX_PAPER_MARGIN);
3472                         scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2, 
3473                                                   offset + 2 + y_top,
3474                                                   offset + y_top + 3 *
3475                                                   DefaultHeight());
3476                         
3477                         y_top += 3 * DefaultHeight();
3478                 }
3479                 
3480                 /* think about user added space */ 
3481                 y_top += int(row_ptr->par->added_space_top.inPixels());
3482                 
3483                 /* think about the parskip */ 
3484                 /* some parskips VERY EASY IMPLEMENTATION */ 
3485                 if (parameters->paragraph_separation == BufferParams::PARSEP_SKIP) {
3486                         if (layout.latextype == LATEX_PARAGRAPH
3487                             && firstpar->GetDepth() == 0
3488                             && firstpar->Previous())
3489                                 y_top += parameters->getDefSkip().inPixels();
3490                         else if (firstpar->Previous()
3491                                  && textclasslist.Style(parameters->textclass,
3492                                                    firstpar->Previous()->GetLayout()).latextype == LATEX_PARAGRAPH
3493                                  && firstpar->Previous()->GetDepth() == 0)
3494                                 // is it right to use defskip here, too? (AS) 
3495                                 y_top += parameters->getDefSkip().inPixels();
3496                 }
3497                 
3498                 if (row_ptr->par->line_top) {      /* draw a top line  */
3499                         y_top +=  GetFont(row_ptr->par, 0).ascent('x');
3500
3501                         scr.drawThickLine(offset + y_top,
3502                                           0, paperwidth);
3503                         y_top +=  GetFont(row_ptr->par, 0).ascent('x');
3504                 }
3505                 
3506                 /* should we print a label? */ 
3507                 if (layout.labeltype >= LABEL_STATIC
3508                     && (layout.labeltype != LABEL_STATIC
3509                         || layout.latextype != LATEX_ENVIRONMENT
3510                         || row_ptr->par->IsFirstInSequence())) {
3511                         font = GetFont(row_ptr->par, -2);
3512                         if (!row_ptr->par->GetLabestring().empty()) {
3513                                 tmpx = x;
3514                                 string tmpstring = row_ptr->par->GetLabestring();
3515                                 
3516                                 if (layout.labeltype == LABEL_COUNTER_CHAPTER) {
3517                                         if (parameters->secnumdepth >= 0){
3518                                                 /* this is special code for the chapter layout. This is printed in
3519                                                  * an extra row and has a pagebreak at the top. */
3520                                                 maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue())
3521                                                         + int(layout.parsep) * DefaultHeight();
3522                                                 scr.drawString(font, tmpstring,
3523                                                                offset + row_ptr->baseline
3524                                                                - row_ptr->ascent_of_text - maxdesc,
3525                                                                int(x));
3526                                         }
3527                                 } else {
3528                                         x -= font.stringWidth( layout.labelsep);
3529                                         x -= font.stringWidth( tmpstring);
3530                                         /* draw it! */
3531                                         scr.drawString(font, tmpstring,
3532                                                        offset + row_ptr->baseline, int(x));
3533                                 }
3534                                 x = tmpx;
3535                         }
3536                         /* the labels at the top of an environment. More or less for bibliography */ 
3537                 } else if (layout.labeltype == LABEL_TOP_ENVIRONMENT ||
3538                            layout.labeltype == LABEL_BIBLIO ||
3539                            layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) {
3540                         if (row_ptr->par->IsFirstInSequence()) {
3541                                 font = GetFont(row_ptr->par, -2);
3542                                 if (!row_ptr->par->GetLabestring().empty()) {
3543                                         string tmpstring = row_ptr->par->GetLabestring();
3544                                         
3545                                         maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue()
3546                                                          + (layout.labelbottomsep * DefaultHeight()));
3547                                         
3548                                         int top_label_x = int(x);
3549                                         if (layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT){
3550                                                 top_label_x = int(x + (paperwidth - RightMargin(row_ptr) - x) / 2); 
3551                                                 top_label_x -= (font.stringWidth( tmpstring)/2);
3552                                         }
3553                                         
3554                                         scr.drawString(font, tmpstring,
3555                                                        offset + row_ptr->baseline
3556                                                        - row_ptr->ascent_of_text - maxdesc,  
3557                                                        top_label_x);                
3558                                 }
3559                         }
3560                 }
3561                 if (layout.labeltype == LABEL_BIBLIO) { // ale970302
3562                         if (row_ptr->par->bibkey) {
3563                                 tmpx = x;
3564                                 x -= font.stringWidth(layout.labelsep);
3565                                 font = GetFont(row_ptr->par, -1);
3566                                 x -= row_ptr->par->bibkey->Width(font);
3567                                 row_ptr->par->bibkey->Draw(font, scr,
3568                                                            offset + row_ptr->baseline, 
3569                                                            x);
3570                                 x = tmpx;
3571                         }
3572                 } 
3573         }
3574         
3575         /* is it a last row? */
3576         par = row_ptr->par->LastPhysicalPar();
3577         if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
3578             && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {     
3579                 
3580                 /* think about the margins */ 
3581                 if (!row_ptr->next)
3582                         y_bottom -= LYX_PAPER_MARGIN;
3583                 
3584                 /* draw a bottom pagebreak */ 
3585                 if (firstpar->pagebreak_bottom) {
3586                         scr.drawOnOffLine(offset + y_bottom - 2 *
3587                                           DefaultHeight(),
3588                                           0, paperwidth);
3589                         y_bottom -= 3 * DefaultHeight();
3590                 }
3591                 
3592                 if (firstpar->added_space_bottom.kind() == VSpace::VFILL) {
3593                         /* draw a vfill bottom  */
3594                         scr.drawLine(gc_fill,
3595                                      offset + y_bottom - 3 * DefaultHeight(),
3596                                      0, LYX_PAPER_MARGIN);
3597                         scr.drawLine(gc_fill, offset + y_bottom - 2,
3598                                      0, LYX_PAPER_MARGIN);
3599                         scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2, 
3600                                                   offset + y_bottom - 3 * DefaultHeight(),
3601                                                   offset + y_bottom - 2
3602                                 );          
3603                         y_bottom -= 3* DefaultHeight();
3604                 }
3605                 
3606                 /* think about user added space */ 
3607                 y_bottom -= int(firstpar->added_space_bottom.inPixels());
3608                 
3609                 if (firstpar->line_bottom) {
3610                         /* draw a bottom line */
3611                         y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
3612
3613                         scr.drawThickLine(offset + y_bottom,
3614                                           0, paperwidth);           
3615                         y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
3616                 }
3617         }
3618         
3619         /* draw the text in the pixmap */  
3620         pos_end = RowLast(row_ptr);
3621         
3622         pos = row_ptr->pos;
3623         /* table stuff -- begin*/
3624         if (row_ptr->par->table) {
3625                 bool on_off;
3626                 int cell = NumberOfCell(row_ptr->par, row_ptr->pos);
3627                 float x_old = x;
3628                 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
3629                 
3630                 while (pos <= pos_end)  {
3631                         if (row_ptr->par->IsNewline(pos)) {
3632                                 
3633                                 x = x_old + row_ptr->par->table->WidthOfColumn(cell);
3634                                 /* draw the table lines, still very simple */
3635                                 on_off = !row_ptr->par->table->TopLine(cell);
3636                                 if ((!on_off ||
3637                                      !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
3638                                     !row_ptr->par->table->IsContRow(cell))
3639                                         scr.drawTableLine(offset + row_ptr->baseline -
3640                                                           row_ptr->ascent_of_text,
3641                                                           int(x_old), int(x - x_old), on_off);
3642                                 on_off = !row_ptr->par->table->BottomLine(cell);
3643                                 if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
3644                                     row_ptr->par->table->VeryLastRow(cell))
3645                                         scr.drawTableLine(offset + y_bottom - 1,
3646                                                           int(x_old), int(x - x_old), on_off);
3647                                 on_off = !row_ptr->par->table->LeftLine(cell);
3648                                 
3649                                 scr.drawVerticalTableLine(int(x_old), 
3650                                                           offset + row_ptr->baseline -
3651                                                           row_ptr->ascent_of_text,
3652                                                           offset + y_bottom - 1,
3653                                                           on_off);
3654                                 on_off = !row_ptr->par->table->RightLine(cell);
3655                                 
3656                                 scr.drawVerticalTableLine(int(x) -
3657                                                           row_ptr->par->table->AdditionalWidth(cell),
3658                                                           offset + row_ptr->baseline -
3659                                                           row_ptr->ascent_of_text,
3660                                                           offset + y_bottom - 1,
3661                                                           on_off);
3662                                 x_old = x;
3663                 /* take care about the alignment and other spaces */
3664                                 cell++;
3665                                 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
3666                                 if (row_ptr->par->table->IsFirstCell(cell))
3667                                         cell--; // little hack, sorry
3668                                 pos++;
3669                         } else if (row_ptr->par->IsHfill(pos)) {
3670                                 x += 1;
3671                                 
3672                                 scr.drawVerticalLine(gc_fill, int(x),  
3673                                                      offset + row_ptr->baseline - DefaultHeight()/2, 
3674                                                      offset + row_ptr->baseline);               
3675                                 x += 2;
3676                                 pos++;
3677                         } else {
3678                                 if (row_ptr->par->IsSeparator(pos)) {
3679                                         tmpx = x;
3680                                         x+= SingleWidth(row_ptr->par, pos);
3681                                         /* -------> Only draw protected spaces when not in
3682                                          * free-spacing mode. */
3683                                         if (row_ptr->par->GetChar(pos) == LyXParagraph::META_PROTECTED_SEPARATOR && !layout.free_spacing) {
3684                                                 scr.drawVerticalLine(gc_fill, int(tmpx),
3685                                                                      offset + row_ptr->baseline - 3,
3686                                                                      offset + row_ptr->baseline - 1);
3687                                                 scr.drawLine(gc_fill,
3688                                                              offset + row_ptr->baseline - 1,
3689                                                              int(tmpx),
3690                                                              int(x-tmpx-2));
3691                                                 scr.drawVerticalLine(gc_fill, int(x-2),
3692                                                                      offset + row_ptr->baseline - 3,
3693                                                                      offset + row_ptr->baseline - 1);                   
3694                                                 /* what about underbars? */
3695                                                 font = GetFont(row_ptr->par, pos); 
3696                                                 if (font.underbar() == LyXFont::ON
3697                                                     && font.latex() != LyXFont::ON) {
3698                                                         scr.drawLine(gc_copy,
3699                                                                      offset +
3700                                                                      row_ptr->baseline + 2,
3701                                                                      int(tmpx),
3702                                                                      int(x - tmpx));                        
3703                                                 }
3704                                         }
3705                                         pos++;
3706                                 } else
3707                                         Draw(row_ptr, pos, scr, offset, x);
3708                         }
3709                 }
3710                 
3711                 /* do not forget the very last cell. This has no NEWLINE so 
3712                  * ignored by the code above*/ 
3713                 if (cell == row_ptr->par->table->GetNumberOfCells()-1){
3714                         x = x_old + row_ptr->par->table->WidthOfColumn(cell);
3715                         on_off = !row_ptr->par->table->TopLine(cell);
3716                         if ((!on_off ||
3717                              !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
3718                             !row_ptr->par->table->IsContRow(cell))
3719                                 
3720                                 scr.drawTableLine(offset + row_ptr->baseline -
3721                                                   row_ptr->ascent_of_text,
3722                                                   int(x_old), int(x - x_old), on_off);      
3723                         on_off = !row_ptr->par->table->BottomLine(cell);
3724                         if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
3725                             row_ptr->par->table->VeryLastRow(cell))
3726                                 
3727                                 scr.drawTableLine(offset + y_bottom - 1,
3728                                                   int(x_old), int(x - x_old), on_off);      
3729                         on_off = !row_ptr->par->table->LeftLine(cell);
3730                         
3731                         scr.drawVerticalTableLine(int(x_old), 
3732                                                   offset + row_ptr->baseline -
3733                                                   row_ptr->ascent_of_text,
3734                                                   offset + y_bottom - 1,
3735                                                   on_off);          
3736                         on_off = !row_ptr->par->table->RightLine(cell);
3737                         
3738                         scr.drawVerticalTableLine(int(x) -
3739                                                   row_ptr->par->table->AdditionalWidth(cell),
3740                                                   offset + row_ptr->baseline -
3741                                                   row_ptr->ascent_of_text,
3742                                                   offset + y_bottom - 1,
3743                                                   on_off);          
3744                 }
3745         } else {
3746                 /* table stuff -- end*/
3747                 
3748                 while (pos <= pos_end)  {
3749                         
3750                         if (row_ptr->par->IsHfill(pos)) {
3751                                 x += 1;
3752                                 scr.drawVerticalLine(gc_fill, int(x),  
3753                                                      offset + row_ptr->baseline - DefaultHeight()/2, 
3754                                                      offset + row_ptr->baseline);               
3755                                 if (HfillExpansion(row_ptr, pos)) {
3756                                         if (pos >= main_body) {
3757                                                 scr.drawOnOffLine(offset + row_ptr->baseline -
3758                                                                   DefaultHeight()/4,
3759                                                                   int(x),
3760                                                                   int(fill_hfill));                     
3761                                                 x += fill_hfill;
3762                     } else {
3763                             scr.drawOnOffLine(offset + row_ptr->baseline -
3764                                               DefaultHeight()/4,
3765                                               int(x),
3766                                               int(fill_label_hfill));
3767                             x += fill_label_hfill;
3768                     }
3769                                         scr.drawVerticalLine(gc_fill, int(x),
3770                                                              offset + row_ptr->baseline -
3771                                                              DefaultHeight()/2, 
3772                                                              offset + row_ptr->baseline);
3773                                 }
3774                                 x += 2;
3775                                 pos++;
3776                         } else {
3777                                 if (row_ptr->par->IsSeparator(pos)) {
3778                                         tmpx = x;
3779                                         x+= SingleWidth(row_ptr->par, pos);
3780                                         if (pos >= main_body)
3781                                                 x+= fill_separator;
3782                                         /* -------> Only draw protected spaces when not in
3783                                          * free-spacing mode. */
3784                                         if (row_ptr->par->GetChar(pos) == LyXParagraph::META_PROTECTED_SEPARATOR && !layout.free_spacing) {
3785                                                 
3786                                                 scr.drawVerticalLine(gc_fill, int(tmpx),
3787                                                                      offset + row_ptr->baseline - 3,
3788                                                                      offset + row_ptr->baseline - 1);
3789                                                 scr.drawLine(gc_fill,
3790                                                              offset + row_ptr->baseline - 1,
3791                                                              int(tmpx),
3792                                                              int(x-tmpx-2));
3793                                                 scr.drawVerticalLine(gc_fill, int(x-2),
3794                                                                      offset + row_ptr->baseline - 3,
3795                                                                      offset + row_ptr->baseline - 1);                   
3796                                                 /* what about underbars? */
3797                                                 font = GetFont(row_ptr->par, pos); 
3798                                                 if (font.underbar() == LyXFont::ON
3799                                                     && font.latex() != LyXFont::ON) {
3800                                                         scr.drawLine(gc_copy,
3801                                              offset + row_ptr->baseline + 2,
3802                                                                      int(tmpx),
3803                                                                      int(x - tmpx));
3804                                                 }
3805                                         }
3806                                         pos++;
3807                                 } else
3808                                         Draw(row_ptr, pos, scr, offset, x);
3809                         }
3810                         if (pos == main_body) {
3811                                 x += GetFont(row_ptr->par, -2).stringWidth(
3812                                         layout.labelsep);
3813                                 if (row_ptr->par->IsLineSeparator(pos - 1))
3814                                         x-= SingleWidth(row_ptr->par, pos - 1);
3815                                 if (x < left_margin)
3816                                         x = left_margin;
3817                         }
3818                 }
3819         }
3820         // check for FAST SELECTION
3821         if (fast_selection || mono_video) {
3822                 if (selection) {
3823                         
3824                         /* selection code */ 
3825                         if (sel_start_cursor.row == row_ptr && sel_end_cursor.row == row_ptr) {
3826                                 scr.fillRectangle(gc_select, sel_start_cursor.x, offset,
3827                                                   sel_end_cursor.x - sel_start_cursor.x,
3828                                                   row_ptr->height); 
3829                         } else if (sel_start_cursor.row == row_ptr) {
3830                                 scr.fillRectangle(gc_select, sel_start_cursor.x, offset,
3831                                                   paperwidth - sel_start_cursor.x,
3832                                                   row_ptr->height);
3833                         } else if (sel_end_cursor.row == row_ptr) {
3834                                 scr.fillRectangle(gc_select, 0, offset,
3835                                                   sel_end_cursor.x,
3836                                                   row_ptr->height);
3837                         } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
3838                                 scr.fillRectangle(gc_select, 0, offset,
3839                                                   paperwidth, row_ptr->height);
3840                                 
3841                         }
3842                 }
3843         }
3844 // end of FAST SELECTION code
3845         /* thats it */ 
3846 }
3847
3848
3849 int LyXText::DefaultHeight() const
3850 {
3851         LyXFont font(LyXFont::ALL_SANE);
3852         return int(font.maxAscent() + font.maxDescent() * 1.5);
3853 }
3854
3855    
3856 /* returns the column near the specified x-coordinate of the row 
3857 * x is set to the real beginning of this column  */ 
3858 int LyXText::GetColumnNearX(Row * row, int & x) const
3859 {
3860         float tmpx = 0.0;
3861         float fill_separator, fill_hfill, fill_label_hfill;
3862    
3863         int left_margin = LabelEnd(row);
3864         PrepareToPrint(row, tmpx, fill_separator,
3865                        fill_hfill, fill_label_hfill);
3866         int main_body = BeginningOfMainBody(row->par);
3867         
3868         int c = row->pos;
3869
3870         int last = RowLast(row);
3871         if (row->par->IsNewline(last))
3872                 last--;
3873    
3874         LyXLayout const & layout = textclasslist.Style(parameters->textclass,
3875                                            row->par->GetLayout());
3876         /* table stuff -- begin */
3877         if (row->par->table) {
3878                 if (!row->next || row->next->par != row->par)
3879                         last = RowLast(row); /* the last row doesn't need a newline at the end*/
3880                 int cell = NumberOfCell(row->par, row->pos);
3881                 float x_old = tmpx;
3882                 bool ready = false;
3883                 tmpx += row->par->table->GetBeginningOfTextInCell(cell);
3884                 while (c <= last
3885                        && tmpx + (SingleWidth(row->par, c)/2) <= x
3886                        && !ready){
3887                         if (row->par->IsNewline(c)) {
3888                                 if (x_old + row->par->table->WidthOfColumn(cell) <= x){
3889                                         tmpx = x_old + row->par->table->WidthOfColumn(cell);
3890                                         x_old = tmpx;
3891                                         cell++;
3892                                         tmpx += row->par->table->GetBeginningOfTextInCell(cell);
3893                                         ++c;
3894                                 } else
3895                                         ready = true;
3896                         } else {
3897                                 tmpx += SingleWidth(row->par, c);
3898                                 ++c;
3899                         }
3900                 }
3901         } else
3902                 /* table stuff -- end*/
3903
3904                 while (c <= last
3905                        && tmpx + (SingleWidth(row->par, c)/2)  <= x) {
3906                         
3907                         if (c && c == main_body
3908                             && !row->par->IsLineSeparator(c - 1)) {
3909                                 tmpx += GetFont(row->par, -2)
3910                                         .stringWidth(layout.labelsep);
3911                                 if (tmpx < left_margin)
3912                                         tmpx = left_margin;
3913                         }
3914              
3915                         tmpx += SingleWidth(row->par, c);
3916                         if (HfillExpansion(row, c)) {
3917                                 if (c >= main_body)
3918                                         tmpx += fill_hfill;
3919                                 else
3920                                         tmpx += fill_label_hfill;
3921                         }
3922                         else if (c >= main_body
3923                                  && row->par->IsSeparator(c)) {
3924                                 tmpx+= fill_separator;  
3925                         }
3926                         c++;
3927                         if (c == main_body
3928                             && row->par->IsLineSeparator(c - 1)) {
3929                                 tmpx += GetFont(row->par, -2)
3930                                         .stringWidth(layout.labelsep);
3931                                 tmpx-= SingleWidth(row->par, c - 1);
3932                                 if (tmpx < left_margin)
3933                                         tmpx = left_margin;
3934                         }
3935                 }
3936         /* make sure that a last space in a row doesnt count */
3937         if (c > 0 && c >= last
3938             && row->par->IsLineSeparator(c - 1)
3939             && !(!row->next || row->next->par != row->par)) {
3940                 tmpx -= SingleWidth(row->par, c - 1);
3941                 tmpx -= fill_separator;
3942         }
3943         c-= row->pos;
3944         
3945         x = int(tmpx);
3946         return c;
3947 }
3948
3949    
3950 /* turn the selection into a new environment. If there is no selection,
3951 * create an empty environment */ 
3952 void LyXText::InsertFootnoteEnvironment(LyXParagraph::footnote_kind kind)
3953 {
3954    /* no footnoteenvironment in a footnoteenvironment */ 
3955    if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3956       WriteAlert(_("Impossible operation"), 
3957                  _("You can't insert a float in a float!"), 
3958                  _("Sorry."));
3959      return;
3960    }
3961    /* no marginpars in minipages */
3962    if (kind == LyXParagraph::MARGIN 
3963       && cursor.par->pextra_type == LyXParagraph::PEXTRA_MINIPAGE) {
3964       WriteAlert(_("Impossible operation"), 
3965                  _("You can't insert a marginpar in a minipage!"), 
3966                  _("Sorry."));
3967       return;
3968    }
3969    
3970    /* this doesnt make sense, if there is no selection */ 
3971    bool dummy_selection = false;
3972    if (!selection) {
3973       sel_start_cursor = cursor;       /* dummy selection  */
3974       sel_end_cursor = cursor;
3975       dummy_selection = true;
3976    }
3977    
3978    LyXParagraph *tmppar;
3979
3980    if (sel_start_cursor.par->table || sel_end_cursor.par->table){
3981       WriteAlert(_("Impossible operation"), _("Cannot cut table."), _("Sorry."));
3982       return;
3983    }
3984      
3985    /* a test to make sure there is not already a footnote
3986     * in the selection. */
3987    
3988    tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
3989    
3990    while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos) && 
3991           tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
3992      tmppar = tmppar->next;
3993    
3994    if (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
3995        || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3996       WriteAlert(_("Impossible operation"), 
3997                  _("Float would include float!"), 
3998                  _("Sorry."));
3999       return;
4000    }
4001    
4002    /* ok we have a selection. This is always between sel_start_cursor
4003     * and sel_end cursor */
4004
4005    SetUndo(Undo::FINISH, 
4006            sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
4007            sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next); 
4008    
4009    if (sel_end_cursor.pos > 0 
4010        && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1))
4011      sel_end_cursor.pos--;             /* please break before a space at
4012                                         * the end */
4013    if (sel_start_cursor.par == sel_end_cursor.par
4014        && sel_start_cursor.pos > sel_end_cursor.pos)
4015      sel_start_cursor.pos--;
4016
4017    sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
4018    
4019    sel_end_cursor.par = sel_end_cursor.par->Next();
4020    sel_end_cursor.pos = 0;
4021    
4022    // don't forget to insert a dummy layout paragraph if necessary
4023    if (sel_start_cursor.par->GetLayout() != sel_end_cursor.par->layout){
4024      sel_end_cursor.par->BreakParagraphConservative(0);
4025      sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
4026      sel_end_cursor.par = sel_end_cursor.par->next;
4027    }
4028    else
4029      sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
4030
4031    cursor = sel_end_cursor;
4032
4033    /* please break behind a space, if there is one. The space should
4034     * be erased too */ 
4035    if (sel_start_cursor.pos > 0 
4036        && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1))
4037      sel_start_cursor.pos--;
4038    if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)) {
4039       sel_start_cursor.par->Erase(sel_start_cursor.pos);
4040    }
4041    
4042    sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
4043    tmppar = sel_start_cursor.par->Next();
4044    
4045    if (dummy_selection) {
4046            tmppar->Clear();
4047            if (kind == LyXParagraph::TAB
4048                || kind == LyXParagraph::FIG 
4049                || kind == LyXParagraph::WIDE_TAB
4050                || kind == LyXParagraph::WIDE_FIG 
4051                || kind == LyXParagraph::ALGORITHM) {
4052                    int lay = textclasslist.NumberOfLayout(parameters->textclass,
4053                                                      "Caption").second;
4054                    if (lay == -1) // layout not found
4055                            // use default layout "Standard" (0)
4056                            lay = 0;
4057                    tmppar->SetLayout(lay);
4058            }
4059    }
4060    else {
4061      if (sel_start_cursor.pos > 0) {
4062        /* the footnote-environment should begin with a standard layout.
4063         * Imagine you insert a footnote within an enumeration, you 
4064         * certainly do not want an enumerated footnote! */ 
4065        tmppar->Clear();
4066      }
4067      else {
4068        /* this is a exception the user would sometimes expect, I hope */
4069        sel_start_cursor.par->Clear();
4070      }
4071    }
4072    
4073    while (tmppar != sel_end_cursor.par) {
4074       tmppar->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
4075       tmppar->footnotekind = kind;
4076       tmppar = tmppar->Next();
4077    } 
4078
4079    RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
4080    
4081    SetCursor(sel_start_cursor.par->Next(), 0);
4082
4083    ClearSelection();
4084 }
4085    
4086
4087 // returns pointer to a specified row
4088 Row * LyXText::GetRow(LyXParagraph * par,
4089                       LyXParagraph::size_type pos, long & y) const
4090 {
4091         Row * tmprow;
4092         
4093         if (currentrow) {
4094                 if (par == currentrow->par || par == currentrow->par->Previous()) {
4095                         // do not dereference par, it may have been deleted
4096                         // already! (Matthias) 
4097                         while (currentrow->previous && currentrow->previous->par != par) {
4098                                 currentrow = currentrow->previous;
4099                                 currentrow_y -= currentrow->height;
4100                         }
4101                         while (currentrow->previous && currentrow->previous->par == par) {
4102                                 currentrow = currentrow->previous;
4103                                 currentrow_y -= currentrow->height;
4104                         }
4105                 }
4106                 tmprow = currentrow;
4107                 y = currentrow_y;
4108                 // find the first row of the specified paragraph
4109                 while (tmprow->next && (tmprow->par != par)) {
4110                         y += tmprow->height;
4111                         tmprow = tmprow->next;
4112                 }
4113                 
4114                 if (tmprow->par == par){
4115                         // now find the wanted row
4116                         while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par && 
4117                                tmprow->next->pos <= pos) {
4118                                 y += tmprow->height;
4119                                 tmprow = tmprow->next;
4120                         }
4121                         currentrow = tmprow;
4122                         currentrow_y = y;
4123                         return tmprow;
4124                 }
4125         }
4126         tmprow = firstrow;
4127         y = 0;
4128         // find the first row of the specified paragraph
4129         while (tmprow->next && (tmprow->par != par)) {
4130                 y += tmprow->height;
4131                 tmprow = tmprow->next;
4132         }
4133         
4134         // now find the wanted row
4135         while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par && 
4136                tmprow->next->pos <= pos) {
4137                 y += tmprow->height;
4138                 tmprow = tmprow->next;
4139         }
4140         
4141         currentrow = tmprow;
4142         currentrow_y = y;
4143         
4144         return tmprow;
4145 }