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