1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright (C) 1995 Matthias Ettrich
7 * Copyright (C) 1995-1998 The LyX Team.
9 * ====================================================== */
16 #pragma implementation "table.h"
20 #include "lyxparagraph.h"
22 #include "support/textutils.h"
23 #include "lyx_gui_misc.h"
26 #include "bufferparams.h"
28 #include "lyxscreen.h"
29 #include "minibuffer.h"
32 static const int LYX_PAPER_MARGIN = 20;
34 extern int mono_video;
35 extern int reverse_video;
36 extern int fast_selection;
37 extern BufferView * current_view;
38 extern int UnlockInset(UpdatableInset * inset);
41 extern int bibitemMaxWidth(LyXFont const &);
44 extern MiniBuffer * minibuffer;
46 int LyXText::SingleWidth(LyXParagraph * par,
47 LyXParagraph::size_type pos)
49 char c = par->GetChar(pos);
50 return SingleWidth(par, pos, c);
54 int LyXText::SingleWidth(LyXParagraph * par,
55 LyXParagraph::size_type pos, char c)
57 LyXFont font = GetFont(par, pos);
59 // The most common case is handled first (Asger)
63 } else if (IsHfillChar(c)) {
64 return 3; /* because of the representation
65 * as vertical lines */
67 } else if (c == LyXParagraph::META_FOOTNOTE ||
68 c == LyXParagraph::META_MARGIN ||
69 c == LyXParagraph::META_FIG ||
70 c == LyXParagraph::META_TAB ||
71 c == LyXParagraph::META_WIDE_FIG ||
72 c == LyXParagraph::META_WIDE_TAB ||
73 c == LyXParagraph::META_ALGORITHM)
77 case LyXParagraph::META_MARGIN:
80 case LyXParagraph::META_FIG:
83 case LyXParagraph::META_TAB:
86 case LyXParagraph::META_ALGORITHM:
89 case LyXParagraph::META_WIDE_FIG:
92 case LyXParagraph::META_WIDE_TAB:
95 case LyXParagraph::META_FOOTNOTE:
101 return font.stringWidth(fs);
104 else if (c == LyXParagraph::META_INSET) {
105 Inset *tmpinset= par->GetInset(pos);
107 return par->GetInset(pos)->Width(font);
111 } else if (IsSeparatorChar(c))
113 else if (IsNewlineChar(c))
115 return font.width(c);
119 /* returns the paragraph position of the last character in the
121 LyXParagraph::size_type LyXText::RowLast(Row * row)
124 return row->par->Last()-1;
125 else if (row->next->par != row->par)
126 return row->par->Last()-1;
128 return row->next->pos - 1;
132 void LyXText::Draw(Row * row, LyXParagraph::size_type & pos,
133 LyXScreen & scr, int offset, float & x)
135 char c = row->par->GetChar(pos);
137 if (IsNewlineChar(c)) {
139 // Draw end-of-line marker
141 LyXFont font = GetFont(row->par, pos);
142 int asc = font.maxAscent();
143 int wid = font.width('n');
144 int y = (offset + row->baseline);
146 p[0].x = int(x + wid*0.375); p[0].y = int(y - 0.875*asc*0.75);
147 p[1].x = int(x); p[1].y = int(y - 0.500*asc*0.75);
148 p[2].x = int(x + wid*0.375); p[2].y = int(y - 0.125*asc*0.75);
149 scr.drawLines(::getGC(gc_new_line), p, 3);
151 p[0].x = int(x); p[0].y = int(y - 0.500*asc*0.75);
152 p[1].x = int(x + wid); p[1].y = int(y - 0.500*asc*0.75);
153 p[2].x = int(x + wid); p[2].y = int(y - asc*0.75);
154 scr.drawLines(::getGC(gc_new_line), p, 3);
158 LyXFont font = GetFont(row->par, pos);
159 LyXFont font2 = font;
161 if (c == LyXParagraph::META_FOOTNOTE ||
162 c == LyXParagraph::META_MARGIN ||
163 c == LyXParagraph::META_FIG ||
164 c == LyXParagraph::META_TAB ||
165 c == LyXParagraph::META_WIDE_FIG ||
166 c == LyXParagraph::META_WIDE_TAB ||
167 c == LyXParagraph::META_ALGORITHM) {
170 case LyXParagraph::META_MARGIN:
172 /* draw a sign at the left margin! */
173 scr.drawText(font, "!", 1, offset + row->baseline,
174 (LYX_PAPER_MARGIN - font.width('!'))/2);
176 case LyXParagraph::META_FIG:
179 case LyXParagraph::META_TAB:
182 case LyXParagraph::META_ALGORITHM:
185 case LyXParagraph::META_WIDE_FIG:
188 case LyXParagraph::META_WIDE_TAB:
191 case LyXParagraph::META_FOOTNOTE:
198 /* calculate the position of the footnotemark */
199 int y = (row->baseline - font2.maxAscent()
202 font.setColor(LyXFont::INSET);
206 /* draw it and set new x position */
207 x += scr.drawString(font, fs, offset + y, int(x));
209 scr.drawLine(gc_foot, offset + row->baseline,
210 int(tmpx), int(x - tmpx));
214 } else if (c == LyXParagraph::META_INSET) {
215 Inset *tmpinset = row->par->GetInset(pos);
217 tmpinset->Draw(font, scr, offset + row->baseline, x);
222 /* usual characters, no insets */
224 // Collect character that we can draw in one command
226 // This is dirty, but fast. Notice that it will never be too small.
227 // For the record, I'll note that Microsoft Word has a limit
228 // of 768 here. We have none :-) (Asger)
230 static char textstring[1024];
232 // Ok. I am the first to admit that the use of std::string will be
233 // a tiny bit slower. However, I claim that this slowdown is so
234 // small that it is close to inperceptive. So IMHO we should go
235 // with the easier and clearer implementation. And even if 1024
236 // is a large number here it might overflow, string will only
237 // overflow if the machine is out of memory...
238 static string textstring;
243 LyXParagraph::size_type last = RowLast(row);
245 // Prevent crash in the extremely unlikely event
246 // that our array is too small
247 if (last > pos+1020) last = pos + 1020;
255 while (pos <= last &&
256 static_cast<char>(c = row->par->GetChar(pos)) > ' ' &&
257 font2 == GetFont(row->par, pos)) {
270 // If monochrome and LaTeX mode, provide reverse background
271 if (mono_video && font.latex() == LyXFont::ON) {
272 int a= font.maxAscent(), d= font.maxDescent();
274 scr.fillRectangle(gc_copy, int(tmpx), offset + row->baseline-a,
275 font.textWidth(textstring, i), a+d);
277 scr.fillRectangle(gc_copy, int(tmpx), offset + row->baseline-a,
278 font.textWidth(textstring.c_str(),
279 textstring.length()), a+d);
283 /* Draw text and set the new x position */
284 x += scr.drawText(font, textstring, i, offset + row->baseline,
287 /* Draw text and set the new x position */
288 x += scr.drawText(font, textstring.c_str(), textstring.length(),
289 offset + row->baseline,
293 /* what about underbars? */
294 if (font.underbar() == LyXFont::ON && font.latex() != LyXFont::ON) {
295 scr.drawLine(gc_copy, offset + row->baseline + 2,
296 int(tmpx), int(x - tmpx));
299 // If we want ulem.sty support, drawing
300 // routines should go here. (Asger)
301 // Why shouldn't LyXFont::drawText handle it internally?
305 /* Returns the left beginning of the text.
306 * This information cannot be taken from the layouts-objekt, because in
307 * LaTeX the beginning of the text fits in some cases (for example sections)
308 * exactly the label-width. */
309 int LyXText::LeftMargin(Row * row)
312 LyXParagraph * newpar;
314 LyXLayout const & layout = textclasslist.Style(parameters->textclass, row->par->GetLayout());
316 string parindent = layout.parindent;
318 /* table stuff -- begin*/
321 /* table stuff -- end*/
323 int x = LYX_PAPER_MARGIN;
325 x += textclasslist.TextClass(parameters->textclass).
326 defaultfont().signedStringWidth(textclasslist.TextClass(parameters->textclass).leftmargin());
328 if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
329 LyXFont font(LyXFont::ALL_SANE);
330 font.setSize(LyXFont::SIZE_SMALL);
331 x += font.textWidth("Mwide-figM", 10) + LYX_PAPER_MARGIN/2;
334 /* this is the way, LyX handles the LaTeX-Environments.
335 * I have had this idea very late, so it seems to be a
336 * later added hack and this is true */
337 if (!row->par->GetDepth()) {
338 if (!row->par->GetLayout()) {
339 /* find the previous same level paragraph */
340 if (row->par->FirstPhysicalPar()->Previous()) {
341 newpar = row->par->DepthHook(row->par->GetDepth());
342 if (newpar && textclasslist.Style(parameters->textclass, newpar->GetLayout()).nextnoindent)
348 /* find the next level paragraph */
350 newpar = row->par->DepthHook(row->par->GetDepth()-1);
352 /* make a corresponding row. Needed to call LeftMargin() */
354 /* check wether it is a sufficent paragraph */
355 if (newpar && newpar->footnoteflag == row->par->footnoteflag
356 && textclasslist.Style(parameters->textclass,
357 newpar->GetLayout()).isEnvironment()) {
358 dummyrow.par = newpar;
359 dummyrow.pos = newpar->Last();
360 x = LeftMargin(&dummyrow);
363 /* this is no longer an error, because this function is used
364 * to clear impossible depths after changing a layout. Since there
365 * is always a redo, LeftMargin() is always called */
367 /* printf("LYX_ERROR (text, LeftMargin()) impossible depth \n");*/
368 row->par->FirstPhysicalPar()->depth = 0;
371 if (newpar && !row->par->GetLayout()) {
372 if (newpar->FirstPhysicalPar()->noindent)
375 parindent = textclasslist.Style(parameters->textclass,
376 newpar->GetLayout()).parindent;
381 labelfont = GetFont(row->par, -2);
382 switch (layout.margintype) {
384 if (!layout.leftmargin.empty()) {
385 x += textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.leftmargin);
387 if (!row->par->GetLabestring().empty()) {
388 x += labelfont.signedStringWidth(layout.labelindent);
389 x += labelfont.stringWidth(row->par->GetLabestring());
390 x += labelfont.stringWidth(layout.labelsep);
394 x += labelfont.signedStringWidth(layout.labelindent);
395 if (row->pos >= BeginningOfMainBody(row->par)) {
396 if (!row->par->GetLabelWidthString().empty()) {
397 x += labelfont.stringWidth(row->par->GetLabelWidthString());
398 x += labelfont.stringWidth(layout.labelsep);
403 x += ( textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.leftmargin) * 4
404 / (row->par->GetDepth() + 4));
406 case MARGIN_FIRST_DYNAMIC:
407 if (layout.labeltype == LABEL_MANUAL) {
408 if (row->pos >= BeginningOfMainBody(row->par)) {
409 x += labelfont.signedStringWidth(layout.leftmargin);
411 x += labelfont.signedStringWidth(layout.labelindent);
415 // Special case to fix problems with theorems (JMarc)
416 || (layout.labeltype == LABEL_STATIC
417 && layout.latextype == LATEX_ENVIRONMENT
418 && ! row->par->IsFirstInSequence())) {
419 x += labelfont.signedStringWidth(layout.leftmargin);
420 } else if (layout.labeltype != LABEL_TOP_ENVIRONMENT
421 && layout.labeltype != LABEL_BIBLIO
422 && layout.labeltype != LABEL_CENTERED_TOP_ENVIRONMENT) {
423 x += labelfont.signedStringWidth(layout.labelindent);
424 x += labelfont.stringWidth(layout.labelsep);
425 x += labelfont.stringWidth(row->par->GetLabestring());
430 case MARGIN_RIGHT_ADDRESS_BOX:
432 /* ok, a terrible hack. The left margin depends on the widest row
433 * in this paragraph. Do not care about footnotes, they are *NOT*
434 * allowed in the LaTeX realisation of this layout. */
436 /* find the first row of this paragraph */
438 while (tmprow->previous && tmprow->previous->par == row->par)
439 tmprow = tmprow->previous;
441 int minfill = tmprow->fill;
442 while (tmprow-> next && tmprow->next->par == row->par) {
443 tmprow = tmprow->next;
444 if (tmprow->fill < minfill)
445 minfill = tmprow->fill;
448 x += textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.leftmargin);
453 if (row->par->pextra_type == LyXParagraph::PEXTRA_INDENT) {
454 if (!row->par->pextra_widthp.empty()) {
455 x += paperwidth * atoi(row->par->pextra_widthp.c_str()) / 100;
456 } else if (!row->par->pextra_width.empty()) {
457 int xx = VSpace(row->par->pextra_width).inPixels();
460 xx = paperwidth * 80 / 100;
462 } else { // should not happen
463 LyXFont font(LyXFont::ALL_SANE);
464 x += font.stringWidth("XXXXXX");
469 if (row->par->FirstPhysicalPar()->align == LYX_ALIGN_LAYOUT)
470 align = layout.align;
472 align = row->par->FirstPhysicalPar()->align;
474 /* set the correct parindent */
476 if ((layout.labeltype == LABEL_NO_LABEL
477 || layout.labeltype == LABEL_TOP_ENVIRONMENT
478 || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT
479 || (layout.labeltype == LABEL_STATIC
480 && layout.latextype == LATEX_ENVIRONMENT
481 && ! row->par->IsFirstInSequence()))
482 && row->par == row->par->FirstPhysicalPar()
483 && align == LYX_ALIGN_BLOCK
484 && !row->par->noindent
485 && (row->par->layout ||
486 parameters->paragraph_separation == BufferParams::PARSEP_INDENT))
487 x += textclasslist.TextClass(parameters->textclass).defaultfont().stringWidth(parindent);
489 if (layout.labeltype == LABEL_BIBLIO) { // ale970405 Right width for bibitems
490 x += bibitemMaxWidth(textclasslist.TextClass(parameters->textclass).defaultfont());
498 int LyXText::RightMargin(Row *row)
500 LyXParagraph * newpar;
502 LyXLayout const & layout = textclasslist.Style(parameters->textclass, row->par->GetLayout());
504 int x = LYX_PAPER_MARGIN;
506 x += textclasslist.TextClass(parameters->textclass).
507 defaultfont().signedStringWidth(textclasslist.TextClass(parameters->textclass).rightmargin());
508 if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
509 x += LYX_PAPER_MARGIN/2;
512 /* this is the way, LyX handles the LaTeX-Environments.
513 * I have had this idea very late, so it seems to be a
514 * later added hack and this is true */
515 if (row->par->GetDepth()) {
516 /* find the next level paragraph */
521 newpar = newpar->FirstPhysicalPar()->Previous();
523 newpar = newpar->FirstPhysicalPar();
524 } while (newpar && newpar->GetDepth() >= row->par->GetDepth()
525 && newpar->footnoteflag == row->par->footnoteflag);
527 /* make a corresponding row. Needed to call LeftMargin() */
529 /* check wether it is a sufficent paragraph */
530 if (newpar && newpar->footnoteflag == row->par->footnoteflag
531 && textclasslist.Style(parameters->textclass,
532 newpar->GetLayout()).isEnvironment()) {
533 dummyrow.par = newpar;
535 x = RightMargin(&dummyrow);
538 /* this is no longer an error, because this function is used
539 * to clear impossible depths after changing a layout. Since there
540 * is always a redo, LeftMargin() is always called */
542 /* printf("LYX_ERROR (text, LeftMargin()) impossible depth \n");*/
543 row->par->FirstPhysicalPar()->depth = 0;
547 //lyxerr << "rightmargin: " << layout->rightmargin << endl;
548 x += (textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.rightmargin) * 4
549 / (row->par->GetDepth() + 4));
555 int LyXText::LabelEnd (Row * row)
557 if (textclasslist.Style(parameters->textclass, row->par->GetLayout()).margintype == MARGIN_MANUAL) {
560 tmprow.pos = row->par->Last();
561 return LeftMargin(&tmprow); /* just the beginning
562 * of the main body */
565 return 0; /* LabelEnd is only needed, if the
566 * layout fills a flushleft
571 /* table stuff -- begin*/
572 int LyXText::NumberOfCell(LyXParagraph * par,
573 LyXParagraph::size_type pos)
576 LyXParagraph::size_type tmp_pos = 0;
577 while (tmp_pos < pos) {
578 if (par->IsNewline(tmp_pos))
586 int LyXText::WidthOfCell(LyXParagraph * par, LyXParagraph::size_type & pos)
589 while (pos < par->Last() && !par->IsNewline(pos)) {
590 w += SingleWidth(par, pos);
593 if (par->IsNewline(pos))
599 char LyXText::HitInTable(Row * row, int x)
602 float fill_separator, fill_hfill, fill_label_hfill;
603 if (!row->par->table)
605 PrepareToPrint(row, tmpx, fill_separator, fill_hfill, fill_label_hfill);
606 return (x > tmpx && x < tmpx + row->par->table->WidthOfTable());
610 bool LyXText::MouseHitInTable(int x, long y)
612 Row * row = GetRowNearY(y);
613 return HitInTable(row, x);
617 /* table stuff -- end*/
620 /* get the next breakpoint in a given paragraph */
621 LyXParagraph::size_type
622 LyXText::NextBreakPoint(Row * row, int width)
625 LyXParagraph::size_type last_separator = -1;
626 /* position of the last possible breakpoint
627 * -1 isn't a suitable value, but a flag */
630 LyXParagraph * par = row->par;
631 LyXParagraph::size_type i = 0;
632 LyXParagraph::size_type pos = row->pos;
634 /* table stuff -- begin*/
636 while (pos < par->size()
637 && (!par->IsNewline(pos)
638 || !par->table->IsFirstCell(NumberOfCell(par, pos+1)))) {
639 if (par->GetChar(pos) == LyXParagraph::META_INSET &&
640 par->GetInset(pos) && par->GetInset(pos)->Display()){
641 par->GetInset(pos)->SetDisplay(false);
647 /* table stuff -- end*/
649 left_margin = LabelEnd(row);
650 width -= RightMargin(row);
651 LyXParagraph::size_type main_body =
652 BeginningOfMainBody(par);
653 LyXLayout const & layout = textclasslist.Style(parameters->textclass, par->GetLayout());
657 if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX) {
658 /* special code for right address boxes, only newlines count */
659 while (i < par->Last()) {
660 if (par->IsNewline(i)) {
662 i = par->Last() - 1;/* this means break */
664 } else if (par->GetChar(i) == LyXParagraph::META_INSET &&
665 par->GetInset(i) && par->GetInset(i)->Display()){
666 par->GetInset(i)->SetDisplay(false);
671 // Last position is an invariant
672 LyXParagraph::size_type const last =
674 /* this is the usual handling */
676 while (x < width && i < last) {
678 if (IsNewlineChar(c)) {
680 x = width; /* this means break */
681 } else if (c == LyXParagraph::META_INSET &&
682 par->GetInset(i) && par->GetInset(i)->Display()){
683 /* check wether a Display() inset is valid here .
684 if not, change it to non-display*/
685 if (layout.isCommand()
686 || (layout.labeltype == LABEL_MANUAL
687 && i < BeginningOfMainBody(par))){
688 /* display istn't allowd */
689 par->GetInset(i)->SetDisplay(false);
690 x += SingleWidth(par, i, c);
692 /* inset is display. So break the line here */
696 if (IsLineSeparatorChar(par->GetChar(i+1)))
699 last_separator = last; // to avoid extra rows
701 last_separator = i - 1;
702 x = width; /* this means break */
705 if (IsLineSeparatorChar(c))
707 x += SingleWidth(par, i, c);
710 if (i == main_body) {
711 x += GetFont(par, -2).stringWidth(layout.labelsep);
712 if (par->IsLineSeparator(i - 1))
713 x-= SingleWidth(par, i - 1);
718 /* end of paragraph is always a suitable separator */
719 if (i == last && x < width)
723 /* well, if last_separator is still 0, the line isn't breakable.
724 * don't care and cut simply at the end */
725 if (last_separator < 0) {
729 /* manual labels cannot be broken in LaTeX, do not care */
730 if (main_body && last_separator < main_body)
731 last_separator = main_body - 1;
733 return last_separator;
737 /* returns the minimum space a row needs on the screen in pixel */
738 int LyXText::Fill(Row * row, int paperwidth)
741 /* get the pure distance */
742 LyXParagraph::size_type last = RowLast(row);
743 /* table stuff -- begin*/
744 if (row->par->table) {
745 /* for tables FILL does calculate the widthes of each cell in
747 LyXParagraph::size_type pos = row->pos;
748 int cell = NumberOfCell(row->par, pos);
751 row->par->table->SetWidthOfCell(cell, WidthOfCell(row->par, pos));
753 } while (pos <= last && !row->par->table->IsFirstCell(cell));
754 /* don't forget the very last table cell without characters */
755 if (cell == row->par->table->GetNumberOfCells()-1)
756 row->par->table->SetWidthOfCell(cell, WidthOfCell(row->par, pos));
758 return 0; /* width of table cannot be returned since
759 * we cannot guarantee its correct value at
762 /* table stuff -- end*/
764 int left_margin = LabelEnd(row);
766 /* if the row ends with newline, this newline will not be relevant */
767 if (last >= 0 && row->par->IsNewline(last))
770 /* if the row ends with a space, this space will not be relevant */
771 if (last >= 0 && row->par->IsLineSeparator(last))
774 /* special handling of the right address boxes */
775 if (textclasslist.Style(parameters->textclass,
776 row->par->GetLayout()).margintype
777 == MARGIN_RIGHT_ADDRESS_BOX) {
778 int tmpfill = row->fill;
779 row->fill = 0; /* the minfill in MarginLeft() */
786 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
787 row->par->GetLayout());
788 LyXParagraph::size_type main_body =
789 BeginningOfMainBody(row->par);
790 LyXParagraph::size_type i = row->pos;
792 w += SingleWidth(row->par, i);
794 if (i == main_body) {
795 w += GetFont(row->par, -2).stringWidth(layout.labelsep);
796 if (row->par->IsLineSeparator(i - 1))
797 w -= SingleWidth(row->par, i - 1);
803 fill = paperwidth - w - RightMargin(row);
808 /* returns the minimum space a manual label needs on the screen in pixel */
809 int LyXText::LabelFill(Row * row)
812 LyXParagraph::size_type last = BeginningOfMainBody(row->par) - 1;
813 /* -1 because a label ends either with a space that is in the label,
814 * or with the beginning of a footnote that is outside the label. */
816 // I don't understand this code in depth, but sometimes "last" is less than
817 // 0 and this causes a crash. This fix seems to work correctly, but I
818 // bet the real error is elsewhere. The bug is triggered when you have an
819 // open footnote in a paragraph environment with a manual label. (Asger)
820 if (last < 0) last = 0;
822 if (row->par->IsLineSeparator(last)) /* a sepearator at this end
829 w += SingleWidth(row->par, i);
834 if (!row->par->labelwidthstring.empty()) {
835 fill = GetFont(row->par, -2).stringWidth(row->par->labelwidthstring) - w;
845 /* returns the number of separators in the specified row. The separator
846 * on the very last column doesnt count */
847 int LyXText::NumberOfSeparators(Row *row)
849 int last = RowLast(row);
852 int main_body = BeginningOfMainBody(row->par);
855 for (; p < last; p++) {
856 if (row->par->IsSeparator(p)) {
864 /* returns the number of hfills in the specified row. The LyX-Hfill is
865 * a LaTeX \hfill so that the hfills at the beginning and at the end were
866 * ignored. This is *MUCH* more usefull than not to ignore! */
867 int LyXText::NumberOfHfills(Row * row)
869 int last = RowLast(row);
870 int first = row->pos;
871 if (first) { /* hfill *DO* count at the beginning
873 while(first <= last && row->par->IsHfill(first))
877 int main_body = BeginningOfMainBody(row->par);
878 if (first < main_body)
881 for (int p = first; p <= last; p++) { // last, because the end is ignored!
882 if (row->par->IsHfill(p)) {
890 /* like NumberOfHfills, but only those in the manual label! */
891 int LyXText::NumberOfLabelHfills(Row * row)
893 LyXParagraph::size_type last = RowLast(row);
894 LyXParagraph::size_type first = row->pos;
895 if (first) { /* hfill *DO* count at the beginning
897 while(first < last && row->par->IsHfill(first))
900 LyXParagraph::size_type main_body =
901 BeginningOfMainBody(row->par);
902 if (last > main_body)
906 for (LyXParagraph::size_type p = first;
907 p < last; ++p) { // last, because the end is ignored!
908 if (row->par->IsHfill(p)) {
916 /* returns true, if a expansion is needed.
917 * Rules are given by LaTeX */
918 bool LyXText::HfillExpansion(Row * row_ptr,
919 LyXParagraph::size_type pos)
921 /* by the way, is it a hfill? */
922 if (!row_ptr->par->IsHfill(pos))
925 /* at the end of a row it does not count */
926 if (pos >= RowLast(row_ptr))
929 /* at the beginning of a row it does not count, if it is not
930 * the first row of a paragaph */
934 /* in some labels it does not count */
935 if ( textclasslist.Style(parameters->textclass, row_ptr->par->GetLayout()).margintype != MARGIN_MANUAL &&
936 pos < BeginningOfMainBody(row_ptr->par))
939 /* if there is anything between the first char of the row and
940 * the sepcified position that is not a newline and not a hfill,
941 * the hfill will count, otherwise not */
942 LyXParagraph::size_type i = row_ptr->pos;
943 while (i < pos && (row_ptr->par->IsNewline(i)
944 || row_ptr->par->IsHfill(i)))
951 void LyXText::SetHeightOfRow(Row * row_ptr)
953 /* get the maximum ascent and the maximum descent */
954 int asc, maxasc, desc, maxdesc, pos_end, pos, labeladdon;
956 float layoutdesc = 0;
961 /* this must not happen before the currentrow for clear reasons.
962 so the trick is just to set the current row onto this row */
964 GetRow(row_ptr->par, row_ptr->pos, unused_y);
966 /* ok , let us initialize the maxasc and maxdesc value.
967 * This depends in LaTeX of the font of the last character
968 * in the paragraph. The hack below is necessary because
969 * of the possibility of open footnotes */
971 /* Correction: only the fontsize count. The other properties
972 are taken from the layoutfont. Nicer on the screen :) */
974 LyXParagraph * par = row_ptr->par->LastPhysicalPar();
975 LyXParagraph * firstpar = row_ptr->par->FirstPhysicalPar();
977 LyXLayout const & layout = textclasslist.Style(parameters->textclass, firstpar->GetLayout());
979 LyXFont font = GetFont(par, par->Last()-1);
980 LyXFont::FONT_SIZE size = font.size();
981 font = GetFont(par, -1);
984 LyXFont labelfont = GetFont(par, -2);
986 maxasc = int(font.maxAscent() *
987 layout.spacing.getValue() *
988 parameters->spacing.getValue());
989 maxdesc = int(font.maxDescent() *
990 layout.spacing.getValue() *
991 parameters->spacing.getValue());
993 pos_end = RowLast(row_ptr);
997 // Check if any insets are larger
998 for (pos = row_ptr->pos; pos <= pos_end; pos++) {
999 if (row_ptr->par->GetChar(pos) == LyXParagraph::META_INSET) {
1000 tmpfont = GetFont(row_ptr->par, pos);
1001 tmpinset = row_ptr->par->GetInset(pos);
1003 asc = tmpinset->Ascent(tmpfont);
1004 desc = tmpinset->Descent(tmpfont);
1013 // Check if any custom fonts are larger (Asger)
1014 // This is not completely correct, but we can live with the small,
1015 // cosmetic error for now.
1016 LyXFont::FONT_SIZE maxsize = row_ptr->par->HighestFontInRange(row_ptr->pos, pos_end);
1017 if (maxsize > font.size()) {
1018 font.setSize(maxsize);
1020 asc = font.maxAscent();
1021 desc = font.maxDescent();
1028 /* table stuff -- begin*/
1029 if (row_ptr->par->table){
1030 // stretch the rows a bit
1034 /* table stuff -- end*/
1036 // This is nicer with box insets:
1040 row_ptr->ascent_of_text = maxasc;
1042 /* is it a top line? */
1043 if (row_ptr->pos == 0
1044 && row_ptr->par == firstpar) {
1046 /* some parksips VERY EASY IMPLEMENTATION */
1047 if (parameters->paragraph_separation == BufferParams::PARSEP_SKIP) {
1048 if (layout.isParagraph()
1049 && firstpar->GetDepth() == 0
1050 && firstpar->Previous())
1051 maxasc += parameters->getDefSkip().inPixels();
1052 else if (firstpar->Previous()
1053 && textclasslist.Style(parameters->textclass,
1054 firstpar->Previous()->GetLayout()).isParagraph()
1055 && firstpar->Previous()->GetDepth() == 0)
1056 // is it right to use defskip here too? (AS)
1057 maxasc += parameters->getDefSkip().inPixels();
1060 /* the paper margins */
1061 if (!row_ptr->par->previous)
1062 maxasc += LYX_PAPER_MARGIN;
1064 /* add the vertical spaces, that the user added */
1065 if (firstpar->added_space_top.kind() != VSpace::NONE)
1066 maxasc += int(firstpar->added_space_top.inPixels());
1068 /* do not forget the DTP-lines!
1069 * there height depends on the font of the nearest character */
1070 if (firstpar->line_top)
1071 maxasc += 2 * GetFont(firstpar, 0).ascent('x');
1073 /* and now the pagebreaks */
1074 if (firstpar->pagebreak_top)
1075 maxasc += 3 * DefaultHeight();
1077 /* this is special code for the chapter, since the label of this
1078 * layout is printed in an extra row */
1079 if (layout.labeltype == LABEL_COUNTER_CHAPTER
1080 && parameters->secnumdepth>= 0) {
1081 labeladdon = int(labelfont.maxDescent() *
1082 layout.spacing.getValue() *
1083 parameters->spacing.getValue())
1084 + int(labelfont.maxAscent() *
1085 layout.spacing.getValue() *
1086 parameters->spacing.getValue());
1089 /* special code for the top label */
1090 if ((layout.labeltype == LABEL_TOP_ENVIRONMENT
1091 || layout.labeltype == LABEL_BIBLIO
1092 || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)
1093 && row_ptr->par->IsFirstInSequence()
1094 && !row_ptr->par->GetLabestring().empty()) {
1096 (labelfont.maxAscent() *
1097 layout.spacing.getValue() *
1098 parameters->spacing.getValue())
1099 +(labelfont.maxDescent() *
1100 layout.spacing.getValue() *
1101 parameters->spacing.getValue())
1102 + layout.topsep * DefaultHeight()
1103 + layout.labelbottomsep * DefaultHeight());
1106 /* and now the layout spaces, for example before and after a section,
1107 * or between the items of a itemize or enumerate environment */
1109 if (!firstpar->pagebreak_top) {
1110 LyXParagraph *prev = row_ptr->par->Previous();
1112 prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth());
1113 if (prev && prev->GetLayout() == firstpar->GetLayout()
1114 && prev->GetDepth() == firstpar->GetDepth()
1115 && prev->GetLabelWidthString() == firstpar->GetLabelWidthString())
1117 layoutasc = (layout.itemsep * DefaultHeight());
1119 else if (row_ptr->previous) {
1120 tmptop = layout.topsep;
1122 if (row_ptr->previous->par->GetDepth() >= row_ptr->par->GetDepth())
1123 tmptop-= textclasslist.Style(parameters->textclass, row_ptr->previous->par->GetLayout()).bottomsep;
1126 layoutasc = (tmptop * DefaultHeight());
1128 else if (row_ptr->par->line_top){
1129 tmptop = layout.topsep;
1132 layoutasc = (tmptop * DefaultHeight());
1135 prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth()-1);
1137 maxasc += int(textclasslist.Style(parameters->textclass,
1138 prev->GetLayout()).parsep * DefaultHeight());
1141 if (firstpar->Previous()
1142 && firstpar->Previous()->GetDepth() == 0
1143 && firstpar->Previous()->GetLayout() != firstpar->GetLayout()) {
1146 else if (firstpar->Previous()){
1147 maxasc += int(layout.parsep * DefaultHeight());
1153 /* is it a bottom line? */
1154 if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
1155 && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {
1157 /* the paper margins */
1159 maxdesc += LYX_PAPER_MARGIN;
1161 /* add the vertical spaces, that the user added */
1162 if (firstpar->added_space_bottom.kind() != VSpace::NONE)
1163 maxdesc += int(firstpar->added_space_bottom.inPixels());
1165 /* do not forget the DTP-lines!
1166 * there height depends on the font of the nearest character */
1167 if (firstpar->line_bottom)
1168 maxdesc += 2 * (GetFont(par, par->Last()-1).ascent('x'));
1170 /* and now the pagebreaks */
1171 if (firstpar->pagebreak_bottom)
1172 maxdesc += 3 * DefaultHeight();
1174 /* and now the layout spaces, for example before and after a section,
1175 * or between the items of a itemize or enumerate environment */
1176 if (!firstpar->pagebreak_bottom && row_ptr->par->Next()) {
1177 LyXParagraph *nextpar = row_ptr->par->Next();
1178 LyXParagraph *comparepar = row_ptr->par;
1182 if (comparepar->GetDepth() > nextpar->GetDepth()) {
1183 usual = (textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1184 comparepar = comparepar->DepthHook(nextpar->GetDepth());
1185 if (comparepar->GetLayout()!= nextpar->GetLayout()
1186 || nextpar->GetLabelWidthString() !=
1187 comparepar->GetLabelWidthString())
1188 unusual = (textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1190 if (unusual > usual)
1191 layoutdesc = unusual;
1195 else if (comparepar->GetDepth() == nextpar->GetDepth()) {
1197 if (comparepar->GetLayout()!= nextpar->GetLayout()
1198 || nextpar->GetLabelWidthString() !=
1199 comparepar->GetLabelWidthString())
1200 layoutdesc = int(textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1205 /* incalculate the layout spaces */
1206 maxasc += int(layoutasc * 2 / (2 + firstpar->GetDepth()));
1207 maxdesc += int(layoutdesc * 2 / (2 + firstpar->GetDepth()));
1209 /* table stuff -- begin*/
1210 if (row_ptr->par->table){
1211 maxasc += row_ptr->par->table->
1212 AdditionalHeight(NumberOfCell(row_ptr->par, row_ptr->pos));
1214 /* table stuff -- end*/
1216 /* calculate the new height of the text */
1217 height -= row_ptr->height;
1219 row_ptr->height= maxasc+maxdesc+labeladdon;
1220 row_ptr->baseline= maxasc+labeladdon;
1222 height += row_ptr->height;
1226 /* Appends the implicit specified paragraph behind the specified row,
1227 * start at the implicit given position */
1228 void LyXText::AppendParagraph(Row * row)
1230 bool not_ready = true;
1232 // The last character position of a paragraph is an invariant so we can
1233 // safely get it here. (Asger)
1234 int lastposition = row->par->Last();
1237 // Get the next breakpoint
1238 int z = NextBreakPoint(row, paperwidth);
1242 // Insert the new row
1243 if (z < lastposition) {
1245 InsertRow(row, row->par, z);
1252 // Set the dimensions of the row
1253 tmprow->fill = Fill(tmprow, paperwidth);
1254 SetHeightOfRow(tmprow);
1256 } while (not_ready);
1260 void LyXText::BreakAgain(Row * row)
1262 bool not_ready = true;
1265 /* get the next breakpoint */
1266 LyXParagraph::size_type z =
1267 NextBreakPoint(row, paperwidth);
1270 if (z < row->par->Last() ) {
1271 if (!row->next || (row->next && row->next->par != row->par)) {
1272 /* insert a new row */
1274 InsertRow(row, row->par, z);
1281 not_ready = false; // the rest will not change
1287 /* if there are some rows too much, delete them */
1288 /* only if you broke the whole paragraph! */
1289 Row * tmprow2 = row;
1290 while (tmprow2->next && tmprow2->next->par == row->par) {
1291 tmprow2 = tmprow2->next;
1293 while (tmprow2 != row) {
1294 tmprow2 = tmprow2->previous;
1295 RemoveRow(tmprow2->next);
1300 /* set the dimensions of the row */
1301 tmprow->fill = Fill(tmprow, paperwidth);
1302 SetHeightOfRow(tmprow);
1303 } while (not_ready);
1307 /* this is just a little changed version of break again */
1308 void LyXText::BreakAgainOneRow(Row * row)
1310 /* get the next breakpoint */
1311 LyXParagraph::size_type z = NextBreakPoint(row, paperwidth);
1314 if (z < row->par->Last() ) {
1315 if (!row->next || (row->next && row->next->par != row->par)) {
1316 /* insert a new row */
1318 InsertRow(row, row->par, z);
1330 /* if there are some rows too much, delete them */
1331 /* only if you broke the whole paragraph! */
1332 Row * tmprow2 = row;
1333 while (tmprow2->next && tmprow2->next->par == row->par) {
1334 tmprow2 = tmprow2->next;
1336 while (tmprow2 != row) {
1337 tmprow2 = tmprow2->previous;
1338 RemoveRow(tmprow2->next);
1342 /* set the dimensions of the row */
1343 tmprow->fill = Fill(tmprow, paperwidth);
1344 SetHeightOfRow(tmprow);
1348 void LyXText::BreakParagraph(char keep_layout)
1350 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
1351 cursor.par->GetLayout());
1353 /* table stuff -- begin*/
1354 if (cursor.par->table) {
1355 // breaking of tables is only allowed at the beginning or the end */
1356 if (cursor.pos && cursor.pos < cursor.par->size() &&
1357 !cursor.par->table->ShouldBeVeryLastCell(NumberOfCell(cursor.par, cursor.pos)))
1358 return; /* no breaking of tables allowed */
1360 /* table stuff -- end*/
1362 /* this is only allowed, if the current paragraph is not empty or caption*/
1363 if ((cursor.par->Last() <= 0 && !cursor.par->IsDummy())
1365 layout.labeltype!= LABEL_SENSITIVE)
1368 SetUndo(Undo::INSERT,
1369 cursor.par->ParFromPos(cursor.pos)->previous,
1370 cursor.par->ParFromPos(cursor.pos)->next);
1372 /* table stuff -- begin*/
1373 if (cursor.par->table) {
1374 int cell = NumberOfCell(cursor.par, cursor.pos);
1375 if (cursor.par->table->ShouldBeVeryLastCell(cell))
1376 SetCursor(cursor.par, cursor.par->text.size());
1378 /* table stuff -- end*/
1379 /* please break alway behind a space */
1380 if (cursor.pos < cursor.par->Last()
1381 && cursor.par->IsLineSeparator(cursor.pos))
1384 /* break the paragraph */
1388 keep_layout = layout.isEnvironment();
1389 cursor.par->BreakParagraph(cursor.pos, keep_layout);
1391 /* table stuff -- begin*/
1392 if (cursor.par->table){
1393 // the table should stay with the contents
1395 cursor.par->Next()->table = cursor.par->table;
1396 cursor.par->table = 0;
1399 /* table stuff -- end*/
1401 /* well this is the caption hack since one caption is really enough */
1402 if (layout.labeltype == LABEL_SENSITIVE){
1404 cursor.par->SetLayout(0); /* set the new paragraph to standard-layout */
1406 cursor.par->Next()->SetLayout(0); /* set the new paragraph to standard-layout */
1410 /* if the cursor is at the beginning of a row without prior newline,
1412 * This touches only the screen-update. Otherwise we would may have
1413 * an empty row on the screen */
1414 if (cursor.pos && !cursor.row->par->IsNewline(cursor.row->pos -1) &&
1415 cursor.row->pos == cursor.pos) {
1419 status = LyXText::NEED_MORE_REFRESH;
1420 refresh_row = cursor.row;
1421 refresh_y = cursor.y - cursor.row->baseline;
1423 /* Do not forget the special right address boxes */
1424 if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX) {
1425 while (refresh_row->previous &&
1426 refresh_row->previous->par == refresh_row->par) {
1427 refresh_row = refresh_row->previous;
1428 refresh_y -= refresh_row->height;
1431 RemoveParagraph(cursor.row);
1433 /* set the dimensions of the cursor row */
1434 cursor.row->fill = Fill(cursor.row, paperwidth);
1436 SetHeightOfRow(cursor.row);
1438 while (!cursor.par->Next()->table && cursor.par->Next()->Last()
1439 && cursor.par->Next()->IsNewline(0))
1440 cursor.par->Next()->Erase(0);
1442 InsertParagraph(cursor.par->Next(), cursor.row);
1444 UpdateCounters(cursor.row->previous);
1446 /* this check is necessary. Otherwise the new empty paragraph will
1447 * be deleted automatically. And it is more friendly for the user! */
1449 SetCursor(cursor.par->Next(), 0);
1451 SetCursor(cursor.par, 0);
1453 if (cursor.row->next)
1454 BreakAgain(cursor.row->next);
1460 void LyXText::OpenFootnote()
1462 LyXParagraph * endpar,* tmppar;
1465 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
1467 /* if there is no footnote in this paragraph, just return. */
1469 || par->next->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1472 /* ok, move the cursor right before the footnote */
1474 /* just a little faster than using CursorRight() */
1475 for (cursor.pos= 0; cursor.par->ParFromPos(cursor.pos)!= par; cursor.pos++);
1476 /* now the cursor is at the beginning of the physical par */
1477 SetCursor(cursor.par,
1478 cursor.pos + cursor.par->ParFromPos(cursor.pos)->text.size());
1480 /* the cursor must be exactly before the footnote */
1481 par = cursor.par->ParFromPos(cursor.pos);
1483 status = LyXText::NEED_MORE_REFRESH;
1484 refresh_row = cursor.row;
1485 refresh_y = cursor.y - cursor.row->baseline;
1487 tmppar = cursor.par;
1488 endpar = cursor.par->Next();
1491 tmppar->OpenFootnote(cursor.pos);
1492 RemoveParagraph(row);
1493 /* set the dimensions of the cursor row */
1494 row->fill = Fill(row, paperwidth);
1495 SetHeightOfRow(row);
1496 tmppar = tmppar->Next();
1498 while (tmppar != endpar) {
1500 InsertParagraph(tmppar, row);
1501 while (row->next && row->next->par == tmppar)
1503 tmppar = tmppar->Next();
1506 SetCursor(par->next, 0);
1507 sel_cursor = cursor;
1511 /* table stuff -- begin*/
1513 void LyXText::TableFeatures(int feature, string val)
1515 if (!cursor.par->table)
1516 return; /* this should never happen */
1518 int actCell = NumberOfCell(cursor.par, cursor.pos);
1519 SetUndo(Undo::FINISH,
1520 cursor.par->ParFromPos(cursor.pos)->previous,
1521 cursor.par->ParFromPos(cursor.pos)->next);
1524 case LyXTable::SET_PWIDTH:
1525 cursor.par->table->SetPWidth(actCell, val);
1527 case LyXTable::SET_SPECIAL_COLUMN:
1528 case LyXTable::SET_SPECIAL_MULTI:
1529 cursor.par->table->SetAlignSpecial(actCell, val, feature);
1538 void LyXText::TableFeatures(int feature)
1541 int setAlign = LYX_ALIGN_LEFT;
1545 if (!cursor.par->table)
1546 return; /* this should never happen */
1548 int actCell = NumberOfCell(cursor.par, cursor.pos);
1549 SetUndo(Undo::FINISH,
1550 cursor.par->ParFromPos(cursor.pos)->previous,
1551 cursor.par->ParFromPos(cursor.pos)->next);
1554 case LyXTable::ALIGN_LEFT:
1555 setAlign= LYX_ALIGN_LEFT;
1557 case LyXTable::ALIGN_RIGHT:
1558 setAlign= LYX_ALIGN_RIGHT;
1560 case LyXTable::ALIGN_CENTER:
1561 setAlign= LYX_ALIGN_CENTER;
1567 case LyXTable::APPEND_ROW: {
1568 LyXParagraph::size_type pos = cursor.pos;
1570 /* move to the next row */
1571 int cell_org = actCell;
1572 int cell = cell_org;
1574 // if there is a ContRow following this row I have to add
1575 // the row after the ContRow's
1576 if ((pos < cursor.par->Last()) &&
1577 cursor.par->table->RowHasContRow(cell_org)) {
1578 while((pos < cursor.par->Last()) &&
1579 !cursor.par->table->IsContRow(cell)) {
1580 while (pos < cursor.par->Last() &&
1581 !cursor.par->IsNewline(pos))
1583 if (pos < cursor.par->Last())
1587 while((pos < cursor.par->Last()) &&
1588 cursor.par->table->IsContRow(cell)) {
1589 while (pos < cursor.par->Last() &&
1590 !cursor.par->IsNewline(pos))
1592 if (pos < cursor.par->Last())
1597 if (pos < cursor.par->Last())
1600 while (pos < cursor.par->Last() &&
1601 (cell == cell_org || !cursor.par->table->IsFirstCell(cell))){
1602 while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1604 if (pos < cursor.par->Last())
1609 /* insert the new cells */
1610 int number = cursor.par->table->NumberOfCellsInRow(cell_org);
1611 for (int i = 0; i < number; ++i)
1612 cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1614 /* append the row into the table */
1615 cursor.par->table->AppendRow(cell_org);
1619 case LyXTable::APPEND_CONT_ROW: {
1620 LyXParagraph::size_type pos = cursor.pos;
1621 /* move to the next row */
1622 int cell_org = actCell;
1623 int cell = cell_org;
1625 // if there is already a controw but not for this cell
1626 // the AppendContRow sets only the right values but does
1627 // not actually add a row
1628 if (cursor.par->table->RowHasContRow(cell_org) &&
1629 (cursor.par->table->CellHasContRow(cell_org)<0)) {
1630 cursor.par->table->AppendContRow(cell_org);
1634 while (pos < cursor.par->Last() &&
1636 || !cursor.par->table->IsFirstCell(cell))){
1637 while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1639 if (pos < cursor.par->Last())
1644 /* insert the new cells */
1645 int number = cursor.par->table->NumberOfCellsInRow(cell_org);
1647 for (i= 0; i<number; i++)
1648 cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1650 /* append the row into the table */
1651 cursor.par->table->AppendContRow(cell_org);
1655 case LyXTable::APPEND_COLUMN: {
1656 LyXParagraph::size_type pos = 0;
1657 int cell_org = actCell;
1660 if (pos && (cursor.par->IsNewline(pos-1))){
1661 if (cursor.par->table->AppendCellAfterCell(cell_org, cell)){
1662 cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1663 if (pos <= cursor.pos)
1670 } while (pos <= cursor.par->Last());
1671 /* remember that the very last cell doesn't end with a newline.
1672 This saves one byte memory per table ;-) */
1673 if (cursor.par->table->AppendCellAfterCell(cell_org, cell))
1674 cursor.par->InsertChar(cursor.par->Last(), LyXParagraph::META_NEWLINE);
1676 /* append the column into the table */
1677 cursor.par->table->AppendColumn(cell_org);
1682 case LyXTable::DELETE_ROW:
1683 if (current_view->buffer()->the_locking_inset)
1684 UnlockInset(current_view->buffer()->the_locking_inset);
1685 RemoveTableRow(&cursor);
1689 case LyXTable::DELETE_COLUMN: {
1690 LyXParagraph::size_type pos = 0;
1691 int cell_org = actCell;
1693 if (current_view->buffer()->the_locking_inset)
1694 UnlockInset(current_view->buffer()->the_locking_inset);
1696 if (!pos || (cursor.par->IsNewline(pos-1))){
1697 if (cursor.par->table->DeleteCellIfColumnIsDeleted(cell, cell_org)){
1699 while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1700 cursor.par->Erase(pos);
1701 if (pos < cursor.par->Last())
1702 cursor.par->Erase(pos);
1704 cursor.par->Erase(pos - 1); // the missing newline at the end of a table
1705 --pos; // because of pos++ below
1710 } while (pos <= cursor.par->Last());
1712 /* delete the column from the table */
1713 cursor.par->table->DeleteColumn(cell_org);
1715 /* set the cursor to the beginning of the table, where else? */
1720 case LyXTable::TOGGLE_LINE_TOP:
1721 lineSet = !cursor.par->table->TopLine(actCell);
1723 cursor.par->table->SetTopLine(actCell, lineSet);
1725 LyXParagraph::size_type i;
1727 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
1728 if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1729 cursor.par->table->SetTopLine(n, lineSet);
1737 case LyXTable::TOGGLE_LINE_BOTTOM:
1738 lineSet = !cursor.par->table->BottomLine(actCell);
1740 cursor.par->table->SetBottomLine(actCell, lineSet);
1742 LyXParagraph::size_type i;
1744 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
1745 if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1746 cursor.par->table->SetBottomLine(n, lineSet);
1754 case LyXTable::TOGGLE_LINE_LEFT:
1755 lineSet = !cursor.par->table->LeftLine(actCell);
1757 cursor.par->table->SetLeftLine(actCell, lineSet);
1759 LyXParagraph::size_type i;
1761 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
1762 if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1763 cursor.par->table->SetLeftLine(n, lineSet);
1771 case LyXTable::TOGGLE_LINE_RIGHT:
1772 lineSet = !cursor.par->table->RightLine(actCell);
1774 cursor.par->table->SetRightLine(actCell, lineSet);
1776 LyXParagraph::size_type i;
1778 for (i= sel_start_cursor.pos; i<= sel_end_cursor.pos; i++){
1779 if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1780 cursor.par->table->SetRightLine(n, lineSet);
1788 case LyXTable::ALIGN_LEFT:
1789 case LyXTable::ALIGN_RIGHT:
1790 case LyXTable::ALIGN_CENTER:
1792 cursor.par->table->SetAlignment(actCell, setAlign);
1794 LyXParagraph::size_type i;
1796 for (i= sel_start_cursor.pos; i<= sel_end_cursor.pos; i++){
1797 if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1798 cursor.par->table->SetAlignment(n, setAlign);
1806 case LyXTable::DELETE_TABLE:
1807 SetCursorIntern(cursor.par, 0);
1808 delete cursor.par->table;
1809 cursor.par->table = 0;
1810 // temporary: Should put table in simple_cut_buffer (with before and after
1811 // dummy-paragraph !!
1812 // not necessar anymore with UNDO :)
1813 for (LyXParagraph::size_type i =
1814 cursor.par->text.size() - 1; i >= 0; --i)
1815 cursor.par->Erase(i);
1819 case LyXTable::MULTICOLUMN: {
1821 // check wether we are completly in a multicol
1822 int multicol = cursor.par->table->IsMultiColumn(actCell);
1823 if (multicol && selection && sel_start_cursor.row == sel_end_cursor.row){
1824 multicol = NumberOfCell(sel_start_cursor.par, sel_start_cursor.pos)
1825 == NumberOfCell(sel_end_cursor.par, sel_end_cursor.pos);
1829 int newlines = cursor.par->table->UnsetMultiColumn(actCell);
1830 LyXParagraph::size_type pos = cursor.pos;
1831 while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1833 for (;newlines;newlines--)
1834 cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1839 // selection must be in one row (or no selection)
1841 cursor.par->table->SetMultiColumn(NumberOfCell(cursor.par,
1848 if (sel_start_cursor.row == sel_end_cursor.row){
1849 LyXParagraph::size_type i;
1851 for (i = sel_start_cursor.pos;
1852 i < sel_end_cursor.pos; ++i){
1853 if (sel_start_cursor.par->IsNewline(i)){
1854 sel_start_cursor.par->Erase(i);
1855 // check for double-blanks
1856 if ((i && !sel_start_cursor.par->IsLineSeparator(i-1))
1858 (i < sel_start_cursor.par->Last()
1859 && !sel_start_cursor.par->IsLineSeparator(i)))
1860 sel_start_cursor.par->InsertChar(i, ' ');
1862 sel_end_cursor.pos--;
1869 SetMultiColumn(NumberOfCell(sel_start_cursor.par,
1870 sel_start_cursor.pos),
1872 cursor.pos = sel_start_cursor.pos;
1877 WriteAlert(_("Impossible Operation!"),
1878 _("Multicolumns can only be horizontally."),
1885 case LyXTable::SET_ALL_LINES:
1887 case LyXTable::UNSET_ALL_LINES:
1889 cursor.par->table->SetAllLines(NumberOfCell(cursor.par,
1893 LyXParagraph::size_type i;
1895 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
1896 if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1897 cursor.par->table->SetAllLines(n, setLines);
1904 case LyXTable::SET_LONGTABLE:
1905 cursor.par->table->SetLongTable(true);
1907 case LyXTable::UNSET_LONGTABLE:
1908 cursor.par->table->SetLongTable(false);
1910 case LyXTable::SET_ROTATE_TABLE:
1911 cursor.par->table->SetRotateTable(true);
1913 case LyXTable::UNSET_ROTATE_TABLE:
1914 cursor.par->table->SetRotateTable(false);
1916 case LyXTable::SET_ROTATE_CELL:
1918 cursor.par->table->SetRotateCell(actCell, true);
1920 LyXParagraph::size_type i;
1922 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
1923 if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1924 cursor.par->table->SetRotateCell(n, true);
1930 case LyXTable::UNSET_ROTATE_CELL:
1932 cursor.par->table->SetRotateCell(actCell, false);
1934 LyXParagraph::size_type i;
1936 for (i= sel_start_cursor.pos; i<= sel_end_cursor.pos; i++){
1937 if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1938 cursor.par->table->SetRotateCell(n, false);
1944 case LyXTable::SET_LINEBREAKS:
1945 what = !cursor.par->table->Linebreaks(cursor.par->table->FirstVirtualCell(actCell));
1947 cursor.par->table->SetLinebreaks(actCell, what);
1949 LyXParagraph::size_type i;
1951 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
1952 if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1953 cursor.par->table->SetLinebreaks(n, what);
1959 case LyXTable::SET_LTFIRSTHEAD:
1960 cursor.par->table->SetLTHead(actCell, true);
1962 case LyXTable::SET_LTHEAD:
1963 cursor.par->table->SetLTHead(actCell, false);
1965 case LyXTable::SET_LTFOOT:
1966 cursor.par->table->SetLTFoot(actCell, false);
1968 case LyXTable::SET_LTLASTFOOT:
1969 cursor.par->table->SetLTFoot(actCell, true);
1971 case LyXTable::SET_LTNEWPAGE:
1972 what = !cursor.par->table->LTNewPage(actCell);
1973 cursor.par->table->SetLTNewPage(actCell, what);
1979 void LyXText::InsertCharInTable(char c)
1984 bool jumped_over_space;
1986 /* first check, if there will be two blanks together or a blank at
1987 * the beginning of a paragraph.
1988 * I decided to handle blanks like normal characters, the main
1989 * difference are the special checks when calculating the row.fill
1990 * (blank does not count at the end of a row) and the check here */
1992 LyXFont realtmpfont = real_current_font;
1993 LyXFont rawtmpfont = current_font; /* store the current font.
1994 * This is because of the use
1995 * of cursor movements. The moving
1996 * cursor would refresh the
1999 // Get the font that is used to calculate the baselineskip
2000 LyXParagraph::size_type const lastpos =
2002 LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2004 jumped_over_space = false;
2005 if (IsLineSeparatorChar(c)) {
2007 /* avoid double blanks but insert the new blank because
2008 * of a possible font change */
2009 if (cursor.pos < lastpos &&
2010 cursor.par->IsLineSeparator(cursor.pos))
2012 cursor.par->Erase(cursor.pos);
2013 jumped_over_space = true;
2015 else if ((cursor.pos > 0 &&
2016 cursor.par->IsLineSeparator(cursor.pos - 1))
2017 || (cursor.pos > 0 && cursor.par->IsNewline(cursor.pos - 1))
2018 || (cursor.pos == 0 &&
2019 !(cursor.par->Previous()
2020 && cursor.par->Previous()->footnoteflag
2021 == LyXParagraph::OPEN_FOOTNOTE)))
2024 else if (IsNewlineChar(c)) {
2025 if (!IsEmptyTableCell()) {
2026 TableFeatures(LyXTable::APPEND_CONT_ROW);
2033 y = cursor.y - row->baseline;
2034 if (c != LyXParagraph::META_INSET) /* in this case LyXText::InsertInset
2035 * already inserted the character */
2036 cursor.par->InsertChar(cursor.pos, c);
2037 SetCharFont(cursor.par, cursor.pos, rawtmpfont);
2039 if (!jumped_over_space) {
2040 /* refresh the positions */
2042 while (tmprow->next && tmprow->next->par == row->par) {
2043 tmprow = tmprow->next;
2050 CheckParagraphInTable(cursor.par, cursor.pos);
2052 current_font = rawtmpfont;
2053 real_current_font = realtmpfont;
2055 /* check, whether the last character's font has changed. */
2056 if (cursor.pos && cursor.pos == cursor.par->Last()
2057 && rawparfont != rawtmpfont)
2058 RedoHeightOfParagraph(cursor);
2062 void LyXText::CheckParagraphInTable(LyXParagraph * par,
2063 LyXParagraph::size_type pos)
2066 if (par->GetChar(pos) == LyXParagraph::META_INSET &&
2067 par->GetInset(pos) && par->GetInset(pos)->Display()){
2068 par->GetInset(pos)->SetDisplay(false);
2072 Row * row = GetRow(par, pos, y);
2074 int tmpheight = row->height;
2075 SetHeightOfRow(row);
2077 LyXParagraph::size_type tmp_pos = pos;
2078 /* update the table information */
2079 while (tmp_pos && !par->IsNewline(tmp_pos - 1))
2081 if (par->table->SetWidthOfCell(NumberOfCell(par, pos),
2082 WidthOfCell(par, tmp_pos))) {
2083 LyXCursor tmpcursor = cursor;
2084 SetCursorIntern(par, pos);
2085 /* make a complete redraw */
2086 RedoDrawingOfParagraph(cursor);
2090 /* redraw only the row */
2091 LyXCursor tmpcursor = cursor;
2092 SetCursorIntern(par, pos);
2094 refresh_x = cursor.x;
2096 refresh_pos = cursor.pos;
2099 if (tmpheight == row->height)
2100 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2102 status = LyXText::NEED_MORE_REFRESH;
2104 SetCursorIntern(cursor.par, cursor.pos);
2108 void LyXText::BackspaceInTable()
2110 Row * tmprow, * row;
2113 LyXFont rawtmpfont = current_font;
2114 LyXFont realtmpfont = real_current_font;
2116 // Get the font that is used to calculate the baselineskip
2117 int const lastpos = cursor.par->Last();
2118 LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2120 if (cursor.pos == 0) {
2121 /* no pasting of table paragraphs */
2126 /* this is the code for a normal backspace, not pasting
2128 SetUndo(Undo::DELETE,
2129 cursor.par->ParFromPos(cursor.pos)->previous,
2130 cursor.par->ParFromPos(cursor.pos)->next);
2134 /* some insets are undeletable here */
2135 if (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
2136 if (!cursor.par->GetInset(cursor.pos)->Deletable())
2141 y = cursor.y - row->baseline;
2143 /* some special code when deleting a newline. */
2144 if (cursor.par->IsNewline(cursor.pos)) {
2149 cursor.par->Erase(cursor.pos);
2151 /* refresh the positions */
2153 while (tmprow->next && tmprow->next->par == row->par) {
2154 tmprow = tmprow->next;
2158 /* delete superfluous blanks */
2159 if (cursor.pos < cursor.par->Last() - 1 &&
2160 (cursor.par->IsLineSeparator(cursor.pos))) {
2162 if (cursor.pos == BeginningOfMainBody(cursor.par)
2164 || cursor.par->IsLineSeparator(cursor.pos - 1)) {
2165 cursor.par->Erase(cursor.pos);
2166 /* refresh the positions */
2168 while (tmprow->next &&
2169 tmprow->next->par == row->par) {
2170 tmprow = tmprow->next;
2173 if (cursor.pos) /* move one character left */
2179 CheckParagraphInTable(cursor.par, cursor.pos);
2181 /* check, wether the last characters font has changed. */
2182 if (cursor.pos && cursor.pos == cursor.par->Last()
2183 && rawparfont != rawtmpfont)
2184 RedoHeightOfParagraph(cursor);
2186 /* restore the current font
2187 * That is what a user expects! */
2188 current_font = rawtmpfont;
2189 real_current_font = realtmpfont;
2191 SetCursorIntern(cursor.par, cursor.pos);
2194 /* table stuff -- end*/
2197 /* just a macro to make some thing easier. */
2198 void LyXText::RedoParagraph()
2200 LyXCursor tmpcursor = cursor;
2202 RedoParagraphs(cursor, cursor.par->Next());;
2203 SetCursorIntern(tmpcursor.par, tmpcursor.pos);
2207 /* insert a character, moves all the following breaks in the
2208 * same Paragraph one to the right and make a rebreak */
2209 void LyXText::InsertChar(char c)
2214 bool jumped_over_space;
2215 LyXFont realtmpfont;
2217 LyXParagraph::size_type z;
2218 LyXParagraph::size_type lastpos;
2221 SetUndo(Undo::INSERT,
2222 cursor.par->ParFromPos(cursor.pos)->previous,
2223 cursor.par->ParFromPos(cursor.pos)->next);
2225 /* When the free-spacing option is set for the current layout,
2226 * all spaces are converted to protected spaces. */
2227 bool freeSpacingBo =
2228 textclasslist.Style(parameters->textclass,
2229 cursor.row->par->GetLayout()).free_spacing;
2231 if (freeSpacingBo && IsLineSeparatorChar(c)
2232 && (!cursor.pos || cursor.par->IsLineSeparator(cursor.pos-1)))
2233 c = LyXParagraph::META_PROTECTED_SEPARATOR;
2235 /* table stuff -- begin*/
2236 if (cursor.par->table) {
2237 InsertCharInTable(c);
2240 /* table stuff -- end*/
2242 /* first check, if there will be two blanks together or a blank at
2243 * the beginning of a paragraph.
2244 * I decided to handle blanks like normal characters, the main
2245 * difference are the special checks when calculating the row.fill
2246 * (blank does not count at the end of a row) and the check here */
2248 // The bug is triggered when we type in a description environment:
2249 // The current_font is not changed when we go from label to main text
2250 // and it should (along with realtmpfont) when we type the space.
2251 #ifdef WITH_WARNINGS
2252 #warning There is a bug here! (Asger)
2255 realtmpfont = real_current_font;
2256 rawtmpfont = current_font; /* store the current font.
2257 * This is because of the use
2258 * of cursor movements. The moving
2259 * cursor would refresh the
2262 // Get the font that is used to calculate the baselineskip
2263 lastpos = cursor.par->Last();
2264 rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2266 jumped_over_space = false;
2268 if (IsLineSeparatorChar(c)) {
2270 if (cursor.pos < lastpos
2271 && cursor.par->IsLineSeparator(cursor.pos)) {
2272 /* the user inserted a space before a space. So we
2273 * will just make a CursorRight. BUT: The font of this
2274 * space should be set to current font. That is why
2275 * we need to rebreak perhaps. If there is a protected
2276 * blank at the end of a row we have to force
2279 minibuffer->Set(_("You cannot type two spaces this way. Please read the Tutorial."));
2280 if (cursor.pos == RowLast(cursor.row)
2281 && !IsLineSeparatorChar(c))
2282 cursor.row->fill = -1; /* force rebreak */
2284 cursor.par->Erase(cursor.pos);
2285 jumped_over_space = true;
2287 } else if ((cursor.pos > 0
2288 && cursor.par->IsLineSeparator(cursor.pos - 1))
2290 && cursor.par->IsNewline(cursor.pos - 1))
2292 && !(cursor.par->Previous()
2293 && cursor.par->Previous()->footnoteflag
2294 == LyXParagraph::OPEN_FOOTNOTE))) {
2295 if (cursor.pos == 0 )
2296 minibuffer->Set(_("You cannot insert a space at the beginning of a paragraph. Please read the Tutorial."));
2298 minibuffer->Set(_("You cannot type two spaces this way. Please read the Tutorial."));
2301 } else if (IsNewlineChar(c)) {
2302 if (cursor.par->FirstPhysicalPar() == cursor.par
2303 && cursor.pos <= BeginningOfMainBody(cursor.par))
2305 /* no newline at first position
2306 * of a paragraph or behind labels.
2307 * TeX does not allow that. */
2309 if (cursor.pos < cursor.par->Last() &&
2310 cursor.par->IsLineSeparator(cursor.pos))
2311 CursorRightIntern(); // newline always after a blank!
2312 cursor.row->fill = -1; // to force a new break
2315 /* the display inset stuff */
2316 if (cursor.row->par->GetChar(cursor.row->pos) == LyXParagraph::META_INSET
2317 && cursor.row->par->GetInset(cursor.row->pos)
2318 && cursor.row->par->GetInset(cursor.row->pos)->Display())
2319 cursor.row->fill = -1; // to force a new break
2321 /* get the cursor row fist */
2322 /* this is a dumb solution, i will try to hold the cursor.row
2324 /* row = GetRow(cursor.par, cursor.pos, y);*/
2325 /* ok, heres a better way: */
2327 y = cursor.y - row->baseline;
2328 if (c != LyXParagraph::META_INSET) /* in this case LyXText::InsertInset
2329 * already insertet the character */
2330 cursor.par->InsertChar(cursor.pos, c);
2331 SetCharFont(cursor.par, cursor.pos, rawtmpfont);
2333 if (!jumped_over_space) {
2334 /* refresh the positions */
2336 while (tmprow->next && tmprow->next->par == row->par) {
2337 tmprow = tmprow->next;
2342 /* Is there a break one row above */
2343 if ((cursor.par->IsLineSeparator(cursor.pos)
2344 || cursor.par->IsNewline(cursor.pos)
2345 || cursor.row->fill == -1)
2346 && row->previous && row->previous->par == row->par) {
2347 z = NextBreakPoint(row->previous, paperwidth);
2348 if ( z >= row->pos) {
2351 /* set the dimensions of the row above */
2352 row->previous->fill = Fill(row->previous, paperwidth);
2354 SetHeightOfRow(row->previous);
2356 y -= row->previous->height;
2358 refresh_row = row->previous;
2359 status = LyXText::NEED_MORE_REFRESH;
2361 BreakAgainOneRow(row);
2362 SetCursor(cursor.par, cursor.pos + 1);
2363 /* cursor MUST be in row now */
2365 if (row->next && row->next->par == row->par)
2366 need_break_row = row->next;
2370 current_font = rawtmpfont;
2371 real_current_font = realtmpfont;
2373 // check, wether the last characters font has changed.
2374 if (cursor.pos && cursor.pos == cursor.par->Last()
2375 && rawparfont != rawtmpfont)
2376 RedoHeightOfParagraph(cursor);
2382 /* recalculate the fill of the row */
2383 if (row->fill >= 0) /* needed because a newline
2384 * will set fill to -1. Otherwise
2385 * we would not get a rebreak! */
2386 row->fill = Fill(row, paperwidth);
2387 if (row->fill < 0 ) {
2390 refresh_x = cursor.x;
2391 refresh_pos = cursor.pos;
2392 status = LyXText::NEED_MORE_REFRESH;
2393 BreakAgainOneRow(row);
2394 /* will the cursor be in another row now? */
2395 if (RowLast(row) <= cursor.pos + 1 && row->next) {
2396 if (row->next && row->next->par == row->par)
2400 BreakAgainOneRow(row);
2402 SetCursor(cursor.par, cursor.pos + 1);
2403 if (row->next && row->next->par == row->par)
2404 need_break_row = row->next;
2408 current_font = rawtmpfont;
2409 real_current_font = realtmpfont;
2412 refresh_x = cursor.x;
2414 refresh_pos = cursor.pos;
2416 int tmpheight = row->height;
2417 SetHeightOfRow(row);
2418 if (tmpheight == row->height)
2419 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2421 status = LyXText::NEED_MORE_REFRESH;
2423 SetCursor(cursor.par, cursor.pos + 1);
2424 current_font = rawtmpfont;
2425 real_current_font = realtmpfont;
2428 /* check, wether the last characters font has changed. */
2429 if (cursor.pos && cursor.pos == cursor.par->Last()
2430 && rawparfont != rawtmpfont) {
2431 RedoHeightOfParagraph(cursor);
2433 /* now the special right address boxes */
2434 if (textclasslist.Style(parameters->textclass,
2435 cursor.par->GetLayout()).margintype
2436 == MARGIN_RIGHT_ADDRESS_BOX) {
2437 RedoDrawingOfParagraph(cursor);
2442 // Here we could call FinishUndo for every 20 characters inserted.
2443 // This is from my experience how emacs does it.
2444 static unsigned short counter = 0;
2455 void LyXText::PrepareToPrint(Row * row, float & x, float & fill_separator,
2456 float & fill_hfill, float & fill_label_hfill)
2460 float w = row->fill;
2462 fill_label_hfill = 0;
2464 fill_label_hfill = 0;
2466 x = LeftMargin(row);
2468 /* is there a manual margin with a manual label */
2469 if (textclasslist.Style(parameters->textclass,
2470 row->par->GetLayout()).margintype == MARGIN_MANUAL
2471 && textclasslist.Style(parameters->textclass,
2472 row->par->GetLayout()).labeltype == LABEL_MANUAL) {
2474 nlh = NumberOfLabelHfills(row) + 1; /* one more since labels
2475 * are left aligned*/
2476 if (nlh && !row->par->GetLabelWidthString().empty()) {
2477 fill_label_hfill = LabelFill(row) / nlh;
2481 /* are there any hfills in the row? */
2482 nh = NumberOfHfills(row);
2484 /* table stuff -- begin*/
2485 if (row->par->table) {
2486 w = paperwidth - row->par->table->WidthOfTable()
2487 - x - RightMargin(row);
2488 nh = 0; /* ignore hfills in tables */
2490 /* table stuff -- end*/
2495 /* is it block, flushleft or flushright?
2496 * set x how you need it */
2498 if (row->par->FirstPhysicalPar()->align == LYX_ALIGN_LAYOUT)
2499 align = textclasslist.Style(parameters->textclass, row->par->GetLayout()).align;
2501 align = row->par->FirstPhysicalPar()->align;
2503 /* center displayed insets */
2504 if (row->par->GetChar(row->pos) == LyXParagraph::META_INSET
2505 && row->par->GetInset(row->pos)
2506 && row->par->GetInset(row->pos)->Display())
2507 align = LYX_ALIGN_CENTER;
2510 case LYX_ALIGN_BLOCK:
2511 ns = NumberOfSeparators(row);
2512 if (ns && row->next && row->next->par == row->par &&
2513 !(row->next->par->IsNewline(row->next->pos-1))
2514 && !(row->next->par->GetChar(row->next->pos) == LyXParagraph::META_INSET
2515 && row->next->par->GetInset(row->next->pos)
2516 && row->next->par->GetInset(row->next->pos)->Display())
2518 fill_separator = w / ns;
2520 case LYX_ALIGN_RIGHT:
2523 case LYX_ALIGN_CENTER:
2531 /* important for the screen */
2534 /* the cursor set functions have a special mechanism. When they
2535 * realize, that you left an empty paragraph, they will delete it.
2536 * They also delete the corresponding row */
2538 void LyXText::CursorRightOneWord()
2540 // treat floats, HFills and Insets as words
2541 LyXCursor tmpcursor = cursor;
2543 if (tmpcursor.pos == tmpcursor.par->Last()
2544 && tmpcursor.par->Next())
2546 tmpcursor.par = tmpcursor.par->Next();
2551 // Skip through initial nonword stuff.
2552 while ( tmpcursor.pos < tmpcursor.par->Last() &&
2553 ! tmpcursor.par->IsWord( tmpcursor.pos ) )
2555 // printf("Current pos1 %d", tmpcursor.pos) ;
2559 // Advance through word.
2560 while ( tmpcursor.pos < tmpcursor.par->Last() &&
2561 tmpcursor.par->IsWord( tmpcursor.pos ) )
2563 // printf("Current pos2 %d", tmpcursor.pos) ;
2568 SetCursor(tmpcursor.par, tmpcursor.pos);
2572 void LyXText::CursorTab()
2574 if (cursor.par->table) {
2575 int cell = NumberOfCell(cursor.par, cursor.pos);
2576 while(cursor.par->table->IsContRow(cell)) {
2578 cell = NumberOfCell(cursor.par, cursor.pos);
2580 if (cursor.par->table->ShouldBeVeryLastCell(cell))
2581 TableFeatures(LyXTable::APPEND_ROW);
2583 LyXCursor tmpcursor = cursor;
2584 while (tmpcursor.pos < tmpcursor.par->Last()
2585 && !tmpcursor.par->IsNewline(tmpcursor.pos))
2588 if (tmpcursor.pos == tmpcursor.par->Last()){
2589 if (tmpcursor.par->Next()) {
2590 tmpcursor.par = tmpcursor.par->Next();
2596 SetCursor(tmpcursor.par, tmpcursor.pos);
2597 if (cursor.par->table) {
2598 int cell = NumberOfCell(cursor.par, cursor.pos);
2599 while (cursor.par->table->IsContRow(cell) &&
2600 !cursor.par->table->ShouldBeVeryLastCell(cell)) {
2602 while (tmpcursor.pos < tmpcursor.par->Last()
2603 && !tmpcursor.par->IsNewline(tmpcursor.pos))
2606 if (tmpcursor.pos == tmpcursor.par->Last()){
2607 if (tmpcursor.par->Next()) {
2608 tmpcursor.par = tmpcursor.par->Next();
2614 SetCursor(tmpcursor.par, tmpcursor.pos);
2615 cell = NumberOfCell(cursor.par, cursor.pos);
2621 /* -------> Skip initial whitespace at end of word and move cursor to *start*
2622 of prior word, not to end of next prior word. */
2624 void LyXText::CursorLeftOneWord()
2626 // treat HFills, floats and Insets as words
2627 LyXCursor tmpcursor = cursor;
2628 while (tmpcursor.pos
2629 && (tmpcursor.par->IsSeparator(tmpcursor.pos - 1)
2630 || tmpcursor.par->IsKomma(tmpcursor.pos - 1))
2631 && !(tmpcursor.par->IsHfill(tmpcursor.pos - 1)
2632 || tmpcursor.par->IsFloat(tmpcursor.pos - 1)
2633 || tmpcursor.par->IsInset(tmpcursor.pos - 1)))
2637 && (tmpcursor.par->IsInset(tmpcursor.pos - 1)
2638 || tmpcursor.par->IsFloat(tmpcursor.pos - 1)
2639 || tmpcursor.par->IsHfill(tmpcursor.pos - 1))) {
2641 } else if (!tmpcursor.pos) {
2642 if (tmpcursor.par->Previous()){
2643 tmpcursor.par = tmpcursor.par->Previous();
2644 tmpcursor.pos = tmpcursor.par->Last();
2646 } else { // Here, tmpcursor != 0
2647 while (tmpcursor.pos > 0 &&
2648 tmpcursor.par->IsWord(tmpcursor.pos-1) )
2651 SetCursor(tmpcursor.par, tmpcursor.pos);
2654 /* -------> Select current word. This depends on behaviour of CursorLeftOneWord(), so it is
2657 void LyXText::SelectWord()
2659 /* Move cursor to the beginning, when not already there. */
2661 && !cursor.par->IsSeparator(cursor.pos-1)
2662 && !cursor.par->IsKomma(cursor.pos-1) )
2663 CursorLeftOneWord();
2665 /* set the sel cursor */
2666 sel_cursor = cursor;
2668 while ( cursor.pos < cursor.par->Last()
2669 && !cursor.par->IsSeparator(cursor.pos)
2670 && !cursor.par->IsKomma(cursor.pos) )
2672 SetCursor( cursor.par, cursor.pos );
2674 /* finally set the selection */
2679 /* -------> Select the word currently under the cursor when:
2680 1: no selection is currently set,
2681 2: the cursor is not at the borders of the word. */
2683 int LyXText::SelectWordWhenUnderCursor()
2685 if ( selection ) return 0;
2686 if ( cursor.pos < cursor.par->Last()
2687 && !cursor.par->IsSeparator(cursor.pos)
2688 && !cursor.par->IsKomma(cursor.pos)
2690 && !cursor.par->IsSeparator(cursor.pos -1)
2691 && !cursor.par->IsKomma(cursor.pos -1) ) {
2699 // This function is only used by the spellchecker for NextWord().
2700 // It doesn't handle LYX_ACCENTs and probably never will.
2701 char * LyXText::SelectNextWord(float & value)
2703 LyXParagraph * tmppar = cursor.par;
2705 // If this is not the very first word, skip rest of
2706 // current word because we are probably in the middle
2707 // of a word if there is text here.
2708 if (cursor.pos || cursor.par->previous) {
2709 while (cursor.pos < cursor.par->Last()
2710 && cursor.par->IsLetter(cursor.pos))
2713 // Now, skip until we have real text (will jump paragraphs)
2714 while ((cursor.par->Last() > cursor.pos
2715 && (!cursor.par->IsLetter(cursor.pos)
2716 || cursor.par->getFont(cursor.pos).latex() == LyXFont::ON))
2717 || (cursor.par->Last() == cursor.pos
2718 && cursor.par->Next())){
2719 if (cursor.pos == cursor.par->Last()) {
2720 cursor.par = cursor.par->Next();
2727 // Update the value if we changed paragraphs
2728 if (cursor.par != tmppar){
2729 SetCursor(cursor.par, cursor.pos);
2730 value = float(cursor.y)/float(height);
2733 /* Start the selection from here */
2734 sel_cursor = cursor;
2738 /* and find the end of the word
2739 (optional hyphens are part of a word) */
2740 while (cursor.pos < cursor.par->Last()
2741 && (cursor.par->IsLetter(cursor.pos))
2742 || (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET &&
2743 cursor.par->GetInset(cursor.pos) != 0 &&
2744 cursor.par->GetInset(cursor.pos)->Latex(latex, 0) == 0 &&
2748 // Finally, we copy the word to a string and return it
2751 if (sel_cursor.pos < cursor.pos) {
2752 str = new char [cursor.pos - sel_cursor.pos + 2];
2753 LyXParagraph::size_type i, j;
2754 for (i = sel_cursor.pos, j = 0; i < cursor.pos; ++i) {
2755 if (cursor.par->GetChar(i) != LyXParagraph::META_INSET)
2756 str[j++] = cursor.par->GetChar(i);
2764 // This one is also only for the spellchecker
2765 void LyXText::SelectSelectedWord()
2767 /* move cursor to the beginning */
2768 SetCursor(sel_cursor.par, sel_cursor.pos);
2770 /* set the sel cursor */
2771 sel_cursor = cursor;
2775 /* now find the end of the word */
2776 while (cursor.pos < cursor.par->Last()
2777 && (cursor.par->IsLetter(cursor.pos)
2778 || (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET &&
2779 cursor.par->GetInset(cursor.pos) != 0 &&
2780 cursor.par->GetInset(cursor.pos)->Latex(latex, 0) == 0 &&
2784 SetCursor(cursor.par, cursor.pos);
2786 /* finally set the selection */
2791 /* -------> Delete from cursor up to the end of the current or next word. */
2792 void LyXText::DeleteWordForward()
2794 LyXCursor tmpcursor = cursor;
2796 if (!cursor.par->Last())
2799 /* -------> Skip initial non-word stuff. */
2800 while ( cursor.pos < cursor.par->Last()
2801 && (cursor.par->IsSeparator(cursor.pos)
2802 || cursor.par->IsKomma(cursor.pos)) )
2805 SetCursorIntern(cursor.par, cursor.pos);
2806 selection = True; // to avoid deletion
2807 CursorRightOneWord();
2808 sel_cursor = cursor;
2812 /* -----> Great, CutSelection() gets rid of multiple spaces. */
2818 /* -------> Delete from cursor to start of current or prior word. */
2819 void LyXText::DeleteWordBackward()
2821 LyXCursor tmpcursor = cursor;
2822 if (!cursor.par->Last())
2825 selection = true; // to avoid deletion
2826 CursorLeftOneWord();
2827 sel_cursor = cursor;
2835 /* -------> Kill to end of line. */
2836 void LyXText::DeleteLineForward()
2838 LyXCursor tmpcursor = cursor;
2839 if (!cursor.par->Last())
2843 sel_cursor = cursor;
2846 if (selection == false) {
2847 DeleteWordForward();
2855 // Change the case of a word at cursor position. The meaning of action
2857 // 0 change to lowercase
2858 // 1 capitalize word
2859 // 2 change to uppercase
2860 // This function directly manipulates LyXParagraph::text because there
2861 // is no LyXParagraph::SetChar currently. I did what I could to ensure
2862 // that it is correct. I guess part of it should be moved to
2863 // LyXParagraph, but it will have to change for 1.1 anyway. At least
2864 // it does not access outside of the allocated array as the older
2865 // version did. (JMarc)
2866 void LyXText::ChangeWordCase(LyXText::TextCase action)
2868 LyXParagraph * tmppar = cursor.par->ParFromPos(cursor.pos);
2870 SetUndo(Undo::FINISH, tmppar->previous, tmppar->next);
2872 LyXParagraph::size_type tmppos =
2873 cursor.par->PositionInParFromPos(cursor.pos);
2874 while (tmppos < tmppar->size()) {
2875 unsigned char c = tmppar->text[tmppos];
2876 if (IsKommaChar(c) || IsLineSeparatorChar(c))
2878 if (c != LyXParagraph::META_INSET) {
2880 case text_lowercase:
2883 case text_capitalization:
2885 action = text_lowercase;
2887 case text_uppercase:
2893 tmppar->text[tmppos] = c;
2896 CheckParagraph(tmppar, tmppos);
2897 CursorRightOneWord();
2901 void LyXText::Delete()
2903 LyXCursor old_cursor = cursor;
2904 /* this is a very easy implementation*/
2906 /* just move to the right */
2907 CursorRightIntern();
2909 if (cursor.par->previous == old_cursor.par->previous
2910 && cursor.par != old_cursor.par)
2911 return; // delete-emty-paragraph-mechanism has done it
2913 /* if you had success make a backspace */
2914 if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) {
2915 LyXCursor tmpcursor = cursor;
2916 cursor = old_cursor; // to make sure undo gets the right cursor position
2917 SetUndo(Undo::DELETE,
2918 cursor.par->ParFromPos(cursor.pos)->previous,
2919 cursor.par->ParFromPos(cursor.pos)->next);
2926 void LyXText::Backspace()
2928 LyXParagraph * tmppar;
2929 Row * tmprow, * row;
2933 /* table stuff -- begin*/
2935 if (cursor.par->table) {
2939 /* table stuff -- end*/
2941 LyXFont rawtmpfont = current_font;
2942 LyXFont realtmpfont = real_current_font;
2944 // Get the font that is used to calculate the baselineskip
2945 int const lastpos = cursor.par->Last();
2946 LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2948 if (cursor.pos == 0) {
2949 /* we may paste some paragraphs */
2951 /* is it an empty paragraph? */
2954 || (lastpos == 1 && cursor.par->IsSeparator(0)))
2955 && !(cursor.par->Next()
2956 && cursor.par->footnoteflag ==
2957 LyXParagraph::NO_FOOTNOTE
2958 && cursor.par->Next()->footnoteflag ==
2959 LyXParagraph::OPEN_FOOTNOTE)) {
2961 if (cursor.par->previous) {
2962 tmppar = cursor.par->previous->FirstPhysicalPar();
2963 if (cursor.par->GetLayout() == tmppar->GetLayout()
2964 && cursor.par->footnoteflag == tmppar->footnoteflag
2965 && cursor.par->GetAlign() == tmppar->GetAlign()) {
2967 tmppar->line_bottom = cursor.par->line_bottom;
2968 tmppar->added_space_bottom = cursor.par->added_space_bottom;
2969 tmppar->pagebreak_bottom = cursor.par->pagebreak_bottom;
2974 /* the layout things can change the height of a row ! */
2975 tmpheight = cursor.row->height;
2976 SetHeightOfRow(cursor.row);
2977 if (cursor.row->height != tmpheight) {
2978 refresh_y = cursor.y - cursor.row->baseline;
2979 refresh_row = cursor.row;
2980 status = LyXText::NEED_MORE_REFRESH;
2985 if (cursor.par->ParFromPos(cursor.pos)->previous){
2986 SetUndo(Undo::DELETE,
2987 cursor.par->ParFromPos(cursor.pos)->previous->previous,
2988 cursor.par->ParFromPos(cursor.pos)->next);
2990 tmppar = cursor.par;
2991 tmprow = cursor.row;
2993 /* Pasting is not allowed, if the paragraphs have different
2994 layout. I think it is a real bug of all other
2995 word processors to allow it. It confuses the user.
2996 Even so with a footnote paragraph and a non-footnote
2997 paragraph. I will not allow pasting in this case,
2998 because the user would be confused if the footnote behaves
2999 different wether it is open or closed.
3001 Correction: Pasting is always allowed with standard-layout
3003 if (cursor.par != tmppar
3004 && (cursor.par->GetLayout() == tmppar->GetLayout()
3005 || !tmppar->GetLayout())
3006 && cursor.par->footnoteflag == tmppar->footnoteflag
3007 /* table stuff -- begin*/
3008 && !cursor.par->table /* no pasting of tables */
3009 /* table stuff -- end*/
3010 && cursor.par->GetAlign() == tmppar->GetAlign()) {
3012 cursor.par->PasteParagraph();
3015 cursor.par->IsSeparator(cursor.pos - 1)))
3016 cursor.par->InsertChar(cursor.pos, ' ');
3021 status = LyXText::NEED_MORE_REFRESH;
3022 refresh_row = cursor.row;
3023 refresh_y = cursor.y - cursor.row->baseline;
3025 /* remove the lost paragraph */
3026 RemoveParagraph(tmprow);
3029 AppendParagraph(cursor.row);
3030 UpdateCounters(cursor.row);
3032 /* the row may have changed, block, hfills etc. */
3033 SetCursor(cursor.par, cursor.pos);
3036 /* this is the code for a normal backspace, not pasting
3038 SetUndo(Undo::DELETE,
3039 cursor.par->ParFromPos(cursor.pos)->previous,
3040 cursor.par->ParFromPos(cursor.pos)->next);
3043 /* some insets are undeletable here */
3044 if (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
3045 if (!cursor.par->GetInset(cursor.pos)->Deletable())
3047 /* force complete redo when erasing display insets */
3048 /* this is a cruel mathod but save..... Matthias */
3049 if (cursor.par->GetInset(cursor.pos)->Display()){
3050 cursor.par->Erase(cursor.pos);
3057 y = cursor.y - row->baseline;
3058 LyXParagraph::size_type z;
3059 /* remember that a space at the end of a row doesnt count
3060 * when calculating the fill */
3061 if (cursor.pos < RowLast(row) ||
3062 !cursor.par->IsLineSeparator(cursor.pos)) {
3063 row->fill += SingleWidth(cursor.par, cursor.pos);
3066 /* some special code when deleting a newline. This is similar
3067 * to the behavior when pasting paragraphs */
3068 if (cursor.pos && cursor.par->IsNewline(cursor.pos)) {
3069 cursor.par->Erase(cursor.pos);
3070 /* refresh the positions */
3072 while (tmprow->next && tmprow->next->par == row->par) {
3073 tmprow = tmprow->next;
3076 if (cursor.par->IsLineSeparator(cursor.pos - 1))
3079 if (cursor.pos < cursor.par->Last() && !cursor.par->IsSeparator(cursor.pos)) {
3080 cursor.par->InsertChar(cursor.pos, ' ');
3081 /* refresh the positions */
3083 while (tmprow->next && tmprow->next->par == row->par) {
3084 tmprow = tmprow->next;
3089 cursor.par->Erase(cursor.pos);
3091 /* refresh the positions */
3093 while (tmprow->next && tmprow->next->par == row->par) {
3094 tmprow = tmprow->next;
3098 /* delete superfluous blanks */
3099 if (cursor.pos < cursor.par->Last() - 1 &&
3100 (cursor.par->IsLineSeparator(cursor.pos))) {
3102 if (cursor.pos == BeginningOfMainBody(cursor.par)
3104 || cursor.par->IsLineSeparator(cursor.pos - 1)) {
3105 cursor.par->Erase(cursor.pos);
3106 /* refresh the positions */
3108 while (tmprow->next &&
3109 tmprow->next->par == row->par) {
3110 tmprow = tmprow->next;
3113 if (cursor.pos) /* move one character left */
3118 /* delete newlines at the beginning of paragraphs */
3119 while (cursor.par->Last() &&
3120 cursor.par->IsNewline(cursor.pos) &&
3121 cursor.pos == BeginningOfMainBody(cursor.par)) {
3122 cursor.par->Erase(cursor.pos);
3123 /* refresh the positions */
3125 while (tmprow->next &&
3126 tmprow->next->par == row->par) {
3127 tmprow = tmprow->next;
3133 /* is there a break one row above */
3134 if (row->previous && row->previous->par == row->par) {
3135 z = NextBreakPoint(row->previous, paperwidth);
3136 if ( z >= row->pos) {
3139 tmprow = row->previous;
3141 /* maybe the current row is now empty */
3142 if (row->pos >= row->par->Last()) {
3148 BreakAgainOneRow(row);
3149 if (row->next && row->next->par == row->par)
3150 need_break_row = row->next;
3155 /* set the dimensions of the row above */
3156 y -= tmprow->height;
3157 tmprow->fill = Fill(tmprow, paperwidth);
3158 SetHeightOfRow(tmprow);
3161 refresh_row = tmprow;
3162 status = LyXText::NEED_MORE_REFRESH;
3163 SetCursor(cursor.par, cursor.pos);
3164 current_font = rawtmpfont;
3165 real_current_font = realtmpfont;
3166 /* check, whether the last character's font has changed. */
3167 rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
3168 if (rawparfont != rawtmpfont)
3169 RedoHeightOfParagraph(cursor);
3174 /* break the cursor row again */
3175 z = NextBreakPoint(row, paperwidth);
3177 if ( z != RowLast(row) ||
3178 (row->next && row->next->par == row->par &&
3179 RowLast(row) == row->par->Last() - 1)){
3181 /* it can happen that a paragraph loses one row
3182 * without a real breakup. This is when a word
3183 * is to long to be broken. Well, I don t care this
3185 if (row->next && row->next->par == row->par &&
3186 RowLast(row) == row->par->Last() - 1)
3187 RemoveRow(row->next);
3191 status = LyXText::NEED_MORE_REFRESH;
3193 BreakAgainOneRow(row);
3195 SetCursor(cursor.par, cursor.pos);
3196 /* cursor MUST be in row now */
3198 if (row->next && row->next->par == row->par)
3199 need_break_row = row->next;
3203 /* set the dimensions of the row */
3204 row->fill = Fill(row, paperwidth);
3205 int tmpheight = row->height;
3206 SetHeightOfRow(row);
3207 if (tmpheight == row->height)
3208 status = LyXText::NEED_VERY_LITTLE_REFRESH;
3210 status = LyXText::NEED_MORE_REFRESH;
3213 SetCursor(cursor.par, cursor.pos);
3217 /* restore the current font
3218 * That is what a user expects! */
3219 current_font = rawtmpfont;
3220 real_current_font = realtmpfont;
3222 /* check, wether the last characters font has changed. */
3223 rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
3224 if (rawparfont != rawtmpfont) {
3225 RedoHeightOfParagraph(cursor);
3227 /* now the special right address boxes */
3228 if (textclasslist.Style(parameters->textclass,
3229 cursor.par->GetLayout()).margintype == MARGIN_RIGHT_ADDRESS_BOX) {
3230 RedoDrawingOfParagraph(cursor);
3236 void LyXText::GetVisibleRow(LyXScreen & scr, int offset,
3237 Row * row_ptr, long y)
3239 /* returns a printed row */
3240 LyXParagraph::size_type pos, pos_end;
3242 int y_top, y_bottom;
3243 float fill_separator, fill_hfill, fill_label_hfill;
3244 LyXParagraph * par, * firstpar;
3248 if (row_ptr->height <= 0) {
3249 lyxerr << "LYX_ERROR: row.height: " << row_ptr->height << endl;
3252 left_margin = LabelEnd(row_ptr);
3253 PrepareToPrint(row_ptr, x, fill_separator,
3254 fill_hfill, fill_label_hfill);
3256 LyXParagraph::size_type main_body =
3257 BeginningOfMainBody(row_ptr->par);
3258 /* initialize the pixmap */
3260 scr.fillRectangle(gc_clear,
3261 0, offset, paperwidth, row_ptr->height);
3262 // check for NOT FAST SELECTION
3263 if (!fast_selection && !mono_video && selection) {
3264 /* selection code */
3265 if (sel_start_cursor.row == row_ptr &&
3266 sel_end_cursor.row == row_ptr) {
3267 scr.fillRectangle(gc_selection, sel_start_cursor.x,
3273 else if (sel_start_cursor.row == row_ptr) {
3274 scr.fillRectangle(gc_selection, sel_start_cursor.x,
3276 paperwidth - sel_start_cursor.x,
3278 } else if (sel_end_cursor.row == row_ptr) {
3279 scr.fillRectangle(gc_selection, 0, offset,
3280 sel_end_cursor.x, row_ptr->height);
3281 } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
3282 scr.fillRectangle(gc_selection, 0, offset,
3283 paperwidth, row_ptr->height);
3286 } // end of NOT FAST SELECTION code
3288 if (row_ptr->par->appendix){
3289 scr.drawVerticalLine(gc_math, 1, offset, offset+row_ptr->height);
3290 scr.drawVerticalLine(gc_math, paperwidth-2 , offset, offset+row_ptr->height);
3293 if (row_ptr->par->pextra_type == LyXParagraph::PEXTRA_MINIPAGE) {
3294 /* draw a marker at the left margin! */
3295 LyXFont font = GetFont(row_ptr->par, 0);
3296 int asc = font.maxAscent();
3297 int x = (LYX_PAPER_MARGIN - font.width('|')) / 2;
3298 int y1 = (offset + row_ptr->baseline);
3299 int y2 = (offset + row_ptr->baseline) - asc;
3301 scr.drawVerticalLine(gc_minipage, x, y1, y2);
3303 if (row_ptr->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3304 LyXFont font(LyXFont::ALL_SANE);
3305 font.setSize(LyXFont::SIZE_FOOTNOTE);
3306 font.setColor(LyXFont::RED);
3308 int box_x = LYX_PAPER_MARGIN;
3309 box_x += font.textWidth(" wide-tab ", 10);
3310 if (row_ptr->previous &&
3311 row_ptr->previous->par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
3313 switch (row_ptr->par->footnotekind) {
3314 case LyXParagraph::MARGIN:
3317 case LyXParagraph::FIG:
3320 case LyXParagraph::TAB:
3323 case LyXParagraph::WIDE_FIG:
3326 case LyXParagraph::WIDE_TAB:
3329 case LyXParagraph::ALGORITHM:
3332 case LyXParagraph::FOOTNOTE:
3337 // Determine background color.
3338 gc_type back = gc_lighted;
3342 scr.fillRectangle(back, LYX_PAPER_MARGIN, offset+1,
3343 box_x - LYX_PAPER_MARGIN,
3344 int(font.maxAscent())+
3345 int(font.maxDescent()));
3347 scr.drawLine(gc_foot,
3350 paperwidth - 2*LYX_PAPER_MARGIN);
3352 scr.drawString(font, fs,
3353 offset + int(font.maxAscent())+1,
3355 scr.drawVerticalLine(gc_foot,
3359 + int(font.maxAscent())+
3360 int(font.maxDescent()));
3362 scr.drawLine(gc_foot,
3364 + int(font.maxAscent())
3365 + int(font.maxDescent()) + 1,
3366 LYX_PAPER_MARGIN, box_x - LYX_PAPER_MARGIN);
3369 /* draw the open floats in a red box */
3370 scr.drawVerticalLine(gc_foot,
3372 offset, offset + row_ptr->height);
3374 scr.drawVerticalLine(gc_foot,
3375 paperwidth - LYX_PAPER_MARGIN,
3377 offset + row_ptr->height);
3381 if (row_ptr->previous &&
3382 row_ptr->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3383 LyXFont font(LyXFont::ALL_SANE);
3384 font.setSize(LyXFont::SIZE_FOOTNOTE);
3386 int box_x = LYX_PAPER_MARGIN;
3387 box_x += font.textWidth(" wide-tab ", 10);
3389 scr.drawLine(gc_foot,
3392 paperwidth - LYX_PAPER_MARGIN - box_x);
3396 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
3397 row_ptr->par->GetLayout());
3398 firstpar = row_ptr->par->FirstPhysicalPar();
3401 y_bottom = row_ptr->height;
3403 /* is it a first row? */
3404 if (row_ptr->pos == 0
3405 && row_ptr->par == firstpar) {
3407 /* start of appendix? */
3408 if (row_ptr->par->start_of_appendix){
3409 scr.drawLine(gc_math,
3414 /* think about the margins */
3415 if (!row_ptr->previous)
3416 y_top += LYX_PAPER_MARGIN;
3418 if (row_ptr->par->pagebreak_top){ /* draw a top pagebreak */
3419 scr.drawOnOffLine(offset + y_top + 2 * DefaultHeight(),
3421 y_top += 3 * DefaultHeight();
3424 if (row_ptr->par->added_space_top.kind() == VSpace::VFILL) {
3425 /* draw a vfill top */
3426 scr.drawLine(gc_fill,
3428 0, LYX_PAPER_MARGIN);
3429 scr.drawLine(gc_fill,
3430 offset + y_top + 3 * DefaultHeight(),
3431 0, LYX_PAPER_MARGIN);
3432 scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2,
3434 offset + y_top + 3 *
3437 y_top += 3 * DefaultHeight();
3440 /* think about user added space */
3441 y_top += int(row_ptr->par->added_space_top.inPixels());
3443 /* think about the parskip */
3444 /* some parskips VERY EASY IMPLEMENTATION */
3445 if (parameters->paragraph_separation == BufferParams::PARSEP_SKIP) {
3446 if (layout.latextype == LATEX_PARAGRAPH
3447 && firstpar->GetDepth() == 0
3448 && firstpar->Previous())
3449 y_top += parameters->getDefSkip().inPixels();
3450 else if (firstpar->Previous()
3451 && textclasslist.Style(parameters->textclass,
3452 firstpar->Previous()->GetLayout()).latextype == LATEX_PARAGRAPH
3453 && firstpar->Previous()->GetDepth() == 0)
3454 // is it right to use defskip here, too? (AS)
3455 y_top += parameters->getDefSkip().inPixels();
3458 if (row_ptr->par->line_top) { /* draw a top line */
3459 y_top += GetFont(row_ptr->par, 0).ascent('x');
3461 scr.drawThickLine(offset + y_top,
3463 y_top += GetFont(row_ptr->par, 0).ascent('x');
3466 /* should we print a label? */
3467 if (layout.labeltype >= LABEL_STATIC
3468 && (layout.labeltype != LABEL_STATIC
3469 || layout.latextype != LATEX_ENVIRONMENT
3470 || row_ptr->par->IsFirstInSequence())) {
3471 font = GetFont(row_ptr->par, -2);
3472 if (!row_ptr->par->GetLabestring().empty()) {
3474 string tmpstring = row_ptr->par->GetLabestring();
3476 if (layout.labeltype == LABEL_COUNTER_CHAPTER) {
3477 if (parameters->secnumdepth >= 0){
3478 /* this is special code for the chapter layout. This is printed in
3479 * an extra row and has a pagebreak at the top. */
3480 maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue())
3481 + int(layout.parsep) * DefaultHeight();
3482 scr.drawString(font, tmpstring,
3483 offset + row_ptr->baseline
3484 - row_ptr->ascent_of_text - maxdesc,
3488 x -= font.stringWidth( layout.labelsep);
3489 x -= font.stringWidth( tmpstring);
3491 scr.drawString(font, tmpstring,
3492 offset + row_ptr->baseline, int(x));
3496 /* the labels at the top of an environment. More or less for bibliography */
3497 } else if (layout.labeltype == LABEL_TOP_ENVIRONMENT ||
3498 layout.labeltype == LABEL_BIBLIO ||
3499 layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) {
3500 if (row_ptr->par->IsFirstInSequence()) {
3501 font = GetFont(row_ptr->par, -2);
3502 if (!row_ptr->par->GetLabestring().empty()) {
3503 string tmpstring = row_ptr->par->GetLabestring();
3505 maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue()
3506 + (layout.labelbottomsep * DefaultHeight()));
3508 int top_label_x = int(x);
3509 if (layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT){
3510 top_label_x = int(x + (paperwidth - RightMargin(row_ptr) - x) / 2);
3511 top_label_x -= (font.stringWidth( tmpstring)/2);
3514 scr.drawString(font, tmpstring,
3515 offset + row_ptr->baseline
3516 - row_ptr->ascent_of_text - maxdesc,
3521 if (layout.labeltype == LABEL_BIBLIO) { // ale970302
3522 if (row_ptr->par->bibkey) {
3524 x -= font.stringWidth(layout.labelsep);
3525 font = GetFont(row_ptr->par, -1);
3526 x -= row_ptr->par->bibkey->Width(font);
3527 row_ptr->par->bibkey->Draw(font, scr,
3528 offset + row_ptr->baseline,
3535 /* is it a last row? */
3536 par = row_ptr->par->LastPhysicalPar();
3537 if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
3538 && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {
3540 /* think about the margins */
3542 y_bottom -= LYX_PAPER_MARGIN;
3544 /* draw a bottom pagebreak */
3545 if (firstpar->pagebreak_bottom) {
3546 scr.drawOnOffLine(offset + y_bottom - 2 *
3549 y_bottom -= 3 * DefaultHeight();
3552 if (firstpar->added_space_bottom.kind() == VSpace::VFILL) {
3553 /* draw a vfill bottom */
3554 scr.drawLine(gc_fill,
3555 offset + y_bottom - 3 * DefaultHeight(),
3556 0, LYX_PAPER_MARGIN);
3557 scr.drawLine(gc_fill, offset + y_bottom - 2,
3558 0, LYX_PAPER_MARGIN);
3559 scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2,
3560 offset + y_bottom - 3 * DefaultHeight(),
3561 offset + y_bottom - 2
3563 y_bottom -= 3* DefaultHeight();
3566 /* think about user added space */
3567 y_bottom -= int(firstpar->added_space_bottom.inPixels());
3569 if (firstpar->line_bottom) {
3570 /* draw a bottom line */
3571 y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
3573 scr.drawThickLine(offset + y_bottom,
3575 y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
3579 /* draw the text in the pixmap */
3580 pos_end = RowLast(row_ptr);
3583 /* table stuff -- begin*/
3584 if (row_ptr->par->table) {
3586 int cell = NumberOfCell(row_ptr->par, row_ptr->pos);
3588 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
3590 while (pos <= pos_end) {
3591 if (row_ptr->par->IsNewline(pos)) {
3593 x = x_old + row_ptr->par->table->WidthOfColumn(cell);
3594 /* draw the table lines, still very simple */
3595 on_off = !row_ptr->par->table->TopLine(cell);
3597 !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
3598 !row_ptr->par->table->IsContRow(cell))
3599 scr.drawTableLine(offset + row_ptr->baseline -
3600 row_ptr->ascent_of_text,
3601 int(x_old), int(x - x_old), on_off);
3602 on_off = !row_ptr->par->table->BottomLine(cell);
3603 if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
3604 row_ptr->par->table->VeryLastRow(cell))
3605 scr.drawTableLine(offset + y_bottom - 1,
3606 int(x_old), int(x - x_old), on_off);
3607 on_off = !row_ptr->par->table->LeftLine(cell);
3609 scr.drawVerticalTableLine(int(x_old),
3610 offset + row_ptr->baseline -
3611 row_ptr->ascent_of_text,
3612 offset + y_bottom - 1,
3614 on_off = !row_ptr->par->table->RightLine(cell);
3616 scr.drawVerticalTableLine(int(x) -
3617 row_ptr->par->table->AdditionalWidth(cell),
3618 offset + row_ptr->baseline -
3619 row_ptr->ascent_of_text,
3620 offset + y_bottom - 1,
3623 /* take care about the alignment and other spaces */
3625 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
3626 if (row_ptr->par->table->IsFirstCell(cell))
3627 cell--; // little hack, sorry
3629 } else if (row_ptr->par->IsHfill(pos)) {
3632 scr.drawVerticalLine(gc_fill, int(x),
3633 offset + row_ptr->baseline - DefaultHeight()/2,
3634 offset + row_ptr->baseline);
3638 if (row_ptr->par->IsSeparator(pos)) {
3640 x+= SingleWidth(row_ptr->par, pos);
3641 /* -------> Only draw protected spaces when not in
3642 * free-spacing mode. */
3643 if (row_ptr->par->GetChar(pos) == LyXParagraph::META_PROTECTED_SEPARATOR && !layout.free_spacing) {
3644 scr.drawVerticalLine(gc_fill, int(tmpx),
3645 offset + row_ptr->baseline - 3,
3646 offset + row_ptr->baseline - 1);
3647 scr.drawLine(gc_fill,
3648 offset + row_ptr->baseline - 1,
3651 scr.drawVerticalLine(gc_fill, int(x-2),
3652 offset + row_ptr->baseline - 3,
3653 offset + row_ptr->baseline - 1);
3654 /* what about underbars? */
3655 font = GetFont(row_ptr->par, pos);
3656 if (font.underbar() == LyXFont::ON
3657 && font.latex() != LyXFont::ON) {
3658 scr.drawLine(gc_copy,
3660 row_ptr->baseline + 2,
3667 Draw(row_ptr, pos, scr, offset, x);
3671 /* do not forget the very last cell. This has no NEWLINE so
3672 * ignored by the code above*/
3673 if (cell == row_ptr->par->table->GetNumberOfCells()-1){
3674 x = x_old + row_ptr->par->table->WidthOfColumn(cell);
3675 on_off = !row_ptr->par->table->TopLine(cell);
3677 !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
3678 !row_ptr->par->table->IsContRow(cell))
3680 scr.drawTableLine(offset + row_ptr->baseline -
3681 row_ptr->ascent_of_text,
3682 int(x_old), int(x - x_old), on_off);
3683 on_off = !row_ptr->par->table->BottomLine(cell);
3684 if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
3685 row_ptr->par->table->VeryLastRow(cell))
3687 scr.drawTableLine(offset + y_bottom - 1,
3688 int(x_old), int(x - x_old), on_off);
3689 on_off = !row_ptr->par->table->LeftLine(cell);
3691 scr.drawVerticalTableLine(int(x_old),
3692 offset + row_ptr->baseline -
3693 row_ptr->ascent_of_text,
3694 offset + y_bottom - 1,
3696 on_off = !row_ptr->par->table->RightLine(cell);
3698 scr.drawVerticalTableLine(int(x) -
3699 row_ptr->par->table->AdditionalWidth(cell),
3700 offset + row_ptr->baseline -
3701 row_ptr->ascent_of_text,
3702 offset + y_bottom - 1,
3706 /* table stuff -- end*/
3708 while (pos <= pos_end) {
3710 if (row_ptr->par->IsHfill(pos)) {
3712 scr.drawVerticalLine(gc_fill, int(x),
3713 offset + row_ptr->baseline - DefaultHeight()/2,
3714 offset + row_ptr->baseline);
3715 if (HfillExpansion(row_ptr, pos)) {
3716 if (pos >= main_body) {
3717 scr.drawOnOffLine(offset + row_ptr->baseline -
3723 scr.drawOnOffLine(offset + row_ptr->baseline -
3726 int(fill_label_hfill));
3727 x += fill_label_hfill;
3729 scr.drawVerticalLine(gc_fill, int(x),
3730 offset + row_ptr->baseline -
3732 offset + row_ptr->baseline);
3737 if (row_ptr->par->IsSeparator(pos)) {
3739 x+= SingleWidth(row_ptr->par, pos);
3740 if (pos >= main_body)
3742 /* -------> Only draw protected spaces when not in
3743 * free-spacing mode. */
3744 if (row_ptr->par->GetChar(pos) == LyXParagraph::META_PROTECTED_SEPARATOR && !layout.free_spacing) {
3746 scr.drawVerticalLine(gc_fill, int(tmpx),
3747 offset + row_ptr->baseline - 3,
3748 offset + row_ptr->baseline - 1);
3749 scr.drawLine(gc_fill,
3750 offset + row_ptr->baseline - 1,
3753 scr.drawVerticalLine(gc_fill, int(x-2),
3754 offset + row_ptr->baseline - 3,
3755 offset + row_ptr->baseline - 1);
3756 /* what about underbars? */
3757 font = GetFont(row_ptr->par, pos);
3758 if (font.underbar() == LyXFont::ON
3759 && font.latex() != LyXFont::ON) {
3760 scr.drawLine(gc_copy,
3761 offset + row_ptr->baseline + 2,
3768 Draw(row_ptr, pos, scr, offset, x);
3770 if (pos == main_body) {
3771 x += GetFont(row_ptr->par, -2).stringWidth(
3773 if (row_ptr->par->IsLineSeparator(pos - 1))
3774 x-= SingleWidth(row_ptr->par, pos - 1);
3775 if (x < left_margin)
3780 // check for FAST SELECTION
3781 if (fast_selection || mono_video){
3784 /* selection code */
3785 if (sel_start_cursor.row == row_ptr && sel_end_cursor.row == row_ptr) {
3786 scr.fillRectangle(gc_select, sel_start_cursor.x, offset,
3787 sel_end_cursor.x - sel_start_cursor.x,
3789 } else if (sel_start_cursor.row == row_ptr) {
3790 scr.fillRectangle(gc_select, sel_start_cursor.x, offset,
3791 paperwidth - sel_start_cursor.x,
3793 } else if (sel_end_cursor.row == row_ptr) {
3794 scr.fillRectangle(gc_select, 0, offset,
3797 } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
3798 scr.fillRectangle(gc_select, 0, offset,
3799 paperwidth, row_ptr->height);
3804 // end of FAST SELECTION code
3809 int LyXText::DefaultHeight()
3811 LyXFont font(LyXFont::ALL_SANE);
3812 return int(font.maxAscent() + font.maxDescent() * 1.5);
3816 /* returns the column near the specified x-coordinate of the row
3817 * x is set to the real beginning of this column */
3818 int LyXText::GetColumnNearX(Row * row, int& x)
3821 float fill_separator, fill_hfill, fill_label_hfill;
3823 int left_margin = LabelEnd(row);
3824 PrepareToPrint(row, tmpx, fill_separator,
3825 fill_hfill, fill_label_hfill);
3826 int main_body = BeginningOfMainBody(row->par);
3830 int last = RowLast(row);
3831 if (row->par->IsNewline(last))
3834 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
3835 row->par->GetLayout());
3836 /* table stuff -- begin */
3837 if (row->par->table) {
3838 if (!row->next || row->next->par != row->par)
3839 last = RowLast(row); /* the last row doesn't need a newline at the end*/
3840 int cell = NumberOfCell(row->par, row->pos);
3843 tmpx += row->par->table->GetBeginningOfTextInCell(cell);
3845 && tmpx + (SingleWidth(row->par, c)/2) <= x
3847 if (row->par->IsNewline(c)) {
3848 if (x_old + row->par->table->WidthOfColumn(cell) <= x){
3849 tmpx = x_old + row->par->table->WidthOfColumn(cell);
3852 tmpx += row->par->table->GetBeginningOfTextInCell(cell);
3857 tmpx += SingleWidth(row->par, c);
3862 /* table stuff -- end*/
3865 && tmpx + (SingleWidth(row->par, c)/2) <= x) {
3867 if (c && c == main_body
3868 && !row->par->IsLineSeparator(c - 1)) {
3869 tmpx += GetFont(row->par, -2)
3870 .stringWidth(layout.labelsep);
3871 if (tmpx < left_margin)
3875 tmpx += SingleWidth(row->par, c);
3876 if (HfillExpansion(row, c)) {
3880 tmpx += fill_label_hfill;
3882 else if (c >= main_body
3883 && row->par->IsSeparator(c)) {
3884 tmpx+= fill_separator;
3888 && row->par->IsLineSeparator(c - 1)) {
3889 tmpx += GetFont(row->par, -2)
3890 .stringWidth(layout.labelsep);
3891 tmpx-= SingleWidth(row->par, c - 1);
3892 if (tmpx < left_margin)
3896 /* make sure that a last space in a row doesnt count */
3897 if (c > 0 && c >= last
3898 && row->par->IsLineSeparator(c - 1)
3899 && !(!row->next || row->next->par != row->par)) {
3900 tmpx -= SingleWidth(row->par, c - 1);
3901 tmpx -= fill_separator;
3910 /* turn the selection into a new environment. If there is no selection,
3911 * create an empty environment */
3912 void LyXText::InsertFootnoteEnvironment(LyXParagraph::footnote_kind kind)
3914 /* no footnoteenvironment in a footnoteenvironment */
3915 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3916 WriteAlert(_("Impossible operation"),
3917 _("You can't insert a float in a float!"),
3921 /* no marginpars in minipages */
3922 if (kind == LyXParagraph::MARGIN
3923 && cursor.par->pextra_type == LyXParagraph::PEXTRA_MINIPAGE) {
3924 WriteAlert(_("Impossible operation"),
3925 _("You can't insert a marginpar in a minipage!"),
3930 /* this doesnt make sense, if there is no selection */
3931 bool dummy_selection = false;
3933 sel_start_cursor = cursor; /* dummy selection */
3934 sel_end_cursor = cursor;
3935 dummy_selection = true;
3938 LyXParagraph *tmppar;
3940 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
3941 WriteAlert(_("Impossible operation"), _("Cannot cut table."), _("Sorry."));
3945 /* a test to make sure there is not already a footnote
3946 * in the selection. */
3948 tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
3950 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos) &&
3951 tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
3952 tmppar = tmppar->next;
3954 if (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
3955 || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3956 WriteAlert(_("Impossible operation"),
3957 _("Float would include float!"),
3962 /* ok we have a selection. This is always between sel_start_cursor
3963 * and sel_end cursor */
3965 SetUndo(Undo::FINISH,
3966 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
3967 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
3969 if (sel_end_cursor.pos > 0
3970 && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1))
3971 sel_end_cursor.pos--; /* please break before a space at
3973 if (sel_start_cursor.par == sel_end_cursor.par
3974 && sel_start_cursor.pos > sel_end_cursor.pos)
3975 sel_start_cursor.pos--;
3977 sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
3979 sel_end_cursor.par = sel_end_cursor.par->Next();
3980 sel_end_cursor.pos = 0;
3982 // don't forget to insert a dummy layout paragraph if necessary
3983 if (sel_start_cursor.par->GetLayout() != sel_end_cursor.par->layout){
3984 sel_end_cursor.par->BreakParagraphConservative(0);
3985 sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
3986 sel_end_cursor.par = sel_end_cursor.par->next;
3989 sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
3991 cursor = sel_end_cursor;
3993 /* please break behind a space, if there is one. The space should
3995 if (sel_start_cursor.pos > 0
3996 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1))
3997 sel_start_cursor.pos--;
3998 if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)) {
3999 sel_start_cursor.par->Erase(sel_start_cursor.pos);
4002 sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
4003 tmppar = sel_start_cursor.par->Next();
4005 if (dummy_selection) {
4007 if (kind == LyXParagraph::TAB
4008 || kind == LyXParagraph::FIG
4009 || kind == LyXParagraph::WIDE_TAB
4010 || kind == LyXParagraph::WIDE_FIG
4011 || kind == LyXParagraph::ALGORITHM) {
4012 int lay = textclasslist.NumberOfLayout(parameters->textclass,
4014 if (lay == -1) // layout not found
4015 // use default layout "Standard" (0)
4017 tmppar->SetLayout(lay);
4021 if (sel_start_cursor.pos > 0) {
4022 /* the footnote-environment should begin with a standard layout.
4023 * Imagine you insert a footnote within an enumeration, you
4024 * certainly do not want an enumerated footnote! */
4028 /* this is a exception the user would sometimes expect, I hope */
4029 sel_start_cursor.par->Clear();
4033 while (tmppar != sel_end_cursor.par) {
4034 tmppar->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
4035 tmppar->footnotekind = kind;
4036 tmppar = tmppar->Next();
4039 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
4041 SetCursor(sel_start_cursor.par->Next(), 0);
4047 /* returns pointer to a specified row */
4048 Row * LyXText::GetRow(LyXParagraph * par, LyXParagraph::size_type pos, long &y)
4053 if (par == currentrow->par || par == currentrow->par->Previous()){
4054 // do not dereference par, it may have been deleted
4055 // already! (Matthias)
4056 while (currentrow->previous && currentrow->previous->par != par){
4057 currentrow = currentrow->previous;
4058 currentrow_y -= currentrow->height;
4060 while (currentrow->previous && currentrow->previous->par == par){
4061 currentrow = currentrow->previous;
4062 currentrow_y -= currentrow->height;
4065 tmprow = currentrow;
4067 /* find the first row of the specified paragraph */
4068 while (tmprow->next && (tmprow->par != par)) {
4069 y += tmprow->height;
4070 tmprow = tmprow->next;
4073 if (tmprow->par == par){
4074 /* now find the wanted row */
4075 while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par &&
4076 tmprow->next->pos <= pos) {
4077 y += tmprow->height;
4078 tmprow = tmprow->next;
4080 currentrow = tmprow;
4087 /* find the first row of the specified paragraph */
4088 while (tmprow->next && (tmprow->par != par)) {
4089 y += tmprow->height;
4090 tmprow = tmprow->next;
4093 /* now find the wanted row */
4094 while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par &&
4095 tmprow->next->pos <= pos) {
4096 y += tmprow->height;
4097 tmprow = tmprow->next;
4100 currentrow = tmprow;