]> git.lyx.org Git - features.git/blob - src/text.C
some small updates to Painter, and make the new painter the default.
[features.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 "gettext.h"
25 #include "bufferparams.h"
26 #include "buffer.h"
27 #include "lyxscreen.h"
28 #include "minibuffer.h"
29 #include "debug.h"
30 #include "lyxrc.h"
31 #include "LyXView.h"
32 #include "lyxrow.h"
33 #include "Painter.h"
34 #ifndef USE_PAINTER
35 #include "lyxdraw.h"
36 #endif
37
38 using std::max;
39 using std::min;
40
41 static const int LYX_PAPER_MARGIN = 20;
42
43 #ifdef MONO
44 extern int mono_video;
45 extern int reverse_video;
46 extern int fast_selection;
47 #endif
48
49 extern BufferView * current_view;
50 extern LyXRC * lyxrc;
51
52 // ale070405
53 #ifdef USE_PAINTER
54 extern int bibitemMaxWidth(Painter &, LyXFont const &);
55 #else
56 extern int bibitemMaxWidth(LyXFont const &);
57 #endif
58
59 #define FIX_DOUBLE_SPACE 1
60
61 int LyXText::SingleWidth(LyXParagraph * par,
62                          LyXParagraph::size_type pos) const
63 {
64         char c = par->GetChar(pos);
65         return SingleWidth(par, pos, c);
66 }
67
68
69 #ifdef USE_PAINTER
70 int LyXText::SingleWidth(LyXParagraph * par,
71                          LyXParagraph::size_type pos, char c) const
72 {
73         LyXFont font = GetFont(par, pos);
74
75         // The most common case is handled first (Asger)
76         if (IsPrintable(c)) {
77                 return font.width(c);
78
79         } else if (IsHfillChar(c)) {
80                 return 3;       /* Because of the representation
81                                  * as vertical lines */
82         } else if (c == LyXParagraph::META_FOOTNOTE ||
83                    c == LyXParagraph::META_MARGIN ||
84                    c == LyXParagraph::META_FIG ||
85                    c == LyXParagraph::META_TAB ||
86                    c == LyXParagraph::META_WIDE_FIG ||
87                    c == LyXParagraph::META_WIDE_TAB ||
88                    c == LyXParagraph::META_ALGORITHM) {
89                 string fs;
90                 switch (c) {
91                 case LyXParagraph::META_MARGIN:
92                         fs = "margin";
93                         break;
94                 case LyXParagraph::META_FIG:
95                         fs = "fig";
96                         break;
97                 case LyXParagraph::META_TAB:
98                         fs = "tab";
99                         break;
100                 case LyXParagraph::META_ALGORITHM:
101                         fs = "alg";
102                         break;
103                 case LyXParagraph::META_WIDE_FIG:
104                         fs = "wide-fig";
105                         break;
106                 case LyXParagraph::META_WIDE_TAB:
107                         fs = "wide-tab";
108                         break;
109                 case LyXParagraph::META_FOOTNOTE:
110                         fs = "foot";
111                         break;
112                 }
113                 font.decSize();
114                 font.decSize();
115                 return font.stringWidth(fs);
116         } else if (c == LyXParagraph::META_INSET) {
117                 Inset * tmpinset= par->GetInset(pos);
118                 if (tmpinset)
119                         return par->GetInset(pos)->width(owner_->painter(),
120                                                          font);
121                 else
122                         return 0;
123
124         } else if (IsSeparatorChar(c))
125                 c = ' ';
126         else if (IsNewlineChar(c))
127                 c = 'n';
128         return font.width(c);
129 }
130 #else
131 int LyXText::SingleWidth(LyXParagraph * par,
132                          LyXParagraph::size_type pos, char c) const
133 {
134         LyXFont font = GetFont(par, pos);
135
136         // The most common case is handled first (Asger)
137         if (IsPrintable(c)) {
138                 return font.width(c);
139
140         } else if (IsHfillChar(c)) {
141                 return 3;       /* Because of the representation
142                                  * as vertical lines */
143
144         } else if (c == LyXParagraph::META_FOOTNOTE ||
145                    c == LyXParagraph::META_MARGIN ||
146                    c == LyXParagraph::META_FIG ||
147                    c == LyXParagraph::META_TAB ||
148                    c == LyXParagraph::META_WIDE_FIG ||
149                    c == LyXParagraph::META_WIDE_TAB ||
150                    c == LyXParagraph::META_ALGORITHM) 
151         {
152                 string fs;
153                 switch (c) {
154                 case LyXParagraph::META_MARGIN:
155                         fs = "margin";
156                         break;
157                 case LyXParagraph::META_FIG:
158                         fs = "fig";
159                         break;
160                 case LyXParagraph::META_TAB:
161                         fs = "tab";
162                         break;
163                 case LyXParagraph::META_ALGORITHM:
164                         fs = "alg";
165                         break;
166                 case LyXParagraph::META_WIDE_FIG:
167                         fs = "wide-fig";
168                         break;
169                 case LyXParagraph::META_WIDE_TAB:
170                         fs = "wide-tab";
171                         break;
172                 case LyXParagraph::META_FOOTNOTE:
173                         fs = "foot";
174                         break;
175                 }
176                 font.decSize();
177                 font.decSize();
178                 return font.stringWidth(fs);
179         } 
180    
181         else if (c == LyXParagraph::META_INSET) {
182                 Inset *tmpinset= par->GetInset(pos);
183                 if (tmpinset)
184                         return par->GetInset(pos)->Width(font);
185                 else
186                         return 0;
187
188         } else if (IsSeparatorChar(c))
189                 c = ' ';
190         else if (IsNewlineChar(c))
191                 c = 'n';
192         return font.width(c);
193 }
194 #endif
195
196
197 // Returns the paragraph position of the last character in the specified row
198 LyXParagraph::size_type LyXText::RowLast(Row const * row) const
199 {
200         if (row->next == 0)
201                 return row->par->Last() - 1;
202         else if (row->next->par != row->par) 
203                 return row->par->Last() - 1;
204         else 
205                 return row->next->pos - 1;
206 }
207
208
209 LyXDirection BufferParams::getDocumentDirection() const
210 {
211         return (lyxrc->rtl_support && language == "hebrew")
212                 ? LYX_DIR_RIGHT_TO_LEFT : LYX_DIR_LEFT_TO_RIGHT;
213 }
214
215 LyXDirection LyXParagraph::getParDirection() const
216 {
217         if (!lyxrc->rtl_support || table)
218                 return LYX_DIR_LEFT_TO_RIGHT;
219
220         if (size() > 0)
221                 return (getFont(0).direction() ==  LyXFont::RTL_DIR)
222                         ? LYX_DIR_RIGHT_TO_LEFT : LYX_DIR_LEFT_TO_RIGHT;
223         else
224                 return current_view->buffer()->params.getDocumentDirection();
225 }
226
227 LyXDirection LyXFont::getFontDirection() const
228 {
229         if (lyxrc->rtl_support 
230             && direction() == LyXFont::RTL_DIR
231             && latex() != LyXFont::ON)
232                 return LYX_DIR_RIGHT_TO_LEFT;
233         else
234                 return LYX_DIR_LEFT_TO_RIGHT;
235 }
236
237 LyXDirection
238 LyXParagraph::getLetterDirection(LyXParagraph::size_type pos) const
239 {
240         if (!lyxrc->rtl_support)
241                 return LYX_DIR_LEFT_TO_RIGHT;
242
243         LyXDirection direction = getFont(pos).getFontDirection();
244         if (IsLineSeparator(pos) && 0 < pos && pos < Last() - 1
245             && !IsLineSeparator(pos + 1)
246             && !(table && IsNewline(pos + 1))
247             && (getFont(pos - 1).getFontDirection() != direction
248                 || getFont(pos + 1).getFontDirection() != direction))
249                 return getParDirection();
250         else
251                 return direction;
252 }
253
254
255 void LyXText::ComputeBidiTables(Row * row) const
256 {
257
258         if (!lyxrc->rtl_support) {
259                 bidi_start = -1;
260                 return;
261         }
262         LyXParagraph::size_type last = RowLast(row);
263         bidi_start = row->pos;
264
265         if (bidi_start > last) {
266                 bidi_start = -1;
267                 return;
268         }
269
270         if (last + 2 - bidi_start >
271             static_cast<LyXParagraph::size_type>(log2vis_list.size())) {
272                 LyXParagraph::size_type new_size = 
273                         (last + 2 - bidi_start < 500) ?
274                         500 : 2 * (last + 2 - bidi_start);
275                 log2vis_list.resize(new_size);
276                 vis2log_list.resize(new_size);
277         }
278
279         vis2log_list[last + 1 - bidi_start] = -1;
280         log2vis_list[last + 1 - bidi_start] = -1;
281
282         LyXParagraph::size_type main_body = BeginningOfMainBody(row->par);
283         if (main_body > 0 && row->pos < main_body - 1 && main_body - 1 <= last
284             && row->par->IsLineSeparator(main_body - 1)) {
285                 // This is needed in case there is a direction change in
286                 // the label which is continued into the main body
287                 if (row->par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT) {
288                         ComputeBidiTablesFromTo(row, bidi_start,
289                                                 main_body - 2, 0);
290                         log2vis_list[main_body - 1 - bidi_start] =
291                                 main_body - 1;
292                         vis2log_list[main_body - 1 - bidi_start] =
293                                 main_body - 1;
294                         if (main_body <= last)
295                                 ComputeBidiTablesFromTo(row,
296                                                         main_body,last, 0);
297                 } else {
298                         ComputeBidiTablesFromTo(row, bidi_start,
299                                                 main_body - 2,
300                                                 last - main_body + 2);
301                         log2vis_list[main_body - 1 - bidi_start] =
302                                 last - main_body + 1 + bidi_start;
303                         vis2log_list[last - main_body + 1 - bidi_start] =
304                                 main_body - 1;
305                         if (main_body <= last)
306                                 ComputeBidiTablesFromTo(row, main_body,
307                                                         last, -main_body);
308                 }
309         } else
310                 ComputeBidiTablesFromTo(row, bidi_start, last, 0);
311 }
312
313
314 void LyXText::ComputeBidiTablesFromTo(Row * row,
315                                       LyXParagraph::size_type from,
316                                       LyXParagraph::size_type to,
317                                       LyXParagraph::size_type offset) const
318 {
319         LyXParagraph::size_type vpos, old_lpos, stack[2];
320         LyXDirection par_direction = row->par->getParDirection();
321         LyXDirection direction = par_direction;
322         LyXParagraph::size_type lpos = from;
323         int level = 0;
324
325         while (lpos <= to) {
326                 if (row->par->getLetterDirection(lpos) == direction) {
327                         log2vis_list[lpos - bidi_start] = direction;
328                         ++lpos;
329                 } else {
330                         if (level == 0 ||
331                             (level == 1 && direction == LYX_DIR_RIGHT_TO_LEFT
332                              && row->par->getFont(lpos).direction() ==
333                              LyXFont::RTL_DIR
334                              && row->par->getFont(lpos).latex() ==
335                              LyXFont::ON ) ) {
336                                 // The last check is needed when the
337                                 // char is a space
338                                 stack[level++] = lpos;
339                         } else {
340                                 old_lpos = stack[--level];
341                                 log2vis_list[old_lpos - bidi_start] = 
342                                         log2vis_list[lpos - bidi_start] =
343                                         (old_lpos - lpos) * direction;
344                                 ++lpos;
345                         }
346                         direction = static_cast<LyXDirection>(-direction);
347                 }
348         }
349
350         while (level > 0) {
351                 old_lpos = stack[--level];
352                 log2vis_list[old_lpos - bidi_start] =
353                         (old_lpos - (to + 1)) * direction; 
354                 direction = static_cast<LyXDirection>(-direction);
355         }
356
357         vpos = (par_direction == LYX_DIR_LEFT_TO_RIGHT)
358                 ? from - 1 : to + 1;
359         vpos += offset;
360         for (lpos = from; lpos <= to; ++lpos) {
361                 vpos += log2vis_list[lpos - bidi_start];
362                 vis2log_list[vpos - bidi_start] = lpos;
363                 log2vis_list[lpos - bidi_start] = vpos;
364         }
365 }
366
367
368 #ifdef USE_PAINTER
369 void LyXText::draw(Row const * row,
370                    LyXParagraph::size_type & vpos,
371                    int offset, float & x)
372 {
373         Painter & pain = owner_->painter();
374         
375         LyXParagraph::size_type pos = vis2log(vpos);
376         char c = row->par->GetChar(pos);
377
378         if (IsNewlineChar(c)) {
379                 ++vpos;
380                 // Draw end-of-line marker
381                 LyXFont font = GetFont(row->par, pos);
382                 int wid = font.width('n');
383                 int asc = font.maxAscent();
384                 int y = offset + row->baseline;
385 #ifdef USE_PAINTER
386                 int xp[3], yp[3];
387                 
388                 if (row->par->getLetterDirection(pos) == LYX_DIR_LEFT_TO_RIGHT) {
389                         xp[0] = int(x + wid * 0.375);
390                         yp[0] = int(y - 0.875 * asc * 0.75);
391                         
392                         xp[1] = int(x);
393                         yp[1] = int(y - 0.500 * asc * 0.75);
394                         
395                         xp[2] = int(x + wid * 0.375);
396                         yp[2] = int(y - 0.125 * asc * 0.75);
397                         
398                         pain.lines(xp, yp, 3, LColor::eolmarker);
399                         
400                         xp[0] = int(x);
401                         yp[0] = int(y - 0.500 * asc * 0.75);
402                         
403                         xp[1] = int(x + wid);
404                         yp[1] = int(y - 0.500 * asc * 0.75);
405                         
406                         xp[2] = int(x + wid);
407                         yp[2] = int(y - asc * 0.75);
408                         
409                         pain.lines(xp, yp, 3, LColor::eolmarker);
410                 } else {
411                         xp[0] = int(x + wid * 0.625);
412                         yp[0] = int(y - 0.875 * asc * 0.75);
413                         
414                         xp[1] = int(x + wid);
415                         yp[1] = int(y - 0.500 * asc * 0.75);
416                         
417                         xp[2] = int(x + wid * 0.625);
418                         yp[2] = int(y - 0.125 * asc * 0.75);
419                         
420                         pain.lines(xp, yp, 3, LColor::eolmarker);
421                         
422                         xp[0] = int(x + wid);
423                         yp[0] = int(y - 0.500 * asc * 0.75);
424                         
425                         xp[1] = int(x);
426                         yp[1] = int(y - 0.500 * asc * 0.75);
427                         
428                         xp[2] = int(x);
429                         yp[2] = int(y - asc * 0.75);
430                         
431                         pain.lines(xp, yp, 3, LColor::eolmarker);
432                 }
433 #else
434                 XPoint p[3];
435                 
436                 if (row->par->getLetterDirection(pos) == LYX_DIR_LEFT_TO_RIGHT) {
437                         p[0].x = int(x + wid*0.375); p[0].y = int(y - 0.875*asc*0.75);
438                         p[1].x = int(x);             p[1].y = int(y - 0.500*asc*0.75);
439                         p[2].x = int(x + wid*0.375); p[2].y = int(y - 0.125*asc*0.75);
440                         scr.drawLines(::getGC(gc_new_line), p, 3);
441                 
442                         p[0].x = int(x);             p[0].y = int(y - 0.500*asc*0.75);
443                         p[1].x = int(x + wid);       p[1].y = int(y - 0.500*asc*0.75);
444                         p[2].x = int(x + wid);       p[2].y = int(y - asc*0.75);
445                         scr.drawLines(::getGC(gc_new_line), p, 3);
446                 } else {
447                         p[0].x = int(x + wid*0.625); p[0].y = int(y - 0.875*asc*0.75);
448                         p[1].x = int(x + wid);       p[1].y = int(y - 0.500*asc*0.75);
449                         p[2].x = int(x + wid*0.625); p[2].y = int(y - 0.125*asc*0.75);
450                         scr.drawLines(::getGC(gc_new_line), p, 3);
451                 
452                         p[0].x = int(x + wid);       p[0].y = int(y - 0.500*asc*0.75);
453                         p[1].x = int(x);             p[1].y = int(y - 0.500*asc*0.75);
454                         p[2].x = int(x);             p[2].y = int(y - asc*0.75);
455                         scr.drawLines(::getGC(gc_new_line), p, 3);
456                 }
457 #endif
458                 x += wid;
459                 return;
460         }
461
462         LyXFont font = GetFont(row->par, pos);
463         LyXFont font2 = font;
464
465         if (c == LyXParagraph::META_FOOTNOTE
466             || c == LyXParagraph::META_MARGIN
467             || c == LyXParagraph::META_FIG
468             || c == LyXParagraph::META_TAB
469             || c == LyXParagraph::META_WIDE_FIG
470             || c == LyXParagraph::META_WIDE_TAB
471             || c == LyXParagraph::META_ALGORITHM) {
472                 string fs;
473                 switch (c) {
474                 case LyXParagraph::META_MARGIN:
475                         fs = "margin";
476                         // Draw a sign at the left margin!
477                         owner_->painter()
478                                 .text((LYX_PAPER_MARGIN - font.width('!'))/2,
479                                       offset + row->baseline, "!", 1, font);
480                         break;
481                 case LyXParagraph::META_FIG:
482                         fs = "fig";
483                         break;
484                 case LyXParagraph::META_TAB:
485                         fs = "tab";
486                         break;
487                 case LyXParagraph::META_ALGORITHM:
488                         fs = "alg";
489                         break;
490                 case LyXParagraph::META_WIDE_FIG:
491                         fs = "wide-fig";
492                         break;
493                 case LyXParagraph::META_WIDE_TAB:
494                         fs = "wide-tab";
495                         break;
496                 case LyXParagraph::META_FOOTNOTE:
497                         fs = "foot";
498                         break;
499                 }
500                 font.decSize();
501                 font.decSize();
502           
503                 // calculate the position of the footnotemark
504                 int y = (row->baseline - font2.maxAscent() 
505                          + font.maxAscent());
506           
507                 font.setColor(LColor::footnote);
508
509                 float tmpx = x;
510
511                 // draw it and set new x position
512                 
513                 pain.text(int(x), offset + y, fs, font);
514                 x += pain.width(fs, font);
515                 pain.line(int(tmpx), offset + row->baseline,
516                           int(x), offset + row->baseline,
517                           LColor::footnote);
518
519           
520                 ++vpos;
521                 return;
522         } else if (c == LyXParagraph::META_INSET) {
523                 Inset * tmpinset = row->par->GetInset(pos);
524                 if (tmpinset) 
525                         tmpinset->draw(owner_->painter(), font,
526                                        offset + row->baseline, x);
527                 ++vpos;
528                 return;
529         }
530
531         /* usual characters, no insets */
532
533         // Collect character that we can draw in one command
534
535         // This is dirty, but fast. Notice that it will never be too small.
536         // For the record, I'll note that Microsoft Word has a limit
537         // of 768 here. We have none :-) (Asger)
538         // Ok. I am the first to admit that the use of std::string will be
539         // a tiny bit slower than using a POD char array. However, I claim
540         // that this slowdown is so small that it is close to inperceptive.
541         // So IMHO we should go with the easier and clearer implementation.
542         // And even if 1024 is a large number here it might overflow, string
543         // will only overflow if the machine is out of memory...
544         static string textstring;
545         textstring = c;
546         ++vpos;
547
548         LyXParagraph::size_type last = RowLast(row);
549         
550         while (vpos <= last &&
551                (pos = vis2log(vpos)) >= 0
552                && static_cast<unsigned char>(c = row->par->GetChar(pos)) > ' '
553                && font2 == GetFont(row->par, pos)) {
554                 textstring += c;
555                 ++vpos;
556         }
557         float tmpx = x;
558
559 #if 0
560         // If monochrome and LaTeX mode, provide reverse background
561         if (mono_video &&
562             font.latex() == LyXFont::ON) {
563                 int a = font.maxAscent();
564                 int d = font.maxDescent();
565                 scr.fillRectangle(gc_copy, int(tmpx),
566                                   offset + row->baseline - a,
567                                   font.textWidth(textstring.c_str(),
568                                                  textstring.length()), a + d);
569         }
570 #endif
571
572         // Draw text and set the new x position
573         pain.text(int(x), offset + row->baseline, textstring, font);
574         x += pain.width(textstring, font);
575         
576         // what about underbars?
577         if (font.underbar() == LyXFont::ON && font.latex() != LyXFont::ON) {
578                 pain.line(tmpx, offset + row->baseline + 2,
579                           x, offset + row->baseline + 2);
580                 
581         }
582
583         // If we want ulem.sty support, drawing
584         // routines should go here. (Asger)
585         // Why shouldn't LyXFont::drawText handle it internally?
586 }
587 #else
588 void LyXText::Draw(Row const * row, LyXParagraph::size_type & vpos,
589                    LyXScreen & scr, int offset, float & x)
590 {
591         LyXParagraph::size_type pos = vis2log(vpos);
592         char c = row->par->GetChar(pos);
593
594         if (IsNewlineChar(c)) {
595                 ++vpos;
596                 // Draw end-of-line marker
597
598                 LyXFont font = GetFont(row->par, pos);
599                 int asc = font.maxAscent();
600                 int wid = font.width('n');
601                 int y = (offset + row->baseline);
602                 XPoint p[3];
603                 if (row->par->getLetterDirection(pos) == LYX_DIR_LEFT_TO_RIGHT) {
604                         p[0].x = int(x + wid*0.375); p[0].y = int(y - 0.875*asc*0.75);
605                         p[1].x = int(x);             p[1].y = int(y - 0.500*asc*0.75);
606                         p[2].x = int(x + wid*0.375); p[2].y = int(y - 0.125*asc*0.75);
607                         scr.drawLines(::getGC(gc_new_line), p, 3);
608                 
609                         p[0].x = int(x);             p[0].y = int(y - 0.500*asc*0.75);
610                         p[1].x = int(x + wid);       p[1].y = int(y - 0.500*asc*0.75);
611                         p[2].x = int(x + wid);       p[2].y = int(y - asc*0.75);
612                         scr.drawLines(::getGC(gc_new_line), p, 3);
613                 } else {
614                         p[0].x = int(x + wid*0.625); p[0].y = int(y - 0.875*asc*0.75);
615                         p[1].x = int(x + wid);       p[1].y = int(y - 0.500*asc*0.75);
616                         p[2].x = int(x + wid*0.625); p[2].y = int(y - 0.125*asc*0.75);
617                         scr.drawLines(::getGC(gc_new_line), p, 3);
618                 
619                         p[0].x = int(x + wid);       p[0].y = int(y - 0.500*asc*0.75);
620                         p[1].x = int(x);             p[1].y = int(y - 0.500*asc*0.75);
621                         p[2].x = int(x);             p[2].y = int(y - asc*0.75);
622                         scr.drawLines(::getGC(gc_new_line), p, 3);
623                 }
624                 x += wid;
625                 return;
626         }
627
628         LyXFont font = GetFont(row->par, pos);
629         LyXFont font2 = font;
630
631         if (c == LyXParagraph::META_FOOTNOTE
632             || c == LyXParagraph::META_MARGIN
633             || c == LyXParagraph::META_FIG
634             || c == LyXParagraph::META_TAB
635             || c == LyXParagraph::META_WIDE_FIG
636             || c == LyXParagraph::META_WIDE_TAB
637             || c == LyXParagraph::META_ALGORITHM) {
638                 string fs;
639                 switch (c) {
640                 case LyXParagraph::META_MARGIN:
641                         fs = "margin";
642                         // Draw a sign at the left margin! 
643                         scr.drawText(font, "!", 1, offset + row->baseline,
644                                      (LYX_PAPER_MARGIN - font.width('!'))/2);
645                         break;
646                 case LyXParagraph::META_FIG:
647                         fs = "fig";
648                         break;
649                 case LyXParagraph::META_TAB:
650                         fs = "tab";
651                         break;
652                 case LyXParagraph::META_ALGORITHM:
653                         fs = "alg";
654                         break;
655                 case LyXParagraph::META_WIDE_FIG:
656                         fs = "wide-fig";
657                         break;
658                 case LyXParagraph::META_WIDE_TAB:
659                         fs = "wide-tab";
660                         break;
661                 case LyXParagraph::META_FOOTNOTE:
662                         fs = "foot";
663                         break;
664                 }
665                 font.decSize();
666                 font.decSize();
667           
668                 // calculate the position of the footnotemark
669                 int y = (row->baseline - font2.maxAscent() 
670                          + font.maxAscent());
671
672 #ifdef USE_PAINTER
673                 font.setColor(LColor::footnote);
674 #else
675                 font.setColor(LyXFont::RED);
676 #endif
677
678                 float tmpx = x;
679
680                 // draw it and set new x position
681                 x += scr.drawString(font, fs, offset + y, int(x));
682
683                 scr.drawLine(gc_foot, offset + row->baseline,
684                              int(tmpx), int(x - tmpx));
685           
686                 ++vpos;
687                 return;
688         } else if (c == LyXParagraph::META_INSET) {
689                 Inset * tmpinset = row->par->GetInset(pos);
690                 if (tmpinset) 
691                         tmpinset->Draw(font, scr, offset + row->baseline, x);
692                 ++vpos;
693                 return;
694         }
695
696         /* usual characters, no insets */
697
698         // Collect character that we can draw in one command
699
700         // This is dirty, but fast. Notice that it will never be too small.
701         // For the record, I'll note that Microsoft Word has a limit
702         // of 768 here. We have none :-) (Asger)
703         // Ok. I am the first to admit that the use of std::string will be
704         // a tiny bit slower than using a POD char array. However, I claim
705         // that this slowdown is so small that it is close to inperceptive.
706         // So IMHO we should go with the easier and clearer implementation.
707         // And even if 1024 is a large number here it might overflow, string
708         // will only overflow if the machine is out of memory...
709         static string textstring;
710         textstring = c;
711         ++vpos;
712
713         LyXParagraph::size_type last = RowLast(row);
714         
715         while (vpos <= last &&
716                (pos = vis2log(vpos)) >= 0
717                && static_cast<unsigned char>(c = row->par->GetChar(pos)) > ' '
718                && font2 == GetFont(row->par, pos)) {
719                 textstring += c;
720                 ++vpos;
721         }
722         float tmpx = x;
723
724         // If monochrome and LaTeX mode, provide reverse background
725         if (mono_video &&
726             font.latex() == LyXFont::ON) {
727                 int a = font.maxAscent();
728                 int d = font.maxDescent();
729                 scr.fillRectangle(gc_copy, int(tmpx),
730                                   offset + row->baseline - a,
731                                   font.textWidth(textstring.c_str(),
732                                                  textstring.length()), a + d);
733         }
734
735         // Draw text and set the new x position
736         x += scr.drawText(font, textstring.c_str(), textstring.length(),
737                           offset + row->baseline, 
738                           int(x));
739         
740         // what about underbars?
741         if (font.underbar() == LyXFont::ON && font.latex() != LyXFont::ON) {
742                 scr.drawLine(gc_copy, offset + row->baseline + 2,
743                              int(tmpx), int(x - tmpx));
744         }
745
746         // If we want ulem.sty support, drawing
747         // routines should go here. (Asger)
748         // Why shouldn't LyXFont::drawText handle it internally?
749 }
750 #endif
751
752
753 // Returns the left beginning of the text. 
754 // This information cannot be taken from the layouts-objekt, because in 
755 // LaTeX the beginning of the text fits in some cases (for example sections)
756 // exactly the label-width.
757 int LyXText::LeftMargin(Row const * row) const
758 {
759         LyXLayout const & layout = textclasslist.Style(parameters->textclass,
760                                                        row->par->GetLayout());
761         
762         string parindent = layout.parindent; 
763         
764         /* table stuff -- begin */ 
765         if (row->par->table)
766                 parindent.clear();
767         /* table stuff -- end */
768         
769         int x = LYX_PAPER_MARGIN;
770         
771         x += textclasslist.TextClass(parameters->textclass)
772                 .defaultfont()
773                 .signedStringWidth(textclasslist
774                                    .TextClass(parameters->textclass)
775                                    .leftmargin());
776         
777         if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)  {
778                 LyXFont font(LyXFont::ALL_SANE);
779                 font.setSize(LyXFont::SIZE_SMALL);
780                 x += font.textWidth("Mwide-figM", 10) + LYX_PAPER_MARGIN/2;
781         }
782         
783         // this is the way, LyX handles the LaTeX-Environments.
784         // I have had this idea very late, so it seems to be a
785         // later added hack and this is true
786         if (!row->par->GetDepth()) {
787                 if (!row->par->GetLayout()) {
788                         // find the previous same level paragraph
789                         if (row->par->FirstPhysicalPar()->Previous()) {
790                                 LyXParagraph * newpar = row->par
791                                         ->DepthHook(row->par->GetDepth());
792                                 if (newpar &&
793                                     textclasslist.Style(parameters->textclass,
794                                                         newpar->GetLayout())
795                                     .nextnoindent)
796                                         parindent.clear();
797                         }
798                 }
799         } else {
800                 // find the next level paragraph
801                 
802                 LyXParagraph * newpar = row->par->DepthHook(row->par->GetDepth()-1);
803                 
804                 // make a corresponding row. Needed to call LeftMargin()
805                 
806                 // check wether it is a sufficent paragraph 
807                 if (newpar && newpar->footnoteflag == row->par->footnoteflag
808                     && textclasslist
809                         .Style(parameters->textclass, 
810                                newpar->GetLayout()).isEnvironment()) {
811                         Row dummyrow;
812                         dummyrow.par = newpar;
813                         dummyrow.pos = newpar->Last();
814                         x = LeftMargin(&dummyrow);
815                 } else {
816                         // this is no longer an error, because this function
817                         // is used to clear impossible depths after changing
818                         // a layout. Since there is always a redo,
819                         // LeftMargin() is always called
820                         row->par->FirstPhysicalPar()->depth = 0;
821                 }
822                 
823                 if (newpar && !row->par->GetLayout()) {
824                         if (newpar->FirstPhysicalPar()->noindent)
825                                 parindent.clear();
826                         else
827                                 parindent = textclasslist
828                                         .Style(parameters->textclass, 
829                                                newpar->GetLayout()).parindent;
830                 }
831                 
832         }
833         
834         LyXFont labelfont = GetFont(row->par, -2);
835         switch (layout.margintype) {
836         case MARGIN_DYNAMIC:
837                 if (!layout.leftmargin.empty()) {
838                         x += textclasslist
839                                 .TextClass(parameters->textclass)
840                                 .defaultfont()
841                                 .signedStringWidth(layout.leftmargin);
842                 }
843                 if (!row->par->GetLabestring().empty()) {
844                         x += labelfont.signedStringWidth(layout.labelindent);
845                         x += labelfont.stringWidth(row->par->GetLabestring());
846                         x += labelfont.stringWidth(layout.labelsep);
847                 }
848                 break;
849         case MARGIN_MANUAL:
850                 x += labelfont.signedStringWidth(layout.labelindent);
851                 if (row->pos >= BeginningOfMainBody(row->par)) {
852                         if (!row->par->GetLabelWidthString().empty()) {
853                                 x += labelfont
854                                         .stringWidth(row->par
855                                                      ->GetLabelWidthString());
856                                 x += labelfont.stringWidth(layout.labelsep);
857                         }
858                 }
859                 break;
860         case MARGIN_STATIC:
861                 x += textclasslist.TextClass(parameters->textclass)
862                         .defaultfont().signedStringWidth(layout.leftmargin) * 4
863                         / (row->par->GetDepth() + 4);
864                 break;
865         case MARGIN_FIRST_DYNAMIC:
866                 if (layout.labeltype == LABEL_MANUAL) {
867                         if (row->pos >= BeginningOfMainBody(row->par)) {
868                                 x += labelfont
869                                         .signedStringWidth(layout.leftmargin);
870                         } else {
871                                 x += labelfont
872                                         .signedStringWidth(layout.labelindent);
873                         }
874                 } else if (row->pos
875                            // Special case to fix problems with
876                            // theorems (JMarc)
877                            || (layout.labeltype == LABEL_STATIC
878                                && layout.latextype == LATEX_ENVIRONMENT
879                                && ! row->par->IsFirstInSequence())) {
880                         x += labelfont.signedStringWidth(layout.leftmargin);
881                 } else if (layout.labeltype != LABEL_TOP_ENVIRONMENT
882                            && layout.labeltype != LABEL_BIBLIO
883                            && layout.labeltype !=
884                            LABEL_CENTERED_TOP_ENVIRONMENT) {
885                         x += labelfont.signedStringWidth(layout.labelindent);
886                         x += labelfont.stringWidth(layout.labelsep);
887                         x += labelfont.stringWidth(row->par->GetLabestring());
888                 } 
889                 break;
890                 
891         case MARGIN_RIGHT_ADDRESS_BOX:
892         {
893                 // ok, a terrible hack. The left margin depends on the widest
894                 // row in this paragraph. Do not care about footnotes, they
895                 // are *NOT* allowed in the LaTeX realisation of this layout.
896                 
897                 // find the first row of this paragraph
898                 Row const * tmprow = row;
899                 while (tmprow->previous && tmprow->previous->par == row->par)
900                         tmprow = tmprow->previous;
901                 
902                 int minfill = tmprow->fill;
903                 while (tmprow->next && tmprow->next->par == row->par) {
904                         tmprow = tmprow->next;
905                         if (tmprow->fill < minfill)
906                                 minfill = tmprow->fill;
907                 }
908                 
909                 x += textclasslist.TextClass(parameters->textclass)
910                         .defaultfont().signedStringWidth(layout.leftmargin);
911                 x += minfill;
912         }
913         break;
914         }
915         if (row->par->pextra_type == LyXParagraph::PEXTRA_INDENT) {
916                 if (!row->par->pextra_widthp.empty()) {
917                         x += paperwidth *
918                                 atoi(row->par->pextra_widthp.c_str()) / 100;
919                 } else if (!row->par->pextra_width.empty()) {
920                         int xx = VSpace(row->par->pextra_width).inPixels();
921                         
922                         if (xx > paperwidth)
923                                 xx = paperwidth * 80 / 100;
924                         x += xx;
925                 } else { // should not happen
926                         LyXFont font(LyXFont::ALL_SANE);
927                         x += font.stringWidth("XXXXXX");
928                 }
929         }
930         
931         int align;
932         if (row->par->FirstPhysicalPar()->align == LYX_ALIGN_LAYOUT)
933                 align = layout.align;
934         else
935                 align = row->par->FirstPhysicalPar()->align;
936         
937         // set the correct parindent
938         if (row->pos == 0) {
939                 if ((layout.labeltype == LABEL_NO_LABEL 
940                      || layout.labeltype == LABEL_TOP_ENVIRONMENT 
941                      || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT
942                      || (layout.labeltype == LABEL_STATIC
943                          && layout.latextype == LATEX_ENVIRONMENT
944                          && ! row->par->IsFirstInSequence()))
945                     && row->par == row->par->FirstPhysicalPar()
946                     && align == LYX_ALIGN_BLOCK
947                     && !row->par->noindent
948                     && (row->par->layout ||
949                         parameters->paragraph_separation ==
950                         BufferParams::PARSEP_INDENT))
951                         x += textclasslist.TextClass(parameters->textclass)
952                                 .defaultfont().signedStringWidth(parindent);
953                 else 
954                         if (layout.labeltype == LABEL_BIBLIO) {
955                                 // ale970405 Right width for bibitems
956 #ifdef USE_PAINTER
957                                 x += bibitemMaxWidth(owner_->painter(),
958                                                      textclasslist
959                                                      .TextClass(parameters
960                                                                 ->textclass)
961                                                      .defaultfont());
962 #else
963                                 x += bibitemMaxWidth(textclasslist
964                                                      .TextClass(parameters
965                                                                 ->textclass)
966                                                      .defaultfont());
967 #endif
968                         }
969         }
970         
971         return x;
972 }
973     
974    
975 int LyXText::RightMargin(Row const * row) const
976 {
977         LyXLayout const & layout =
978                 textclasslist.Style(parameters->textclass,
979                                     row->par->GetLayout());
980         
981         int x = LYX_PAPER_MARGIN
982                 + textclasslist
983                 .TextClass(parameters->textclass)
984                 .defaultfont()
985                 .signedStringWidth(textclasslist
986                                    .TextClass(parameters->textclass)
987                                    .rightmargin());
988         
989         if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)  {
990                 x += LYX_PAPER_MARGIN / 2;
991         }
992         
993         // this is the way, LyX handles the LaTeX-Environments.
994         // I have had this idea very late, so it seems to be a
995         // later added hack and this is true
996         if (row->par->GetDepth()) {
997                 // find the next level paragraph
998                 
999                 LyXParagraph * newpar = row->par;
1000                 
1001                 do {
1002                         newpar = newpar->FirstPhysicalPar()->Previous();
1003                         if (newpar) 
1004                                 newpar = newpar->FirstPhysicalPar();
1005                 } while (newpar && newpar->GetDepth() >= row->par->GetDepth()
1006                          && newpar->footnoteflag == row->par->footnoteflag);
1007                 
1008                 // make a corresponding row. Needed to call LeftMargin()
1009                 
1010                 // check wether it is a sufficent paragraph
1011                 if (newpar && newpar->footnoteflag == row->par->footnoteflag
1012                     && textclasslist.Style(parameters->textclass,
1013                                            newpar->GetLayout())
1014                        .isEnvironment()) {
1015                         Row dummyrow;
1016                         dummyrow.par = newpar;
1017                         dummyrow.pos = 0;
1018                         x = RightMargin(&dummyrow);
1019                 } else {
1020                         // this is no longer an error, because this function
1021                         // is used to clear impossible depths after changing
1022                         // a layout. Since there is always a redo,
1023                         // LeftMargin() is always called
1024                         row->par->FirstPhysicalPar()->depth = 0;
1025                 }
1026         }
1027         
1028         //lyxerr << "rightmargin: " << layout->rightmargin << endl;
1029         x += textclasslist.TextClass(parameters->textclass)
1030                 .defaultfont()
1031                 .signedStringWidth(layout.rightmargin) * 4
1032               / (row->par->GetDepth() + 4);
1033         return x;
1034 }
1035
1036
1037 int LyXText::LabelEnd (Row const * row) const
1038 {
1039         if (textclasslist.Style(parameters->textclass,
1040                                 row->par->GetLayout()).margintype
1041             == MARGIN_MANUAL) {
1042                 Row tmprow;
1043                 tmprow = *row;
1044                 tmprow.pos = row->par->Last();
1045                 return LeftMargin(&tmprow);  /* just the beginning 
1046                                                 of the main body */
1047         } else
1048                 return 0;  /* LabelEnd is only needed, if the  
1049                               layout fills a flushleft
1050                               label. */
1051 }
1052
1053
1054 /* table stuff -- begin*/
1055 int LyXText::NumberOfCell(LyXParagraph * par,
1056                           LyXParagraph::size_type pos) const
1057 {
1058    int cell = 0;
1059    LyXParagraph::size_type tmp_pos = 0;
1060    while (tmp_pos < pos) {
1061       if (par->IsNewline(tmp_pos))
1062          ++cell;
1063       ++tmp_pos;
1064    }
1065    return cell;
1066 }
1067
1068
1069 int LyXText::WidthOfCell(LyXParagraph * par,
1070                          LyXParagraph::size_type & pos) const
1071 {
1072    int w = 0;
1073    while (pos < par->Last() && !par->IsNewline(pos)) {
1074       w += SingleWidth(par, pos);
1075       ++pos;
1076    }
1077    if (par->IsNewline(pos))
1078       ++pos;
1079    return w;
1080 }
1081
1082
1083 bool LyXText::HitInTable(Row * row, int x) const
1084 {
1085         float tmpx;
1086         float fill_separator, fill_hfill, fill_label_hfill;
1087         if (!row->par->table)
1088                 return false;
1089         PrepareToPrint(row, tmpx, fill_separator,
1090                        fill_hfill, fill_label_hfill, false);
1091         return (x > tmpx && x < tmpx + row->par->table->WidthOfTable());
1092 }
1093
1094
1095 bool LyXText::MouseHitInTable(int x, long y) const
1096 {
1097         Row * row = GetRowNearY(y);
1098         return HitInTable(row, x);
1099 }
1100
1101
1102 /* table stuff -- end*/
1103
1104
1105 // get the next breakpoint in a given paragraph
1106 LyXParagraph::size_type
1107 LyXText::NextBreakPoint(Row const * row, int width) const
1108 {
1109         LyXParagraph * par = row->par;
1110         LyXParagraph::size_type pos = row->pos;
1111         
1112         /* table stuff -- begin*/ 
1113         if (par->table) {
1114                 while (pos < par->size()
1115                        && (!par->IsNewline(pos) 
1116                            || !par->table->IsFirstCell(NumberOfCell(par, pos+1)))) {
1117                         if (par->GetChar(pos) == LyXParagraph::META_INSET &&
1118                             par->GetInset(pos) && par->GetInset(pos)->display()){
1119                                 par->GetInset(pos)->display(false);
1120                         }
1121                         ++pos;
1122                 }
1123                 return pos;
1124         }
1125         /* table stuff -- end*/ 
1126         
1127         // position of the last possible breakpoint 
1128         // -1 isn't a suitable value, but a flag
1129         LyXParagraph::size_type last_separator = -1;
1130         int left_margin = LabelEnd(row);
1131         width -= RightMargin(row);
1132         
1133         LyXParagraph::size_type main_body = BeginningOfMainBody(par);
1134         LyXLayout const & layout =
1135                 textclasslist.Style(parameters->textclass, par->GetLayout());
1136         LyXParagraph::size_type i = pos;
1137
1138         if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX) {
1139                 /* special code for right address boxes, only newlines count */
1140                 while (i < par->Last()) {
1141                         if (par->IsNewline(i)) {
1142                                 last_separator = i;
1143                                 i = par->Last() - 1; // this means break
1144                                 //x = width;
1145                         } else if (par->GetChar(i) == LyXParagraph::META_INSET &&
1146                                    par->GetInset(i) && par->GetInset(i)->display()){
1147                                 par->GetInset(i)->display(false);
1148                         }
1149                         ++i;
1150                 }
1151         } else {
1152                 // Last position is an invariant
1153                 LyXParagraph::size_type const last = 
1154                         par->Last();
1155                 // this is the usual handling
1156                 int x = LeftMargin(row);
1157                 while (x < width && i < last) {
1158                         char c = par->GetChar(i);
1159                         if (IsNewlineChar(c)) {
1160                                 last_separator = i;
1161                                 x = width; // this means break
1162                         } else if (c == LyXParagraph::META_INSET &&
1163                                    par->GetInset(i) && par->GetInset(i)->display()){
1164                                 // check wether a Display() inset is
1165                                 // valid here. if not, change it to
1166                                 // non-display
1167                                 if (layout.isCommand()
1168                                     || (layout.labeltype == LABEL_MANUAL
1169                                         && i < BeginningOfMainBody(par))){
1170                                         // display istn't allowd
1171                                         par->GetInset(i)->display(false);
1172                                         x += SingleWidth(par, i, c);
1173                                 } else {
1174                                         // inset is display. So break the line here
1175                                         if (i == pos){
1176                                                 if (pos < last-1) {
1177                                                         last_separator = i;
1178                                                         if (IsLineSeparatorChar(par->GetChar(i+1)))
1179                                                                 ++last_separator;
1180                                                 } else
1181                                                         last_separator = last; // to avoid extra rows
1182                                         } else
1183                                                 last_separator = i - 1;
1184                                         x = width;  // this means break
1185                                 }
1186                         } else  {
1187                                 if (IsLineSeparatorChar(c))
1188                                         last_separator = i;
1189                                 x += SingleWidth(par, i, c);
1190                         }
1191                         ++i;
1192                         if (i == main_body) {
1193                                 x += GetFont(par, -2).stringWidth(layout.labelsep);
1194                                 if (par->IsLineSeparator(i - 1))
1195                                         x-= SingleWidth(par, i - 1);
1196                                 if (x < left_margin)
1197                                         x = left_margin;
1198                         }
1199                 }
1200                 // end of paragraph is always a suitable separator
1201                 if (i == last && x < width)
1202                         last_separator = i;
1203         }
1204         
1205         // well, if last_separator is still 0, the line isn't breakable. 
1206         // don't care and cut simply at the end
1207         if (last_separator < 0) {
1208                 last_separator = i;
1209         }
1210         
1211         // manual labels cannot be broken in LaTeX, do not care
1212         if (main_body && last_separator < main_body)
1213                 last_separator = main_body - 1;
1214         
1215         return last_separator;
1216 }
1217
1218
1219 // returns the minimum space a row needs on the screen in pixel
1220 int LyXText::Fill(Row const * row, int paper_width) const
1221 {
1222         int w, fill;
1223         // get the pure distance
1224         LyXParagraph::size_type last = RowLast(row);
1225         /* table stuff -- begin */
1226         if (row->par->table) {
1227                 // for tables FILL does calculate the widthes of each cell in 
1228                 // the row
1229                 LyXParagraph::size_type pos = row->pos;
1230                 int cell = NumberOfCell(row->par, pos);
1231                 w = 0;
1232                 do {
1233                         row->par->table->SetWidthOfCell(cell,
1234                                                         WidthOfCell(row->par,
1235                                                                     pos));
1236                         ++cell;
1237                 } while (pos <= last && !row->par->table->IsFirstCell(cell));
1238                 // don't forget the very last table cell without characters
1239                 if (cell == row->par->table->GetNumberOfCells() - 1)
1240                         row->par->table->SetWidthOfCell(cell,
1241                                                         WidthOfCell(row->par,
1242                                                                     pos));
1243                 
1244                 return 0; /* width of table cannot be returned since
1245                            * we cannot guarantee its correct value at
1246                            * this point. */ 
1247         }
1248         /* table stuff -- end*/ 
1249         
1250         int left_margin = LabelEnd(row);
1251         
1252         // if the row ends with newline, this newline will not be relevant
1253         //if (last >= 0 && row->par->IsNewline(last))
1254         //      --last;
1255         
1256         // if the row ends with a space, this space will not be relevant
1257         if (last >= 0 && row->par->IsLineSeparator(last))
1258                 --last;
1259         
1260         // special handling of the right address boxes
1261         if (textclasslist.Style(parameters->textclass,
1262                                 row->par->GetLayout()).margintype
1263             == MARGIN_RIGHT_ADDRESS_BOX) {
1264                 int tmpfill = row->fill;
1265                 row->fill = 0; // the minfill in MarginLeft()
1266                 w = LeftMargin(row);
1267                 row->fill = tmpfill;
1268         } else
1269                 w = LeftMargin(row);
1270         
1271         LyXLayout const & layout = textclasslist.Style(parameters->textclass,
1272                                                        row->par->GetLayout());
1273         LyXParagraph::size_type main_body = 
1274                 BeginningOfMainBody(row->par);
1275         LyXParagraph::size_type i = row->pos;
1276
1277         while (i <= last) {
1278                 if (main_body > 0 && i == main_body) {
1279                         w += GetFont(row->par, -2).
1280                                 stringWidth(layout.labelsep);
1281                         if (row->par->IsLineSeparator(i - 1))
1282                                 w -= SingleWidth(row->par, i - 1);
1283                         if (w < left_margin)
1284                                 w = left_margin;
1285                 }
1286                 w += SingleWidth(row->par, i);
1287                 ++i;
1288         }
1289         if (main_body > 0 && main_body > last) {
1290                 w += GetFont(row->par, -2).stringWidth(layout.labelsep);
1291                 if (last >= 0 && row->par->IsLineSeparator(last))
1292                         w -= SingleWidth(row->par, last);
1293                 if (w < left_margin)
1294                         w = left_margin;
1295         }
1296         
1297         fill = paper_width - w - RightMargin(row);
1298         return fill;
1299 }
1300
1301
1302 // returns the minimum space a manual label needs on the screen in pixel
1303 int LyXText::LabelFill(Row const * row) const
1304 {
1305         LyXParagraph::size_type last = BeginningOfMainBody(row->par) - 1;
1306         // -1 because a label ends either with a space that is in the label, 
1307         // or with the beginning of a footnote that is outside the label.
1308
1309         // I don't understand this code in depth, but sometimes "last" is
1310         // less than 0 and this causes a crash. This fix seems to work
1311         // correctly, but I bet the real error is elsewhere.  The bug is
1312         // triggered when you have an open footnote in a paragraph
1313         // environment with a manual label. (Asger)
1314         if (last < 0) last = 0;
1315         
1316         if (row->par->IsLineSeparator(last)) /* a sepearator at this end 
1317                                                 does not count */
1318                 --last;
1319         
1320         int w = 0;
1321         int i = row->pos;
1322         while (i <= last) {
1323                 w += SingleWidth(row->par, i);
1324                 ++i;
1325         }
1326         
1327         int fill = 0;
1328         if (!row->par->labelwidthstring.empty()) {
1329                 fill = GetFont(row->par, -2)
1330                         .stringWidth(row->par->labelwidthstring) - w;
1331         }
1332         
1333         if (fill < 0)
1334                 fill = 0;
1335         
1336         return fill;
1337 }
1338
1339
1340 // returns the number of separators in the specified row. The separator 
1341 // on the very last column doesnt count
1342 int LyXText::NumberOfSeparators(Row const * row) const
1343 {
1344         int last = RowLast(row);
1345         //int p = row->pos;
1346         //int main_body = BeginningOfMainBody(row->par);
1347         //if (p < main_body)
1348         //      p = main_body;
1349         // I think this is equivalent to the above. (Lgb)
1350         int p = max(row->pos, BeginningOfMainBody(row->par));
1351         int n = 0;
1352         for (; p < last; ++p) {
1353                 if (row->par->IsSeparator(p)) {
1354                         ++n;
1355                 }
1356         }
1357         return n;
1358 }
1359
1360
1361 // returns the number of hfills in the specified row. The LyX-Hfill is
1362 // a LaTeX \hfill so that the hfills at the beginning and at the end were 
1363 // ignored. This is *MUCH* more usefull than not to ignore!
1364 int LyXText::NumberOfHfills(Row const * row) const
1365 {
1366         int last = RowLast(row);
1367         int first = row->pos;
1368         if (first) { /* hfill *DO* count at the beginning 
1369                       * of paragraphs! */
1370                 while(first <= last && row->par->IsHfill(first))
1371                         ++first;
1372         }
1373
1374         //int main_body = BeginningOfMainBody(row->par);
1375         //if (first < main_body)
1376         //      first = main_body;
1377         // I think this is equivalent to the above. (Lgb)
1378         first = max(first, BeginningOfMainBody(row->par));
1379         int n = 0;
1380         for (int p = first; p <= last; ++p) { // last, because the end is ignored!
1381                 if (row->par->IsHfill(p)) {
1382                         ++n;
1383                 }
1384         }
1385         return n;
1386 }
1387
1388
1389 // like NumberOfHfills, but only those in the manual label!
1390 int LyXText::NumberOfLabelHfills(Row const * row) const
1391 {
1392         LyXParagraph::size_type last = RowLast(row);
1393         LyXParagraph::size_type first = row->pos;
1394         if (first) { /* hfill *DO* count at the beginning 
1395                       * of paragraphs! */
1396                 while(first < last && row->par->IsHfill(first))
1397                         ++first;
1398         }
1399         //LyXParagraph::size_type main_body = 
1400         //BeginningOfMainBody(row->par);
1401         //if (last > main_body)
1402         //last = main_body;
1403         // I think this is eqvialent to the above. (Lgb)
1404         last = min(last, BeginningOfMainBody(row->par));
1405         int n = 0;
1406         for (LyXParagraph::size_type p = first;
1407              p < last; ++p) {  // last, because the end is ignored!
1408                 if (row->par->IsHfill(p)) {
1409                         ++n;
1410                 }
1411         }
1412         return n;
1413 }
1414
1415
1416 // returns true, if a expansion is needed.
1417 // Rules are given by LaTeX
1418 bool LyXText::HfillExpansion(Row const * row_ptr,
1419                              LyXParagraph::size_type pos) const
1420 {
1421         // by the way, is it a hfill?
1422         if (!row_ptr->par->IsHfill(pos))
1423                 return false;
1424         
1425         // at the end of a row it does not count
1426         if (pos >= RowLast(row_ptr))
1427                 return false;
1428         
1429         // at the beginning of a row it does not count, if it is not 
1430         // the first row of a paragaph
1431         if (!row_ptr->pos)
1432                 return true;
1433         
1434         // in some labels  it does not count
1435         if (textclasslist.Style(parameters->textclass,
1436                                 row_ptr->par->GetLayout()).margintype
1437             != MARGIN_MANUAL
1438             && pos < BeginningOfMainBody(row_ptr->par))
1439                 return false; 
1440         
1441         // if there is anything between the first char of the row and
1442         // the sepcified position that is not a newline and not a hfill,
1443         // the hfill will count, otherwise not
1444         LyXParagraph::size_type i = row_ptr->pos;
1445         while (i < pos && (row_ptr->par->IsNewline(i)
1446                            || row_ptr->par->IsHfill(i)))
1447                 ++i;
1448         
1449         return i != pos;
1450 }
1451
1452
1453 #ifdef USE_PAINTER
1454 void LyXText::SetHeightOfRow(Row * row_ptr) const
1455 {
1456     /* get the maximum ascent and the maximum descent */
1457    int asc, desc, pos;
1458    float layoutasc = 0;
1459    float layoutdesc = 0;
1460    float tmptop = 0;
1461    LyXFont tmpfont;
1462    Inset * tmpinset;
1463
1464    /* this must not happen before the currentrow for clear reasons.
1465       so the trick is just to set the current row onto this row */
1466    long unused_y;
1467    GetRow(row_ptr->par, row_ptr->pos, unused_y);
1468
1469    /* ok , let us initialize the maxasc and maxdesc value. 
1470     * This depends in LaTeX of the font of the last character
1471     * in the paragraph. The hack below is necessary because
1472     * of the possibility of open footnotes */
1473
1474    /* Correction: only the fontsize count. The other properties
1475       are taken from the layoutfont. Nicer on the screen :) */
1476    
1477    LyXParagraph * par = row_ptr->par->LastPhysicalPar();
1478    LyXParagraph * firstpar = row_ptr->par->FirstPhysicalPar();
1479    
1480    LyXLayout const & layout = textclasslist.Style(parameters->textclass,
1481                                                   firstpar->GetLayout());
1482    
1483    LyXFont font = GetFont(par, par->Last()-1);
1484    LyXFont::FONT_SIZE size = font.size();
1485    font = GetFont(par, -1);
1486    font.setSize(size);
1487
1488    LyXFont labelfont = GetFont(par, -2);
1489
1490    int maxasc = int(font.maxAscent() *
1491                    layout.spacing.getValue() *
1492                    parameters->spacing.getValue());
1493    int maxdesc = int(font.maxDescent() *
1494                     layout.spacing.getValue() *
1495                     parameters->spacing.getValue());
1496
1497    int pos_end = RowLast(row_ptr);
1498    
1499    int labeladdon = 0;
1500
1501    // Check if any insets are larger
1502    for (pos = row_ptr->pos; pos <= pos_end; ++pos) {
1503       if (row_ptr->par->GetChar(pos) == LyXParagraph::META_INSET) {
1504          tmpfont = GetFont(row_ptr->par, pos);
1505          tmpinset = row_ptr->par->GetInset(pos);
1506          if (tmpinset) {
1507             asc = tmpinset->ascent(owner_->painter(), tmpfont);
1508             desc = tmpinset->descent(owner_->painter(), tmpfont);
1509             if (asc > maxasc) 
1510               maxasc = asc;
1511             if (desc > maxdesc)
1512               maxdesc = desc;
1513          }
1514       }
1515    }
1516
1517    // Check if any custom fonts are larger (Asger)
1518    // This is not completely correct, but we can live with the small,
1519    // cosmetic error for now.
1520    LyXFont::FONT_SIZE maxsize = row_ptr->par->HighestFontInRange(row_ptr->pos,
1521                                                                  pos_end);
1522    if (maxsize > font.size()) {
1523         font.setSize(maxsize);
1524
1525         asc = font.maxAscent();
1526         desc = font.maxDescent();
1527         if (asc > maxasc) 
1528                 maxasc = asc;
1529         if (desc > maxdesc)
1530                 maxdesc = desc;
1531    }
1532
1533    /* table stuff -- begin*/
1534    if (row_ptr->par->table){
1535      // stretch the rows a bit
1536       maxasc += 1;
1537       maxdesc += 1;
1538    }
1539    /* table stuff -- end*/
1540
1541    // This is nicer with box insets:
1542    ++maxasc;
1543    ++maxdesc;
1544
1545    row_ptr->ascent_of_text = maxasc;
1546    
1547    /* is it a top line? */ 
1548    if (row_ptr->pos == 0
1549        && row_ptr->par == firstpar) {
1550       
1551       /* some parksips VERY EASY IMPLEMENTATION */ 
1552       if (parameters->paragraph_separation == BufferParams::PARSEP_SKIP) {
1553          if (layout.isParagraph()
1554              && firstpar->GetDepth() == 0
1555              && firstpar->Previous())
1556             maxasc += parameters->getDefSkip().inPixels();
1557          else if (firstpar->Previous()
1558                   && textclasslist.Style(parameters->textclass,
1559                            firstpar->Previous()->GetLayout()).isParagraph()
1560                   && firstpar->Previous()->GetDepth() == 0)
1561            // is it right to use defskip here too? (AS)
1562            maxasc += parameters->getDefSkip().inPixels();
1563       }
1564       
1565       /* the paper margins */ 
1566       if (!row_ptr->par->previous)
1567          maxasc += LYX_PAPER_MARGIN;
1568       
1569       /* add the vertical spaces, that the user added */
1570       if (firstpar->added_space_top.kind() != VSpace::NONE)
1571          maxasc += int(firstpar->added_space_top.inPixels());
1572       
1573       /* do not forget the DTP-lines! 
1574        * there height depends on the font of the nearest character */
1575       if (firstpar->line_top)
1576          maxasc += 2 * GetFont(firstpar, 0).ascent('x');
1577       
1578       /* and now the pagebreaks */ 
1579       if (firstpar->pagebreak_top)
1580          maxasc += 3 * DefaultHeight();
1581       
1582       /*  this is special code for the chapter, since the label of this
1583        * layout is printed in an extra row */ 
1584       if (layout.labeltype == LABEL_COUNTER_CHAPTER
1585           && parameters->secnumdepth>= 0) {
1586               labeladdon = int(labelfont.maxDescent() *
1587                                   layout.spacing.getValue() *
1588                                   parameters->spacing.getValue())
1589                       + int(labelfont.maxAscent() *
1590                                layout.spacing.getValue() *
1591                                parameters->spacing.getValue());
1592       }
1593       
1594       /* special code for the top label */ 
1595       if ((layout.labeltype == LABEL_TOP_ENVIRONMENT
1596            || layout.labeltype == LABEL_BIBLIO
1597            || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)
1598           && row_ptr->par->IsFirstInSequence()
1599           && !row_ptr->par->GetLabestring().empty()) {
1600          labeladdon = int(
1601                  (labelfont.maxAscent() *
1602                   layout.spacing.getValue() *
1603                   parameters->spacing.getValue())
1604                  +(labelfont.maxDescent() *
1605                    layout.spacing.getValue() *
1606                    parameters->spacing.getValue())
1607                  + layout.topsep * DefaultHeight()
1608                  + layout.labelbottomsep *  DefaultHeight());
1609       }
1610    
1611       /* and now the layout spaces, for example before and after a section, 
1612        * or between the items of a itemize or enumerate environment */ 
1613       
1614       if (!firstpar->pagebreak_top) {
1615          LyXParagraph * prev = row_ptr->par->Previous();
1616          if (prev)
1617             prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth());
1618          if (prev && prev->GetLayout() == firstpar->GetLayout()
1619              && prev->GetDepth() == firstpar->GetDepth()
1620              && prev->GetLabelWidthString() == firstpar->GetLabelWidthString())
1621            {
1622               layoutasc = (layout.itemsep * DefaultHeight());
1623            }
1624          else if (row_ptr->previous) {
1625             tmptop = layout.topsep;
1626             
1627             if (row_ptr->previous->par->GetDepth() >= row_ptr->par->GetDepth())
1628                tmptop-= textclasslist.Style(parameters->textclass, row_ptr->previous->par->GetLayout()).bottomsep;
1629             
1630             if (tmptop > 0)
1631                layoutasc = (tmptop * DefaultHeight());
1632          }
1633          else if (row_ptr->par->line_top){
1634             tmptop = layout.topsep;
1635             
1636             if (tmptop > 0)
1637                layoutasc = (tmptop * DefaultHeight());
1638          }
1639          
1640          prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth()-1);
1641          if (prev)  {
1642             maxasc += int(textclasslist.Style(parameters->textclass,
1643                                          prev->GetLayout()).parsep * DefaultHeight());
1644          }
1645          else {
1646                 if (firstpar->Previous()
1647                     && firstpar->Previous()->GetDepth() == 0
1648                     && firstpar->Previous()->GetLayout() != firstpar->GetLayout()) {
1649                    /* avoid parsep */ 
1650                 }
1651             else if (firstpar->Previous()){
1652                maxasc += int(layout.parsep * DefaultHeight());
1653             }
1654          }
1655       }
1656    }
1657    
1658    /* is it a bottom line? */ 
1659    if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
1660        && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {     
1661           
1662           /* the paper margins */ 
1663           if (!par->next)
1664             maxdesc += LYX_PAPER_MARGIN;
1665         
1666           /* add the vertical spaces, that the user added */
1667           if (firstpar->added_space_bottom.kind() != VSpace::NONE)
1668             maxdesc += int(firstpar->added_space_bottom.inPixels());
1669           
1670           /* do not forget the DTP-lines! 
1671            * there height depends on the font of the nearest character */
1672           if (firstpar->line_bottom)
1673             maxdesc += 2 * (GetFont(par, par->Last()-1).ascent('x'));
1674           
1675           /* and now the pagebreaks */
1676           if (firstpar->pagebreak_bottom)
1677             maxdesc += 3 * DefaultHeight();
1678           
1679           /* and now the layout spaces, for example before and after a section, 
1680            * or between the items of a itemize or enumerate environment */
1681           if (!firstpar->pagebreak_bottom && row_ptr->par->Next()) {
1682              LyXParagraph * nextpar = row_ptr->par->Next();
1683              LyXParagraph * comparepar = row_ptr->par;
1684              float usual = 0;
1685              float  unusual = 0;
1686              
1687              if (comparepar->GetDepth() > nextpar->GetDepth()) {
1688                 usual = (textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1689                 comparepar = comparepar->DepthHook(nextpar->GetDepth());
1690                 if (comparepar->GetLayout()!= nextpar->GetLayout()
1691                     || nextpar->GetLabelWidthString() != 
1692                         comparepar->GetLabelWidthString())
1693                   unusual = (textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1694                 
1695                 if (unusual > usual)
1696                   layoutdesc = unusual;
1697                 else
1698                   layoutdesc = usual;
1699              }
1700              else if (comparepar->GetDepth() ==  nextpar->GetDepth()) {
1701                 
1702                 if (comparepar->GetLayout()!= nextpar->GetLayout()
1703                     || nextpar->GetLabelWidthString() != 
1704                         comparepar->GetLabelWidthString())
1705                   layoutdesc = int(textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1706              }
1707           }
1708        }
1709    
1710    /* incalculate the layout spaces */ 
1711    maxasc += int(layoutasc * 2 / (2 + firstpar->GetDepth()));
1712    maxdesc += int(layoutdesc * 2 / (2 + firstpar->GetDepth()));
1713
1714    /* table stuff -- begin*/
1715    if (row_ptr->par->table){
1716       maxasc += row_ptr->par->table->
1717         AdditionalHeight(NumberOfCell(row_ptr->par, row_ptr->pos));
1718    }
1719    /* table stuff -- end*/
1720    
1721    /* calculate the new height of the text */ 
1722    height -= row_ptr->height;
1723    
1724    row_ptr->height = maxasc + maxdesc + labeladdon;
1725    row_ptr->baseline = maxasc + labeladdon;
1726    
1727    height += row_ptr->height;
1728 }
1729 #else
1730 void LyXText::SetHeightOfRow(Row * row_ptr) const
1731 {
1732     /* get the maximum ascent and the maximum descent */
1733    int asc, maxasc, desc, maxdesc, pos_end, pos, labeladdon;
1734    float layoutasc = 0;
1735    float layoutdesc = 0;
1736    float tmptop = 0;
1737    LyXFont tmpfont;
1738    Inset * tmpinset;
1739
1740    /* this must not happen before the currentrow for clear reasons.
1741       so the trick is just to set the current row onto this row */
1742    long unused_y;
1743    GetRow(row_ptr->par, row_ptr->pos, unused_y);
1744
1745    /* ok , let us initialize the maxasc and maxdesc value. 
1746     * This depends in LaTeX of the font of the last character
1747     * in the paragraph. The hack below is necessary because
1748     * of the possibility of open footnotes */
1749
1750    /* Correction: only the fontsize count. The other properties
1751       are taken from the layoutfont. Nicer on the screen :) */
1752    
1753    LyXParagraph * par = row_ptr->par->LastPhysicalPar();
1754    LyXParagraph * firstpar = row_ptr->par->FirstPhysicalPar();
1755    
1756    LyXLayout const & layout = textclasslist.Style(parameters->textclass, firstpar->GetLayout());
1757    
1758    LyXFont font = GetFont(par, par->Last()-1);
1759    LyXFont::FONT_SIZE size = font.size();
1760    font = GetFont(par, -1);
1761    font.setSize(size);
1762
1763    LyXFont labelfont = GetFont(par, -2);
1764
1765    maxasc = int(font.maxAscent() *
1766                    layout.spacing.getValue() *
1767                    parameters->spacing.getValue());
1768    maxdesc = int(font.maxDescent() *
1769                     layout.spacing.getValue() *
1770                     parameters->spacing.getValue());
1771
1772    pos_end = RowLast(row_ptr);
1773    
1774    labeladdon = 0;
1775
1776    // Check if any insets are larger
1777    for (pos = row_ptr->pos; pos <= pos_end; ++pos) {
1778       if (row_ptr->par->GetChar(pos) == LyXParagraph::META_INSET) {
1779          tmpfont = GetFont(row_ptr->par, pos);
1780          tmpinset = row_ptr->par->GetInset(pos);
1781          if (tmpinset) {
1782             asc = tmpinset->Ascent(tmpfont);
1783             desc = tmpinset->Descent(tmpfont);
1784             if (asc > maxasc) 
1785               maxasc = asc;
1786             if (desc > maxdesc)
1787               maxdesc = desc;
1788          }
1789       }
1790    }
1791
1792    // Check if any custom fonts are larger (Asger)
1793    // This is not completely correct, but we can live with the small,
1794    // cosmetic error for now.
1795    LyXFont::FONT_SIZE maxsize = row_ptr->par->HighestFontInRange(row_ptr->pos,
1796                                                                  pos_end);
1797    if (maxsize > font.size()) {
1798         font.setSize(maxsize);
1799
1800         asc = font.maxAscent();
1801         desc = font.maxDescent();
1802         if (asc > maxasc) 
1803                 maxasc = asc;
1804         if (desc > maxdesc)
1805                 maxdesc = desc;
1806    }
1807
1808    /* table stuff -- begin*/
1809    if (row_ptr->par->table){
1810      // stretch the rows a bit
1811       maxasc += 1;
1812       maxdesc += 1;
1813    }
1814    /* table stuff -- end*/
1815
1816    // This is nicer with box insets:
1817    ++maxasc;
1818    ++maxdesc;
1819
1820    row_ptr->ascent_of_text = maxasc;
1821    
1822    /* is it a top line? */ 
1823    if (row_ptr->pos == 0
1824        && row_ptr->par == firstpar) {
1825       
1826       /* some parksips VERY EASY IMPLEMENTATION */ 
1827       if (parameters->paragraph_separation == BufferParams::PARSEP_SKIP) {
1828          if (layout.isParagraph()
1829              && firstpar->GetDepth() == 0
1830              && firstpar->Previous())
1831             maxasc += parameters->getDefSkip().inPixels();
1832          else if (firstpar->Previous()
1833                   && textclasslist.Style(parameters->textclass,
1834                            firstpar->Previous()->GetLayout()).isParagraph()
1835                   && firstpar->Previous()->GetDepth() == 0)
1836            // is it right to use defskip here too? (AS)
1837            maxasc += parameters->getDefSkip().inPixels();
1838       }
1839       
1840       /* the paper margins */ 
1841       if (!row_ptr->par->previous)
1842          maxasc += LYX_PAPER_MARGIN;
1843       
1844       /* add the vertical spaces, that the user added */
1845       if (firstpar->added_space_top.kind() != VSpace::NONE)
1846          maxasc += int(firstpar->added_space_top.inPixels());
1847       
1848       /* do not forget the DTP-lines! 
1849        * there height depends on the font of the nearest character */
1850       if (firstpar->line_top)
1851          maxasc += 2 * GetFont(firstpar, 0).ascent('x');
1852       
1853       /* and now the pagebreaks */ 
1854       if (firstpar->pagebreak_top)
1855          maxasc += 3 * DefaultHeight();
1856       
1857       /*  this is special code for the chapter, since the label of this
1858        * layout is printed in an extra row */ 
1859       if (layout.labeltype == LABEL_COUNTER_CHAPTER
1860           && parameters->secnumdepth>= 0) {
1861               labeladdon = int(labelfont.maxDescent() *
1862                                   layout.spacing.getValue() *
1863                                   parameters->spacing.getValue())
1864                       + int(labelfont.maxAscent() *
1865                                layout.spacing.getValue() *
1866                                parameters->spacing.getValue());
1867       }
1868       
1869       /* special code for the top label */ 
1870       if ((layout.labeltype == LABEL_TOP_ENVIRONMENT
1871            || layout.labeltype == LABEL_BIBLIO
1872            || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)
1873           && row_ptr->par->IsFirstInSequence()
1874           && !row_ptr->par->GetLabestring().empty()) {
1875          labeladdon = int(
1876                  (labelfont.maxAscent() *
1877                   layout.spacing.getValue() *
1878                   parameters->spacing.getValue())
1879                  +(labelfont.maxDescent() *
1880                    layout.spacing.getValue() *
1881                    parameters->spacing.getValue())
1882                  + layout.topsep * DefaultHeight()
1883                  + layout.labelbottomsep *  DefaultHeight());
1884       }
1885    
1886       /* and now the layout spaces, for example before and after a section, 
1887        * or between the items of a itemize or enumerate environment */ 
1888       
1889       if (!firstpar->pagebreak_top) {
1890          LyXParagraph *prev = row_ptr->par->Previous();
1891          if (prev)
1892             prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth());
1893          if (prev && prev->GetLayout() == firstpar->GetLayout()
1894              && prev->GetDepth() == firstpar->GetDepth()
1895              && prev->GetLabelWidthString() == firstpar->GetLabelWidthString())
1896            {
1897               layoutasc = (layout.itemsep * DefaultHeight());
1898            }
1899          else if (row_ptr->previous) {
1900             tmptop = layout.topsep;
1901             
1902             if (row_ptr->previous->par->GetDepth() >= row_ptr->par->GetDepth())
1903                tmptop-= textclasslist.Style(parameters->textclass, row_ptr->previous->par->GetLayout()).bottomsep;
1904             
1905             if (tmptop > 0)
1906                layoutasc = (tmptop * DefaultHeight());
1907          }
1908          else if (row_ptr->par->line_top){
1909             tmptop = layout.topsep;
1910             
1911             if (tmptop > 0)
1912                layoutasc = (tmptop * DefaultHeight());
1913          }
1914          
1915          prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth()-1);
1916          if (prev)  {
1917             maxasc += int(textclasslist.Style(parameters->textclass,
1918                                          prev->GetLayout()).parsep * DefaultHeight());
1919          }
1920          else {
1921                 if (firstpar->Previous()
1922                     && firstpar->Previous()->GetDepth() == 0
1923                     && firstpar->Previous()->GetLayout() != firstpar->GetLayout()) {
1924                    /* avoid parsep */ 
1925                 }
1926             else if (firstpar->Previous()){
1927                maxasc += int(layout.parsep * DefaultHeight());
1928             }
1929          }
1930       }
1931    }
1932    
1933    /* is it a bottom line? */ 
1934    if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
1935        && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {     
1936           
1937           /* the paper margins */ 
1938           if (!par->next)
1939             maxdesc += LYX_PAPER_MARGIN;
1940         
1941           /* add the vertical spaces, that the user added */
1942           if (firstpar->added_space_bottom.kind() != VSpace::NONE)
1943             maxdesc += int(firstpar->added_space_bottom.inPixels());
1944           
1945           /* do not forget the DTP-lines! 
1946            * there height depends on the font of the nearest character */
1947           if (firstpar->line_bottom)
1948             maxdesc += 2 * (GetFont(par, par->Last()-1).ascent('x'));
1949           
1950           /* and now the pagebreaks */
1951           if (firstpar->pagebreak_bottom)
1952             maxdesc += 3 * DefaultHeight();
1953           
1954           /* and now the layout spaces, for example before and after a section, 
1955            * or between the items of a itemize or enumerate environment */
1956           if (!firstpar->pagebreak_bottom && row_ptr->par->Next()) {
1957              LyXParagraph *nextpar = row_ptr->par->Next();
1958              LyXParagraph *comparepar = row_ptr->par;
1959              float usual = 0;
1960              float  unusual = 0;
1961              
1962              if (comparepar->GetDepth() > nextpar->GetDepth()) {
1963                 usual = (textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1964                 comparepar = comparepar->DepthHook(nextpar->GetDepth());
1965                 if (comparepar->GetLayout()!= nextpar->GetLayout()
1966                     || nextpar->GetLabelWidthString() != 
1967                         comparepar->GetLabelWidthString())
1968                   unusual = (textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1969                 
1970                 if (unusual > usual)
1971                   layoutdesc = unusual;
1972                 else
1973                   layoutdesc = usual;
1974              }
1975              else if (comparepar->GetDepth() ==  nextpar->GetDepth()) {
1976                 
1977                 if (comparepar->GetLayout()!= nextpar->GetLayout()
1978                     || nextpar->GetLabelWidthString() != 
1979                         comparepar->GetLabelWidthString())
1980                   layoutdesc = int(textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1981              }
1982           }
1983        }
1984    
1985    /* incalculate the layout spaces */ 
1986    maxasc += int(layoutasc * 2 / (2 + firstpar->GetDepth()));
1987    maxdesc += int(layoutdesc * 2 / (2 + firstpar->GetDepth()));
1988
1989    /* table stuff -- begin*/
1990    if (row_ptr->par->table){
1991       maxasc += row_ptr->par->table->
1992         AdditionalHeight(NumberOfCell(row_ptr->par, row_ptr->pos));
1993    }
1994    /* table stuff -- end*/
1995    
1996    /* calculate the new height of the text */ 
1997    height -= row_ptr->height;
1998    
1999    row_ptr->height= maxasc+maxdesc+labeladdon;
2000    row_ptr->baseline= maxasc+labeladdon;
2001    
2002    height += row_ptr->height;
2003 }
2004 #endif
2005
2006
2007 /* Appends the implicit specified paragraph behind the specified row,
2008  * start at the implicit given position */
2009 void LyXText::AppendParagraph(Row * row) const
2010 {
2011    bool not_ready = true;
2012    
2013    // The last character position of a paragraph is an invariant so we can 
2014    // safely get it here. (Asger)
2015    int lastposition = row->par->Last();
2016
2017    do {
2018       // Get the next breakpoint
2019       int z = NextBreakPoint(row, paperwidth);
2020       
2021       Row * tmprow = row;
2022
2023       // Insert the new row
2024       if (z < lastposition) {
2025          ++z;
2026          InsertRow(row, row->par, z);
2027          row = row->next;
2028
2029          row->height = 0;
2030       } else
2031          not_ready = false;
2032       
2033       // Set the dimensions of the row
2034       tmprow->fill = Fill(tmprow, paperwidth);
2035       SetHeightOfRow(tmprow);
2036
2037    } while (not_ready);
2038 }
2039
2040
2041 void LyXText::BreakAgain(Row * row) const
2042 {
2043    bool not_ready = true;
2044    
2045    do  {
2046       /* get the next breakpoint */
2047         LyXParagraph::size_type z = 
2048                 NextBreakPoint(row, paperwidth);
2049       Row * tmprow = row;
2050       
2051       if (z < row->par->Last() ) {
2052          if (!row->next || (row->next && row->next->par != row->par)) {
2053                  // insert a new row
2054             ++z;
2055             InsertRow(row, row->par, z);
2056             row = row->next;
2057             row->height = 0;
2058          } else  {
2059             row = row->next;
2060             ++z;
2061             if (row->pos == z)
2062                     not_ready = false;     // the rest will not change
2063             else {
2064                row->pos = z;
2065             }
2066          }
2067       } else {
2068          /* if there are some rows too much, delete them */
2069          /* only if you broke the whole paragraph! */ 
2070          Row * tmprow2 = row;
2071          while (tmprow2->next && tmprow2->next->par == row->par) {
2072             tmprow2 = tmprow2->next;
2073          }
2074          while (tmprow2 != row) {
2075             tmprow2 = tmprow2->previous;
2076             RemoveRow(tmprow2->next);
2077          }
2078          not_ready = false;
2079       }
2080        
2081       /* set the dimensions of the row */ 
2082       tmprow->fill = Fill(tmprow, paperwidth);
2083       SetHeightOfRow(tmprow);
2084    } while (not_ready);
2085 }
2086
2087
2088 /* this is just a little changed version of break again */ 
2089 void LyXText::BreakAgainOneRow(Row * row)
2090 {
2091    /* get the next breakpoint */
2092    LyXParagraph::size_type z = NextBreakPoint(row, paperwidth);
2093    Row * tmprow = row;
2094    
2095    if (z < row->par->Last() ) {
2096       if (!row->next || (row->next && row->next->par != row->par)) {
2097          /* insert a new row */ 
2098          ++z;
2099          InsertRow(row, row->par, z);
2100          row = row->next;
2101          row->height = 0;
2102       }
2103       else  {
2104          row= row->next;
2105          ++z;
2106          if (row->pos != z)
2107             row->pos = z;
2108       }
2109    }
2110    else {
2111       /* if there are some rows too much, delete them */
2112       /* only if you broke the whole paragraph! */ 
2113       Row * tmprow2 = row;
2114       while (tmprow2->next && tmprow2->next->par == row->par) {
2115          tmprow2 = tmprow2->next;
2116       }
2117       while (tmprow2 != row) {
2118          tmprow2 = tmprow2->previous;
2119          RemoveRow(tmprow2->next);
2120       }
2121    }
2122    
2123    /* set the dimensions of the row */ 
2124    tmprow->fill = Fill(tmprow, paperwidth);
2125    SetHeightOfRow(tmprow);
2126 }
2127
2128
2129 void LyXText::BreakParagraph(char keep_layout)
2130 {
2131    LyXLayout const & layout = textclasslist.Style(parameters->textclass,
2132                                       cursor.par->GetLayout());
2133    
2134    /* table stuff -- begin */
2135    if (cursor.par->table) {
2136        // breaking of tables is only allowed at the beginning or the end */
2137        if (cursor.pos && cursor.pos < cursor.par->size() &&
2138            !cursor.par->table->ShouldBeVeryLastCell(NumberOfCell(cursor.par, cursor.pos)))
2139                return; // no breaking of tables allowed
2140    }
2141    /* table stuff -- end */
2142
2143    // this is only allowed, if the current paragraph is not empty or caption
2144    if ((cursor.par->Last() <= 0 && !cursor.par->IsDummy())
2145        && 
2146        layout.labeltype!= LABEL_SENSITIVE)
2147      return;
2148
2149    SetUndo(Undo::INSERT, 
2150            cursor.par->ParFromPos(cursor.pos)->previous, 
2151            cursor.par->ParFromPos(cursor.pos)->next); 
2152
2153    /* table stuff -- begin */
2154    if (cursor.par->table) {
2155        int cell = NumberOfCell(cursor.par, cursor.pos);
2156        if (cursor.par->table->ShouldBeVeryLastCell(cell))
2157            SetCursor(cursor.par, cursor.par->text.size());
2158    }
2159    /* table stuff -- end */
2160    
2161    // please break always behind a space
2162    if (cursor.pos < cursor.par->Last()
2163        && cursor.par->IsLineSeparator(cursor.pos))
2164      cursor.pos++;
2165    
2166    // break the paragraph
2167    if (keep_layout)
2168      keep_layout = 2;
2169    else 
2170      keep_layout = layout.isEnvironment();
2171    cursor.par->BreakParagraph(cursor.pos, keep_layout);
2172
2173    /* table stuff -- begin */
2174    if (cursor.par->table){
2175      // the table should stay with the contents
2176      if (!cursor.pos){
2177        cursor.par->Next()->table = cursor.par->table;
2178        cursor.par->table = 0;
2179      }
2180    }
2181    /* table stuff -- end */
2182
2183    // well this is the caption hack since one caption is really enough
2184    if (layout.labeltype == LABEL_SENSITIVE){
2185      if (!cursor.pos)
2186              cursor.par->SetLayout(0); // set to standard-layout
2187      else
2188              cursor.par->Next()->SetLayout(0); // set to standard-layout
2189    }
2190    
2191    /* if the cursor is at the beginning of a row without prior newline, 
2192     * move one row up! 
2193     * This touches only the screen-update. Otherwise we would may have
2194     * an empty row on the screen */
2195    if (cursor.pos && !cursor.row->par->IsNewline(cursor.row->pos -1) &&
2196        cursor.row->pos == cursor.pos) {
2197      CursorLeft();
2198    } 
2199    
2200    status = LyXText::NEED_MORE_REFRESH;
2201    refresh_row = cursor.row;
2202    refresh_y = cursor.y - cursor.row->baseline;
2203    
2204    // Do not forget the special right address boxes
2205    if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX) {
2206       while (refresh_row->previous &&
2207              refresh_row->previous->par == refresh_row->par) {
2208                 refresh_row = refresh_row->previous;
2209                 refresh_y -= refresh_row->height;
2210              }
2211    }
2212    RemoveParagraph(cursor.row);
2213    
2214    // set the dimensions of the cursor row
2215    cursor.row->fill = Fill(cursor.row, paperwidth);
2216
2217    SetHeightOfRow(cursor.row);
2218    
2219    while (!cursor.par->Next()->table && cursor.par->Next()->Last()
2220           && cursor.par->Next()->IsNewline(0))
2221      cursor.par->Next()->Erase(0);
2222    
2223    InsertParagraph(cursor.par->Next(), cursor.row);
2224
2225    UpdateCounters(cursor.row->previous);
2226    
2227    /* This check is necessary. Otherwise the new empty paragraph will
2228     * be deleted automatically. And it is more friendly for the user! */ 
2229    if (cursor.pos)
2230      SetCursor(cursor.par->Next(), 0);
2231    else
2232      SetCursor(cursor.par, 0);
2233    
2234    if (cursor.row->next)
2235      BreakAgain(cursor.row->next);
2236
2237    need_break_row = 0;
2238 }
2239
2240
2241 void LyXText::OpenFootnote()
2242 {
2243    LyXParagraph * endpar,* tmppar;
2244    Row * row;
2245    
2246    LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
2247    
2248    /* if there is no footnote in this paragraph, just return. */ 
2249    if (!par->next
2250        || par->next->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
2251      return;
2252    
2253    /* ok, move the cursor right before the footnote */ 
2254    
2255    /* just a little faster than using CursorRight() */
2256    for (cursor.pos = 0;
2257         cursor.par->ParFromPos(cursor.pos) != par; cursor.pos++);
2258    /* now the cursor is at the beginning of the physical par */
2259    SetCursor(cursor.par,
2260              cursor.pos + cursor.par->ParFromPos(cursor.pos)->text.size());
2261    
2262    /* the cursor must be exactly before the footnote */ 
2263    par = cursor.par->ParFromPos(cursor.pos);
2264    
2265    status = LyXText::NEED_MORE_REFRESH;
2266    refresh_row = cursor.row;
2267    refresh_y = cursor.y - cursor.row->baseline;
2268    
2269    tmppar = cursor.par;
2270    endpar = cursor.par->Next();
2271    row = cursor.row;
2272    
2273    tmppar->OpenFootnote(cursor.pos);
2274    RemoveParagraph(row);
2275    /* set the dimensions of the cursor row */
2276    row->fill = Fill(row, paperwidth);
2277    SetHeightOfRow(row);
2278    tmppar = tmppar->Next();
2279    
2280    while (tmppar != endpar) {
2281       if (tmppar) {
2282          InsertParagraph(tmppar, row);
2283          while (row->next && row->next->par == tmppar)
2284            row = row->next;
2285          tmppar = tmppar->Next();
2286       }
2287    }
2288    SetCursor(par->next, 0);
2289    sel_cursor = cursor;
2290 }
2291    
2292
2293 /* table stuff -- begin*/
2294
2295 void LyXText::TableFeatures(int feature, string const & val) const
2296 {
2297         if (!cursor.par->table)
2298                 return; /* this should never happen */
2299   
2300         int actCell = NumberOfCell(cursor.par, cursor.pos);
2301         SetUndo(Undo::FINISH, 
2302                 cursor.par->ParFromPos(cursor.pos)->previous, 
2303                 cursor.par->ParFromPos(cursor.pos)->next); 
2304         
2305         switch (feature){
2306         case LyXTable::SET_PWIDTH:
2307                 cursor.par->table->SetPWidth(actCell, val);
2308                 break;
2309         case LyXTable::SET_SPECIAL_COLUMN:
2310         case LyXTable::SET_SPECIAL_MULTI:
2311                 cursor.par->table->SetAlignSpecial(actCell, val, feature);
2312                 break;
2313         default:
2314                 break;
2315         }
2316         RedoParagraph();
2317 }
2318
2319
2320 void LyXText::TableFeatures(int feature) const
2321 {
2322         int setLines = 0;
2323         int setAlign = LYX_ALIGN_LEFT;
2324         int lineSet;
2325         bool what;
2326     
2327     if (!cursor.par->table)
2328         return; /* this should never happen */
2329   
2330     int actCell = NumberOfCell(cursor.par, cursor.pos);
2331     SetUndo(Undo::FINISH, 
2332             cursor.par->ParFromPos(cursor.pos)->previous, 
2333             cursor.par->ParFromPos(cursor.pos)->next); 
2334
2335     switch (feature){
2336       case LyXTable::ALIGN_LEFT:
2337           setAlign= LYX_ALIGN_LEFT;
2338           break;
2339       case LyXTable::ALIGN_RIGHT:
2340           setAlign= LYX_ALIGN_RIGHT;
2341           break;
2342       case LyXTable::ALIGN_CENTER:
2343           setAlign= LYX_ALIGN_CENTER;
2344           break;
2345       default:
2346           break;
2347     }
2348     switch (feature){
2349       case LyXTable::APPEND_ROW: {
2350               LyXParagraph::size_type pos = cursor.pos;
2351
2352               /* move to the next row */
2353           int cell_org = actCell;
2354           int cell = cell_org;
2355
2356           // if there is a ContRow following this row I have to add
2357           // the row after the ContRow's
2358           if ((pos < cursor.par->Last()) &&
2359               cursor.par->table->RowHasContRow(cell_org)) {
2360               while((pos < cursor.par->Last()) &&
2361                     !cursor.par->table->IsContRow(cell)) {
2362                   while (pos < cursor.par->Last() &&
2363                          !cursor.par->IsNewline(pos))
2364                       ++pos;
2365                   if (pos < cursor.par->Last())
2366                       ++pos;
2367                   ++cell;
2368               }
2369               while((pos < cursor.par->Last()) &&
2370                     cursor.par->table->IsContRow(cell)) {
2371                   while (pos < cursor.par->Last() &&
2372                          !cursor.par->IsNewline(pos))
2373                       ++pos;
2374                   if (pos < cursor.par->Last())
2375                       ++pos;
2376                   ++cell;
2377               }
2378               cell_org = --cell;
2379               if (pos < cursor.par->Last())
2380                   --pos;
2381           }
2382           while (pos < cursor.par->Last() && 
2383                  (cell == cell_org || !cursor.par->table->IsFirstCell(cell))){
2384               while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
2385                   ++pos;
2386               if (pos < cursor.par->Last())
2387                   ++pos;
2388               ++cell;
2389           }
2390                 
2391           /* insert the new cells */ 
2392           int number = cursor.par->table->NumberOfCellsInRow(cell_org);
2393           for (int i = 0; i < number; ++i)
2394               cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
2395                 
2396           /* append the row into the table */
2397           cursor.par->table->AppendRow(cell_org);
2398           RedoParagraph();
2399           return;
2400       }
2401       case LyXTable::APPEND_CONT_ROW: {
2402               LyXParagraph::size_type pos = cursor.pos;
2403           /* move to the next row */
2404           int cell_org = actCell;
2405           int cell = cell_org;
2406
2407           // if there is already a controw but not for this cell
2408           // the AppendContRow sets only the right values but does
2409           // not actually add a row
2410           if (cursor.par->table->RowHasContRow(cell_org) &&
2411               (cursor.par->table->CellHasContRow(cell_org)<0)) {
2412               cursor.par->table->AppendContRow(cell_org);
2413               RedoParagraph();
2414               return;
2415           }
2416           while (pos < cursor.par->Last() && 
2417                  (cell == cell_org
2418                   || !cursor.par->table->IsFirstCell(cell))){
2419               while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
2420                   ++pos;
2421               if (pos < cursor.par->Last())
2422                   ++pos;
2423               ++cell;
2424           }
2425                 
2426           /* insert the new cells */ 
2427           int number = cursor.par->table->NumberOfCellsInRow(cell_org);
2428           for (int i = 0; i < number; ++i)
2429               cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
2430                 
2431           /* append the row into the table */
2432           cursor.par->table->AppendContRow(cell_org);
2433           RedoParagraph();
2434           return;
2435       }
2436       case LyXTable::APPEND_COLUMN: {
2437               LyXParagraph::size_type pos = 0;
2438           int cell_org = actCell;
2439           int cell = 0;
2440           do{
2441               if (pos && (cursor.par->IsNewline(pos-1))){
2442                   if (cursor.par->table->AppendCellAfterCell(cell_org, cell)){
2443                       cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
2444                       if (pos <= cursor.pos)
2445                           cursor.pos++;
2446                       ++pos;
2447                   }
2448                   ++cell;
2449               }
2450               ++pos;
2451           } while (pos <= cursor.par->Last());
2452           /* remember that the very last cell doesn't end with a newline.
2453              This saves one byte memory per table ;-) */ 
2454           if (cursor.par->table->AppendCellAfterCell(cell_org, cell))
2455               cursor.par->InsertChar(cursor.par->Last(), LyXParagraph::META_NEWLINE);
2456                 
2457           /* append the column into the table */ 
2458           cursor.par->table->AppendColumn(cell_org);
2459                 
2460           RedoParagraph();
2461           return;
2462       }
2463       case LyXTable::DELETE_ROW:
2464           if (current_view->the_locking_inset)
2465               current_view->unlockInset(current_view->the_locking_inset);
2466           RemoveTableRow(&cursor);
2467           RedoParagraph();
2468           return;
2469         
2470       case LyXTable::DELETE_COLUMN: {
2471               LyXParagraph::size_type pos = 0;
2472           int cell_org = actCell;
2473           int cell = 0;
2474           if (current_view->the_locking_inset)
2475               current_view->unlockInset(current_view->the_locking_inset);
2476           do {
2477               if (!pos || (cursor.par->IsNewline(pos-1))){
2478                   if (cursor.par->table->DeleteCellIfColumnIsDeleted(cell, cell_org)){
2479                       // delete one cell
2480                       while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
2481                           cursor.par->Erase(pos);
2482                       if (pos < cursor.par->Last())
2483                           cursor.par->Erase(pos);
2484                       else 
2485                           cursor.par->Erase(pos - 1); // the missing newline at the end of a table
2486                       --pos; // because of pos++ below
2487                   }   
2488                   ++cell;
2489               }
2490               ++pos;
2491           } while (pos <= cursor.par->Last());
2492                 
2493           /* delete the column from the table */ 
2494           cursor.par->table->DeleteColumn(cell_org);
2495                 
2496           /* set the cursor to the beginning of the table, where else? */ 
2497           cursor.pos = 0;
2498           RedoParagraph();
2499           return;
2500       }
2501       case LyXTable::TOGGLE_LINE_TOP:
2502           lineSet = !cursor.par->table->TopLine(actCell);
2503           if (!selection){
2504               cursor.par->table->SetTopLine(actCell, lineSet);
2505           } else {
2506                   LyXParagraph::size_type i;
2507                   int n = -1, m = -2;
2508               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
2509                   if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
2510                       cursor.par->table->SetTopLine(n, lineSet);
2511                       m = n;
2512                   }
2513               }
2514           }
2515           RedoParagraph();
2516           return;
2517     
2518       case LyXTable::TOGGLE_LINE_BOTTOM:
2519           lineSet = !cursor.par->table->BottomLine(actCell);
2520           if (!selection){
2521               cursor.par->table->SetBottomLine(actCell, lineSet);
2522           } else {
2523                   LyXParagraph::size_type i;
2524                   int n = -1, m = -2;
2525               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
2526                   if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
2527                       cursor.par->table->SetBottomLine(n, lineSet);
2528                       m = n;
2529                   }
2530               }
2531           }
2532           RedoParagraph();
2533           return;
2534                 
2535       case LyXTable::TOGGLE_LINE_LEFT:
2536           lineSet = !cursor.par->table->LeftLine(actCell);
2537           if (!selection){
2538               cursor.par->table->SetLeftLine(actCell, lineSet);
2539           } else {
2540                   LyXParagraph::size_type i;
2541                   int n = -1, m = -2;
2542               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
2543                   if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
2544                       cursor.par->table->SetLeftLine(n, lineSet);
2545                       m = n;
2546                   }
2547               }
2548           }
2549           RedoParagraph();
2550           return;
2551
2552       case LyXTable::TOGGLE_LINE_RIGHT:
2553           lineSet = !cursor.par->table->RightLine(actCell);
2554           if (!selection){
2555               cursor.par->table->SetRightLine(actCell, lineSet);
2556           } else {
2557                   int n = -1, m = -2;
2558                   LyXParagraph::size_type i = sel_start_cursor.pos;
2559               for (; i <= sel_end_cursor.pos; ++i) {
2560                   if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
2561                       cursor.par->table->SetRightLine(n, lineSet);
2562                       m = n;
2563                   }
2564               }
2565           }
2566           RedoParagraph();
2567           return;
2568     
2569       case LyXTable::ALIGN_LEFT:
2570       case LyXTable::ALIGN_RIGHT:
2571       case LyXTable::ALIGN_CENTER:
2572           if (!selection){
2573               cursor.par->table->SetAlignment(actCell, setAlign);
2574           } else {
2575               int n = -1, m = -2;
2576               LyXParagraph::size_type i = sel_start_cursor.pos;
2577               for (; i <= sel_end_cursor.pos; ++i) {
2578                   if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
2579                       cursor.par->table->SetAlignment(n, setAlign);
2580                       m = n;
2581                   }
2582               }
2583           }
2584           RedoParagraph();
2585           return;
2586                 
2587       case LyXTable::DELETE_TABLE:
2588           SetCursorIntern(cursor.par, 0);
2589           delete cursor.par->table;
2590           cursor.par->table = 0;
2591           // temporary: Should put table in simple_cut_buffer (with before and after
2592           // dummy-paragraph !! 
2593           // not necessar anymore with UNDO :)
2594           for (LyXParagraph::size_type i = 
2595                        cursor.par->text.size() - 1; i >= 0; --i)
2596               cursor.par->Erase(i);
2597           RedoParagraph();
2598           return;
2599                 
2600       case LyXTable::MULTICOLUMN: {
2601           int number = 0;
2602           // check wether we are completly in a multicol
2603           int multicol = cursor.par->table->IsMultiColumn(actCell);
2604           if (multicol && selection && sel_start_cursor.row == sel_end_cursor.row){
2605               multicol = NumberOfCell(sel_start_cursor.par, sel_start_cursor.pos)
2606                   == NumberOfCell(sel_end_cursor.par, sel_end_cursor.pos);
2607           }
2608
2609           if (multicol){
2610               int newlines = cursor.par->table->UnsetMultiColumn(actCell);
2611               LyXParagraph::size_type pos = cursor.pos;
2612               while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
2613                   ++pos;
2614               for (; newlines; --newlines)
2615                   cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
2616               RedoParagraph();
2617               return;
2618           }
2619           else {
2620               // selection must be in one row (or no selection)
2621               if (!selection){
2622                   cursor.par->table->SetMultiColumn(NumberOfCell(cursor.par,
2623                                                                  cursor.pos),
2624                                                     1);
2625                   RedoParagraph();
2626                   return;
2627               }
2628               else {
2629                   if (sel_start_cursor.row == sel_end_cursor.row){
2630                       LyXParagraph::size_type i;
2631                       number = 1;
2632                       for (i = sel_start_cursor.pos;
2633                            i < sel_end_cursor.pos; ++i){
2634                           if (sel_start_cursor.par->IsNewline(i)){
2635                               sel_start_cursor.par->Erase(i);
2636                               // check for double-blanks
2637                               if ((i && !sel_start_cursor.par->IsLineSeparator(i-1))
2638                                   &&
2639                                   (i < sel_start_cursor.par->Last() 
2640                                    && !sel_start_cursor.par->IsLineSeparator(i)))
2641                                   sel_start_cursor.par->InsertChar(i, ' ');
2642                               else {
2643                                   sel_end_cursor.pos--;
2644                                   --i;
2645                               }
2646                               ++number;
2647                           }
2648                       }
2649                       cursor.par->table->
2650                           SetMultiColumn(NumberOfCell(sel_start_cursor.par,
2651                                                       sel_start_cursor.pos),
2652                                          number);
2653                       cursor.pos = sel_start_cursor.pos;
2654                       RedoParagraph();
2655                       return;
2656                   }
2657                   else {
2658                       WriteAlert(_("Impossible Operation!"), 
2659                                  _("Multicolumns can only be horizontally."), 
2660                                  _("Sorry."));
2661                   }
2662               }
2663           }
2664           break;
2665       }
2666       case LyXTable::SET_ALL_LINES:
2667           setLines = 1;
2668       case LyXTable::UNSET_ALL_LINES:
2669           if (!selection){
2670               cursor.par->table->SetAllLines(NumberOfCell(cursor.par,
2671                                                           cursor.pos),
2672                                              setLines);
2673           } else {
2674                   LyXParagraph::size_type i;
2675                   int n = -1, m = -2;
2676               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
2677                   if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
2678                       cursor.par->table->SetAllLines(n, setLines);
2679                       m = n;
2680                   }
2681               }
2682           }
2683           RedoParagraph();
2684           return;
2685       case LyXTable::SET_LONGTABLE:
2686           cursor.par->table->SetLongTable(true);
2687           return;
2688       case LyXTable::UNSET_LONGTABLE:
2689           cursor.par->table->SetLongTable(false);
2690           return;
2691       case LyXTable::SET_ROTATE_TABLE:
2692           cursor.par->table->SetRotateTable(true);
2693           return;
2694       case LyXTable::UNSET_ROTATE_TABLE:
2695           cursor.par->table->SetRotateTable(false);
2696           return;
2697       case LyXTable::SET_ROTATE_CELL:
2698           if (!selection){
2699               cursor.par->table->SetRotateCell(actCell, true);
2700           } else {
2701                   LyXParagraph::size_type i;
2702                   int n = -1, m = -2;
2703               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
2704                   if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
2705                       cursor.par->table->SetRotateCell(n, true);
2706                       m = n;
2707                   }
2708               }
2709           }
2710           return;
2711       case LyXTable::UNSET_ROTATE_CELL:
2712           if (!selection){
2713               cursor.par->table->SetRotateCell(actCell, false);
2714           } else {
2715                   int n = -1, m = -2;
2716                   LyXParagraph::size_type i = sel_start_cursor.pos;
2717               for (; i <= sel_end_cursor.pos; ++i) {
2718                   if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
2719                       cursor.par->table->SetRotateCell(n, false);
2720                       m = n;
2721                   }
2722               }
2723           }
2724           return;
2725       case LyXTable::SET_LINEBREAKS:
2726           what = !cursor.par->table->Linebreaks(cursor.par->table->FirstVirtualCell(actCell));
2727           if (!selection){
2728               cursor.par->table->SetLinebreaks(actCell, what);
2729           } else {
2730                   LyXParagraph::size_type i;
2731                   int n = -1, m = -2;
2732               for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
2733                   if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
2734                       cursor.par->table->SetLinebreaks(n, what);
2735                       m = n;
2736                   }
2737               }
2738           }
2739           return;
2740       case LyXTable::SET_LTFIRSTHEAD:
2741           cursor.par->table->SetLTHead(actCell, true);
2742           return;
2743       case LyXTable::SET_LTHEAD:
2744           cursor.par->table->SetLTHead(actCell, false);
2745           return;
2746       case LyXTable::SET_LTFOOT:
2747           cursor.par->table->SetLTFoot(actCell, false);
2748           return;
2749       case LyXTable::SET_LTLASTFOOT:
2750           cursor.par->table->SetLTFoot(actCell, true);
2751           return;
2752       case LyXTable::SET_LTNEWPAGE:
2753           what = !cursor.par->table->LTNewPage(actCell);
2754           cursor.par->table->SetLTNewPage(actCell, what);
2755           return;
2756     }
2757 }
2758         
2759
2760 void LyXText::InsertCharInTable(char c)
2761 {
2762         Row * row;
2763         Row * tmprow;
2764         long y;
2765         bool jumped_over_space;
2766         
2767         /* first check, if there will be two blanks together or a blank at 
2768          * the beginning of a paragraph. 
2769          * I decided to handle blanks like normal characters, the main 
2770          * difference are the special checks when calculating the row.fill
2771          * (blank does not count at the end of a row) and the check here */ 
2772         
2773         LyXFont realtmpfont = real_current_font;
2774         LyXFont rawtmpfont = current_font; /* store the current font.
2775                                             * This is because of the use
2776                                             * of cursor movements. The moving
2777                                             * cursor would refresh the 
2778                                             * current font */
2779
2780         // Get the font that is used to calculate the baselineskip
2781         LyXParagraph::size_type const lastpos = 
2782                 cursor.par->Last();
2783         LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2784
2785         jumped_over_space = false;
2786         if (IsLineSeparatorChar(c)) {
2787
2788 #ifndef FIX_DOUBLE_SPACE
2789                 /* avoid double blanks but insert the new blank because
2790                  * of a possible font change */
2791                 if (cursor.pos < lastpos &&
2792                     cursor.par->IsLineSeparator(cursor.pos)) {
2793                         cursor.par->Erase(cursor.pos);
2794                         jumped_over_space = true;
2795                 } else
2796 #endif
2797                         if ((cursor.pos > 0 && 
2798                           cursor.par->IsLineSeparator(cursor.pos - 1))
2799                          || (cursor.pos > 0 && cursor.par->IsNewline(cursor.pos - 1))
2800                           || (cursor.pos == 0 &&
2801                               !(cursor.par->Previous()
2802                               && cursor.par->Previous()->footnoteflag
2803                               == LyXParagraph::OPEN_FOOTNOTE)))
2804                         return;
2805         } else if (IsNewlineChar(c)) {
2806             if (!IsEmptyTableCell()) {
2807                 TableFeatures(LyXTable::APPEND_CONT_ROW);
2808                 CursorDown();
2809             }
2810           return;
2811         }
2812    
2813         row = cursor.row;
2814         y = cursor.y - row->baseline;
2815         if (c != LyXParagraph::META_INSET)      /* in this case LyXText::InsertInset 
2816                                          * already inserted the character */
2817                 cursor.par->InsertChar(cursor.pos, c);
2818         SetCharFont(cursor.par, cursor.pos, rawtmpfont);
2819
2820         if (!jumped_over_space) {
2821                 /* refresh the positions */
2822                 tmprow = row;
2823                 while (tmprow->next && tmprow->next->par == row->par) {
2824                         tmprow = tmprow->next;
2825                         tmprow->pos++;
2826                 }
2827         }
2828
2829         cursor.pos++;
2830
2831         CheckParagraphInTable(cursor.par, cursor.pos);
2832         
2833         current_font = rawtmpfont;
2834         real_current_font = realtmpfont;
2835         
2836         /* check, whether the last character's font has changed. */
2837         if (cursor.pos && cursor.pos == cursor.par->Last()
2838             && rawparfont != rawtmpfont)
2839                 RedoHeightOfParagraph(cursor);
2840 }
2841
2842
2843 void LyXText::CheckParagraphInTable(LyXParagraph * par,
2844                                     LyXParagraph::size_type pos)
2845 {
2846         
2847         if (par->GetChar(pos) == LyXParagraph::META_INSET &&
2848             par->GetInset(pos) && par->GetInset(pos)->display()){
2849           par->GetInset(pos)->display(false);
2850         }
2851
2852         long y;
2853         Row * row = GetRow(par, pos, y);
2854         
2855         int tmpheight = row->height;
2856         SetHeightOfRow(row);
2857
2858         LyXParagraph::size_type tmp_pos = pos;
2859         /* update the table information */
2860         while (tmp_pos && !par->IsNewline(tmp_pos - 1))
2861                 --tmp_pos;
2862         if (par->table->SetWidthOfCell(NumberOfCell(par, pos),
2863                                        WidthOfCell(par, tmp_pos))) {
2864                 LyXCursor tmpcursor = cursor;
2865                 SetCursorIntern(par, pos);
2866                 /* make a complete redraw */
2867                 RedoDrawingOfParagraph(cursor);
2868                 cursor = tmpcursor;
2869         }
2870         else {
2871                 /* redraw only the row */
2872                 LyXCursor tmpcursor = cursor;
2873                 SetCursorIntern(par, pos);
2874                 refresh_y = y;
2875                 refresh_x = cursor.x;
2876                 refresh_row = row;
2877                 refresh_pos = cursor.pos;
2878                 cursor = tmpcursor;
2879                 
2880                 if (tmpheight == row->height)
2881                         status = LyXText::NEED_VERY_LITTLE_REFRESH;
2882                 else
2883                         status = LyXText::NEED_MORE_REFRESH;
2884         }
2885         SetCursorIntern(cursor.par, cursor.pos);
2886 }
2887
2888
2889 void LyXText::BackspaceInTable()
2890 {
2891         Row * tmprow, * row;
2892         long y;
2893         
2894         LyXFont rawtmpfont = current_font;
2895         LyXFont realtmpfont = real_current_font;
2896
2897         // Get the font that is used to calculate the baselineskip
2898         int const lastpos = cursor.par->Last();
2899         LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2900         
2901         if (cursor.pos == 0) {
2902                 /* no pasting of table paragraphs */
2903                 
2904                 CursorLeft();
2905         } else {
2906                 /* this is the code for a normal backspace, not pasting
2907                  * any paragraphs */ 
2908                 SetUndo(Undo::DELETE, 
2909                         cursor.par->ParFromPos(cursor.pos)->previous, 
2910                         cursor.par->ParFromPos(cursor.pos)->next); 
2911           
2912                 CursorLeftIntern();
2913                 
2914                 /* some insets are undeletable here */
2915                 if (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
2916                         if (!cursor.par->GetInset(cursor.pos)->Deletable())
2917                                 return;
2918                 }
2919                 
2920                 row = cursor.row;
2921                 y = cursor.y - row->baseline;
2922                 
2923                 /* some special code when deleting a newline. */
2924                 if (cursor.par->IsNewline(cursor.pos)) {
2925                         /* nothing :-) */
2926                         return;
2927                 }
2928                 else {
2929                         cursor.par->Erase(cursor.pos);
2930                         
2931                         /* refresh the positions */
2932                         tmprow = row;
2933                         while (tmprow->next && tmprow->next->par == row->par) {
2934                                 tmprow = tmprow->next;
2935                                 tmprow->pos--;
2936                         }
2937
2938 #ifndef FIX_DOUBLE_SPACE
2939                         /* delete superfluous blanks */ 
2940                         if (cursor.pos < cursor.par->Last() - 1 &&
2941                         (cursor.par->IsLineSeparator(cursor.pos))) {
2942                                 
2943                                 if (cursor.pos == BeginningOfMainBody(cursor.par)
2944                                 || !cursor.pos 
2945                                 || cursor.par->IsLineSeparator(cursor.pos - 1)) {
2946                                         cursor.par->Erase(cursor.pos);
2947                                         /* refresh the positions */
2948                                         tmprow = row;
2949                                         while (tmprow->next && 
2950                                                tmprow->next->par == row->par) {
2951                                                 tmprow = tmprow->next;
2952                                                 tmprow->pos--;
2953                                         }
2954                                         if (cursor.pos)   /* move one character left */
2955                                                 cursor.pos--;
2956                                 }
2957                         }
2958 #endif
2959                 }
2960       
2961                 CheckParagraphInTable(cursor.par, cursor.pos);
2962       
2963                 /* check, wether the last characters font has changed. */ 
2964                 if (cursor.pos && cursor.pos == cursor.par->Last()
2965                     && rawparfont != rawtmpfont)
2966                         RedoHeightOfParagraph(cursor);
2967
2968                 /* restore the current font 
2969                  * That is what a user expects! */
2970                 current_font = rawtmpfont;
2971                 real_current_font = realtmpfont;
2972         }
2973         SetCursorIntern(cursor.par, cursor.pos);
2974 }
2975
2976 /* table stuff -- end*/
2977
2978
2979 /* just a macro to make some thing easier. */ 
2980 void LyXText::RedoParagraph() const
2981 {
2982 #if 1
2983         // I suspect this version will work
2984         // also.
2985         ClearSelection();
2986         RedoParagraphs(cursor, cursor.par->Next());
2987         SetCursorIntern(cursor.par, cursor.pos);
2988 #else
2989         LyXCursor tmpcursor = cursor;
2990         ClearSelection();
2991         RedoParagraphs(cursor, cursor.par->Next());
2992         SetCursorIntern(tmpcursor.par, tmpcursor.pos);
2993 #endif
2994 }
2995
2996
2997 /* insert a character, moves all the following breaks in the 
2998  * same Paragraph one to the right and make a rebreak */
2999 void  LyXText::InsertChar(char c)
3000 {
3001         SetUndo(Undo::INSERT, 
3002                 cursor.par->ParFromPos(cursor.pos)->previous, 
3003                 cursor.par->ParFromPos(cursor.pos)->next);
3004
3005         /* When the free-spacing option is set for the current layout,
3006          * all spaces are converted to protected spaces. */
3007         bool freeSpacingBo = 
3008                 textclasslist.Style(parameters->textclass,
3009                                cursor.row->par->GetLayout()).free_spacing;
3010    
3011         if (freeSpacingBo && IsLineSeparatorChar(c) 
3012             && (!cursor.pos || cursor.par->IsLineSeparator(cursor.pos - 1))) 
3013                 c = LyXParagraph::META_PROTECTED_SEPARATOR;
3014    
3015         /* table stuff -- begin*/
3016         if (cursor.par->table) {
3017                 InsertCharInTable(c);
3018                 charInserted();
3019                 return;
3020         }
3021         /* table stuff -- end*/
3022    
3023         /* First check, if there will be two blanks together or a blank at 
3024           the beginning of a paragraph. 
3025           I decided to handle blanks like normal characters, the main 
3026           difference are the special checks when calculating the row.fill
3027           (blank does not count at the end of a row) and the check here */ 
3028
3029         // The bug is triggered when we type in a description environment:
3030         // The current_font is not changed when we go from label to main text
3031         // and it should (along with realtmpfont) when we type the space.
3032 #ifdef WITH_WARNINGS
3033 #warning There is a bug here! (Asger)
3034 #endif
3035         
3036         LyXFont realtmpfont = real_current_font;
3037         LyXFont rawtmpfont = current_font;  /* store the current font.
3038                                      * This is because of the use
3039                                      * of cursor movements. The moving
3040                                      * cursor would refresh the 
3041                                      * current font */
3042
3043         // Get the font that is used to calculate the baselineskip
3044         LyXParagraph::size_type lastpos = cursor.par->Last();
3045         LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
3046
3047         bool jumped_over_space = false;
3048    
3049         if (IsLineSeparatorChar(c)) {
3050 #ifndef FIX_DOUBLE_SPACE
3051                 if (cursor.pos < lastpos
3052                     && cursor.par->IsLineSeparator(cursor.pos)) {
3053                         /* the user inserted a space before a space. So we
3054                          * will just make a CursorRight. BUT: The font of this
3055                          * space should be set to current font. That is why
3056                          * we need to rebreak perhaps. If there is a protected
3057                          * blank at the end of a row we have to force
3058                          * a rebreak.*/ 
3059            
3060                         current_view->owner()->getMiniBuffer()
3061                                 ->Set(_("You cannot type two spaces this way. "
3062                                         " Please read the Tutorial."));
3063 #if 1
3064                         // How can this ever happen?
3065                         if (cursor.pos == RowLast(cursor.row)
3066                             && !IsLineSeparatorChar(c))
3067                                 cursor.row->fill = -1;  // force rebreak
3068                         cursor.par->Erase(cursor.pos);
3069                         jumped_over_space = true;
3070 #else
3071                         // Seems to me that this works just as well.
3072                         CursorRight();
3073                         charInserted();
3074                         return;
3075 #endif
3076                 } else
3077 #endif   
3078                 if ((cursor.pos > 0 
3079                      && cursor.par->IsLineSeparator(cursor.pos - 1))
3080                     || (cursor.pos > 0
3081                         && cursor.par->IsNewline(cursor.pos - 1))
3082                     || (cursor.pos == 0
3083                         && !(cursor.par->Previous()
3084                              && cursor.par->Previous()->footnoteflag
3085                              == LyXParagraph::OPEN_FOOTNOTE))) {
3086                         if (cursor.pos == 0 )
3087                                 current_view->owner()->getMiniBuffer()->Set(_("You cannot insert a space at the beginning of a paragraph.  Please read the Tutorial."));
3088                         else
3089                                 current_view->owner()->getMiniBuffer()->Set(_("You cannot type two spaces this way.  Please read the Tutorial."));
3090                         charInserted();
3091                         return;
3092                 }
3093         } else if (IsNewlineChar(c)) {
3094                 if (cursor.par->FirstPhysicalPar() == cursor.par
3095                     && cursor.pos <= BeginningOfMainBody(cursor.par)) {
3096                         charInserted();
3097                         return;
3098                 }
3099                 /* No newline at first position 
3100                  * of a paragraph or behind labels. 
3101                  * TeX does not allow that. */
3102                 
3103                 if (cursor.pos < cursor.par->Last() &&
3104                     cursor.par->IsLineSeparator(cursor.pos))
3105                         CursorRightIntern(); // newline always after a blank!
3106                 cursor.row->fill = -1;         // to force a new break
3107         }
3108    
3109         // the display inset stuff
3110         if (cursor.row->par->GetChar(cursor.row->pos) == LyXParagraph::META_INSET
3111             && cursor.row->par->GetInset(cursor.row->pos)
3112             && cursor.row->par->GetInset(cursor.row->pos)->display())
3113                 cursor.row->fill = -1; // to force a new break  
3114
3115         // get the cursor row fist
3116         Row * row = cursor.row;
3117         long y = cursor.y - row->baseline;
3118         if (c != LyXParagraph::META_INSET) /* Here case LyXText::InsertInset 
3119                                             * already insertet the character */
3120                 cursor.par->InsertChar(cursor.pos, c);
3121         SetCharFont(cursor.par, cursor.pos, rawtmpfont);
3122
3123         if (!jumped_over_space) {
3124                 // refresh the positions
3125                 Row * tmprow = row;
3126                 while (tmprow->next && tmprow->next->par == row->par) {
3127                         tmprow = tmprow->next;
3128                         tmprow->pos++;
3129                 }
3130         }
3131    
3132         // Is there a break one row above
3133         if ((cursor.par->IsLineSeparator(cursor.pos)
3134              || cursor.par->IsNewline(cursor.pos)
3135              || cursor.row->fill == -1)
3136             && row->previous && row->previous->par == row->par) {
3137                 LyXParagraph::size_type z = NextBreakPoint(row->previous,
3138                                                            paperwidth);
3139                 if ( z >= row->pos) {
3140                         row->pos = z + 1;
3141                         
3142                         // set the dimensions of the row above
3143                         row->previous->fill = Fill(row->previous, paperwidth);
3144
3145                         SetHeightOfRow(row->previous);
3146              
3147                         y -= row->previous->height;
3148                         refresh_y = y;
3149                         refresh_row = row->previous;
3150                         status = LyXText::NEED_MORE_REFRESH;
3151              
3152                         BreakAgainOneRow(row);
3153
3154                         current_font = rawtmpfont;
3155                         real_current_font = realtmpfont;
3156                         SetCursor(cursor.par, cursor.pos + 1, false);
3157                         /* cursor MUST be in row now */
3158              
3159                         if (row->next && row->next->par == row->par)
3160                                 need_break_row = row->next;
3161                         else
3162                                 need_break_row = 0;
3163              
3164                         // check, wether the last characters font has changed. 
3165                         if (cursor.pos && cursor.pos == cursor.par->Last()
3166                             && rawparfont != rawtmpfont)
3167                                 RedoHeightOfParagraph(cursor);
3168                         
3169                         charInserted();
3170                         return;
3171                 }
3172         }
3173    
3174         /* recalculate the fill of the row */ 
3175         if (row->fill >= 0)  /* needed because a newline
3176                               * will set fill to -1. Otherwise
3177                               * we would not get a rebreak! */
3178                 row->fill = Fill(row, paperwidth);
3179         if (row->fill < 0 ) {
3180                 refresh_y = y;
3181                 refresh_row = row; 
3182                 refresh_x = cursor.x;
3183                 refresh_pos = cursor.pos;
3184                 status = LyXText::NEED_MORE_REFRESH;
3185                 BreakAgainOneRow(row); 
3186                 /* will the cursor be in another row now? */ 
3187                 if (RowLast(row) <= cursor.pos + 1 && row->next) {
3188                         if (row->next && row->next->par == row->par)
3189                                 /* this should
3190                                  * always be true */
3191                                 row = row->next;
3192                         BreakAgainOneRow(row);
3193                 }
3194                 current_font = rawtmpfont;
3195                 real_current_font = realtmpfont;
3196                 SetCursor(cursor.par, cursor.pos + 1, false);
3197                 if (row->next && row->next->par == row->par)
3198                         need_break_row = row->next;
3199                 else
3200                         need_break_row = 0;             
3201         } else {
3202                 refresh_y = y;
3203                 refresh_x = cursor.x;
3204                 refresh_row = row;
3205                 refresh_pos = cursor.pos;
3206                 
3207                 int tmpheight = row->height;
3208                 SetHeightOfRow(row);
3209                 if (tmpheight == row->height)
3210                         status = LyXText::NEED_VERY_LITTLE_REFRESH;
3211                 else
3212                         status = LyXText::NEED_MORE_REFRESH;
3213             
3214                 current_font = rawtmpfont;
3215                 real_current_font = realtmpfont;
3216                 SetCursor(cursor.par, cursor.pos + 1, false);
3217         }
3218
3219         /* check, wether the last characters font has changed. */ 
3220         if (cursor.pos && cursor.pos == cursor.par->Last()
3221             && rawparfont != rawtmpfont) {
3222                 RedoHeightOfParagraph(cursor);
3223         } else {
3224                 /* now the special right address boxes */
3225                 if (textclasslist.Style(parameters->textclass,
3226                                    cursor.par->GetLayout()).margintype
3227                     == MARGIN_RIGHT_ADDRESS_BOX) {
3228                         RedoDrawingOfParagraph(cursor); 
3229                 }
3230         }
3231
3232         charInserted();
3233 }
3234    
3235
3236 void LyXText::charInserted()
3237 {
3238         // Here we could call FinishUndo for every 20 characters inserted.
3239         // This is from my experience how emacs does it.
3240         static unsigned int counter = 0;
3241         if (counter < 20) {
3242                 ++counter;
3243         } else {
3244                 FinishUndo();
3245                 counter = 0;
3246         }
3247 }
3248
3249 void LyXText::PrepareToPrint(Row * row, float & x,
3250                              float & fill_separator, 
3251                              float & fill_hfill,
3252                              float & fill_label_hfill,
3253                              bool bidi) const
3254 {
3255         float nh, nlh, ns;
3256         
3257         float w = row->fill;
3258         fill_hfill = 0;
3259         fill_label_hfill = 0;
3260         fill_separator = 0;
3261         fill_label_hfill = 0;
3262
3263         LyXDirection direction = row->par->getParDirection();
3264
3265         if (direction == LYX_DIR_RIGHT_TO_LEFT) {
3266                 x = RightMargin(row);
3267                 if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3268                         LyXFont font(LyXFont::ALL_SANE);
3269                         font.setSize(LyXFont::SIZE_SMALL);
3270                         x += font.textWidth("Mwide-figM", 10);
3271                 }
3272         }
3273         else
3274                 x = LeftMargin(row);
3275         
3276         /* is there a manual margin with a manual label */ 
3277         if (textclasslist.Style(parameters->textclass,
3278                            row->par->GetLayout()).margintype == MARGIN_MANUAL
3279             && textclasslist.Style(parameters->textclass,
3280                               row->par->GetLayout()).labeltype == LABEL_MANUAL) {
3281                
3282                 nlh = NumberOfLabelHfills(row) + 1; /* one more since labels 
3283                                                     * are left aligned*/ 
3284                 if (nlh && !row->par->GetLabelWidthString().empty()) {
3285                         fill_label_hfill = LabelFill(row) / nlh;
3286                 }
3287         }
3288                 
3289         /* are there any hfills in the row? */ 
3290         nh = NumberOfHfills(row);
3291         
3292 /* table stuff -- begin*/
3293         if (row->par->table) {
3294            w = paperwidth - row->par->table->WidthOfTable()
3295            - x - RightMargin(row);
3296            nh = 0; /* ignore hfills in tables */ 
3297         }
3298 /* table stuff -- end*/
3299
3300         if (nh)
3301           fill_hfill = w /nh;
3302         else  {
3303            /* is it block, flushleft or flushright? 
3304             * set x how you need it */
3305         int align;
3306         if (row->par->FirstPhysicalPar()->align == LYX_ALIGN_LAYOUT)
3307           align = textclasslist.Style(parameters->textclass, row->par->GetLayout()).align;
3308         else
3309           align = row->par->FirstPhysicalPar()->align;
3310            
3311            /* center displayed insets */ 
3312            if (row->par->GetChar(row->pos) == LyXParagraph::META_INSET
3313                && row->par->GetInset(row->pos)
3314                && row->par->GetInset(row->pos)->display())
3315              align = LYX_ALIGN_CENTER;
3316
3317            switch (align) {
3318             case LYX_ALIGN_BLOCK:
3319               ns = NumberOfSeparators(row);
3320               if (ns && row->next && row->next->par == row->par &&
3321                   !(row->next->par->IsNewline(row->next->pos-1))
3322                   && !(row->next->par->GetChar(row->next->pos) == LyXParagraph::META_INSET
3323                        && row->next->par->GetInset(row->next->pos)
3324                        && row->next->par->GetInset(row->next->pos)->display())
3325                   )
3326                 fill_separator = w / ns;
3327               else if (direction == LYX_DIR_RIGHT_TO_LEFT)
3328                 x += w;
3329               break;
3330             case LYX_ALIGN_RIGHT:
3331               x += w;
3332               break;
3333             case LYX_ALIGN_CENTER:
3334               x += w / 2;
3335               break;
3336            }
3337         }
3338         if (!bidi)
3339                 return;
3340
3341         ComputeBidiTables(row);
3342         if (direction == LYX_DIR_RIGHT_TO_LEFT) {
3343                 LyXParagraph::size_type main_body = 
3344                         BeginningOfMainBody(row->par);
3345                 LyXParagraph::size_type last = RowLast(row);
3346
3347                 if (row->pos <= last
3348                     && !row->par->table
3349                     && last != vis2log(last)
3350                     && row->par->IsLineSeparator(last)) {
3351                         if (!(main_body > 0 && main_body-1 == last))
3352                                 x -= fill_separator+SingleWidth(row->par,last);
3353                 } else if (main_body > 0 &&
3354                            (main_body-1 > last || 
3355                             !row->par->IsLineSeparator(main_body-1))) {
3356                         LyXLayout const & layout = textclasslist.Style(parameters->textclass,
3357                                                                        row->par->GetLayout());
3358                         x += GetFont(row->par, -2).stringWidth(layout.labelsep);
3359                         if (main_body-1 <= last)
3360                                 x += fill_label_hfill;
3361                 }
3362         }
3363 }
3364       
3365 /* important for the screen */
3366
3367
3368 /* the cursor set functions have a special mechanism. When they
3369 * realize, that you left an empty paragraph, they will delete it.
3370 * They also delete the corresponding row */
3371
3372 void LyXText::CursorRightOneWord() const
3373 {
3374         // treat floats, HFills and Insets as words
3375         LyXCursor tmpcursor = cursor;
3376
3377         if (tmpcursor.pos == tmpcursor.par->Last()
3378             && tmpcursor.par->Next())
3379         {
3380                         tmpcursor.par = tmpcursor.par->Next();
3381                         tmpcursor.pos = 0;
3382         } else {
3383                 int steps = 0;
3384
3385                 // Skip through initial nonword stuff.
3386                 while ( tmpcursor.pos < tmpcursor.par->Last() &&
3387                         ! tmpcursor.par->IsWord( tmpcursor.pos ) ) 
3388                 {
3389                   //    printf("Current pos1 %d", tmpcursor.pos) ;
3390                         tmpcursor.pos++;
3391                         ++steps;
3392                 }
3393                 // Advance through word.
3394                 while ( tmpcursor.pos < tmpcursor.par->Last() &&
3395                         tmpcursor.par->IsWord( tmpcursor.pos ) )
3396                 {
3397                   //     printf("Current pos2 %d", tmpcursor.pos) ;
3398                         tmpcursor.pos++;
3399                         ++steps;
3400                 }
3401         }
3402         SetCursor(tmpcursor.par, tmpcursor.pos);
3403 }
3404
3405
3406 void LyXText::CursorTab() const
3407 {
3408     if (cursor.par->table) {
3409         int cell = NumberOfCell(cursor.par, cursor.pos);
3410         while(cursor.par->table->IsContRow(cell)) {
3411             CursorUp();
3412             cell = NumberOfCell(cursor.par, cursor.pos);
3413         }
3414         if (cursor.par->table->ShouldBeVeryLastCell(cell))
3415             TableFeatures(LyXTable::APPEND_ROW);
3416     }
3417     LyXCursor tmpcursor = cursor;
3418     while (tmpcursor.pos < tmpcursor.par->Last()
3419            && !tmpcursor.par->IsNewline(tmpcursor.pos))
3420         tmpcursor.pos++;
3421    
3422     if (tmpcursor.pos == tmpcursor.par->Last()){
3423         if (tmpcursor.par->Next()) {
3424             tmpcursor.par = tmpcursor.par->Next();
3425             tmpcursor.pos = 0;
3426         }
3427     }
3428     else
3429         tmpcursor.pos++;
3430     SetCursor(tmpcursor.par, tmpcursor.pos);
3431     if (cursor.par->table) {
3432         int cell = NumberOfCell(cursor.par, cursor.pos);
3433         while (cursor.par->table->IsContRow(cell) &&
3434                !cursor.par->table->ShouldBeVeryLastCell(cell)) {
3435             tmpcursor = cursor;
3436             while (tmpcursor.pos < tmpcursor.par->Last()
3437                    && !tmpcursor.par->IsNewline(tmpcursor.pos))
3438                 tmpcursor.pos++;
3439    
3440             if (tmpcursor.pos == tmpcursor.par->Last()){
3441                 if (tmpcursor.par->Next()) {
3442                     tmpcursor.par = tmpcursor.par->Next();
3443                     tmpcursor.pos = 0;
3444                 }
3445             }
3446             else
3447                 tmpcursor.pos++;
3448             SetCursor(tmpcursor.par, tmpcursor.pos);
3449             cell = NumberOfCell(cursor.par, cursor.pos);
3450         }
3451     }
3452 }
3453
3454
3455 /* -------> Skip initial whitespace at end of word and move cursor to *start*
3456             of prior word, not to end of next prior word. */
3457
3458 void LyXText::CursorLeftOneWord()  const
3459 {
3460         // treat HFills, floats and Insets as words
3461         LyXCursor tmpcursor = cursor;
3462         while (tmpcursor.pos 
3463                && (tmpcursor.par->IsSeparator(tmpcursor.pos - 1) 
3464                    || tmpcursor.par->IsKomma(tmpcursor.pos - 1))
3465                && !(tmpcursor.par->IsHfill(tmpcursor.pos - 1)
3466                     || tmpcursor.par->IsFloat(tmpcursor.pos - 1)
3467                     || tmpcursor.par->IsInset(tmpcursor.pos - 1)))
3468                 tmpcursor.pos--;
3469
3470         if (tmpcursor.pos
3471             && (tmpcursor.par->IsInset(tmpcursor.pos - 1)
3472                 || tmpcursor.par->IsFloat(tmpcursor.pos - 1)
3473                 || tmpcursor.par->IsHfill(tmpcursor.pos - 1))) {
3474                 tmpcursor.pos--;
3475         } else if (!tmpcursor.pos) {
3476                 if (tmpcursor.par->Previous()){
3477                         tmpcursor.par = tmpcursor.par->Previous();
3478                         tmpcursor.pos = tmpcursor.par->Last();
3479                 }
3480         } else {                // Here, tmpcursor != 0 
3481                 while (tmpcursor.pos > 0 &&
3482                        tmpcursor.par->IsWord(tmpcursor.pos-1) )
3483                         tmpcursor.pos-- ;
3484         }
3485         SetCursor(tmpcursor.par, tmpcursor.pos);
3486 }
3487
3488 /* -------> Select current word. This depends on behaviour of CursorLeftOneWord(), so it is
3489                         patched as well. */
3490
3491 void LyXText::SelectWord() 
3492 {
3493         /* Move cursor to the beginning, when not already there. */
3494         if ( cursor.pos
3495              && !cursor.par->IsSeparator(cursor.pos-1)
3496              && !cursor.par->IsKomma(cursor.pos-1) )
3497                 CursorLeftOneWord();
3498
3499         /* set the sel cursor */
3500         sel_cursor = cursor;
3501
3502         while ( cursor.pos < cursor.par->Last()
3503                         && !cursor.par->IsSeparator(cursor.pos)
3504                         && !cursor.par->IsKomma(cursor.pos) )
3505                 cursor.pos++;
3506         SetCursor( cursor.par, cursor.pos );
3507         
3508         /* finally set the selection */ 
3509         SetSelection();
3510 }
3511
3512
3513 /* -------> Select the word currently under the cursor when:
3514                         1: no selection is currently set,
3515                         2: the cursor is not at the borders of the word. */
3516
3517 int LyXText::SelectWordWhenUnderCursor() 
3518 {
3519         if ( selection ) return 0;
3520         if ( cursor.pos < cursor.par->Last()
3521                  && !cursor.par->IsSeparator(cursor.pos)
3522                  && !cursor.par->IsKomma(cursor.pos)
3523                  && cursor.pos 
3524                  && !cursor.par->IsSeparator(cursor.pos -1)
3525                  && !cursor.par->IsKomma(cursor.pos -1) ) {
3526                 SelectWord();
3527                 return 1;
3528         }
3529         return 0;
3530 }
3531
3532
3533 // This function is only used by the spellchecker for NextWord().
3534 // It doesn't handle LYX_ACCENTs and probably never will.
3535 char * LyXText::SelectNextWord(float & value)
3536 {
3537         LyXParagraph * tmppar = cursor.par;
3538         
3539         // If this is not the very first word, skip rest of
3540         // current word because we are probably in the middle
3541         // of a word if there is text here.
3542         if (cursor.pos || cursor.par->previous) {
3543                 while (cursor.pos < cursor.par->Last()
3544                        && cursor.par->IsLetter(cursor.pos))
3545                         cursor.pos++;
3546         }
3547         // Now, skip until we have real text (will jump paragraphs)
3548         while ((cursor.par->Last() > cursor.pos
3549                 && (!cursor.par->IsLetter(cursor.pos)
3550                     || cursor.par->getFont(cursor.pos).latex() == LyXFont::ON))
3551                || (cursor.par->Last() == cursor.pos
3552                    && cursor.par->Next())){
3553                 if (cursor.pos == cursor.par->Last()) {
3554                         cursor.par = cursor.par->Next();
3555                         cursor.pos = 0;
3556                 }
3557                 else
3558                         cursor.pos++;
3559         }
3560   
3561         // Update the value if we changed paragraphs
3562         if (cursor.par != tmppar){
3563                 SetCursor(cursor.par, cursor.pos);
3564                 value = float(cursor.y)/float(height);
3565         }
3566
3567         /* Start the selection from here */
3568         sel_cursor = cursor;
3569
3570         string latex;
3571    
3572         /* and find the end of the word 
3573            (optional hyphens are part of a word) */
3574         while (cursor.pos < cursor.par->Last()
3575                && (cursor.par->IsLetter(cursor.pos)) 
3576                    || (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET &&
3577                        cursor.par->GetInset(cursor.pos) != 0 &&
3578                        cursor.par->GetInset(cursor.pos)->Latex(latex, 0) == 0 &&
3579                        latex == "\\-"))
3580                 cursor.pos++;
3581
3582         // Finally, we copy the word to a string and return it
3583         char * str = 0;
3584
3585         if (sel_cursor.pos < cursor.pos) {
3586                 str = new char [cursor.pos - sel_cursor.pos + 2];
3587                 LyXParagraph::size_type i, j;
3588                 for (i = sel_cursor.pos, j = 0; i < cursor.pos; ++i) {
3589                         if (cursor.par->GetChar(i) != LyXParagraph::META_INSET)
3590                                 str[j++] = cursor.par->GetChar(i);
3591                 }
3592                 str[j] = '\0';
3593         }
3594         return str;
3595 }
3596
3597
3598 // This one is also only for the spellchecker
3599 void LyXText::SelectSelectedWord()
3600 {
3601         /* move cursor to the beginning */
3602         SetCursor(sel_cursor.par, sel_cursor.pos);
3603         
3604         /* set the sel cursor */
3605         sel_cursor = cursor;
3606
3607         string latex;
3608         
3609         /* now find the end of the word */
3610         while (cursor.pos < cursor.par->Last()
3611                && (cursor.par->IsLetter(cursor.pos)
3612                    || (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET &&
3613                        cursor.par->GetInset(cursor.pos) != 0 &&
3614                        cursor.par->GetInset(cursor.pos)->Latex(latex, 0) == 0 &&
3615                        latex == "\\-")))
3616                 cursor.pos++;
3617         
3618         SetCursor(cursor.par, cursor.pos);
3619         
3620         /* finally set the selection */ 
3621         SetSelection();
3622 }
3623
3624
3625 /* -------> Delete from cursor up to the end of the current or next word. */
3626 void LyXText::DeleteWordForward()
3627 {
3628         LyXCursor tmpcursor = cursor;
3629         
3630         if (!cursor.par->Last())
3631                 CursorRight();
3632         else {
3633                 /* -------> Skip initial non-word stuff. */
3634                 while ( cursor.pos < cursor.par->Last() 
3635                         && (cursor.par->IsSeparator(cursor.pos)
3636                             || cursor.par->IsKomma(cursor.pos)) )
3637                         cursor.pos++;
3638                 
3639                 SetCursorIntern(cursor.par, cursor.pos);
3640                 selection = True; // to avoid deletion 
3641                 CursorRightOneWord();
3642                 sel_cursor = cursor;
3643                 cursor = tmpcursor;
3644                 SetSelection(); 
3645                 
3646                 /* -----> Great, CutSelection() gets rid of multiple spaces. */
3647                 CutSelection();
3648         }
3649 }
3650
3651
3652 /* -------> Delete from cursor to start of current or prior word. */
3653 void LyXText::DeleteWordBackward()
3654 {
3655        LyXCursor tmpcursor = cursor;
3656        if (!cursor.par->Last())
3657          CursorLeft();
3658        else{
3659          selection = true; // to avoid deletion 
3660          CursorLeftOneWord();
3661          sel_cursor = cursor;
3662          cursor = tmpcursor;
3663          SetSelection();
3664          CutSelection();
3665        }
3666 }
3667
3668
3669 /* -------> Kill to end of line. */
3670 void LyXText::DeleteLineForward()
3671 {
3672         LyXCursor tmpcursor = cursor;
3673         if (!cursor.par->Last())
3674                 CursorRight();
3675         else {
3676                 CursorEnd();
3677                 sel_cursor = cursor;
3678                 cursor = tmpcursor;
3679                 SetSelection();
3680                 if (selection == false) {
3681                         DeleteWordForward();
3682                 } else {
3683                         CutSelection();
3684                 }
3685         }
3686 }
3687
3688
3689 // Change the case of a word at cursor position. The meaning of action
3690 // is:
3691 // 0  change to lowercase
3692 // 1  capitalize word
3693 // 2  change to uppercase
3694 // This function directly manipulates LyXParagraph::text because there
3695 // is no LyXParagraph::SetChar currently. I did what I could to ensure
3696 // that it is correct. I guess part of it should be moved to
3697 // LyXParagraph, but it will have to change for 1.1 anyway. At least
3698 // it does not access outside of the allocated array as the older
3699 // version did. (JMarc) 
3700 void LyXText::ChangeWordCase(LyXText::TextCase action) 
3701 {
3702         LyXParagraph * tmppar = cursor.par->ParFromPos(cursor.pos);
3703
3704         SetUndo(Undo::FINISH, tmppar->previous, tmppar->next); 
3705
3706         LyXParagraph::size_type tmppos = 
3707                 cursor.par->PositionInParFromPos(cursor.pos);
3708         while (tmppos < tmppar->size()) {
3709                 unsigned char c = tmppar->text[tmppos];
3710                 if (IsKommaChar(c) || IsLineSeparatorChar(c))
3711                         break;
3712                 if (c != LyXParagraph::META_INSET) {
3713                         switch (action) {
3714                         case text_lowercase:
3715                                 c = tolower(c);
3716                                 break;
3717                         case text_capitalization:
3718                                 c = toupper(c);
3719                                 action = text_lowercase;
3720                                 break;
3721                         case text_uppercase:
3722                                 c = toupper(c);
3723                                 break;
3724                         }
3725                 }
3726                 
3727                 tmppar->text[tmppos] = c;
3728                 ++tmppos;
3729         }
3730         CheckParagraph(tmppar, tmppos);
3731         CursorRightOneWord();
3732 }
3733
3734
3735 void LyXText::Delete()
3736 {
3737         // this is a very easy implementation
3738
3739         LyXCursor old_cursor = cursor;
3740         int old_cur_par_id = old_cursor.par->id();
3741         int old_cur_par_prev_id = old_cursor.par->previous ?
3742                 old_cursor.par->previous->id() : 0;
3743         
3744         // just move to the right
3745         CursorRightIntern();
3746
3747         // This check is not very good...
3748         // The CursorRightIntern calls DeleteEmptyParagrapgMechanism
3749         // and that can very well delete the par or par->previous in
3750         // old_cursor. Will a solution where we compare paragraph id's
3751         //work better?
3752 #if 1
3753         if ((cursor.par->previous ? cursor.par->previous->id() : 0)
3754             == old_cur_par_prev_id
3755             && cursor.par->id() != old_cur_par_id)
3756                 return; // delete-empty-paragraph-mechanism has done it
3757 #else
3758         if (cursor.par->previous == old_cursor.par->previous
3759             && cursor.par != old_cursor.par)
3760                 return; // delete-empty-paragraph-mechanism has done it
3761 #endif
3762         // if you had success make a backspace
3763         if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) {
3764                 LyXCursor tmpcursor = cursor;
3765                 cursor = old_cursor; // to make sure undo gets the right cursor position
3766                 SetUndo(Undo::DELETE, 
3767                         cursor.par->ParFromPos(cursor.pos)->previous, 
3768                         cursor.par->ParFromPos(cursor.pos)->next); 
3769                 cursor = tmpcursor;
3770                 Backspace();
3771         }
3772 }
3773
3774
3775 void  LyXText::Backspace()
3776 {
3777         LyXParagraph * tmppar;
3778         Row * tmprow, * row;
3779         long y;
3780         int tmpheight;
3781
3782         /* table stuff -- begin */
3783         if (cursor.par->table) {
3784                 BackspaceInTable();
3785                 return;
3786         }
3787         /* table stuff -- end */
3788         
3789         LyXFont rawtmpfont = current_font;
3790         LyXFont realtmpfont = real_current_font;
3791    
3792         // Get the font that is used to calculate the baselineskip
3793         int const lastpos = cursor.par->Last();
3794         LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
3795
3796         if (cursor.pos == 0) {
3797                 // we may paste some paragraphs
3798       
3799                 // is it an empty paragraph?
3800       
3801                 if ((lastpos == 0
3802                      || (lastpos == 1 && cursor.par->IsSeparator(0)))
3803                     && !(cursor.par->Next() 
3804                          && cursor.par->footnoteflag == 
3805                          LyXParagraph::NO_FOOTNOTE
3806                          && cursor.par->Next()->footnoteflag == 
3807                          LyXParagraph::OPEN_FOOTNOTE)) {
3808                         
3809                         if (cursor.par->previous) {
3810                                 tmppar = cursor.par->previous->FirstPhysicalPar();
3811                                 if (cursor.par->GetLayout() == tmppar->GetLayout()
3812                                     && cursor.par->footnoteflag == tmppar->footnoteflag
3813                                     && cursor.par->GetAlign() == tmppar->GetAlign()) {
3814                                         
3815                                         tmppar->line_bottom = cursor.par->line_bottom;
3816                                         tmppar->added_space_bottom = cursor.par->added_space_bottom;
3817                                         tmppar->pagebreak_bottom = cursor.par->pagebreak_bottom;
3818                                 }
3819                                 
3820                                 CursorLeftIntern();
3821                      
3822                                 // the layout things can change the height of a row !
3823                                 tmpheight = cursor.row->height;
3824                                 SetHeightOfRow(cursor.row);
3825                                 if (cursor.row->height != tmpheight) {
3826                                         refresh_y = cursor.y - cursor.row->baseline;
3827                                         refresh_row = cursor.row;
3828                                         status = LyXText::NEED_MORE_REFRESH;
3829                                 }
3830                                 return;
3831                         }
3832                 }
3833                 if (cursor.par->ParFromPos(cursor.pos)->previous){
3834                         SetUndo(Undo::DELETE,
3835                                 cursor.par->ParFromPos(cursor.pos)->previous->previous,
3836                                 cursor.par->ParFromPos(cursor.pos)->next);
3837                 }
3838                 tmppar = cursor.par;
3839                 tmprow = cursor.row;
3840                 CursorLeftIntern();
3841                 /* Pasting is not allowed, if the paragraphs have different
3842                    layout. I think it is a real bug of all other
3843                    word processors to allow it. It confuses the user.
3844                    Even so with a footnote paragraph and a non-footnote
3845                    paragraph. I will not allow pasting in this case, 
3846                    because the user would be confused if the footnote behaves 
3847                    different wether it is open or closed.
3848                   
3849                    Correction: Pasting is always allowed with standard-layout
3850                 */
3851                 if (cursor.par != tmppar
3852                     && (cursor.par->GetLayout() == tmppar->GetLayout()
3853                         || !tmppar->GetLayout())
3854                     && cursor.par->footnoteflag == tmppar->footnoteflag
3855                     /* table stuff -- begin*/
3856                     && !cursor.par->table /* no pasting of tables */ 
3857                     /* table stuff -- end*/
3858                     && cursor.par->GetAlign() == tmppar->GetAlign()) {
3859                         
3860                         cursor.par->PasteParagraph();
3861                         
3862                         if (!(cursor.pos &&
3863                               cursor.par->IsSeparator(cursor.pos - 1)))
3864                                 cursor.par->InsertChar(cursor.pos, ' ');
3865                         else
3866                                 if (cursor.pos)
3867                                         cursor.pos--;
3868                         
3869                         status = LyXText::NEED_MORE_REFRESH;
3870                         refresh_row = cursor.row;
3871                         refresh_y = cursor.y - cursor.row->baseline;
3872                         
3873                         // remove the lost paragraph
3874                         RemoveParagraph(tmprow);
3875                         RemoveRow(tmprow);  
3876                         
3877                         AppendParagraph(cursor.row);
3878                         UpdateCounters(cursor.row);
3879                         
3880                         // the row may have changed, block, hfills etc.
3881                         SetCursor(cursor.par, cursor.pos);
3882                 }
3883         } else {
3884                 /* this is the code for a normal backspace, not pasting
3885                  * any paragraphs */ 
3886                 SetUndo(Undo::DELETE, 
3887                         cursor.par->ParFromPos(cursor.pos)->previous, 
3888                         cursor.par->ParFromPos(cursor.pos)->next); 
3889                 CursorLeftIntern();
3890                 
3891                 // some insets are undeletable here
3892                 if (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
3893                         if (!cursor.par->GetInset(cursor.pos)->Deletable())
3894                                 return; 
3895                         // force complete redo when erasing display insets
3896                         // this is a cruel mathod but save..... Matthias 
3897                         if (cursor.par->GetInset(cursor.pos)->display()){
3898                                 cursor.par->Erase(cursor.pos);
3899                                 RedoParagraph();
3900                                 return;
3901                         }
3902                 }
3903                 
3904                 row = cursor.row;
3905                 y = cursor.y - row->baseline;
3906                 LyXParagraph::size_type z;
3907                 /* remember that a space at the end of a row doesnt count
3908                  * when calculating the fill */ 
3909                 if (cursor.pos < RowLast(row) ||
3910                     !cursor.par->IsLineSeparator(cursor.pos)) {
3911                         row->fill += SingleWidth(cursor.par, cursor.pos);
3912                 }
3913                 
3914                 /* some special code when deleting a newline. This is similar
3915                  * to the behavior when pasting paragraphs */ 
3916                 if (cursor.pos && cursor.par->IsNewline(cursor.pos)) {
3917                         cursor.par->Erase(cursor.pos);
3918                         // refresh the positions
3919                         tmprow = row;
3920                         while (tmprow->next && tmprow->next->par == row->par) {
3921                                 tmprow = tmprow->next;
3922                                 tmprow->pos--;
3923                         }
3924                         if (cursor.par->IsLineSeparator(cursor.pos - 1))
3925                                 cursor.pos--;
3926                         
3927                         if (cursor.pos < cursor.par->Last() && !cursor.par->IsSeparator(cursor.pos)) {
3928                                 cursor.par->InsertChar(cursor.pos, ' ');
3929                                 // refresh the positions
3930                                 tmprow = row;
3931                                 while (tmprow->next && tmprow->next->par == row->par) {
3932                                         tmprow = tmprow->next;
3933                                         tmprow->pos++;
3934                                 }
3935                         }
3936                 } else {
3937                         cursor.par->Erase(cursor.pos);
3938                         
3939                         // refresh the positions
3940                         tmprow = row;
3941                         while (tmprow->next && tmprow->next->par == row->par) {
3942                                 tmprow = tmprow->next;
3943                                 tmprow->pos--;
3944                         }
3945
3946 #ifndef FIX_DOUBLE_SPACE
3947                         // delete superfluous blanks 
3948                         if (cursor.pos < cursor.par->Last() - 1 &&
3949                             (cursor.par->IsLineSeparator(cursor.pos))) {
3950                                 
3951                                 if (cursor.pos == BeginningOfMainBody(cursor.par)
3952                                     || !cursor.pos 
3953                                     || cursor.par->IsLineSeparator(cursor.pos - 1)) {
3954                                         cursor.par->Erase(cursor.pos);
3955                                         // refresh the positions
3956                                         tmprow = row;
3957                                         while (tmprow->next && 
3958                                                tmprow->next->par == row->par) {
3959                                                 tmprow = tmprow->next;
3960                                                 tmprow->pos--;
3961                                         }
3962                                         if (cursor.pos)   // move one character left
3963                                                 cursor.pos--;
3964                                 }
3965                         }
3966 #endif
3967                         
3968                         // delete newlines at the beginning of paragraphs
3969                         while (cursor.par->Last() &&
3970                                cursor.par->IsNewline(cursor.pos) &&
3971                                cursor.pos == BeginningOfMainBody(cursor.par)) {
3972                                 cursor.par->Erase(cursor.pos);
3973                                 // refresh the positions
3974                                 tmprow = row;
3975                                 while (tmprow->next && 
3976                                        tmprow->next->par == row->par) {
3977                                         tmprow = tmprow->next;
3978                                         tmprow->pos--;
3979                                 }
3980                         }
3981                 }
3982                 
3983                 // is there a break one row above
3984                 if (row->previous && row->previous->par == row->par) {
3985                         z = NextBreakPoint(row->previous, paperwidth);
3986                         if ( z >= row->pos) {
3987                                 row->pos = z + 1;
3988                                 
3989                                 tmprow = row->previous;
3990                                 
3991                                 // maybe the current row is now empty
3992                                 if (row->pos >= row->par->Last()) {
3993                                         // remove it
3994                                         RemoveRow(row);
3995                                         need_break_row = 0;
3996                                 } else {
3997                                         BreakAgainOneRow(row);
3998                                         if (row->next && row->next->par == row->par)
3999                                                 need_break_row = row->next;
4000                                         else
4001                                                 need_break_row = 0;
4002                                 }
4003                                 
4004                                 // set the dimensions of the row above
4005                                 y -= tmprow->height;
4006                                 tmprow->fill = Fill(tmprow, paperwidth);
4007                                 SetHeightOfRow(tmprow);
4008                                 
4009                                 refresh_y = y;
4010                                 refresh_row = tmprow;
4011                                 status = LyXText::NEED_MORE_REFRESH;
4012                                 current_font = rawtmpfont;
4013                                 real_current_font = realtmpfont;
4014                                 SetCursor(cursor.par, cursor.pos, false);
4015                                 // check, whether the last character's font has changed.
4016                                 rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
4017                                 if (rawparfont != rawtmpfont)
4018                                         RedoHeightOfParagraph(cursor);
4019                                 return;
4020                         }
4021                 }
4022                 
4023                 // break the cursor row again
4024                 z = NextBreakPoint(row, paperwidth);
4025                 
4026                 if (z != RowLast(row) || 
4027                     (row->next && row->next->par == row->par &&
4028                      RowLast(row) == row->par->Last() - 1)){
4029                         
4030                         /* it can happen that a paragraph loses one row
4031                          * without a real breakup. This is when a word
4032                          * is to long to be broken. Well, I don t care this 
4033                          * hack ;-) */ 
4034                         if (row->next && row->next->par == row->par &&
4035                             RowLast(row) == row->par->Last() - 1)
4036                                 RemoveRow(row->next);
4037                         
4038                         refresh_y = y;
4039                         refresh_row = row;
4040                         status = LyXText::NEED_MORE_REFRESH;
4041                         
4042                         BreakAgainOneRow(row);
4043                         current_font = rawtmpfont; 
4044                         real_current_font = realtmpfont;
4045                         SetCursor(cursor.par, cursor.pos, false);
4046                         // cursor MUST be in row now
4047                         
4048                         if (row->next && row->next->par == row->par)
4049                                 need_break_row = row->next;
4050                         else
4051                                 need_break_row = 0;
4052                 } else  {
4053                         // set the dimensions of the row
4054                         row->fill = Fill(row, paperwidth);
4055                         int tmpheight = row->height;
4056                         SetHeightOfRow(row);
4057                         if (tmpheight == row->height)
4058                                 status = LyXText::NEED_VERY_LITTLE_REFRESH;
4059                         else
4060                                 status = LyXText::NEED_MORE_REFRESH;
4061                         refresh_y = y;
4062                         refresh_row = row;
4063                         current_font = rawtmpfont; 
4064                         real_current_font = realtmpfont;
4065                         SetCursor(cursor.par, cursor.pos, false);
4066                 }
4067         }
4068    
4069         // restore the current font
4070         // That is what a user expects!
4071         current_font = rawtmpfont; 
4072         real_current_font = realtmpfont;
4073         
4074         // check, wether the last characters font has changed.
4075         rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
4076         if (rawparfont != rawtmpfont) {
4077                 RedoHeightOfParagraph(cursor);
4078         } else {
4079                 // now the special right address boxes
4080                 if (textclasslist.Style(parameters->textclass,
4081                                         cursor.par->GetLayout()).margintype == MARGIN_RIGHT_ADDRESS_BOX) {
4082                         RedoDrawingOfParagraph(cursor); 
4083                 }
4084         }
4085 }
4086
4087
4088 #ifdef USE_PAINTER
4089 void LyXText::GetVisibleRow(int offset, 
4090                             Row * row_ptr, long y)
4091 {
4092         /* returns a printed row */
4093         Painter & pain = owner_->painter();
4094         
4095         LyXDirection direction = row_ptr->par->getParDirection();
4096         LyXParagraph::size_type vpos, pos, pos_end;
4097         float x, tmpx;
4098         int y_top, y_bottom;
4099         float fill_separator, fill_hfill, fill_label_hfill;
4100         LyXParagraph * par, * firstpar;
4101         LyXFont font;
4102         int maxdesc;
4103         if (row_ptr->height <= 0) {
4104                 lyxerr << "LYX_ERROR: row.height: " << row_ptr->height << endl;
4105                 return;
4106         }
4107         PrepareToPrint(row_ptr, x, fill_separator,
4108                        fill_hfill, fill_label_hfill);
4109
4110         /* initialize the pixmap */
4111         
4112         pain.fillRectangle(0, offset, paperwidth, row_ptr->height);
4113         
4114         // check for NOT FAST SELECTION
4115         if (
4116 #ifdef MONO
4117                 !fast_selection && !mono_video &&
4118 #endif
4119                 selection) {
4120                 /* selection code */ 
4121                 if (sel_start_cursor.row == row_ptr &&
4122                     sel_end_cursor.row == row_ptr) {
4123                         if (sel_start_cursor.x < sel_end_cursor.x)
4124                                 pain.fillRectangle(sel_start_cursor.x, offset,
4125                                                    sel_end_cursor.x - sel_start_cursor.x,
4126                                                    row_ptr->height,
4127                                                    LColor::selection);
4128                         else
4129                                 pain.fillRectangle(sel_end_cursor.x, offset,
4130                                                    sel_start_cursor.x - sel_end_cursor.x,
4131                                                    row_ptr->height,
4132                                                    LColor::selection);
4133                 } else if (sel_start_cursor.row == row_ptr) {
4134                      if (direction == LYX_DIR_LEFT_TO_RIGHT)
4135                              pain.fillRectangle(sel_start_cursor.x, offset,
4136                                                 paperwidth - sel_start_cursor.x,
4137                                                 row_ptr->height,
4138                                                 LColor::selection);
4139                      else
4140                              pain.fillRectangle(0, offset,
4141                                                 sel_start_cursor.x,
4142                                                 row_ptr->height,
4143                                                 LColor::selection);
4144                 } else if (sel_end_cursor.row == row_ptr) {
4145                      if (direction == LYX_DIR_LEFT_TO_RIGHT)
4146                              pain.fillRectangle(0, offset,
4147                                                 sel_end_cursor.x,
4148                                                 row_ptr->height,
4149                                                 LColor::selection);
4150                      else
4151                              pain.fillRectangle(sel_end_cursor.x, offset,
4152                                                 paperwidth - sel_end_cursor.x,
4153                                                 row_ptr->height,
4154                                                 LColor::selection);
4155
4156                 } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
4157                         pain.fillRectangle(0, offset,
4158                                            paperwidth, row_ptr->height,
4159                                            LColor::selection);
4160                 }
4161         } // end of NOT FAST SELECTION code
4162         
4163         if (row_ptr->par->appendix){
4164                 pain.line(1, offset,
4165                           1, offset + row_ptr->height,
4166                           LColor::appendixline);
4167                 pain.line(paperwidth - 2, offset,
4168                           paperwidth - 2, offset + row_ptr->height,
4169                           LColor::appendixline);
4170         }
4171
4172         if (row_ptr->par->pextra_type == LyXParagraph::PEXTRA_MINIPAGE) {
4173                 /* draw a marker at the left margin! */ 
4174                 LyXFont font = GetFont(row_ptr->par, 0);
4175                 int asc = font.maxAscent();
4176                 int x = (LYX_PAPER_MARGIN - font.width('|')) / 2;
4177                 int y1 = (offset + row_ptr->baseline);
4178                 int y2 = (offset + row_ptr->baseline) - asc;
4179                 pain.line(x, y1, x, y2, LColor::minipageline);
4180         }       
4181         if (row_ptr->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
4182                 LyXFont font(LyXFont::ALL_SANE);
4183                 font.setSize(LyXFont::SIZE_FOOTNOTE);
4184                 font.setColor(LColor::footnote);
4185                 
4186                 int box_x = LYX_PAPER_MARGIN;
4187                 box_x += font.textWidth(" wide-tab ", 10);
4188                 if (row_ptr->previous && 
4189                     row_ptr->previous->par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
4190                         string fs;
4191                         switch (row_ptr->par->footnotekind) {
4192                         case LyXParagraph::MARGIN:
4193                                 fs = " margin";
4194                                 break;
4195                         case LyXParagraph::FIG:
4196                                 fs = " fig";
4197                                 break;
4198                         case LyXParagraph::TAB:
4199                                 fs = " tab";
4200                                 break;
4201                         case LyXParagraph::WIDE_FIG:
4202                                 fs = " wide-fig";
4203                                 break;
4204                         case LyXParagraph::WIDE_TAB:
4205                                 fs = " wide-tab";
4206                                 break;
4207                         case LyXParagraph::ALGORITHM:
4208                                 fs = " alg";
4209                                 break;
4210                         case LyXParagraph::FOOTNOTE:
4211                                 fs = " foot";
4212                                 break;
4213                         }
4214
4215 #if 0
4216                         // Determine background color.
4217                         gc_type back = gc_lighted;
4218                         if (mono_video) {
4219                                 back = gc_clear;
4220                         }
4221 #endif
4222                         pain.fillRectangle(LYX_PAPER_MARGIN,
4223                                            offset + 1,
4224                                            box_x - LYX_PAPER_MARGIN,
4225                                            int(font.maxAscent()
4226                                                + font.maxDescent()),
4227                                            LColor::footnotebg);
4228
4229                         pain.line(LYX_PAPER_MARGIN, offset,
4230                                   paperwidth - LYX_PAPER_MARGIN, offset,
4231                                   LColor::footnoteframe);
4232
4233                         pain.text(LYX_PAPER_MARGIN,
4234                                   offset + int(font.maxAscent()) + 1,
4235                                   fs, font);
4236
4237                         pain.line(LYX_PAPER_MARGIN, offset,
4238                                   LYX_PAPER_MARGIN,
4239                                   offset + int(font.maxAscent()
4240                                                + font.maxDescent()),
4241                                   LColor::footnoteframe);
4242
4243                         pain.line(LYX_PAPER_MARGIN,
4244                                   offset + int(font.maxAscent()
4245                                                + font.maxDescent()) + 1,
4246                                   box_x,
4247                                   offset + int(font.maxAscent()
4248                                                + font.maxDescent()) + 1,
4249                                   LColor::footnoteframe);
4250                         
4251                 }
4252                 
4253                 /* draw the open floats in a red box */
4254                 pain.line(box_x, offset,
4255                           box_x, offset + row_ptr->height,
4256                           LColor::footnoteframe);
4257
4258                 pain.line(paperwidth - LYX_PAPER_MARGIN,
4259                           offset,
4260                           paperwidth - LYX_PAPER_MARGIN,
4261                           offset + row_ptr->height,
4262                           LColor::footnoteframe);
4263         } else  {
4264                 if (row_ptr->previous &&
4265                     row_ptr->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
4266                         LyXFont font(LyXFont::ALL_SANE);
4267                         font.setSize(LyXFont::SIZE_FOOTNOTE);
4268
4269                         int box_x = LYX_PAPER_MARGIN;
4270                         box_x += font.textWidth(" wide-tab ", 10);
4271
4272                         pain.line(box_x, offset,
4273                                   paperwidth - LYX_PAPER_MARGIN,
4274                                   offset, LColor::footnote);
4275                 }
4276         }
4277         
4278         LyXLayout const & layout = textclasslist.Style(parameters->textclass,
4279                                            row_ptr->par->GetLayout());
4280         firstpar = row_ptr->par->FirstPhysicalPar();
4281         
4282         y_top = 0;
4283         y_bottom = row_ptr->height;
4284         
4285         /* is it a first row? */ 
4286         if (row_ptr->pos == 0
4287             && row_ptr->par == firstpar) {
4288                 
4289                  /* start of appendix? */
4290                 if (row_ptr->par->start_of_appendix){
4291                         pain.line(1, offset,
4292                                   paperwidth - 2, offset,
4293                                   LColor::appendixline);
4294                 }
4295
4296                 /* think about the margins */ 
4297                 if (!row_ptr->previous)
4298                         y_top += LYX_PAPER_MARGIN;
4299                 
4300                 if (row_ptr->par->pagebreak_top){ /* draw a top pagebreak  */
4301                         pain.line(0, offset + y_top + 2 * DefaultHeight(),
4302                                   paperwidth,
4303                                   offset + y_top + 2 * DefaultHeight(),
4304                                   LColor::pagebreak, Painter::line_onoffdash);
4305                         y_top += 3 * DefaultHeight();
4306                 }
4307                 
4308                 if (row_ptr->par->added_space_top.kind() == VSpace::VFILL) {
4309                         /* draw a vfill top  */
4310                         pain.line(0, offset + 2 + y_top,
4311                                   LYX_PAPER_MARGIN, offset + 2 + y_top,
4312                                   LColor::vfillline);
4313                         
4314                         pain.line(0, offset + y_top + 3 * DefaultHeight(),
4315                                   LYX_PAPER_MARGIN,
4316                                   offset + y_top + 3 * DefaultHeight(),
4317                                   LColor::vfillline);
4318                         
4319                         pain.line(LYX_PAPER_MARGIN / 2, offset + 2 + y_top,
4320                                   LYX_PAPER_MARGIN / 2,
4321                                   offset + y_top + 3 * DefaultHeight(),
4322                                   LColor::vfillline);
4323                         
4324                         y_top += 3 * DefaultHeight();
4325                 }
4326                 
4327                 /* think about user added space */ 
4328                 y_top += int(row_ptr->par->added_space_top.inPixels());
4329                 
4330                 /* think about the parskip */ 
4331                 /* some parskips VERY EASY IMPLEMENTATION */ 
4332                 if (parameters->paragraph_separation == BufferParams::PARSEP_SKIP) {
4333                         if (layout.latextype == LATEX_PARAGRAPH
4334                             && firstpar->GetDepth() == 0
4335                             && firstpar->Previous())
4336                                 y_top += parameters->getDefSkip().inPixels();
4337                         else if (firstpar->Previous()
4338                                  && textclasslist.Style(parameters->textclass,
4339                                                    firstpar->Previous()->GetLayout()).latextype == LATEX_PARAGRAPH
4340                                  && firstpar->Previous()->GetDepth() == 0)
4341                                 // is it right to use defskip here, too? (AS) 
4342                                 y_top += parameters->getDefSkip().inPixels();
4343                 }
4344                 
4345                 if (row_ptr->par->line_top) {      /* draw a top line  */
4346                         y_top +=  GetFont(row_ptr->par, 0).ascent('x');
4347
4348                         pain.line(0, offset + y_top,
4349                                   paperwidth, offset + y_top,
4350                                   LColor::topline,
4351                                   Painter::line_solid,
4352                                   Painter::line_thick);
4353                         
4354                         y_top +=  GetFont(row_ptr->par, 0).ascent('x');
4355                 }
4356                 
4357                 /* should we print a label? */ 
4358                 if (layout.labeltype >= LABEL_STATIC
4359                     && (layout.labeltype != LABEL_STATIC
4360                         || layout.latextype != LATEX_ENVIRONMENT
4361                         || row_ptr->par->IsFirstInSequence())) {
4362                         font = GetFont(row_ptr->par, -2);
4363                         if (!row_ptr->par->GetLabestring().empty()) {
4364                                 tmpx = x;
4365                                 string tmpstring = row_ptr->par->GetLabestring();
4366                                 
4367                                 if (layout.labeltype == LABEL_COUNTER_CHAPTER) {
4368                                         if (parameters->secnumdepth >= 0){
4369                                                 /* this is special code for the chapter layout. This is printed in
4370                                                  * an extra row and has a pagebreak at the top. */
4371                                                 maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue())
4372                                                         + int(layout.parsep) * DefaultHeight();
4373                                                 if (direction == LYX_DIR_RIGHT_TO_LEFT)
4374                                                         tmpx = paperwidth - LeftMargin(row_ptr) - 
4375                                                                 font.stringWidth(tmpstring);
4376                                                 pain.text(int(tmpx),
4377                                                           offset + row_ptr->baseline - row_ptr->ascent_of_text - maxdesc,
4378                                                           tmpstring, font);
4379                                         }
4380                                 } else {
4381                                         if (direction == LYX_DIR_LEFT_TO_RIGHT)
4382                                                 tmpx = x - font.stringWidth(layout.labelsep)
4383                                                         - font.stringWidth(tmpstring);
4384                                         else {
4385                                                 tmpx = paperwidth - LeftMargin(row_ptr)
4386                                                         + font.stringWidth(layout.labelsep);
4387                                                 if (row_ptr->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)  {
4388                                                         LyXFont font(LyXFont::ALL_SANE);
4389                                                         font.setSize(LyXFont::SIZE_SMALL);
4390                                                         tmpx += font.textWidth("Mwide-figM", 10);
4391                                                 }
4392                                         }
4393                                         /* draw it! */
4394                                         pain.text(int(tmpx),
4395                                                   offset + row_ptr->baseline,
4396                                                   tmpstring, font);
4397                                 }
4398                         }
4399                         /* the labels at the top of an environment. More or less for bibliography */ 
4400                 } else if (layout.labeltype == LABEL_TOP_ENVIRONMENT ||
4401                            layout.labeltype == LABEL_BIBLIO ||
4402                            layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) {
4403                         if (row_ptr->par->IsFirstInSequence()) {
4404                                 font = GetFont(row_ptr->par, -2);
4405                                 if (!row_ptr->par->GetLabestring().empty()) {
4406                                         string tmpstring = row_ptr->par->GetLabestring();
4407                                         
4408                                         maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue()
4409                                                          + (layout.labelbottomsep * DefaultHeight()));
4410                                         
4411                                         tmpx = x;
4412                                         if (layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT){
4413                                                 tmpx = ( ((direction == LYX_DIR_LEFT_TO_RIGHT)
4414                                                           ? x : LeftMargin(row_ptr) )
4415                                                          + paperwidth - RightMargin(row_ptr) ) / 2; 
4416                                                 tmpx -= (font.stringWidth(tmpstring)/2);
4417                                         } else if (direction == LYX_DIR_RIGHT_TO_LEFT)
4418                                                 tmpx = paperwidth - LeftMargin(row_ptr) - 
4419                                                         font.stringWidth(tmpstring);
4420                                         pain.text(int(tmpx),
4421                                                   offset + row_ptr->baseline
4422                                                   - row_ptr->ascent_of_text
4423                                                   - maxdesc,
4424                                                   tmpstring, font);
4425                                 }
4426                         }
4427                 }
4428                 if (layout.labeltype == LABEL_BIBLIO) { // ale970302
4429                         if (row_ptr->par->bibkey) {
4430                                 font = GetFont(row_ptr->par, -1);
4431                                 if (direction == LYX_DIR_LEFT_TO_RIGHT)
4432                                         tmpx = x - font.stringWidth(layout.labelsep)
4433                                                 - row_ptr->par->bibkey->width(owner_->painter(), font);
4434                                 else
4435                                         tmpx = paperwidth - LeftMargin(row_ptr)
4436                                                 + font.stringWidth(layout.labelsep);
4437                                 row_ptr->par->bibkey->draw(owner_->painter(),
4438                                                            font,
4439                                                            offset + row_ptr->baseline, 
4440                                                            tmpx);
4441                         }
4442                 } 
4443         }
4444         
4445         /* is it a last row? */
4446         par = row_ptr->par->LastPhysicalPar();
4447         if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
4448             && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {     
4449                 
4450                 /* think about the margins */ 
4451                 if (!row_ptr->next)
4452                         y_bottom -= LYX_PAPER_MARGIN;
4453                 
4454                 /* draw a bottom pagebreak */ 
4455                 if (firstpar->pagebreak_bottom) {
4456                         pain.line(0, offset + y_bottom - 2 * DefaultHeight(),
4457                                   paperwidth,
4458                                   offset + y_bottom - 2 * DefaultHeight(),
4459                                   LColor::pagebreak, Painter::line_onoffdash);
4460                         y_bottom -= 3 * DefaultHeight();
4461                 }
4462                 
4463                 if (firstpar->added_space_bottom.kind() == VSpace::VFILL) {
4464                         /* draw a vfill bottom  */
4465                         pain.line(0, offset + y_bottom - 3 * DefaultHeight(),
4466                                   LYX_PAPER_MARGIN,
4467                                   offset + y_bottom - 3 * DefaultHeight(),
4468                                   LColor::vfillline);
4469                         pain.line(0, offset + y_bottom - 2,
4470                                   LYX_PAPER_MARGIN,
4471                                   offset + y_bottom - 2,
4472                                   LColor::vfillline);
4473                         pain.line(LYX_PAPER_MARGIN / 2,
4474                                   offset + y_bottom - 3 * DefaultHeight(),
4475                                   LYX_PAPER_MARGIN / 2,
4476                                   offset + y_bottom - 2,
4477                                   LColor::vfillline);
4478                         y_bottom -= 3* DefaultHeight();
4479                 }
4480                 
4481                 /* think about user added space */ 
4482                 y_bottom -= int(firstpar->added_space_bottom.inPixels());
4483                 
4484                 if (firstpar->line_bottom) {
4485                         /* draw a bottom line */
4486                         y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
4487                         pain.line(0, offset + y_bottom,
4488                                   paperwidth, offset + y_bottom,
4489                                   LColor::topline, Painter::line_solid,
4490                                   Painter::line_thick);
4491                         y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
4492                 }
4493         }
4494         
4495         /* draw the text in the pixmap */  
4496         pos_end = RowLast(row_ptr);
4497         
4498         vpos = row_ptr->pos;
4499         /* table stuff -- begin*/
4500         if (row_ptr->par->table) {
4501                 bool on_off;
4502                 int cell = NumberOfCell(row_ptr->par, row_ptr->pos);
4503                 float x_old = x;
4504                 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
4505                 
4506                 while (vpos <= pos_end)  {
4507                         pos = vis2log(vpos);
4508                         if (row_ptr->par->IsNewline(pos)) {
4509                                 
4510                                 x = x_old + row_ptr->par->table->WidthOfColumn(cell);
4511                                 /* draw the table lines, still very simple */
4512                                 on_off = !row_ptr->par->table->TopLine(cell);
4513                                 if ((!on_off ||
4514                                      !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
4515                                     !row_ptr->par->table->IsContRow(cell))
4516                                         pain.line(int(x_old),
4517                                                   offset + row_ptr->baseline - row_ptr->ascent_of_text,
4518                                                   int(x),
4519                                                   offset + row_ptr->baseline - row_ptr->ascent_of_text,
4520                                                   LColor::tableline,
4521                                                   on_off ? Painter::line_onoffdash : Painter::line_solid);
4522                                 
4523                                 on_off = !row_ptr->par->table->BottomLine(cell);
4524                                 if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
4525                                     row_ptr->par->table->VeryLastRow(cell))
4526
4527                                         pain.line(int(x_old),
4528                                                   offset + y_bottom - 1,
4529                                                   int(x),
4530                                                   offset + y_bottom - 1,
4531                                                   LColor::tableline,
4532                                                   on_off ? Painter::line_onoffdash : Painter::line_solid);
4533
4534                                 on_off = !row_ptr->par->table->LeftLine(cell);
4535
4536                                 pain.line(int(x_old),
4537                                           offset + row_ptr->baseline - row_ptr->ascent_of_text,
4538                                           int(x_old),
4539                                           offset + y_bottom - 1,
4540                                           LColor::tableline,
4541                                           on_off ? Painter::line_onoffdash : Painter::line_solid);
4542                                 
4543                                 on_off = !row_ptr->par->table->RightLine(cell);
4544
4545                                 pain.line(int(x) - row_ptr->par->table->AdditionalWidth(cell),
4546                                           offset + row_ptr->baseline - row_ptr->ascent_of_text,
4547                                           int(x) - row_ptr->par->table->AdditionalWidth(cell),
4548                                           offset + y_bottom - 1,
4549                                           LColor::tableline,
4550                                           on_off ? Painter::line_onoffdash : Painter::line_solid);
4551                                 
4552                                 x_old = x;
4553                 /* take care about the alignment and other spaces */
4554                                 ++cell;
4555                                 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
4556                                 if (row_ptr->par->table->IsFirstCell(cell))
4557                                         --cell; // little hack, sorry
4558                                 ++vpos;
4559                         } else if (row_ptr->par->IsHfill(pos)) {
4560                                 x += 1;
4561
4562                                 pain.line(int(x),
4563                                           offset + row_ptr->baseline - DefaultHeight() / 2,
4564                                           int(x),
4565                                           offset + row_ptr->baseline,
4566                                           LColor::vfillline);
4567                                 
4568                                 x += 2;
4569                                 ++vpos;
4570                         } else {
4571                                 if (row_ptr->par->IsSeparator(pos)) {
4572                                         tmpx = x;
4573                                         x+= SingleWidth(row_ptr->par, pos);
4574                                         /* -------> Only draw protected spaces when not in
4575                                          * free-spacing mode. */
4576                                         if (row_ptr->par->GetChar(pos) == LyXParagraph::META_PROTECTED_SEPARATOR && !layout.free_spacing) {
4577                                                 pain.line(int(tmpx),
4578                                                           offset + row_ptr->baseline - 3,
4579                                                           int(tmpx),
4580                                                           offset + row_ptr->baseline - 1,
4581                                                           LColor::vfillline);
4582                                                 
4583                                                 pain.line(int(tmpx),
4584                                                           offset + row_ptr->baseline - 1,
4585                                                           int(x - 2),
4586                                                           offset + row_ptr->baseline - 1,
4587                                                           LColor::vfillline);
4588                                                 
4589                                                 pain.line(int(x - 2),
4590                                                           offset + row_ptr->baseline - 3,
4591                                                           int(x - 2),
4592                                                           offset + row_ptr->baseline - 1,
4593                                                           LColor::vfillline);
4594                                                 
4595                                                 /* what about underbars? */
4596                                                 font = GetFont(row_ptr->par, pos); 
4597                                                 if (font.underbar() == LyXFont::ON
4598                                                     && font.latex() != LyXFont::ON) {
4599                                                         pain.line(int(tmpx),
4600                                                                   offset + row_ptr->baseline + 2,
4601                                                                   int(x - tmpx),
4602                                                                   offset + row_ptr->baseline + 2);
4603                                                 }
4604                                         }
4605                                         ++vpos;
4606                                 } else
4607                                         draw(row_ptr, vpos, offset, x);
4608                         }
4609                 }
4610                 
4611                 /* do not forget the very last cell. This has no NEWLINE so 
4612                  * ignored by the code above*/ 
4613                 if (cell == row_ptr->par->table->GetNumberOfCells()-1){
4614                         x = x_old + row_ptr->par->table->WidthOfColumn(cell);
4615                         on_off = !row_ptr->par->table->TopLine(cell);
4616                         if ((!on_off ||
4617                              !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
4618                             !row_ptr->par->table->IsContRow(cell))
4619
4620                                 pain.line(int(x_old),
4621                                           offset + row_ptr->baseline - row_ptr->ascent_of_text,
4622                                           int(x),
4623                                           offset + row_ptr->baseline - row_ptr->ascent_of_text,
4624                                           LColor::tableline,
4625                                           on_off ? Painter::line_onoffdash : Painter::line_solid);
4626                         on_off = !row_ptr->par->table->BottomLine(cell);
4627                         if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
4628                             row_ptr->par->table->VeryLastRow(cell))
4629
4630                                 pain.line(int(x_old),
4631                                           offset + y_bottom - 1,
4632                                           int(x),
4633                                           offset + y_bottom - 1,
4634                                           LColor::tableline,
4635                                           on_off ? Painter::line_onoffdash : Painter::line_solid);
4636                         
4637                         on_off = !row_ptr->par->table->LeftLine(cell);
4638
4639                         pain.line(int(x_old),
4640                                   offset + row_ptr->baseline - row_ptr->ascent_of_text,
4641                                   int(x_old),
4642                                   offset + y_bottom - 1,
4643                                   LColor::tableline,
4644                                   on_off ? Painter::line_onoffdash : Painter::line_solid);
4645                         
4646                         on_off = !row_ptr->par->table->RightLine(cell);
4647
4648                         pain.line(int(x) - row_ptr->par->table->AdditionalWidth(cell),
4649                                   offset + row_ptr->baseline - row_ptr->ascent_of_text,
4650                                   int(x) - row_ptr->par->table->AdditionalWidth(cell),
4651                                   offset + y_bottom - 1,
4652                                   LColor::tableline,
4653                                   on_off ? Painter::line_onoffdash : Painter::line_solid);
4654                 }
4655         } else {
4656                 /* table stuff -- end*/
4657                 LyXParagraph::size_type main_body = 
4658                         BeginningOfMainBody(row_ptr->par);
4659                 if (main_body > 0 &&
4660                     (main_body-1 > pos_end || 
4661                      !row_ptr->par->IsLineSeparator(main_body-1)))
4662                         main_body = 0;
4663
4664                 while (vpos <= pos_end)  {
4665                         pos = vis2log(vpos);
4666                         if (main_body > 0 && pos == main_body-1) {
4667                                 x += fill_label_hfill
4668                                         + GetFont(row_ptr->par, -2).stringWidth(layout.labelsep)
4669                                         - SingleWidth(row_ptr->par, main_body-1);
4670                         }
4671
4672                         if (row_ptr->par->IsHfill(pos)) {
4673                                 x += 1;
4674                                 pain.line(int(x),
4675                                           offset + row_ptr->baseline - DefaultHeight() / 2,
4676                                           int(x),
4677                                           offset + row_ptr->baseline,
4678                                           LColor::vfillline);
4679                                 
4680                                 if (HfillExpansion(row_ptr, pos)) {
4681                                         if (pos >= main_body) {
4682                                                 pain.line(int(x),
4683                                                           offset + row_ptr->baseline - DefaultHeight() / 4,
4684                                                           int(x + fill_hfill),
4685                                                           offset + row_ptr->baseline - DefaultHeight() / 4,
4686                                                           LColor::vfillline,
4687                                                           Painter::line_onoffdash);
4688                                                 x += fill_hfill;
4689                     } else {
4690                             pain.line(int(x),
4691                                       offset + row_ptr->baseline - DefaultHeight() / 4,
4692                                       int(x + fill_label_hfill),
4693                                       offset + row_ptr->baseline - DefaultHeight() / 4,
4694                                       LColor::vfillline,
4695                                       Painter::line_onoffdash);
4696                             
4697                             x += fill_label_hfill;
4698                     }
4699                                         pain.line(int(x),
4700                                                   offset + row_ptr->baseline - DefaultHeight() / 2,
4701                                                   int(x),
4702                                                   offset + row_ptr->baseline,
4703                                                   LColor::vfillline);
4704                                 }
4705                                 x += 2;
4706                                 ++vpos;
4707                         } else {
4708                                 if (row_ptr->par->IsSeparator(pos)) {
4709                                         tmpx = x;
4710                                         x+= SingleWidth(row_ptr->par, pos);
4711                                         if (pos >= main_body)
4712                                                 x+= fill_separator;
4713                                         /* -------> Only draw protected spaces when not in
4714                                          * free-spacing mode. */
4715                                         if (row_ptr->par->GetChar(pos) == LyXParagraph::META_PROTECTED_SEPARATOR && !layout.free_spacing) {
4716
4717                                                 pain.line(int(tmpx),
4718                                                           offset + row_ptr->baseline - 3,
4719                                                           int(tmpx),
4720                                                           offset + row_ptr->baseline - 1,
4721                                                           LColor::vfillline);
4722                                                 
4723                                                 pain.line(int(tmpx),
4724                                                           offset + row_ptr->baseline - 1,
4725                                                           int(x - 2),
4726                                                           offset + row_ptr->baseline - 1,
4727                                                           LColor::vfillline);
4728
4729                                                 pain.line(int(x - 2),
4730                                                           offset + row_ptr->baseline - 3,
4731                                                           int(x - 2),
4732                                                           offset + row_ptr->baseline - 1,
4733                                                           LColor::vfillline);
4734                                                 
4735                                                 /* what about underbars? */
4736                                                 font = GetFont(row_ptr->par, pos); 
4737                                                 if (font.underbar() == LyXFont::ON
4738                                                     && font.latex() != LyXFont::ON) {
4739                                                         pain.line(int(tmpx),
4740                                                                   offset + row_ptr->baseline + 2,
4741                                                                   int(x - tmpx),
4742                                                                   offset + row_ptr->baseline + 2);
4743                                                 }
4744                                         }
4745                                         ++vpos;
4746                                 } else
4747                                         draw(row_ptr, vpos, offset, x);
4748                         }
4749                 }
4750         }
4751 #if 0
4752         // check for FAST SELECTION
4753         if (fast_selection || mono_video) {
4754                 if (selection) {
4755                         
4756                         /* selection code */ 
4757                         if (sel_start_cursor.row == row_ptr && sel_end_cursor.row == row_ptr) {
4758                                 scr.fillRectangle(gc_select, sel_start_cursor.x, offset,
4759                                                   sel_end_cursor.x - sel_start_cursor.x,
4760                                                   row_ptr->height); 
4761                         } else if (sel_start_cursor.row == row_ptr) {
4762                                 scr.fillRectangle(gc_select, sel_start_cursor.x, offset,
4763                                                   paperwidth - sel_start_cursor.x,
4764                                                   row_ptr->height);
4765                         } else if (sel_end_cursor.row == row_ptr) {
4766                                 scr.fillRectangle(gc_select, 0, offset,
4767                                                   sel_end_cursor.x,
4768                                                   row_ptr->height);
4769                         } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
4770                                 scr.fillRectangle(gc_select, 0, offset,
4771                                                   paperwidth, row_ptr->height);
4772                                 
4773                         }
4774                 }
4775         }
4776 // end of FAST SELECTION code
4777         /* thats it */
4778 #endif
4779 }
4780 #else
4781 void LyXText::GetVisibleRow(LyXScreen & scr, int offset, 
4782                             Row * row_ptr, long y)
4783 {
4784         /* returns a printed row */
4785         LyXDirection direction = row_ptr->par->getParDirection();
4786         LyXParagraph::size_type vpos, pos, pos_end;
4787         float x, tmpx;
4788         int y_top, y_bottom;
4789         float fill_separator, fill_hfill, fill_label_hfill;
4790         LyXParagraph * par, * firstpar;
4791         LyXFont font;
4792         int maxdesc;
4793         if (row_ptr->height <= 0) {
4794                 lyxerr << "LYX_ERROR: row.height: " << row_ptr->height << endl;
4795                 return;
4796         }
4797         PrepareToPrint(row_ptr, x, fill_separator,
4798                        fill_hfill, fill_label_hfill);
4799
4800         /* initialize the pixmap */
4801         
4802         scr.fillRectangle(gc_clear,
4803                           0, offset, paperwidth, row_ptr->height);
4804         // check for NOT FAST SELECTION
4805         if (!fast_selection && !mono_video && selection) {
4806                 /* selection code */ 
4807                 if (sel_start_cursor.row == row_ptr &&
4808                     sel_end_cursor.row == row_ptr) {
4809                         if (sel_start_cursor.x < sel_end_cursor.x)
4810                           scr.fillRectangle(gc_selection, sel_start_cursor.x,
4811                                           offset,
4812                                           sel_end_cursor.x - sel_start_cursor.x,
4813                                           row_ptr->height);
4814                         else
4815                           scr.fillRectangle(gc_selection, sel_end_cursor.x,
4816                                           offset,
4817                                           sel_start_cursor.x - sel_end_cursor.x,
4818                                           row_ptr->height);
4819                 }
4820                 else if (sel_start_cursor.row == row_ptr) {
4821                      if (direction == LYX_DIR_LEFT_TO_RIGHT)
4822                         scr.fillRectangle(gc_selection, sel_start_cursor.x,
4823                                           offset,
4824                                           paperwidth - sel_start_cursor.x,
4825                                           row_ptr->height);
4826                      else
4827                         scr.fillRectangle(gc_selection, 0, offset,
4828                                           sel_start_cursor.x, row_ptr->height);
4829                 } else if (sel_end_cursor.row == row_ptr) {
4830                      if (direction == LYX_DIR_LEFT_TO_RIGHT)
4831                         scr.fillRectangle(gc_selection, 0, offset,
4832                                           sel_end_cursor.x, row_ptr->height);
4833                      else
4834                         scr.fillRectangle(gc_selection, sel_end_cursor.x,
4835                                           offset,
4836                                           paperwidth - sel_end_cursor.x,
4837                                           row_ptr->height);
4838                 } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
4839                         scr.fillRectangle(gc_selection, 0, offset,
4840                                           paperwidth, row_ptr->height);
4841                         
4842                 }
4843         } // end of NOT FAST SELECTION code
4844         
4845         if (row_ptr->par->appendix){
4846           scr.drawVerticalLine(gc_math, 1, offset, offset+row_ptr->height);
4847           scr.drawVerticalLine(gc_math, paperwidth-2 , offset, offset+row_ptr->height);
4848         }
4849
4850         if (row_ptr->par->pextra_type == LyXParagraph::PEXTRA_MINIPAGE) {
4851                 /* draw a marker at the left margin! */ 
4852                 LyXFont font = GetFont(row_ptr->par, 0);
4853                 int asc = font.maxAscent();
4854                 int x = (LYX_PAPER_MARGIN - font.width('|')) / 2;
4855                 int y1 = (offset + row_ptr->baseline);
4856                 int y2 = (offset + row_ptr->baseline) - asc;
4857
4858                 scr.drawVerticalLine(gc_minipage, x, y1, y2);
4859         }       
4860         if (row_ptr->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
4861                 LyXFont font(LyXFont::ALL_SANE);
4862                 font.setSize(LyXFont::SIZE_FOOTNOTE);
4863 #ifdef USE_PAINTER
4864                 font.setColor(LColor::footnote);
4865 #else
4866                 font.setColor(LyXFont::RED);
4867 #endif
4868                 
4869                 int box_x = LYX_PAPER_MARGIN;
4870                 box_x += font.textWidth(" wide-tab ", 10);
4871                 if (row_ptr->previous && 
4872                     row_ptr->previous->par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
4873                         string fs;
4874                         switch (row_ptr->par->footnotekind) {
4875                         case LyXParagraph::MARGIN:
4876                                 fs = " margin";
4877                                 break;
4878                         case LyXParagraph::FIG:
4879                                 fs = " fig";
4880                                 break;
4881                         case LyXParagraph::TAB:
4882                                 fs = " tab";
4883                                 break;
4884                         case LyXParagraph::WIDE_FIG:
4885                                 fs = " wide-fig";
4886                                 break;
4887                         case LyXParagraph::WIDE_TAB:
4888                                 fs = " wide-tab";
4889                                 break;
4890                         case LyXParagraph::ALGORITHM:
4891                                 fs = " alg";
4892                                 break;
4893                         case LyXParagraph::FOOTNOTE:
4894                                 fs = " foot";
4895                                 break;
4896                         }
4897                         
4898                         // Determine background color.
4899                         gc_type back = gc_lighted;
4900                         if (mono_video) {
4901                                 back = gc_clear;
4902                         }
4903                         scr.fillRectangle(back, LYX_PAPER_MARGIN, offset+1,
4904                                           box_x - LYX_PAPER_MARGIN, 
4905                                           int(font.maxAscent())+
4906                                           int(font.maxDescent()));
4907                         
4908                         scr.drawLine(gc_foot,
4909                                      offset,
4910                                      LYX_PAPER_MARGIN,
4911                                      paperwidth - 2*LYX_PAPER_MARGIN);
4912                         
4913                         scr.drawString(font, fs,
4914                                        offset + int(font.maxAscent())+1,
4915                                        LYX_PAPER_MARGIN);
4916                         scr.drawVerticalLine(gc_foot,
4917                                              LYX_PAPER_MARGIN,
4918                                              offset,
4919                                              offset
4920                                              + int(font.maxAscent())+
4921                                              int(font.maxDescent()));
4922                         
4923                         scr.drawLine(gc_foot,
4924                                      offset
4925                                      + int(font.maxAscent())
4926                                      + int(font.maxDescent()) + 1,
4927                                      LYX_PAPER_MARGIN, box_x - LYX_PAPER_MARGIN); 
4928                 }
4929                 
4930                 /* draw the open floats in a red box */
4931                 scr.drawVerticalLine(gc_foot,
4932                                      box_x,
4933                                      offset,  offset + row_ptr->height);
4934                 
4935                 scr.drawVerticalLine(gc_foot,
4936                                      paperwidth - LYX_PAPER_MARGIN,
4937                                      offset,
4938                                      offset + row_ptr->height);
4939                                         
4940         } else  {
4941                 if (row_ptr->previous &&
4942                     row_ptr->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
4943                         LyXFont font(LyXFont::ALL_SANE);
4944                         font.setSize(LyXFont::SIZE_FOOTNOTE);
4945
4946                         int box_x = LYX_PAPER_MARGIN;
4947                         box_x += font.textWidth(" wide-tab ", 10);
4948                         
4949                         scr.drawLine(gc_foot,
4950                                      offset,
4951                                      box_x,
4952                                      paperwidth - LYX_PAPER_MARGIN - box_x);
4953                 }
4954         }
4955         
4956         LyXLayout const & layout = textclasslist.Style(parameters->textclass,
4957                                            row_ptr->par->GetLayout());
4958         firstpar = row_ptr->par->FirstPhysicalPar();
4959         
4960         y_top = 0;
4961         y_bottom = row_ptr->height;
4962         
4963         /* is it a first row? */ 
4964         if (row_ptr->pos == 0
4965             && row_ptr->par == firstpar) {
4966                 
4967                  /* start of appendix? */
4968                 if (row_ptr->par->start_of_appendix){
4969                   scr.drawLine(gc_math, 
4970                                offset,
4971                                1, paperwidth-2);
4972                 }
4973
4974                 /* think about the margins */ 
4975                 if (!row_ptr->previous)
4976                         y_top += LYX_PAPER_MARGIN;
4977                 
4978                 if (row_ptr->par->pagebreak_top){ /* draw a top pagebreak  */
4979                         scr.drawOnOffLine(offset + y_top + 2 * DefaultHeight(),
4980                                           0, paperwidth);
4981                         y_top += 3 * DefaultHeight();
4982                 }
4983                 
4984                 if (row_ptr->par->added_space_top.kind() == VSpace::VFILL) {
4985                         /* draw a vfill top  */
4986                         scr.drawLine(gc_fill, 
4987                                      offset + 2 + y_top,
4988                                      0, LYX_PAPER_MARGIN);
4989                         scr.drawLine(gc_fill,
4990                                      offset + y_top + 3 * DefaultHeight(),
4991                                      0, LYX_PAPER_MARGIN);
4992                         scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2, 
4993                                                   offset + 2 + y_top,
4994                                                   offset + y_top + 3 *
4995                                                   DefaultHeight());
4996                         
4997                         y_top += 3 * DefaultHeight();
4998                 }
4999                 
5000                 /* think about user added space */ 
5001                 y_top += int(row_ptr->par->added_space_top.inPixels());
5002                 
5003                 /* think about the parskip */ 
5004                 /* some parskips VERY EASY IMPLEMENTATION */ 
5005                 if (parameters->paragraph_separation == BufferParams::PARSEP_SKIP) {
5006                         if (layout.latextype == LATEX_PARAGRAPH
5007                             && firstpar->GetDepth() == 0
5008                             && firstpar->Previous())
5009                                 y_top += parameters->getDefSkip().inPixels();
5010                         else if (firstpar->Previous()
5011                                  && textclasslist.Style(parameters->textclass,
5012                                                    firstpar->Previous()->GetLayout()).latextype == LATEX_PARAGRAPH
5013                                  && firstpar->Previous()->GetDepth() == 0)
5014                                 // is it right to use defskip here, too? (AS) 
5015                                 y_top += parameters->getDefSkip().inPixels();
5016                 }
5017                 
5018                 if (row_ptr->par->line_top) {      /* draw a top line  */
5019                         y_top +=  GetFont(row_ptr->par, 0).ascent('x');
5020
5021                         scr.drawThickLine(offset + y_top,
5022                                           0, paperwidth);
5023                         y_top +=  GetFont(row_ptr->par, 0).ascent('x');
5024                 }
5025                 
5026                 /* should we print a label? */ 
5027                 if (layout.labeltype >= LABEL_STATIC
5028                     && (layout.labeltype != LABEL_STATIC
5029                         || layout.latextype != LATEX_ENVIRONMENT
5030                         || row_ptr->par->IsFirstInSequence())) {
5031                         font = GetFont(row_ptr->par, -2);
5032                         if (!row_ptr->par->GetLabestring().empty()) {
5033                                 tmpx = x;
5034                                 string tmpstring = row_ptr->par->GetLabestring();
5035                                 
5036                                 if (layout.labeltype == LABEL_COUNTER_CHAPTER) {
5037                                         if (parameters->secnumdepth >= 0){
5038                                                 /* this is special code for the chapter layout. This is printed in
5039                                                  * an extra row and has a pagebreak at the top. */
5040                                                 maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue())
5041                                                         + int(layout.parsep) * DefaultHeight();
5042                                                 if (direction == LYX_DIR_RIGHT_TO_LEFT)
5043                                                         tmpx = paperwidth - LeftMargin(row_ptr) - 
5044                                                                 font.stringWidth(tmpstring);
5045                                                 scr.drawString(font, tmpstring,
5046                                                                offset + row_ptr->baseline
5047                                                                - row_ptr->ascent_of_text - maxdesc,
5048                                                                int(tmpx));
5049                                         }
5050                                 } else {
5051                                         if (direction == LYX_DIR_LEFT_TO_RIGHT)
5052                                                 tmpx = x - font.stringWidth(layout.labelsep)
5053                                                         - font.stringWidth(tmpstring);
5054                                         else {
5055                                                 tmpx = paperwidth - LeftMargin(row_ptr)
5056                                                         + font.stringWidth(layout.labelsep);
5057                                                 if (row_ptr->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)  {
5058                                                         LyXFont font(LyXFont::ALL_SANE);
5059                                                         font.setSize(LyXFont::SIZE_SMALL);
5060                                                         tmpx += font.textWidth("Mwide-figM", 10);
5061                                                 }
5062                                         }
5063                                         /* draw it! */
5064                                         scr.drawString(font, tmpstring,
5065                                                        offset + row_ptr->baseline, int(tmpx));
5066                                 }
5067                         }
5068                         /* the labels at the top of an environment. More or less for bibliography */ 
5069                 } else if (layout.labeltype == LABEL_TOP_ENVIRONMENT ||
5070                            layout.labeltype == LABEL_BIBLIO ||
5071                            layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) {
5072                         if (row_ptr->par->IsFirstInSequence()) {
5073                                 font = GetFont(row_ptr->par, -2);
5074                                 if (!row_ptr->par->GetLabestring().empty()) {
5075                                         string tmpstring = row_ptr->par->GetLabestring();
5076                                         
5077                                         maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue()
5078                                                          + (layout.labelbottomsep * DefaultHeight()));
5079                                         
5080                                         tmpx = x;
5081                                         if (layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT){
5082                                                 tmpx = ( ((direction == LYX_DIR_LEFT_TO_RIGHT)
5083                                                           ? x : LeftMargin(row_ptr) )
5084                                                          + paperwidth - RightMargin(row_ptr) ) / 2; 
5085                                                 tmpx -= (font.stringWidth(tmpstring)/2);
5086                                         } else if (direction == LYX_DIR_RIGHT_TO_LEFT)
5087                                                 tmpx = paperwidth - LeftMargin(row_ptr) - 
5088                                                         font.stringWidth(tmpstring);
5089
5090                                         scr.drawString(font, tmpstring,
5091                                                        offset + row_ptr->baseline
5092                                                        - row_ptr->ascent_of_text - maxdesc,  
5093                                                        int(tmpx));                  
5094                                 }
5095                         }
5096                 }
5097                 if (layout.labeltype == LABEL_BIBLIO) { // ale970302
5098                         if (row_ptr->par->bibkey) {
5099                                 font = GetFont(row_ptr->par, -1);
5100                                 if (direction == LYX_DIR_LEFT_TO_RIGHT)
5101                                         tmpx = x - font.stringWidth(layout.labelsep)
5102                                                 - row_ptr->par->bibkey->Width(font);
5103                                 else
5104                                         tmpx = paperwidth - LeftMargin(row_ptr)
5105                                                 + font.stringWidth(layout.labelsep);
5106                                 row_ptr->par->bibkey->Draw(font, scr,
5107                                                            offset + row_ptr->baseline, 
5108                                                            tmpx);
5109                         }
5110                 } 
5111         }
5112         
5113         /* is it a last row? */
5114         par = row_ptr->par->LastPhysicalPar();
5115         if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
5116             && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {     
5117                 
5118                 /* think about the margins */ 
5119                 if (!row_ptr->next)
5120                         y_bottom -= LYX_PAPER_MARGIN;
5121                 
5122                 /* draw a bottom pagebreak */ 
5123                 if (firstpar->pagebreak_bottom) {
5124                         scr.drawOnOffLine(offset + y_bottom - 2 *
5125                                           DefaultHeight(),
5126                                           0, paperwidth);
5127                         y_bottom -= 3 * DefaultHeight();
5128                 }
5129                 
5130                 if (firstpar->added_space_bottom.kind() == VSpace::VFILL) {
5131                         /* draw a vfill bottom  */
5132                         scr.drawLine(gc_fill,
5133                                      offset + y_bottom - 3 * DefaultHeight(),
5134                                      0, LYX_PAPER_MARGIN);
5135                         scr.drawLine(gc_fill, offset + y_bottom - 2,
5136                                      0, LYX_PAPER_MARGIN);
5137                         scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2, 
5138                                                   offset + y_bottom - 3 * DefaultHeight(),
5139                                                   offset + y_bottom - 2
5140                                 );          
5141                         y_bottom -= 3* DefaultHeight();
5142                 }
5143                 
5144                 /* think about user added space */ 
5145                 y_bottom -= int(firstpar->added_space_bottom.inPixels());
5146                 
5147                 if (firstpar->line_bottom) {
5148                         /* draw a bottom line */
5149                         y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
5150
5151                         scr.drawThickLine(offset + y_bottom,
5152                                           0, paperwidth);           
5153                         y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
5154                 }
5155         }
5156         
5157         /* draw the text in the pixmap */  
5158         pos_end = RowLast(row_ptr);
5159         
5160         vpos = row_ptr->pos;
5161         /* table stuff -- begin*/
5162         if (row_ptr->par->table) {
5163                 bool on_off;
5164                 int cell = NumberOfCell(row_ptr->par, row_ptr->pos);
5165                 float x_old = x;
5166                 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
5167                 
5168                 while (vpos <= pos_end)  {
5169                         pos = vis2log(vpos);
5170                         if (row_ptr->par->IsNewline(pos)) {
5171                                 
5172                                 x = x_old + row_ptr->par->table->WidthOfColumn(cell);
5173                                 /* draw the table lines, still very simple */
5174                                 on_off = !row_ptr->par->table->TopLine(cell);
5175                                 if ((!on_off ||
5176                                      !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
5177                                     !row_ptr->par->table->IsContRow(cell))
5178                                         scr.drawTableLine(offset + row_ptr->baseline -
5179                                                           row_ptr->ascent_of_text,
5180                                                           int(x_old), int(x - x_old), on_off);
5181                                 on_off = !row_ptr->par->table->BottomLine(cell);
5182                                 if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
5183                                     row_ptr->par->table->VeryLastRow(cell))
5184                                         scr.drawTableLine(offset + y_bottom - 1,
5185                                                           int(x_old), int(x - x_old), on_off);
5186                                 on_off = !row_ptr->par->table->LeftLine(cell);
5187                                 
5188                                 scr.drawVerticalTableLine(int(x_old), 
5189                                                           offset + row_ptr->baseline -
5190                                                           row_ptr->ascent_of_text,
5191                                                           offset + y_bottom - 1,
5192                                                           on_off);
5193                                 on_off = !row_ptr->par->table->RightLine(cell);
5194                                 
5195                                 scr.drawVerticalTableLine(int(x) -
5196                                                           row_ptr->par->table->AdditionalWidth(cell),
5197                                                           offset + row_ptr->baseline -
5198                                                           row_ptr->ascent_of_text,
5199                                                           offset + y_bottom - 1,
5200                                                           on_off);
5201                                 x_old = x;
5202                 /* take care about the alignment and other spaces */
5203                                 ++cell;
5204                                 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
5205                                 if (row_ptr->par->table->IsFirstCell(cell))
5206                                         --cell; // little hack, sorry
5207                                 ++vpos;
5208                         } else if (row_ptr->par->IsHfill(pos)) {
5209                                 x += 1;
5210                                 
5211                                 scr.drawVerticalLine(gc_fill, int(x),  
5212                                                      offset + row_ptr->baseline - DefaultHeight()/2, 
5213                                                      offset + row_ptr->baseline);               
5214                                 x += 2;
5215                                 ++vpos;
5216                         } else {
5217                                 if (row_ptr->par->IsSeparator(pos)) {
5218                                         tmpx = x;
5219                                         x+= SingleWidth(row_ptr->par, pos);
5220                                         /* -------> Only draw protected spaces when not in
5221                                          * free-spacing mode. */
5222                                         if (row_ptr->par->GetChar(pos) == LyXParagraph::META_PROTECTED_SEPARATOR && !layout.free_spacing) {
5223                                                 scr.drawVerticalLine(gc_fill, int(tmpx),
5224                                                                      offset + row_ptr->baseline - 3,
5225                                                                      offset + row_ptr->baseline - 1);
5226                                                 scr.drawLine(gc_fill,
5227                                                              offset + row_ptr->baseline - 1,
5228                                                              int(tmpx),
5229                                                              int(x-tmpx-2));
5230                                                 scr.drawVerticalLine(gc_fill, int(x-2),
5231                                                                      offset + row_ptr->baseline - 3,
5232                                                                      offset + row_ptr->baseline - 1);                   
5233                                                 /* what about underbars? */
5234                                                 font = GetFont(row_ptr->par, pos); 
5235                                                 if (font.underbar() == LyXFont::ON
5236                                                     && font.latex() != LyXFont::ON) {
5237                                                         scr.drawLine(gc_copy,
5238                                                                      offset +
5239                                                                      row_ptr->baseline + 2,
5240                                                                      int(tmpx),
5241                                                                      int(x - tmpx));                        
5242                                                 }
5243                                         }
5244                                         ++vpos;
5245                                 } else
5246                                         Draw(row_ptr, vpos, scr, offset, x);
5247                         }
5248                 }
5249                 
5250                 /* do not forget the very last cell. This has no NEWLINE so 
5251                  * ignored by the code above*/ 
5252                 if (cell == row_ptr->par->table->GetNumberOfCells()-1){
5253                         x = x_old + row_ptr->par->table->WidthOfColumn(cell);
5254                         on_off = !row_ptr->par->table->TopLine(cell);
5255                         if ((!on_off ||
5256                              !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
5257                             !row_ptr->par->table->IsContRow(cell))
5258                                 
5259                                 scr.drawTableLine(offset + row_ptr->baseline -
5260                                                   row_ptr->ascent_of_text,
5261                                                   int(x_old), int(x - x_old), on_off);      
5262                         on_off = !row_ptr->par->table->BottomLine(cell);
5263                         if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
5264                             row_ptr->par->table->VeryLastRow(cell))
5265                                 
5266                                 scr.drawTableLine(offset + y_bottom - 1,
5267                                                   int(x_old), int(x - x_old), on_off);      
5268                         on_off = !row_ptr->par->table->LeftLine(cell);
5269                         
5270                         scr.drawVerticalTableLine(int(x_old), 
5271                                                   offset + row_ptr->baseline -
5272                                                   row_ptr->ascent_of_text,
5273                                                   offset + y_bottom - 1,
5274                                                   on_off);          
5275                         on_off = !row_ptr->par->table->RightLine(cell);
5276                         
5277                         scr.drawVerticalTableLine(int(x) -
5278                                                   row_ptr->par->table->AdditionalWidth(cell),
5279                                                   offset + row_ptr->baseline -
5280                                                   row_ptr->ascent_of_text,
5281                                                   offset + y_bottom - 1,
5282                                                   on_off);          
5283                 }
5284         } else {
5285                 /* table stuff -- end*/
5286                 LyXParagraph::size_type main_body = 
5287                         BeginningOfMainBody(row_ptr->par);
5288                 if (main_body > 0 &&
5289                     (main_body-1 > pos_end || 
5290                      !row_ptr->par->IsLineSeparator(main_body-1)))
5291                         main_body = 0;
5292
5293                 while (vpos <= pos_end)  {
5294                         pos = vis2log(vpos);
5295                         if (main_body > 0 && pos == main_body-1) {
5296                                 x += fill_label_hfill
5297                                         + GetFont(row_ptr->par, -2).stringWidth(layout.labelsep)
5298                                         - SingleWidth(row_ptr->par, main_body-1);
5299                         }
5300
5301                         if (row_ptr->par->IsHfill(pos)) {
5302                                 x += 1;
5303                                 scr.drawVerticalLine(gc_fill, int(x),  
5304                                                      offset + row_ptr->baseline - DefaultHeight()/2, 
5305                                                      offset + row_ptr->baseline);               
5306                                 if (HfillExpansion(row_ptr, pos)) {
5307                                         if (pos >= main_body) {
5308                                                 scr.drawOnOffLine(offset + row_ptr->baseline -
5309                                                                   DefaultHeight()/4,
5310                                                                   int(x),
5311                                                                   int(fill_hfill));                     
5312                                                 x += fill_hfill;
5313                     } else {
5314                             scr.drawOnOffLine(offset + row_ptr->baseline -
5315                                               DefaultHeight()/4,
5316                                               int(x),
5317                                               int(fill_label_hfill));
5318                             x += fill_label_hfill;
5319                     }
5320                                         scr.drawVerticalLine(gc_fill, int(x),
5321                                                              offset + row_ptr->baseline -
5322                                                              DefaultHeight()/2, 
5323                                                              offset + row_ptr->baseline);
5324                                 }
5325                                 x += 2;
5326                                 ++vpos;
5327                         } else {
5328                                 if (row_ptr->par->IsSeparator(pos)) {
5329                                         tmpx = x;
5330                                         x+= SingleWidth(row_ptr->par, pos);
5331                                         if (pos >= main_body)
5332                                                 x+= fill_separator;
5333                                         /* -------> Only draw protected spaces when not in
5334                                          * free-spacing mode. */
5335                                         if (row_ptr->par->GetChar(pos) == LyXParagraph::META_PROTECTED_SEPARATOR && !layout.free_spacing) {
5336                                                 
5337                                                 scr.drawVerticalLine(gc_fill, int(tmpx),
5338                                                                      offset + row_ptr->baseline - 3,
5339                                                                      offset + row_ptr->baseline - 1);
5340                                                 scr.drawLine(gc_fill,
5341                                                              offset + row_ptr->baseline - 1,
5342                                                              int(tmpx),
5343                                                              int(x-tmpx-2));
5344                                                 scr.drawVerticalLine(gc_fill, int(x-2),
5345                                                                      offset + row_ptr->baseline - 3,
5346                                                                      offset + row_ptr->baseline - 1);                   
5347                                                 /* what about underbars? */
5348                                                 font = GetFont(row_ptr->par, pos); 
5349                                                 if (font.underbar() == LyXFont::ON
5350                                                     && font.latex() != LyXFont::ON) {
5351                                                         scr.drawLine(gc_copy,
5352                                              offset + row_ptr->baseline + 2,
5353                                                                      int(tmpx),
5354                                                                      int(x - tmpx));
5355                                                 }
5356                                         }
5357                                         ++vpos;
5358                                 } else
5359                                         Draw(row_ptr, vpos, scr, offset, x);
5360                         }
5361                 }
5362         }
5363         // check for FAST SELECTION
5364         if (fast_selection || mono_video) {
5365                 if (selection) {
5366                         
5367                         /* selection code */ 
5368                         if (sel_start_cursor.row == row_ptr && sel_end_cursor.row == row_ptr) {
5369                                 scr.fillRectangle(gc_select, sel_start_cursor.x, offset,
5370                                                   sel_end_cursor.x - sel_start_cursor.x,
5371                                                   row_ptr->height); 
5372                         } else if (sel_start_cursor.row == row_ptr) {
5373                                 scr.fillRectangle(gc_select, sel_start_cursor.x, offset,
5374                                                   paperwidth - sel_start_cursor.x,
5375                                                   row_ptr->height);
5376                         } else if (sel_end_cursor.row == row_ptr) {
5377                                 scr.fillRectangle(gc_select, 0, offset,
5378                                                   sel_end_cursor.x,
5379                                                   row_ptr->height);
5380                         } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
5381                                 scr.fillRectangle(gc_select, 0, offset,
5382                                                   paperwidth, row_ptr->height);
5383                                 
5384                         }
5385                 }
5386         }
5387 // end of FAST SELECTION code
5388         /* thats it */ 
5389 }
5390 #endif
5391
5392 int LyXText::DefaultHeight() const
5393 {
5394         LyXFont font(LyXFont::ALL_SANE);
5395         return int(font.maxAscent() + font.maxDescent() * 1.5);
5396 }
5397
5398    
5399 /* returns the column near the specified x-coordinate of the row 
5400 * x is set to the real beginning of this column  */ 
5401 int LyXText::GetColumnNearX(Row * row, int & x) const
5402 {
5403         float tmpx = 0.0;
5404         float fill_separator, fill_hfill, fill_label_hfill;
5405    
5406         PrepareToPrint(row, tmpx, fill_separator,
5407                        fill_hfill, fill_label_hfill);
5408
5409         LyXDirection direction = row->par->getParDirection();
5410         LyXParagraph::size_type vc = row->pos;
5411         LyXParagraph::size_type last = RowLast(row);
5412         LyXParagraph::size_type c;
5413
5414         LyXLayout const & layout = textclasslist.Style(parameters->textclass,
5415                                            row->par->GetLayout());
5416         /* table stuff -- begin */
5417         if (row->par->table) {
5418                 if (row->next && row->next->par == row->par //the last row doesn't need a newline at the end
5419                     && row->par->IsNewline(last))
5420                         last--;
5421                 int cell = NumberOfCell(row->par, row->pos);
5422                 float x_old = tmpx;
5423                 bool ready = false;
5424                 tmpx += row->par->table->GetBeginningOfTextInCell(cell);
5425                 while (vc <= last
5426                        && (c = vis2log(vc)) >= 0
5427                        && tmpx + (SingleWidth(row->par, c)/2) <= x
5428                        && !ready){
5429                         if (row->par->IsNewline(c)) {
5430                                 if (x_old + row->par->table->WidthOfColumn(cell) <= x){
5431                                         tmpx = x_old + row->par->table->WidthOfColumn(cell);
5432                                         x_old = tmpx;
5433                                         ++cell;
5434                                         tmpx += row->par->table->GetBeginningOfTextInCell(cell);
5435                                         ++vc;
5436                                 } else
5437                                         ready = true;
5438                         } else {
5439                                 tmpx += SingleWidth(row->par, c);
5440                                 ++vc;
5441                         }
5442                 }
5443         } else {
5444                 /* table stuff -- end*/
5445                 LyXParagraph::size_type main_body = BeginningOfMainBody(row->par);
5446                 float last_tmpx = tmpx;
5447
5448                 if (main_body > 0 &&
5449                     (main_body-1 > last || 
5450                      !row->par->IsLineSeparator(main_body-1)))
5451                         main_body = 0;
5452
5453                 while (vc <= last && tmpx <= x) {
5454                         c = vis2log(vc);
5455                         last_tmpx = tmpx;
5456                         if (main_body > 0 && c == main_body-1) {
5457                                 tmpx += fill_label_hfill +
5458                                         GetFont(row->par, -2).stringWidth(layout.labelsep);
5459                                 if (row->par->IsLineSeparator(main_body-1))
5460                                         tmpx -= SingleWidth(row->par, main_body-1);
5461                         }
5462              
5463                         tmpx += SingleWidth(row->par, c);
5464                         if (HfillExpansion(row, c)) {
5465                                 if (c >= main_body)
5466                                         tmpx += fill_hfill;
5467                                 else
5468                                         tmpx += fill_label_hfill;
5469                         }
5470                         else if (c >= main_body
5471                                  && row->par->IsSeparator(c)) {
5472                                 tmpx+= fill_separator;  
5473                         }
5474                         ++vc;
5475                 }
5476
5477                 if (vc > row->pos && (tmpx+last_tmpx)/2 > x) {
5478                         vc--;
5479                         tmpx = last_tmpx;
5480                 }
5481         }
5482         /* make sure that a last space in a row doesnt count */
5483         if (row->pos <= last
5484             && !(!row->next || row->next->par != row->par))
5485                 if (direction == LYX_DIR_LEFT_TO_RIGHT && vc > last
5486                     && row->par->IsLineSeparator(vis2log(last)) ) {
5487                         vc = last;
5488                         tmpx -= fill_separator+SingleWidth(row->par, vis2log(last));
5489                 } else if (direction == LYX_DIR_RIGHT_TO_LEFT 
5490                            && vc == row->pos
5491                            && row->par->IsLineSeparator(vis2log(row->pos)) ) {
5492                         vc = row->pos+1;
5493                         tmpx += fill_separator+SingleWidth(row->par, vis2log(row->pos));
5494                 }
5495
5496         if (row->pos > last)  // Row is empty?
5497                 c = row->pos;
5498         else if (vc <= last) {
5499                 c = vis2log(vc);
5500                 LyXDirection direction = row->par->getLetterDirection(c);
5501                 if (vc > row->pos && row->par->IsLineSeparator(c)
5502                     && row->par->getLetterDirection(vis2log(vc - 1)) != direction)
5503                         c = vis2log(vc-1);
5504                 if (direction == LYX_DIR_RIGHT_TO_LEFT)
5505                         ++c;
5506         } else {
5507                 c = vis2log(last)+1;
5508                 if (row->par->getLetterDirection(c - 1) == LYX_DIR_RIGHT_TO_LEFT)
5509                         --c;            
5510         }
5511
5512         if (!row->par->table && row->pos <= last && c > last
5513             && row->par->IsNewline(last)) {
5514                 if (row->par->getLetterDirection(last) == LYX_DIR_LEFT_TO_RIGHT)
5515                         tmpx -= SingleWidth(row->par, last);
5516                 else
5517                         tmpx += SingleWidth(row->par, last);
5518                 c = last;
5519         }
5520
5521         c -= row->pos;
5522         x = int(tmpx);
5523         return c;
5524 }
5525
5526    
5527 /* turn the selection into a new environment. If there is no selection,
5528 * create an empty environment */ 
5529 void LyXText::InsertFootnoteEnvironment(LyXParagraph::footnote_kind kind)
5530 {
5531    /* no footnoteenvironment in a footnoteenvironment */ 
5532    if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
5533       WriteAlert(_("Impossible operation"), 
5534                  _("You can't insert a float in a float!"), 
5535                  _("Sorry."));
5536      return;
5537    }
5538    /* no marginpars in minipages */
5539    if (kind == LyXParagraph::MARGIN 
5540       && cursor.par->pextra_type == LyXParagraph::PEXTRA_MINIPAGE) {
5541       WriteAlert(_("Impossible operation"), 
5542                  _("You can't insert a marginpar in a minipage!"), 
5543                  _("Sorry."));
5544       return;
5545    }
5546    
5547    /* this doesnt make sense, if there is no selection */ 
5548    bool dummy_selection = false;
5549    if (!selection) {
5550       sel_start_cursor = cursor;       /* dummy selection  */
5551       sel_end_cursor = cursor;
5552       dummy_selection = true;
5553    }
5554    
5555    LyXParagraph *tmppar;
5556
5557    if (sel_start_cursor.par->table || sel_end_cursor.par->table){
5558       WriteAlert(_("Impossible operation"), _("Cannot cut table."), _("Sorry."));
5559       return;
5560    }
5561      
5562    /* a test to make sure there is not already a footnote
5563     * in the selection. */
5564    
5565    tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
5566    
5567    while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos) && 
5568           tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
5569      tmppar = tmppar->next;
5570    
5571    if (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
5572        || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
5573       WriteAlert(_("Impossible operation"), 
5574                  _("Float would include float!"), 
5575                  _("Sorry."));
5576       return;
5577    }
5578    
5579    /* ok we have a selection. This is always between sel_start_cursor
5580     * and sel_end cursor */
5581
5582    SetUndo(Undo::FINISH, 
5583            sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
5584            sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next); 
5585    
5586    if (sel_end_cursor.pos > 0 
5587        && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1))
5588      sel_end_cursor.pos--;             /* please break before a space at
5589                                         * the end */
5590    if (sel_start_cursor.par == sel_end_cursor.par
5591        && sel_start_cursor.pos > sel_end_cursor.pos)
5592      sel_start_cursor.pos--;
5593
5594    sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
5595    
5596    sel_end_cursor.par = sel_end_cursor.par->Next();
5597    sel_end_cursor.pos = 0;
5598    
5599    // don't forget to insert a dummy layout paragraph if necessary
5600    if (sel_start_cursor.par->GetLayout() != sel_end_cursor.par->layout){
5601      sel_end_cursor.par->BreakParagraphConservative(0);
5602      sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
5603      sel_end_cursor.par = sel_end_cursor.par->next;
5604    }
5605    else
5606      sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
5607
5608    cursor = sel_end_cursor;
5609
5610    /* please break behind a space, if there is one. The space should
5611     * be erased too */ 
5612    if (sel_start_cursor.pos > 0 
5613        && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1))
5614      sel_start_cursor.pos--;
5615    if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)) {
5616       sel_start_cursor.par->Erase(sel_start_cursor.pos);
5617    }
5618    
5619    sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
5620    tmppar = sel_start_cursor.par->Next();
5621    
5622    if (dummy_selection) {
5623            tmppar->Clear();
5624            if (kind == LyXParagraph::TAB
5625                || kind == LyXParagraph::FIG 
5626                || kind == LyXParagraph::WIDE_TAB
5627                || kind == LyXParagraph::WIDE_FIG 
5628                || kind == LyXParagraph::ALGORITHM) {
5629                    int lay = textclasslist.NumberOfLayout(parameters->textclass,
5630                                                      "Caption").second;
5631                    if (lay == -1) // layout not found
5632                            // use default layout "Standard" (0)
5633                            lay = 0;
5634                    tmppar->SetLayout(lay);
5635            }
5636    }
5637    else {
5638      if (sel_start_cursor.pos > 0) {
5639        /* the footnote-environment should begin with a standard layout.
5640         * Imagine you insert a footnote within an enumeration, you 
5641         * certainly do not want an enumerated footnote! */ 
5642        tmppar->Clear();
5643      }
5644      else {
5645        /* this is a exception the user would sometimes expect, I hope */
5646        sel_start_cursor.par->Clear();
5647      }
5648    }
5649    
5650    while (tmppar != sel_end_cursor.par) {
5651       tmppar->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
5652       tmppar->footnotekind = kind;
5653       tmppar = tmppar->Next();
5654    } 
5655
5656    RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
5657    
5658    SetCursor(sel_start_cursor.par->Next(), 0);
5659
5660    ClearSelection();
5661 }
5662    
5663
5664 // returns pointer to a specified row
5665 Row * LyXText::GetRow(LyXParagraph * par,
5666                       LyXParagraph::size_type pos, long & y) const
5667 {
5668         Row * tmprow;
5669         
5670         if (currentrow) {
5671                 if (par == currentrow->par || par == currentrow->par->Previous()) {
5672                         // do not dereference par, it may have been deleted
5673                         // already! (Matthias) 
5674                         while (currentrow->previous && currentrow->previous->par != par) {
5675                                 currentrow = currentrow->previous;
5676                                 currentrow_y -= currentrow->height;
5677                         }
5678                         while (currentrow->previous && currentrow->previous->par == par) {
5679                                 currentrow = currentrow->previous;
5680                                 currentrow_y -= currentrow->height;
5681                         }
5682                 }
5683                 tmprow = currentrow;
5684                 y = currentrow_y;
5685                 // find the first row of the specified paragraph
5686                 while (tmprow->next && (tmprow->par != par)) {
5687                         y += tmprow->height;
5688                         tmprow = tmprow->next;
5689                 }
5690                 
5691                 if (tmprow->par == par){
5692                         // now find the wanted row
5693                         while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par && 
5694                                tmprow->next->pos <= pos) {
5695                                 y += tmprow->height;
5696                                 tmprow = tmprow->next;
5697                         }
5698                         currentrow = tmprow;
5699                         currentrow_y = y;
5700                         return tmprow;
5701                 }
5702         }
5703         tmprow = firstrow;
5704         y = 0;
5705         // find the first row of the specified paragraph
5706         while (tmprow->next && (tmprow->par != par)) {
5707                 y += tmprow->height;
5708                 tmprow = tmprow->next;
5709         }
5710         
5711         // now find the wanted row
5712         while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par && 
5713                tmprow->next->pos <= pos) {
5714                 y += tmprow->height;
5715                 tmprow = tmprow->next;
5716         }
5717         
5718         currentrow = tmprow;
5719         currentrow_y = y;
5720         
5721         return tmprow;
5722 }