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)
229 // Ok. I am the first to admit that the use of std::string will be
230 // a tiny bit slower than using a POD char array. However, I claim
231 // that this slowdown is so small that it is close to inperceptive.
232 // So IMHO we should go with the easier and clearer implementation.
233 // And even if 1024 is a large number here it might overflow, string
234 // will only overflow if the machine is out of memory...
235 static string textstring;
239 LyXParagraph::size_type last = RowLast(row);
242 && static_cast<char>(c = row->par->GetChar(pos)) > ' '
243 && font2 == GetFont(row->par, pos)) {
249 // If monochrome and LaTeX mode, provide reverse background
250 if (mono_video && font.latex() == LyXFont::ON) {
251 int a = font.maxAscent(), d = font.maxDescent();
252 scr.fillRectangle(gc_copy, int(tmpx), offset + row->baseline-a,
253 font.textWidth(textstring.c_str(),
254 textstring.length()), a+d);
256 // Draw text and set the new x position
257 x += scr.drawText(font, textstring.c_str(), textstring.length(),
258 offset + row->baseline,
261 // what about underbars?
262 if (font.underbar() == LyXFont::ON && font.latex() != LyXFont::ON) {
263 scr.drawLine(gc_copy, offset + row->baseline + 2,
264 int(tmpx), int(x - tmpx));
267 // If we want ulem.sty support, drawing
268 // routines should go here. (Asger)
269 // Why shouldn't LyXFont::drawText handle it internally?
273 /* Returns the left beginning of the text.
274 * This information cannot be taken from the layouts-objekt, because in
275 * LaTeX the beginning of the text fits in some cases (for example sections)
276 * exactly the label-width. */
277 int LyXText::LeftMargin(Row * row)
280 LyXParagraph * newpar;
282 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
283 row->par->GetLayout());
285 string parindent = layout.parindent;
287 /* table stuff -- begin*/
290 /* table stuff -- end*/
292 int x = LYX_PAPER_MARGIN;
294 x += textclasslist.TextClass(parameters->textclass).
295 defaultfont().signedStringWidth(textclasslist.TextClass(parameters->textclass).leftmargin());
297 if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
298 LyXFont font(LyXFont::ALL_SANE);
299 font.setSize(LyXFont::SIZE_SMALL);
300 x += font.textWidth("Mwide-figM", 10) + LYX_PAPER_MARGIN/2;
303 /* this is the way, LyX handles the LaTeX-Environments.
304 * I have had this idea very late, so it seems to be a
305 * later added hack and this is true */
306 if (!row->par->GetDepth()) {
307 if (!row->par->GetLayout()) {
308 /* find the previous same level paragraph */
309 if (row->par->FirstPhysicalPar()->Previous()) {
310 newpar = row->par->DepthHook(row->par->GetDepth());
311 if (newpar && textclasslist.Style(parameters->textclass,
312 newpar->GetLayout()).nextnoindent)
318 /* find the next level paragraph */
320 newpar = row->par->DepthHook(row->par->GetDepth()-1);
322 /* make a corresponding row. Needed to call LeftMargin() */
324 /* check wether it is a sufficent paragraph */
325 if (newpar && newpar->footnoteflag == row->par->footnoteflag
326 && textclasslist.Style(parameters->textclass,
327 newpar->GetLayout()).isEnvironment()) {
328 dummyrow.par = newpar;
329 dummyrow.pos = newpar->Last();
330 x = LeftMargin(&dummyrow);
333 /* this is no longer an error, because this function is used
334 * to clear impossible depths after changing a layout. Since there
335 * is always a redo, LeftMargin() is always called */
337 /* printf("LYX_ERROR (text, LeftMargin()) impossible depth \n");*/
338 row->par->FirstPhysicalPar()->depth = 0;
341 if (newpar && !row->par->GetLayout()) {
342 if (newpar->FirstPhysicalPar()->noindent)
345 parindent = textclasslist.Style(parameters->textclass,
346 newpar->GetLayout()).parindent;
351 labelfont = GetFont(row->par, -2);
352 switch (layout.margintype) {
354 if (!layout.leftmargin.empty()) {
355 x += textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.leftmargin);
357 if (!row->par->GetLabestring().empty()) {
358 x += labelfont.signedStringWidth(layout.labelindent);
359 x += labelfont.stringWidth(row->par->GetLabestring());
360 x += labelfont.stringWidth(layout.labelsep);
364 x += labelfont.signedStringWidth(layout.labelindent);
365 if (row->pos >= BeginningOfMainBody(row->par)) {
366 if (!row->par->GetLabelWidthString().empty()) {
367 x += labelfont.stringWidth(row->par->GetLabelWidthString());
368 x += labelfont.stringWidth(layout.labelsep);
373 x += ( textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.leftmargin) * 4
374 / (row->par->GetDepth() + 4));
376 case MARGIN_FIRST_DYNAMIC:
377 if (layout.labeltype == LABEL_MANUAL) {
378 if (row->pos >= BeginningOfMainBody(row->par)) {
379 x += labelfont.signedStringWidth(layout.leftmargin);
381 x += labelfont.signedStringWidth(layout.labelindent);
385 // Special case to fix problems with theorems (JMarc)
386 || (layout.labeltype == LABEL_STATIC
387 && layout.latextype == LATEX_ENVIRONMENT
388 && ! row->par->IsFirstInSequence())) {
389 x += labelfont.signedStringWidth(layout.leftmargin);
390 } else if (layout.labeltype != LABEL_TOP_ENVIRONMENT
391 && layout.labeltype != LABEL_BIBLIO
392 && layout.labeltype != LABEL_CENTERED_TOP_ENVIRONMENT) {
393 x += labelfont.signedStringWidth(layout.labelindent);
394 x += labelfont.stringWidth(layout.labelsep);
395 x += labelfont.stringWidth(row->par->GetLabestring());
400 case MARGIN_RIGHT_ADDRESS_BOX:
402 /* ok, a terrible hack. The left margin depends on the widest row
403 * in this paragraph. Do not care about footnotes, they are *NOT*
404 * allowed in the LaTeX realisation of this layout. */
406 /* find the first row of this paragraph */
408 while (tmprow->previous && tmprow->previous->par == row->par)
409 tmprow = tmprow->previous;
411 int minfill = tmprow->fill;
412 while (tmprow-> next && tmprow->next->par == row->par) {
413 tmprow = tmprow->next;
414 if (tmprow->fill < minfill)
415 minfill = tmprow->fill;
418 x += textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.leftmargin);
423 if (row->par->pextra_type == LyXParagraph::PEXTRA_INDENT) {
424 if (!row->par->pextra_widthp.empty()) {
425 x += paperwidth * atoi(row->par->pextra_widthp.c_str()) / 100;
426 } else if (!row->par->pextra_width.empty()) {
427 int xx = VSpace(row->par->pextra_width).inPixels();
430 xx = paperwidth * 80 / 100;
432 } else { // should not happen
433 LyXFont font(LyXFont::ALL_SANE);
434 x += font.stringWidth("XXXXXX");
439 if (row->par->FirstPhysicalPar()->align == LYX_ALIGN_LAYOUT)
440 align = layout.align;
442 align = row->par->FirstPhysicalPar()->align;
444 /* set the correct parindent */
446 if ((layout.labeltype == LABEL_NO_LABEL
447 || layout.labeltype == LABEL_TOP_ENVIRONMENT
448 || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT
449 || (layout.labeltype == LABEL_STATIC
450 && layout.latextype == LATEX_ENVIRONMENT
451 && ! row->par->IsFirstInSequence()))
452 && row->par == row->par->FirstPhysicalPar()
453 && align == LYX_ALIGN_BLOCK
454 && !row->par->noindent
455 && (row->par->layout ||
456 parameters->paragraph_separation == BufferParams::PARSEP_INDENT))
457 x += textclasslist.TextClass(parameters->textclass).defaultfont().stringWidth(parindent);
459 if (layout.labeltype == LABEL_BIBLIO) { // ale970405 Right width for bibitems
460 x += bibitemMaxWidth(textclasslist.TextClass(parameters->textclass).defaultfont());
468 int LyXText::RightMargin(Row *row)
470 LyXParagraph * newpar;
472 LyXLayout const & layout = textclasslist.Style(parameters->textclass, row->par->GetLayout());
474 int x = LYX_PAPER_MARGIN;
476 x += textclasslist.TextClass(parameters->textclass).
477 defaultfont().signedStringWidth(textclasslist.TextClass(parameters->textclass).rightmargin());
478 if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
479 x += LYX_PAPER_MARGIN/2;
482 /* this is the way, LyX handles the LaTeX-Environments.
483 * I have had this idea very late, so it seems to be a
484 * later added hack and this is true */
485 if (row->par->GetDepth()) {
486 /* find the next level paragraph */
491 newpar = newpar->FirstPhysicalPar()->Previous();
493 newpar = newpar->FirstPhysicalPar();
494 } while (newpar && newpar->GetDepth() >= row->par->GetDepth()
495 && newpar->footnoteflag == row->par->footnoteflag);
497 /* make a corresponding row. Needed to call LeftMargin() */
499 /* check wether it is a sufficent paragraph */
500 if (newpar && newpar->footnoteflag == row->par->footnoteflag
501 && textclasslist.Style(parameters->textclass,
502 newpar->GetLayout()).isEnvironment()) {
503 dummyrow.par = newpar;
505 x = RightMargin(&dummyrow);
508 /* this is no longer an error, because this function is used
509 * to clear impossible depths after changing a layout. Since there
510 * is always a redo, LeftMargin() is always called */
512 /* printf("LYX_ERROR (text, LeftMargin()) impossible depth \n");*/
513 row->par->FirstPhysicalPar()->depth = 0;
517 //lyxerr << "rightmargin: " << layout->rightmargin << endl;
518 x += (textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.rightmargin) * 4
519 / (row->par->GetDepth() + 4));
525 int LyXText::LabelEnd (Row * row)
527 if (textclasslist.Style(parameters->textclass, row->par->GetLayout()).margintype == MARGIN_MANUAL) {
530 tmprow.pos = row->par->Last();
531 return LeftMargin(&tmprow); /* just the beginning
532 * of the main body */
535 return 0; /* LabelEnd is only needed, if the
536 * layout fills a flushleft
541 /* table stuff -- begin*/
542 int LyXText::NumberOfCell(LyXParagraph * par,
543 LyXParagraph::size_type pos)
546 LyXParagraph::size_type tmp_pos = 0;
547 while (tmp_pos < pos) {
548 if (par->IsNewline(tmp_pos))
556 int LyXText::WidthOfCell(LyXParagraph * par, LyXParagraph::size_type & pos)
559 while (pos < par->Last() && !par->IsNewline(pos)) {
560 w += SingleWidth(par, pos);
563 if (par->IsNewline(pos))
569 bool LyXText::HitInTable(Row * row, int x)
572 float fill_separator, fill_hfill, fill_label_hfill;
573 if (!row->par->table)
575 PrepareToPrint(row, tmpx, fill_separator, fill_hfill, fill_label_hfill);
576 return (x > tmpx && x < tmpx + row->par->table->WidthOfTable());
580 bool LyXText::MouseHitInTable(int x, long y)
582 Row * row = GetRowNearY(y);
583 return HitInTable(row, x);
587 /* table stuff -- end*/
590 /* get the next breakpoint in a given paragraph */
591 LyXParagraph::size_type
592 LyXText::NextBreakPoint(Row * row, int width)
595 LyXParagraph::size_type last_separator = -1;
596 /* position of the last possible breakpoint
597 * -1 isn't a suitable value, but a flag */
600 LyXParagraph * par = row->par;
601 LyXParagraph::size_type i = 0;
602 LyXParagraph::size_type pos = row->pos;
604 /* table stuff -- begin*/
606 while (pos < par->size()
607 && (!par->IsNewline(pos)
608 || !par->table->IsFirstCell(NumberOfCell(par, pos+1)))) {
609 if (par->GetChar(pos) == LyXParagraph::META_INSET &&
610 par->GetInset(pos) && par->GetInset(pos)->display()){
611 par->GetInset(pos)->display(false);
617 /* table stuff -- end*/
619 left_margin = LabelEnd(row);
620 width -= RightMargin(row);
621 LyXParagraph::size_type main_body =
622 BeginningOfMainBody(par);
623 LyXLayout const & layout = textclasslist.Style(parameters->textclass, par->GetLayout());
627 if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX) {
628 /* special code for right address boxes, only newlines count */
629 while (i < par->Last()) {
630 if (par->IsNewline(i)) {
632 i = par->Last() - 1;/* this means break */
634 } else if (par->GetChar(i) == LyXParagraph::META_INSET &&
635 par->GetInset(i) && par->GetInset(i)->display()){
636 par->GetInset(i)->display(false);
641 // Last position is an invariant
642 LyXParagraph::size_type const last =
644 /* this is the usual handling */
646 while (x < width && i < last) {
648 if (IsNewlineChar(c)) {
650 x = width; /* this means break */
651 } else if (c == LyXParagraph::META_INSET &&
652 par->GetInset(i) && par->GetInset(i)->display()){
653 /* check wether a Display() inset is valid here .
654 if not, change it to non-display*/
655 if (layout.isCommand()
656 || (layout.labeltype == LABEL_MANUAL
657 && i < BeginningOfMainBody(par))){
658 /* display istn't allowd */
659 par->GetInset(i)->display(false);
660 x += SingleWidth(par, i, c);
662 /* inset is display. So break the line here */
666 if (IsLineSeparatorChar(par->GetChar(i+1)))
669 last_separator = last; // to avoid extra rows
671 last_separator = i - 1;
672 x = width; /* this means break */
675 if (IsLineSeparatorChar(c))
677 x += SingleWidth(par, i, c);
680 if (i == main_body) {
681 x += GetFont(par, -2).stringWidth(layout.labelsep);
682 if (par->IsLineSeparator(i - 1))
683 x-= SingleWidth(par, i - 1);
688 /* end of paragraph is always a suitable separator */
689 if (i == last && x < width)
693 /* well, if last_separator is still 0, the line isn't breakable.
694 * don't care and cut simply at the end */
695 if (last_separator < 0) {
699 /* manual labels cannot be broken in LaTeX, do not care */
700 if (main_body && last_separator < main_body)
701 last_separator = main_body - 1;
703 return last_separator;
707 /* returns the minimum space a row needs on the screen in pixel */
708 int LyXText::Fill(Row * row, int paperwidth)
711 /* get the pure distance */
712 LyXParagraph::size_type last = RowLast(row);
713 /* table stuff -- begin*/
714 if (row->par->table) {
715 /* for tables FILL does calculate the widthes of each cell in
717 LyXParagraph::size_type pos = row->pos;
718 int cell = NumberOfCell(row->par, pos);
721 row->par->table->SetWidthOfCell(cell, WidthOfCell(row->par, pos));
723 } while (pos <= last && !row->par->table->IsFirstCell(cell));
724 /* don't forget the very last table cell without characters */
725 if (cell == row->par->table->GetNumberOfCells()-1)
726 row->par->table->SetWidthOfCell(cell, WidthOfCell(row->par, pos));
728 return 0; /* width of table cannot be returned since
729 * we cannot guarantee its correct value at
732 /* table stuff -- end*/
734 int left_margin = LabelEnd(row);
736 /* if the row ends with newline, this newline will not be relevant */
737 if (last >= 0 && row->par->IsNewline(last))
740 /* if the row ends with a space, this space will not be relevant */
741 if (last >= 0 && row->par->IsLineSeparator(last))
744 /* special handling of the right address boxes */
745 if (textclasslist.Style(parameters->textclass,
746 row->par->GetLayout()).margintype
747 == MARGIN_RIGHT_ADDRESS_BOX) {
748 int tmpfill = row->fill;
749 row->fill = 0; /* the minfill in MarginLeft() */
756 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
757 row->par->GetLayout());
758 LyXParagraph::size_type main_body =
759 BeginningOfMainBody(row->par);
760 LyXParagraph::size_type i = row->pos;
762 w += SingleWidth(row->par, i);
764 if (i == main_body) {
765 w += GetFont(row->par, -2).stringWidth(layout.labelsep);
766 if (row->par->IsLineSeparator(i - 1))
767 w -= SingleWidth(row->par, i - 1);
773 fill = paperwidth - w - RightMargin(row);
778 /* returns the minimum space a manual label needs on the screen in pixel */
779 int LyXText::LabelFill(Row * row)
782 LyXParagraph::size_type last = BeginningOfMainBody(row->par) - 1;
783 /* -1 because a label ends either with a space that is in the label,
784 * or with the beginning of a footnote that is outside the label. */
786 // I don't understand this code in depth, but sometimes "last" is less than
787 // 0 and this causes a crash. This fix seems to work correctly, but I
788 // bet the real error is elsewhere. The bug is triggered when you have an
789 // open footnote in a paragraph environment with a manual label. (Asger)
790 if (last < 0) last = 0;
792 if (row->par->IsLineSeparator(last)) /* a sepearator at this end
799 w += SingleWidth(row->par, i);
804 if (!row->par->labelwidthstring.empty()) {
805 fill = GetFont(row->par, -2).stringWidth(row->par->labelwidthstring) - w;
815 /* returns the number of separators in the specified row. The separator
816 * on the very last column doesnt count */
817 int LyXText::NumberOfSeparators(Row *row)
819 int last = RowLast(row);
822 int main_body = BeginningOfMainBody(row->par);
825 for (; p < last; p++) {
826 if (row->par->IsSeparator(p)) {
834 /* returns the number of hfills in the specified row. The LyX-Hfill is
835 * a LaTeX \hfill so that the hfills at the beginning and at the end were
836 * ignored. This is *MUCH* more usefull than not to ignore! */
837 int LyXText::NumberOfHfills(Row * row)
839 int last = RowLast(row);
840 int first = row->pos;
841 if (first) { /* hfill *DO* count at the beginning
843 while(first <= last && row->par->IsHfill(first))
847 int main_body = BeginningOfMainBody(row->par);
848 if (first < main_body)
851 for (int p = first; p <= last; p++) { // last, because the end is ignored!
852 if (row->par->IsHfill(p)) {
860 /* like NumberOfHfills, but only those in the manual label! */
861 int LyXText::NumberOfLabelHfills(Row * row)
863 LyXParagraph::size_type last = RowLast(row);
864 LyXParagraph::size_type first = row->pos;
865 if (first) { /* hfill *DO* count at the beginning
867 while(first < last && row->par->IsHfill(first))
870 LyXParagraph::size_type main_body =
871 BeginningOfMainBody(row->par);
872 if (last > main_body)
876 for (LyXParagraph::size_type p = first;
877 p < last; ++p) { // last, because the end is ignored!
878 if (row->par->IsHfill(p)) {
886 /* returns true, if a expansion is needed.
887 * Rules are given by LaTeX */
888 bool LyXText::HfillExpansion(Row * row_ptr,
889 LyXParagraph::size_type pos)
891 /* by the way, is it a hfill? */
892 if (!row_ptr->par->IsHfill(pos))
895 /* at the end of a row it does not count */
896 if (pos >= RowLast(row_ptr))
899 /* at the beginning of a row it does not count, if it is not
900 * the first row of a paragaph */
904 /* in some labels it does not count */
905 if ( textclasslist.Style(parameters->textclass, row_ptr->par->GetLayout()).margintype != MARGIN_MANUAL &&
906 pos < BeginningOfMainBody(row_ptr->par))
909 /* if there is anything between the first char of the row and
910 * the sepcified position that is not a newline and not a hfill,
911 * the hfill will count, otherwise not */
912 LyXParagraph::size_type i = row_ptr->pos;
913 while (i < pos && (row_ptr->par->IsNewline(i)
914 || row_ptr->par->IsHfill(i)))
921 void LyXText::SetHeightOfRow(Row * row_ptr)
923 /* get the maximum ascent and the maximum descent */
924 int asc, maxasc, desc, maxdesc, pos_end, pos, labeladdon;
926 float layoutdesc = 0;
931 /* this must not happen before the currentrow for clear reasons.
932 so the trick is just to set the current row onto this row */
934 GetRow(row_ptr->par, row_ptr->pos, unused_y);
936 /* ok , let us initialize the maxasc and maxdesc value.
937 * This depends in LaTeX of the font of the last character
938 * in the paragraph. The hack below is necessary because
939 * of the possibility of open footnotes */
941 /* Correction: only the fontsize count. The other properties
942 are taken from the layoutfont. Nicer on the screen :) */
944 LyXParagraph * par = row_ptr->par->LastPhysicalPar();
945 LyXParagraph * firstpar = row_ptr->par->FirstPhysicalPar();
947 LyXLayout const & layout = textclasslist.Style(parameters->textclass, firstpar->GetLayout());
949 LyXFont font = GetFont(par, par->Last()-1);
950 LyXFont::FONT_SIZE size = font.size();
951 font = GetFont(par, -1);
954 LyXFont labelfont = GetFont(par, -2);
956 maxasc = int(font.maxAscent() *
957 layout.spacing.getValue() *
958 parameters->spacing.getValue());
959 maxdesc = int(font.maxDescent() *
960 layout.spacing.getValue() *
961 parameters->spacing.getValue());
963 pos_end = RowLast(row_ptr);
967 // Check if any insets are larger
968 for (pos = row_ptr->pos; pos <= pos_end; pos++) {
969 if (row_ptr->par->GetChar(pos) == LyXParagraph::META_INSET) {
970 tmpfont = GetFont(row_ptr->par, pos);
971 tmpinset = row_ptr->par->GetInset(pos);
973 asc = tmpinset->Ascent(tmpfont);
974 desc = tmpinset->Descent(tmpfont);
983 // Check if any custom fonts are larger (Asger)
984 // This is not completely correct, but we can live with the small,
985 // cosmetic error for now.
986 LyXFont::FONT_SIZE maxsize = row_ptr->par->HighestFontInRange(row_ptr->pos, pos_end);
987 if (maxsize > font.size()) {
988 font.setSize(maxsize);
990 asc = font.maxAscent();
991 desc = font.maxDescent();
998 /* table stuff -- begin*/
999 if (row_ptr->par->table){
1000 // stretch the rows a bit
1004 /* table stuff -- end*/
1006 // This is nicer with box insets:
1010 row_ptr->ascent_of_text = maxasc;
1012 /* is it a top line? */
1013 if (row_ptr->pos == 0
1014 && row_ptr->par == firstpar) {
1016 /* some parksips VERY EASY IMPLEMENTATION */
1017 if (parameters->paragraph_separation == BufferParams::PARSEP_SKIP) {
1018 if (layout.isParagraph()
1019 && firstpar->GetDepth() == 0
1020 && firstpar->Previous())
1021 maxasc += parameters->getDefSkip().inPixels();
1022 else if (firstpar->Previous()
1023 && textclasslist.Style(parameters->textclass,
1024 firstpar->Previous()->GetLayout()).isParagraph()
1025 && firstpar->Previous()->GetDepth() == 0)
1026 // is it right to use defskip here too? (AS)
1027 maxasc += parameters->getDefSkip().inPixels();
1030 /* the paper margins */
1031 if (!row_ptr->par->previous)
1032 maxasc += LYX_PAPER_MARGIN;
1034 /* add the vertical spaces, that the user added */
1035 if (firstpar->added_space_top.kind() != VSpace::NONE)
1036 maxasc += int(firstpar->added_space_top.inPixels());
1038 /* do not forget the DTP-lines!
1039 * there height depends on the font of the nearest character */
1040 if (firstpar->line_top)
1041 maxasc += 2 * GetFont(firstpar, 0).ascent('x');
1043 /* and now the pagebreaks */
1044 if (firstpar->pagebreak_top)
1045 maxasc += 3 * DefaultHeight();
1047 /* this is special code for the chapter, since the label of this
1048 * layout is printed in an extra row */
1049 if (layout.labeltype == LABEL_COUNTER_CHAPTER
1050 && parameters->secnumdepth>= 0) {
1051 labeladdon = int(labelfont.maxDescent() *
1052 layout.spacing.getValue() *
1053 parameters->spacing.getValue())
1054 + int(labelfont.maxAscent() *
1055 layout.spacing.getValue() *
1056 parameters->spacing.getValue());
1059 /* special code for the top label */
1060 if ((layout.labeltype == LABEL_TOP_ENVIRONMENT
1061 || layout.labeltype == LABEL_BIBLIO
1062 || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)
1063 && row_ptr->par->IsFirstInSequence()
1064 && !row_ptr->par->GetLabestring().empty()) {
1066 (labelfont.maxAscent() *
1067 layout.spacing.getValue() *
1068 parameters->spacing.getValue())
1069 +(labelfont.maxDescent() *
1070 layout.spacing.getValue() *
1071 parameters->spacing.getValue())
1072 + layout.topsep * DefaultHeight()
1073 + layout.labelbottomsep * DefaultHeight());
1076 /* and now the layout spaces, for example before and after a section,
1077 * or between the items of a itemize or enumerate environment */
1079 if (!firstpar->pagebreak_top) {
1080 LyXParagraph *prev = row_ptr->par->Previous();
1082 prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth());
1083 if (prev && prev->GetLayout() == firstpar->GetLayout()
1084 && prev->GetDepth() == firstpar->GetDepth()
1085 && prev->GetLabelWidthString() == firstpar->GetLabelWidthString())
1087 layoutasc = (layout.itemsep * DefaultHeight());
1089 else if (row_ptr->previous) {
1090 tmptop = layout.topsep;
1092 if (row_ptr->previous->par->GetDepth() >= row_ptr->par->GetDepth())
1093 tmptop-= textclasslist.Style(parameters->textclass, row_ptr->previous->par->GetLayout()).bottomsep;
1096 layoutasc = (tmptop * DefaultHeight());
1098 else if (row_ptr->par->line_top){
1099 tmptop = layout.topsep;
1102 layoutasc = (tmptop * DefaultHeight());
1105 prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth()-1);
1107 maxasc += int(textclasslist.Style(parameters->textclass,
1108 prev->GetLayout()).parsep * DefaultHeight());
1111 if (firstpar->Previous()
1112 && firstpar->Previous()->GetDepth() == 0
1113 && firstpar->Previous()->GetLayout() != firstpar->GetLayout()) {
1116 else if (firstpar->Previous()){
1117 maxasc += int(layout.parsep * DefaultHeight());
1123 /* is it a bottom line? */
1124 if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
1125 && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {
1127 /* the paper margins */
1129 maxdesc += LYX_PAPER_MARGIN;
1131 /* add the vertical spaces, that the user added */
1132 if (firstpar->added_space_bottom.kind() != VSpace::NONE)
1133 maxdesc += int(firstpar->added_space_bottom.inPixels());
1135 /* do not forget the DTP-lines!
1136 * there height depends on the font of the nearest character */
1137 if (firstpar->line_bottom)
1138 maxdesc += 2 * (GetFont(par, par->Last()-1).ascent('x'));
1140 /* and now the pagebreaks */
1141 if (firstpar->pagebreak_bottom)
1142 maxdesc += 3 * DefaultHeight();
1144 /* and now the layout spaces, for example before and after a section,
1145 * or between the items of a itemize or enumerate environment */
1146 if (!firstpar->pagebreak_bottom && row_ptr->par->Next()) {
1147 LyXParagraph *nextpar = row_ptr->par->Next();
1148 LyXParagraph *comparepar = row_ptr->par;
1152 if (comparepar->GetDepth() > nextpar->GetDepth()) {
1153 usual = (textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1154 comparepar = comparepar->DepthHook(nextpar->GetDepth());
1155 if (comparepar->GetLayout()!= nextpar->GetLayout()
1156 || nextpar->GetLabelWidthString() !=
1157 comparepar->GetLabelWidthString())
1158 unusual = (textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1160 if (unusual > usual)
1161 layoutdesc = unusual;
1165 else if (comparepar->GetDepth() == nextpar->GetDepth()) {
1167 if (comparepar->GetLayout()!= nextpar->GetLayout()
1168 || nextpar->GetLabelWidthString() !=
1169 comparepar->GetLabelWidthString())
1170 layoutdesc = int(textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1175 /* incalculate the layout spaces */
1176 maxasc += int(layoutasc * 2 / (2 + firstpar->GetDepth()));
1177 maxdesc += int(layoutdesc * 2 / (2 + firstpar->GetDepth()));
1179 /* table stuff -- begin*/
1180 if (row_ptr->par->table){
1181 maxasc += row_ptr->par->table->
1182 AdditionalHeight(NumberOfCell(row_ptr->par, row_ptr->pos));
1184 /* table stuff -- end*/
1186 /* calculate the new height of the text */
1187 height -= row_ptr->height;
1189 row_ptr->height= maxasc+maxdesc+labeladdon;
1190 row_ptr->baseline= maxasc+labeladdon;
1192 height += row_ptr->height;
1196 /* Appends the implicit specified paragraph behind the specified row,
1197 * start at the implicit given position */
1198 void LyXText::AppendParagraph(Row * row)
1200 bool not_ready = true;
1202 // The last character position of a paragraph is an invariant so we can
1203 // safely get it here. (Asger)
1204 int lastposition = row->par->Last();
1207 // Get the next breakpoint
1208 int z = NextBreakPoint(row, paperwidth);
1212 // Insert the new row
1213 if (z < lastposition) {
1215 InsertRow(row, row->par, z);
1222 // Set the dimensions of the row
1223 tmprow->fill = Fill(tmprow, paperwidth);
1224 SetHeightOfRow(tmprow);
1226 } while (not_ready);
1230 void LyXText::BreakAgain(Row * row)
1232 bool not_ready = true;
1235 /* get the next breakpoint */
1236 LyXParagraph::size_type z =
1237 NextBreakPoint(row, paperwidth);
1240 if (z < row->par->Last() ) {
1241 if (!row->next || (row->next && row->next->par != row->par)) {
1242 /* insert a new row */
1244 InsertRow(row, row->par, z);
1251 not_ready = false; // the rest will not change
1257 /* if there are some rows too much, delete them */
1258 /* only if you broke the whole paragraph! */
1259 Row * tmprow2 = row;
1260 while (tmprow2->next && tmprow2->next->par == row->par) {
1261 tmprow2 = tmprow2->next;
1263 while (tmprow2 != row) {
1264 tmprow2 = tmprow2->previous;
1265 RemoveRow(tmprow2->next);
1270 /* set the dimensions of the row */
1271 tmprow->fill = Fill(tmprow, paperwidth);
1272 SetHeightOfRow(tmprow);
1273 } while (not_ready);
1277 /* this is just a little changed version of break again */
1278 void LyXText::BreakAgainOneRow(Row * row)
1280 /* get the next breakpoint */
1281 LyXParagraph::size_type z = NextBreakPoint(row, paperwidth);
1284 if (z < row->par->Last() ) {
1285 if (!row->next || (row->next && row->next->par != row->par)) {
1286 /* insert a new row */
1288 InsertRow(row, row->par, z);
1300 /* if there are some rows too much, delete them */
1301 /* only if you broke the whole paragraph! */
1302 Row * tmprow2 = row;
1303 while (tmprow2->next && tmprow2->next->par == row->par) {
1304 tmprow2 = tmprow2->next;
1306 while (tmprow2 != row) {
1307 tmprow2 = tmprow2->previous;
1308 RemoveRow(tmprow2->next);
1312 /* set the dimensions of the row */
1313 tmprow->fill = Fill(tmprow, paperwidth);
1314 SetHeightOfRow(tmprow);
1318 void LyXText::BreakParagraph(char keep_layout)
1320 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
1321 cursor.par->GetLayout());
1323 /* table stuff -- begin*/
1324 if (cursor.par->table) {
1325 // breaking of tables is only allowed at the beginning or the end */
1326 if (cursor.pos && cursor.pos < cursor.par->size() &&
1327 !cursor.par->table->ShouldBeVeryLastCell(NumberOfCell(cursor.par, cursor.pos)))
1328 return; /* no breaking of tables allowed */
1330 /* table stuff -- end*/
1332 /* this is only allowed, if the current paragraph is not empty or caption*/
1333 if ((cursor.par->Last() <= 0 && !cursor.par->IsDummy())
1335 layout.labeltype!= LABEL_SENSITIVE)
1338 SetUndo(Undo::INSERT,
1339 cursor.par->ParFromPos(cursor.pos)->previous,
1340 cursor.par->ParFromPos(cursor.pos)->next);
1342 /* table stuff -- begin*/
1343 if (cursor.par->table) {
1344 int cell = NumberOfCell(cursor.par, cursor.pos);
1345 if (cursor.par->table->ShouldBeVeryLastCell(cell))
1346 SetCursor(cursor.par, cursor.par->text.size());
1348 /* table stuff -- end*/
1349 /* please break alway behind a space */
1350 if (cursor.pos < cursor.par->Last()
1351 && cursor.par->IsLineSeparator(cursor.pos))
1354 /* break the paragraph */
1358 keep_layout = layout.isEnvironment();
1359 cursor.par->BreakParagraph(cursor.pos, keep_layout);
1361 /* table stuff -- begin*/
1362 if (cursor.par->table){
1363 // the table should stay with the contents
1365 cursor.par->Next()->table = cursor.par->table;
1366 cursor.par->table = 0;
1369 /* table stuff -- end*/
1371 /* well this is the caption hack since one caption is really enough */
1372 if (layout.labeltype == LABEL_SENSITIVE){
1374 cursor.par->SetLayout(0); /* set the new paragraph to standard-layout */
1376 cursor.par->Next()->SetLayout(0); /* set the new paragraph to standard-layout */
1380 /* if the cursor is at the beginning of a row without prior newline,
1382 * This touches only the screen-update. Otherwise we would may have
1383 * an empty row on the screen */
1384 if (cursor.pos && !cursor.row->par->IsNewline(cursor.row->pos -1) &&
1385 cursor.row->pos == cursor.pos) {
1389 status = LyXText::NEED_MORE_REFRESH;
1390 refresh_row = cursor.row;
1391 refresh_y = cursor.y - cursor.row->baseline;
1393 /* Do not forget the special right address boxes */
1394 if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX) {
1395 while (refresh_row->previous &&
1396 refresh_row->previous->par == refresh_row->par) {
1397 refresh_row = refresh_row->previous;
1398 refresh_y -= refresh_row->height;
1401 RemoveParagraph(cursor.row);
1403 /* set the dimensions of the cursor row */
1404 cursor.row->fill = Fill(cursor.row, paperwidth);
1406 SetHeightOfRow(cursor.row);
1408 while (!cursor.par->Next()->table && cursor.par->Next()->Last()
1409 && cursor.par->Next()->IsNewline(0))
1410 cursor.par->Next()->Erase(0);
1412 InsertParagraph(cursor.par->Next(), cursor.row);
1414 UpdateCounters(cursor.row->previous);
1416 /* this check is necessary. Otherwise the new empty paragraph will
1417 * be deleted automatically. And it is more friendly for the user! */
1419 SetCursor(cursor.par->Next(), 0);
1421 SetCursor(cursor.par, 0);
1423 if (cursor.row->next)
1424 BreakAgain(cursor.row->next);
1430 void LyXText::OpenFootnote()
1432 LyXParagraph * endpar,* tmppar;
1435 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
1437 /* if there is no footnote in this paragraph, just return. */
1439 || par->next->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1442 /* ok, move the cursor right before the footnote */
1444 /* just a little faster than using CursorRight() */
1445 for (cursor.pos= 0; cursor.par->ParFromPos(cursor.pos)!= par; cursor.pos++);
1446 /* now the cursor is at the beginning of the physical par */
1447 SetCursor(cursor.par,
1448 cursor.pos + cursor.par->ParFromPos(cursor.pos)->text.size());
1450 /* the cursor must be exactly before the footnote */
1451 par = cursor.par->ParFromPos(cursor.pos);
1453 status = LyXText::NEED_MORE_REFRESH;
1454 refresh_row = cursor.row;
1455 refresh_y = cursor.y - cursor.row->baseline;
1457 tmppar = cursor.par;
1458 endpar = cursor.par->Next();
1461 tmppar->OpenFootnote(cursor.pos);
1462 RemoveParagraph(row);
1463 /* set the dimensions of the cursor row */
1464 row->fill = Fill(row, paperwidth);
1465 SetHeightOfRow(row);
1466 tmppar = tmppar->Next();
1468 while (tmppar != endpar) {
1470 InsertParagraph(tmppar, row);
1471 while (row->next && row->next->par == tmppar)
1473 tmppar = tmppar->Next();
1476 SetCursor(par->next, 0);
1477 sel_cursor = cursor;
1481 /* table stuff -- begin*/
1483 void LyXText::TableFeatures(int feature, string val)
1485 if (!cursor.par->table)
1486 return; /* this should never happen */
1488 int actCell = NumberOfCell(cursor.par, cursor.pos);
1489 SetUndo(Undo::FINISH,
1490 cursor.par->ParFromPos(cursor.pos)->previous,
1491 cursor.par->ParFromPos(cursor.pos)->next);
1494 case LyXTable::SET_PWIDTH:
1495 cursor.par->table->SetPWidth(actCell, val);
1497 case LyXTable::SET_SPECIAL_COLUMN:
1498 case LyXTable::SET_SPECIAL_MULTI:
1499 cursor.par->table->SetAlignSpecial(actCell, val, feature);
1508 void LyXText::TableFeatures(int feature)
1511 int setAlign = LYX_ALIGN_LEFT;
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::ALIGN_LEFT:
1525 setAlign= LYX_ALIGN_LEFT;
1527 case LyXTable::ALIGN_RIGHT:
1528 setAlign= LYX_ALIGN_RIGHT;
1530 case LyXTable::ALIGN_CENTER:
1531 setAlign= LYX_ALIGN_CENTER;
1537 case LyXTable::APPEND_ROW: {
1538 LyXParagraph::size_type pos = cursor.pos;
1540 /* move to the next row */
1541 int cell_org = actCell;
1542 int cell = cell_org;
1544 // if there is a ContRow following this row I have to add
1545 // the row after the ContRow's
1546 if ((pos < cursor.par->Last()) &&
1547 cursor.par->table->RowHasContRow(cell_org)) {
1548 while((pos < cursor.par->Last()) &&
1549 !cursor.par->table->IsContRow(cell)) {
1550 while (pos < cursor.par->Last() &&
1551 !cursor.par->IsNewline(pos))
1553 if (pos < cursor.par->Last())
1557 while((pos < cursor.par->Last()) &&
1558 cursor.par->table->IsContRow(cell)) {
1559 while (pos < cursor.par->Last() &&
1560 !cursor.par->IsNewline(pos))
1562 if (pos < cursor.par->Last())
1567 if (pos < cursor.par->Last())
1570 while (pos < cursor.par->Last() &&
1571 (cell == cell_org || !cursor.par->table->IsFirstCell(cell))){
1572 while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1574 if (pos < cursor.par->Last())
1579 /* insert the new cells */
1580 int number = cursor.par->table->NumberOfCellsInRow(cell_org);
1581 for (int i = 0; i < number; ++i)
1582 cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1584 /* append the row into the table */
1585 cursor.par->table->AppendRow(cell_org);
1589 case LyXTable::APPEND_CONT_ROW: {
1590 LyXParagraph::size_type pos = cursor.pos;
1591 /* move to the next row */
1592 int cell_org = actCell;
1593 int cell = cell_org;
1595 // if there is already a controw but not for this cell
1596 // the AppendContRow sets only the right values but does
1597 // not actually add a row
1598 if (cursor.par->table->RowHasContRow(cell_org) &&
1599 (cursor.par->table->CellHasContRow(cell_org)<0)) {
1600 cursor.par->table->AppendContRow(cell_org);
1604 while (pos < cursor.par->Last() &&
1606 || !cursor.par->table->IsFirstCell(cell))){
1607 while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1609 if (pos < cursor.par->Last())
1614 /* insert the new cells */
1615 int number = cursor.par->table->NumberOfCellsInRow(cell_org);
1617 for (i= 0; i<number; i++)
1618 cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1620 /* append the row into the table */
1621 cursor.par->table->AppendContRow(cell_org);
1625 case LyXTable::APPEND_COLUMN: {
1626 LyXParagraph::size_type pos = 0;
1627 int cell_org = actCell;
1630 if (pos && (cursor.par->IsNewline(pos-1))){
1631 if (cursor.par->table->AppendCellAfterCell(cell_org, cell)){
1632 cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1633 if (pos <= cursor.pos)
1640 } while (pos <= cursor.par->Last());
1641 /* remember that the very last cell doesn't end with a newline.
1642 This saves one byte memory per table ;-) */
1643 if (cursor.par->table->AppendCellAfterCell(cell_org, cell))
1644 cursor.par->InsertChar(cursor.par->Last(), LyXParagraph::META_NEWLINE);
1646 /* append the column into the table */
1647 cursor.par->table->AppendColumn(cell_org);
1652 case LyXTable::DELETE_ROW:
1653 if (current_view->buffer()->the_locking_inset)
1654 UnlockInset(current_view->buffer()->the_locking_inset);
1655 RemoveTableRow(&cursor);
1659 case LyXTable::DELETE_COLUMN: {
1660 LyXParagraph::size_type pos = 0;
1661 int cell_org = actCell;
1663 if (current_view->buffer()->the_locking_inset)
1664 UnlockInset(current_view->buffer()->the_locking_inset);
1666 if (!pos || (cursor.par->IsNewline(pos-1))){
1667 if (cursor.par->table->DeleteCellIfColumnIsDeleted(cell, cell_org)){
1669 while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1670 cursor.par->Erase(pos);
1671 if (pos < cursor.par->Last())
1672 cursor.par->Erase(pos);
1674 cursor.par->Erase(pos - 1); // the missing newline at the end of a table
1675 --pos; // because of pos++ below
1680 } while (pos <= cursor.par->Last());
1682 /* delete the column from the table */
1683 cursor.par->table->DeleteColumn(cell_org);
1685 /* set the cursor to the beginning of the table, where else? */
1690 case LyXTable::TOGGLE_LINE_TOP:
1691 lineSet = !cursor.par->table->TopLine(actCell);
1693 cursor.par->table->SetTopLine(actCell, lineSet);
1695 LyXParagraph::size_type i;
1697 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
1698 if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1699 cursor.par->table->SetTopLine(n, lineSet);
1707 case LyXTable::TOGGLE_LINE_BOTTOM:
1708 lineSet = !cursor.par->table->BottomLine(actCell);
1710 cursor.par->table->SetBottomLine(actCell, lineSet);
1712 LyXParagraph::size_type i;
1714 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
1715 if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1716 cursor.par->table->SetBottomLine(n, lineSet);
1724 case LyXTable::TOGGLE_LINE_LEFT:
1725 lineSet = !cursor.par->table->LeftLine(actCell);
1727 cursor.par->table->SetLeftLine(actCell, lineSet);
1729 LyXParagraph::size_type i;
1731 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
1732 if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1733 cursor.par->table->SetLeftLine(n, lineSet);
1741 case LyXTable::TOGGLE_LINE_RIGHT:
1742 lineSet = !cursor.par->table->RightLine(actCell);
1744 cursor.par->table->SetRightLine(actCell, lineSet);
1746 LyXParagraph::size_type i;
1748 for (i= sel_start_cursor.pos; i<= sel_end_cursor.pos; i++){
1749 if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1750 cursor.par->table->SetRightLine(n, lineSet);
1758 case LyXTable::ALIGN_LEFT:
1759 case LyXTable::ALIGN_RIGHT:
1760 case LyXTable::ALIGN_CENTER:
1762 cursor.par->table->SetAlignment(actCell, setAlign);
1764 LyXParagraph::size_type i;
1766 for (i= sel_start_cursor.pos; i<= sel_end_cursor.pos; i++){
1767 if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1768 cursor.par->table->SetAlignment(n, setAlign);
1776 case LyXTable::DELETE_TABLE:
1777 SetCursorIntern(cursor.par, 0);
1778 delete cursor.par->table;
1779 cursor.par->table = 0;
1780 // temporary: Should put table in simple_cut_buffer (with before and after
1781 // dummy-paragraph !!
1782 // not necessar anymore with UNDO :)
1783 for (LyXParagraph::size_type i =
1784 cursor.par->text.size() - 1; i >= 0; --i)
1785 cursor.par->Erase(i);
1789 case LyXTable::MULTICOLUMN: {
1791 // check wether we are completly in a multicol
1792 int multicol = cursor.par->table->IsMultiColumn(actCell);
1793 if (multicol && selection && sel_start_cursor.row == sel_end_cursor.row){
1794 multicol = NumberOfCell(sel_start_cursor.par, sel_start_cursor.pos)
1795 == NumberOfCell(sel_end_cursor.par, sel_end_cursor.pos);
1799 int newlines = cursor.par->table->UnsetMultiColumn(actCell);
1800 LyXParagraph::size_type pos = cursor.pos;
1801 while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1803 for (;newlines;newlines--)
1804 cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1809 // selection must be in one row (or no selection)
1811 cursor.par->table->SetMultiColumn(NumberOfCell(cursor.par,
1818 if (sel_start_cursor.row == sel_end_cursor.row){
1819 LyXParagraph::size_type i;
1821 for (i = sel_start_cursor.pos;
1822 i < sel_end_cursor.pos; ++i){
1823 if (sel_start_cursor.par->IsNewline(i)){
1824 sel_start_cursor.par->Erase(i);
1825 // check for double-blanks
1826 if ((i && !sel_start_cursor.par->IsLineSeparator(i-1))
1828 (i < sel_start_cursor.par->Last()
1829 && !sel_start_cursor.par->IsLineSeparator(i)))
1830 sel_start_cursor.par->InsertChar(i, ' ');
1832 sel_end_cursor.pos--;
1839 SetMultiColumn(NumberOfCell(sel_start_cursor.par,
1840 sel_start_cursor.pos),
1842 cursor.pos = sel_start_cursor.pos;
1847 WriteAlert(_("Impossible Operation!"),
1848 _("Multicolumns can only be horizontally."),
1855 case LyXTable::SET_ALL_LINES:
1857 case LyXTable::UNSET_ALL_LINES:
1859 cursor.par->table->SetAllLines(NumberOfCell(cursor.par,
1863 LyXParagraph::size_type i;
1865 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
1866 if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1867 cursor.par->table->SetAllLines(n, setLines);
1874 case LyXTable::SET_LONGTABLE:
1875 cursor.par->table->SetLongTable(true);
1877 case LyXTable::UNSET_LONGTABLE:
1878 cursor.par->table->SetLongTable(false);
1880 case LyXTable::SET_ROTATE_TABLE:
1881 cursor.par->table->SetRotateTable(true);
1883 case LyXTable::UNSET_ROTATE_TABLE:
1884 cursor.par->table->SetRotateTable(false);
1886 case LyXTable::SET_ROTATE_CELL:
1888 cursor.par->table->SetRotateCell(actCell, true);
1890 LyXParagraph::size_type i;
1892 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
1893 if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1894 cursor.par->table->SetRotateCell(n, true);
1900 case LyXTable::UNSET_ROTATE_CELL:
1902 cursor.par->table->SetRotateCell(actCell, false);
1904 LyXParagraph::size_type i;
1906 for (i= sel_start_cursor.pos; i<= sel_end_cursor.pos; i++){
1907 if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1908 cursor.par->table->SetRotateCell(n, false);
1914 case LyXTable::SET_LINEBREAKS:
1915 what = !cursor.par->table->Linebreaks(cursor.par->table->FirstVirtualCell(actCell));
1917 cursor.par->table->SetLinebreaks(actCell, what);
1919 LyXParagraph::size_type i;
1921 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
1922 if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1923 cursor.par->table->SetLinebreaks(n, what);
1929 case LyXTable::SET_LTFIRSTHEAD:
1930 cursor.par->table->SetLTHead(actCell, true);
1932 case LyXTable::SET_LTHEAD:
1933 cursor.par->table->SetLTHead(actCell, false);
1935 case LyXTable::SET_LTFOOT:
1936 cursor.par->table->SetLTFoot(actCell, false);
1938 case LyXTable::SET_LTLASTFOOT:
1939 cursor.par->table->SetLTFoot(actCell, true);
1941 case LyXTable::SET_LTNEWPAGE:
1942 what = !cursor.par->table->LTNewPage(actCell);
1943 cursor.par->table->SetLTNewPage(actCell, what);
1949 void LyXText::InsertCharInTable(char c)
1954 bool jumped_over_space;
1956 /* first check, if there will be two blanks together or a blank at
1957 * the beginning of a paragraph.
1958 * I decided to handle blanks like normal characters, the main
1959 * difference are the special checks when calculating the row.fill
1960 * (blank does not count at the end of a row) and the check here */
1962 LyXFont realtmpfont = real_current_font;
1963 LyXFont rawtmpfont = current_font; /* store the current font.
1964 * This is because of the use
1965 * of cursor movements. The moving
1966 * cursor would refresh the
1969 // Get the font that is used to calculate the baselineskip
1970 LyXParagraph::size_type const lastpos =
1972 LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
1974 jumped_over_space = false;
1975 if (IsLineSeparatorChar(c)) {
1977 /* avoid double blanks but insert the new blank because
1978 * of a possible font change */
1979 if (cursor.pos < lastpos &&
1980 cursor.par->IsLineSeparator(cursor.pos))
1982 cursor.par->Erase(cursor.pos);
1983 jumped_over_space = true;
1985 else if ((cursor.pos > 0 &&
1986 cursor.par->IsLineSeparator(cursor.pos - 1))
1987 || (cursor.pos > 0 && cursor.par->IsNewline(cursor.pos - 1))
1988 || (cursor.pos == 0 &&
1989 !(cursor.par->Previous()
1990 && cursor.par->Previous()->footnoteflag
1991 == LyXParagraph::OPEN_FOOTNOTE)))
1994 else if (IsNewlineChar(c)) {
1995 if (!IsEmptyTableCell()) {
1996 TableFeatures(LyXTable::APPEND_CONT_ROW);
2003 y = cursor.y - row->baseline;
2004 if (c != LyXParagraph::META_INSET) /* in this case LyXText::InsertInset
2005 * already inserted the character */
2006 cursor.par->InsertChar(cursor.pos, c);
2007 SetCharFont(cursor.par, cursor.pos, rawtmpfont);
2009 if (!jumped_over_space) {
2010 /* refresh the positions */
2012 while (tmprow->next && tmprow->next->par == row->par) {
2013 tmprow = tmprow->next;
2020 CheckParagraphInTable(cursor.par, cursor.pos);
2022 current_font = rawtmpfont;
2023 real_current_font = realtmpfont;
2025 /* check, whether the last character's font has changed. */
2026 if (cursor.pos && cursor.pos == cursor.par->Last()
2027 && rawparfont != rawtmpfont)
2028 RedoHeightOfParagraph(cursor);
2032 void LyXText::CheckParagraphInTable(LyXParagraph * par,
2033 LyXParagraph::size_type pos)
2036 if (par->GetChar(pos) == LyXParagraph::META_INSET &&
2037 par->GetInset(pos) && par->GetInset(pos)->display()){
2038 par->GetInset(pos)->display(false);
2042 Row * row = GetRow(par, pos, y);
2044 int tmpheight = row->height;
2045 SetHeightOfRow(row);
2047 LyXParagraph::size_type tmp_pos = pos;
2048 /* update the table information */
2049 while (tmp_pos && !par->IsNewline(tmp_pos - 1))
2051 if (par->table->SetWidthOfCell(NumberOfCell(par, pos),
2052 WidthOfCell(par, tmp_pos))) {
2053 LyXCursor tmpcursor = cursor;
2054 SetCursorIntern(par, pos);
2055 /* make a complete redraw */
2056 RedoDrawingOfParagraph(cursor);
2060 /* redraw only the row */
2061 LyXCursor tmpcursor = cursor;
2062 SetCursorIntern(par, pos);
2064 refresh_x = cursor.x;
2066 refresh_pos = cursor.pos;
2069 if (tmpheight == row->height)
2070 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2072 status = LyXText::NEED_MORE_REFRESH;
2074 SetCursorIntern(cursor.par, cursor.pos);
2078 void LyXText::BackspaceInTable()
2080 Row * tmprow, * row;
2083 LyXFont rawtmpfont = current_font;
2084 LyXFont realtmpfont = real_current_font;
2086 // Get the font that is used to calculate the baselineskip
2087 int const lastpos = cursor.par->Last();
2088 LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2090 if (cursor.pos == 0) {
2091 /* no pasting of table paragraphs */
2096 /* this is the code for a normal backspace, not pasting
2098 SetUndo(Undo::DELETE,
2099 cursor.par->ParFromPos(cursor.pos)->previous,
2100 cursor.par->ParFromPos(cursor.pos)->next);
2104 /* some insets are undeletable here */
2105 if (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
2106 if (!cursor.par->GetInset(cursor.pos)->Deletable())
2111 y = cursor.y - row->baseline;
2113 /* some special code when deleting a newline. */
2114 if (cursor.par->IsNewline(cursor.pos)) {
2119 cursor.par->Erase(cursor.pos);
2121 /* refresh the positions */
2123 while (tmprow->next && tmprow->next->par == row->par) {
2124 tmprow = tmprow->next;
2128 /* delete superfluous blanks */
2129 if (cursor.pos < cursor.par->Last() - 1 &&
2130 (cursor.par->IsLineSeparator(cursor.pos))) {
2132 if (cursor.pos == BeginningOfMainBody(cursor.par)
2134 || cursor.par->IsLineSeparator(cursor.pos - 1)) {
2135 cursor.par->Erase(cursor.pos);
2136 /* refresh the positions */
2138 while (tmprow->next &&
2139 tmprow->next->par == row->par) {
2140 tmprow = tmprow->next;
2143 if (cursor.pos) /* move one character left */
2149 CheckParagraphInTable(cursor.par, cursor.pos);
2151 /* check, wether the last characters font has changed. */
2152 if (cursor.pos && cursor.pos == cursor.par->Last()
2153 && rawparfont != rawtmpfont)
2154 RedoHeightOfParagraph(cursor);
2156 /* restore the current font
2157 * That is what a user expects! */
2158 current_font = rawtmpfont;
2159 real_current_font = realtmpfont;
2161 SetCursorIntern(cursor.par, cursor.pos);
2164 /* table stuff -- end*/
2167 /* just a macro to make some thing easier. */
2168 void LyXText::RedoParagraph()
2170 LyXCursor tmpcursor = cursor;
2172 RedoParagraphs(cursor, cursor.par->Next());;
2173 SetCursorIntern(tmpcursor.par, tmpcursor.pos);
2177 /* insert a character, moves all the following breaks in the
2178 * same Paragraph one to the right and make a rebreak */
2179 void LyXText::InsertChar(char c)
2181 SetUndo(Undo::INSERT,
2182 cursor.par->ParFromPos(cursor.pos)->previous,
2183 cursor.par->ParFromPos(cursor.pos)->next);
2185 /* When the free-spacing option is set for the current layout,
2186 * all spaces are converted to protected spaces. */
2187 bool freeSpacingBo =
2188 textclasslist.Style(parameters->textclass,
2189 cursor.row->par->GetLayout()).free_spacing;
2191 if (freeSpacingBo && IsLineSeparatorChar(c)
2192 && (!cursor.pos || cursor.par->IsLineSeparator(cursor.pos-1)))
2193 c = LyXParagraph::META_PROTECTED_SEPARATOR;
2195 /* table stuff -- begin*/
2196 if (cursor.par->table) {
2197 InsertCharInTable(c);
2201 /* table stuff -- end*/
2203 /* first check, if there will be two blanks together or a blank at
2204 * the beginning of a paragraph.
2205 * I decided to handle blanks like normal characters, the main
2206 * difference are the special checks when calculating the row.fill
2207 * (blank does not count at the end of a row) and the check here */
2209 // The bug is triggered when we type in a description environment:
2210 // The current_font is not changed when we go from label to main text
2211 // and it should (along with realtmpfont) when we type the space.
2212 #ifdef WITH_WARNINGS
2213 #warning There is a bug here! (Asger)
2216 LyXFont realtmpfont = real_current_font;
2217 LyXFont rawtmpfont = current_font; /* store the current font.
2218 * This is because of the use
2219 * of cursor movements. The moving
2220 * cursor would refresh the
2223 // Get the font that is used to calculate the baselineskip
2224 LyXParagraph::size_type lastpos = cursor.par->Last();
2225 LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2227 bool jumped_over_space = false;
2229 if (IsLineSeparatorChar(c)) {
2231 if (cursor.pos < lastpos
2232 && cursor.par->IsLineSeparator(cursor.pos)) {
2233 /* the user inserted a space before a space. So we
2234 * will just make a CursorRight. BUT: The font of this
2235 * space should be set to current font. That is why
2236 * we need to rebreak perhaps. If there is a protected
2237 * blank at the end of a row we have to force
2240 minibuffer->Set(_("You cannot type two spaces this way. Please read the Tutorial."));
2241 if (cursor.pos == RowLast(cursor.row)
2242 && !IsLineSeparatorChar(c))
2243 cursor.row->fill = -1; /* force rebreak */
2245 cursor.par->Erase(cursor.pos);
2246 jumped_over_space = true;
2248 } else if ((cursor.pos > 0
2249 && cursor.par->IsLineSeparator(cursor.pos - 1))
2251 && cursor.par->IsNewline(cursor.pos - 1))
2253 && !(cursor.par->Previous()
2254 && cursor.par->Previous()->footnoteflag
2255 == LyXParagraph::OPEN_FOOTNOTE))) {
2256 if (cursor.pos == 0 )
2257 minibuffer->Set(_("You cannot insert a space at the beginning of a paragraph. Please read the Tutorial."));
2259 minibuffer->Set(_("You cannot type two spaces this way. Please read the Tutorial."));
2263 } else if (IsNewlineChar(c)) {
2264 if (cursor.par->FirstPhysicalPar() == cursor.par
2265 && cursor.pos <= BeginningOfMainBody(cursor.par)) {
2269 /* no newline at first position
2270 * of a paragraph or behind labels.
2271 * TeX does not allow that. */
2273 if (cursor.pos < cursor.par->Last() &&
2274 cursor.par->IsLineSeparator(cursor.pos))
2275 CursorRightIntern(); // newline always after a blank!
2276 cursor.row->fill = -1; // to force a new break
2279 /* the display inset stuff */
2280 if (cursor.row->par->GetChar(cursor.row->pos) == LyXParagraph::META_INSET
2281 && cursor.row->par->GetInset(cursor.row->pos)
2282 && cursor.row->par->GetInset(cursor.row->pos)->display())
2283 cursor.row->fill = -1; // to force a new break
2285 /* get the cursor row fist */
2286 /* this is a dumb solution, i will try to hold the cursor.row
2288 /* row = GetRow(cursor.par, cursor.pos, y);*/
2289 /* ok, heres a better way: */
2290 Row * row = cursor.row;
2291 long y = cursor.y - row->baseline;
2292 if (c != LyXParagraph::META_INSET) /* in this case LyXText::InsertInset
2293 * already insertet the character */
2294 cursor.par->InsertChar(cursor.pos, c);
2295 SetCharFont(cursor.par, cursor.pos, rawtmpfont);
2297 if (!jumped_over_space) {
2298 /* refresh the positions */
2300 while (tmprow->next && tmprow->next->par == row->par) {
2301 tmprow = tmprow->next;
2306 /* Is there a break one row above */
2307 if ((cursor.par->IsLineSeparator(cursor.pos)
2308 || cursor.par->IsNewline(cursor.pos)
2309 || cursor.row->fill == -1)
2310 && row->previous && row->previous->par == row->par) {
2311 LyXParagraph::size_type z = NextBreakPoint(row->previous,
2313 if ( z >= row->pos) {
2316 /* set the dimensions of the row above */
2317 row->previous->fill = Fill(row->previous, paperwidth);
2319 SetHeightOfRow(row->previous);
2321 y -= row->previous->height;
2323 refresh_row = row->previous;
2324 status = LyXText::NEED_MORE_REFRESH;
2326 BreakAgainOneRow(row);
2327 SetCursor(cursor.par, cursor.pos + 1);
2328 /* cursor MUST be in row now */
2330 if (row->next && row->next->par == row->par)
2331 need_break_row = row->next;
2335 current_font = rawtmpfont;
2336 real_current_font = realtmpfont;
2338 // check, wether the last characters font has changed.
2339 if (cursor.pos && cursor.pos == cursor.par->Last()
2340 && rawparfont != rawtmpfont)
2341 RedoHeightOfParagraph(cursor);
2348 /* recalculate the fill of the row */
2349 if (row->fill >= 0) /* needed because a newline
2350 * will set fill to -1. Otherwise
2351 * we would not get a rebreak! */
2352 row->fill = Fill(row, paperwidth);
2353 if (row->fill < 0 ) {
2356 refresh_x = cursor.x;
2357 refresh_pos = cursor.pos;
2358 status = LyXText::NEED_MORE_REFRESH;
2359 BreakAgainOneRow(row);
2360 /* will the cursor be in another row now? */
2361 if (RowLast(row) <= cursor.pos + 1 && row->next) {
2362 if (row->next && row->next->par == row->par)
2366 BreakAgainOneRow(row);
2368 SetCursor(cursor.par, cursor.pos + 1);
2369 if (row->next && row->next->par == row->par)
2370 need_break_row = row->next;
2374 current_font = rawtmpfont;
2375 real_current_font = realtmpfont;
2378 refresh_x = cursor.x;
2380 refresh_pos = cursor.pos;
2382 int tmpheight = row->height;
2383 SetHeightOfRow(row);
2384 if (tmpheight == row->height)
2385 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2387 status = LyXText::NEED_MORE_REFRESH;
2389 SetCursor(cursor.par, cursor.pos + 1);
2390 current_font = rawtmpfont;
2391 real_current_font = realtmpfont;
2394 /* check, wether the last characters font has changed. */
2395 if (cursor.pos && cursor.pos == cursor.par->Last()
2396 && rawparfont != rawtmpfont) {
2397 RedoHeightOfParagraph(cursor);
2399 /* now the special right address boxes */
2400 if (textclasslist.Style(parameters->textclass,
2401 cursor.par->GetLayout()).margintype
2402 == MARGIN_RIGHT_ADDRESS_BOX) {
2403 RedoDrawingOfParagraph(cursor);
2411 void LyXText::charInserted()
2413 // Here we could call FinishUndo for every 20 characters inserted.
2414 // This is from my experience how emacs does it.
2415 static unsigned int counter = 0;
2425 void LyXText::PrepareToPrint(Row * row, float & x, float & fill_separator,
2426 float & fill_hfill, float & fill_label_hfill)
2430 float w = row->fill;
2432 fill_label_hfill = 0;
2434 fill_label_hfill = 0;
2436 x = LeftMargin(row);
2438 /* is there a manual margin with a manual label */
2439 if (textclasslist.Style(parameters->textclass,
2440 row->par->GetLayout()).margintype == MARGIN_MANUAL
2441 && textclasslist.Style(parameters->textclass,
2442 row->par->GetLayout()).labeltype == LABEL_MANUAL) {
2444 nlh = NumberOfLabelHfills(row) + 1; /* one more since labels
2445 * are left aligned*/
2446 if (nlh && !row->par->GetLabelWidthString().empty()) {
2447 fill_label_hfill = LabelFill(row) / nlh;
2451 /* are there any hfills in the row? */
2452 nh = NumberOfHfills(row);
2454 /* table stuff -- begin*/
2455 if (row->par->table) {
2456 w = paperwidth - row->par->table->WidthOfTable()
2457 - x - RightMargin(row);
2458 nh = 0; /* ignore hfills in tables */
2460 /* table stuff -- end*/
2465 /* is it block, flushleft or flushright?
2466 * set x how you need it */
2468 if (row->par->FirstPhysicalPar()->align == LYX_ALIGN_LAYOUT)
2469 align = textclasslist.Style(parameters->textclass, row->par->GetLayout()).align;
2471 align = row->par->FirstPhysicalPar()->align;
2473 /* center displayed insets */
2474 if (row->par->GetChar(row->pos) == LyXParagraph::META_INSET
2475 && row->par->GetInset(row->pos)
2476 && row->par->GetInset(row->pos)->display())
2477 align = LYX_ALIGN_CENTER;
2480 case LYX_ALIGN_BLOCK:
2481 ns = NumberOfSeparators(row);
2482 if (ns && row->next && row->next->par == row->par &&
2483 !(row->next->par->IsNewline(row->next->pos-1))
2484 && !(row->next->par->GetChar(row->next->pos) == LyXParagraph::META_INSET
2485 && row->next->par->GetInset(row->next->pos)
2486 && row->next->par->GetInset(row->next->pos)->display())
2488 fill_separator = w / ns;
2490 case LYX_ALIGN_RIGHT:
2493 case LYX_ALIGN_CENTER:
2501 /* important for the screen */
2504 /* the cursor set functions have a special mechanism. When they
2505 * realize, that you left an empty paragraph, they will delete it.
2506 * They also delete the corresponding row */
2508 void LyXText::CursorRightOneWord()
2510 // treat floats, HFills and Insets as words
2511 LyXCursor tmpcursor = cursor;
2513 if (tmpcursor.pos == tmpcursor.par->Last()
2514 && tmpcursor.par->Next())
2516 tmpcursor.par = tmpcursor.par->Next();
2521 // Skip through initial nonword stuff.
2522 while ( tmpcursor.pos < tmpcursor.par->Last() &&
2523 ! tmpcursor.par->IsWord( tmpcursor.pos ) )
2525 // printf("Current pos1 %d", tmpcursor.pos) ;
2529 // Advance through word.
2530 while ( tmpcursor.pos < tmpcursor.par->Last() &&
2531 tmpcursor.par->IsWord( tmpcursor.pos ) )
2533 // printf("Current pos2 %d", tmpcursor.pos) ;
2538 SetCursor(tmpcursor.par, tmpcursor.pos);
2542 void LyXText::CursorTab()
2544 if (cursor.par->table) {
2545 int cell = NumberOfCell(cursor.par, cursor.pos);
2546 while(cursor.par->table->IsContRow(cell)) {
2548 cell = NumberOfCell(cursor.par, cursor.pos);
2550 if (cursor.par->table->ShouldBeVeryLastCell(cell))
2551 TableFeatures(LyXTable::APPEND_ROW);
2553 LyXCursor tmpcursor = cursor;
2554 while (tmpcursor.pos < tmpcursor.par->Last()
2555 && !tmpcursor.par->IsNewline(tmpcursor.pos))
2558 if (tmpcursor.pos == tmpcursor.par->Last()){
2559 if (tmpcursor.par->Next()) {
2560 tmpcursor.par = tmpcursor.par->Next();
2566 SetCursor(tmpcursor.par, tmpcursor.pos);
2567 if (cursor.par->table) {
2568 int cell = NumberOfCell(cursor.par, cursor.pos);
2569 while (cursor.par->table->IsContRow(cell) &&
2570 !cursor.par->table->ShouldBeVeryLastCell(cell)) {
2572 while (tmpcursor.pos < tmpcursor.par->Last()
2573 && !tmpcursor.par->IsNewline(tmpcursor.pos))
2576 if (tmpcursor.pos == tmpcursor.par->Last()){
2577 if (tmpcursor.par->Next()) {
2578 tmpcursor.par = tmpcursor.par->Next();
2584 SetCursor(tmpcursor.par, tmpcursor.pos);
2585 cell = NumberOfCell(cursor.par, cursor.pos);
2591 /* -------> Skip initial whitespace at end of word and move cursor to *start*
2592 of prior word, not to end of next prior word. */
2594 void LyXText::CursorLeftOneWord()
2596 // treat HFills, floats and Insets as words
2597 LyXCursor tmpcursor = cursor;
2598 while (tmpcursor.pos
2599 && (tmpcursor.par->IsSeparator(tmpcursor.pos - 1)
2600 || tmpcursor.par->IsKomma(tmpcursor.pos - 1))
2601 && !(tmpcursor.par->IsHfill(tmpcursor.pos - 1)
2602 || tmpcursor.par->IsFloat(tmpcursor.pos - 1)
2603 || tmpcursor.par->IsInset(tmpcursor.pos - 1)))
2607 && (tmpcursor.par->IsInset(tmpcursor.pos - 1)
2608 || tmpcursor.par->IsFloat(tmpcursor.pos - 1)
2609 || tmpcursor.par->IsHfill(tmpcursor.pos - 1))) {
2611 } else if (!tmpcursor.pos) {
2612 if (tmpcursor.par->Previous()){
2613 tmpcursor.par = tmpcursor.par->Previous();
2614 tmpcursor.pos = tmpcursor.par->Last();
2616 } else { // Here, tmpcursor != 0
2617 while (tmpcursor.pos > 0 &&
2618 tmpcursor.par->IsWord(tmpcursor.pos-1) )
2621 SetCursor(tmpcursor.par, tmpcursor.pos);
2624 /* -------> Select current word. This depends on behaviour of CursorLeftOneWord(), so it is
2627 void LyXText::SelectWord()
2629 /* Move cursor to the beginning, when not already there. */
2631 && !cursor.par->IsSeparator(cursor.pos-1)
2632 && !cursor.par->IsKomma(cursor.pos-1) )
2633 CursorLeftOneWord();
2635 /* set the sel cursor */
2636 sel_cursor = cursor;
2638 while ( cursor.pos < cursor.par->Last()
2639 && !cursor.par->IsSeparator(cursor.pos)
2640 && !cursor.par->IsKomma(cursor.pos) )
2642 SetCursor( cursor.par, cursor.pos );
2644 /* finally set the selection */
2649 /* -------> Select the word currently under the cursor when:
2650 1: no selection is currently set,
2651 2: the cursor is not at the borders of the word. */
2653 int LyXText::SelectWordWhenUnderCursor()
2655 if ( selection ) return 0;
2656 if ( cursor.pos < cursor.par->Last()
2657 && !cursor.par->IsSeparator(cursor.pos)
2658 && !cursor.par->IsKomma(cursor.pos)
2660 && !cursor.par->IsSeparator(cursor.pos -1)
2661 && !cursor.par->IsKomma(cursor.pos -1) ) {
2669 // This function is only used by the spellchecker for NextWord().
2670 // It doesn't handle LYX_ACCENTs and probably never will.
2671 char * LyXText::SelectNextWord(float & value)
2673 LyXParagraph * tmppar = cursor.par;
2675 // If this is not the very first word, skip rest of
2676 // current word because we are probably in the middle
2677 // of a word if there is text here.
2678 if (cursor.pos || cursor.par->previous) {
2679 while (cursor.pos < cursor.par->Last()
2680 && cursor.par->IsLetter(cursor.pos))
2683 // Now, skip until we have real text (will jump paragraphs)
2684 while ((cursor.par->Last() > cursor.pos
2685 && (!cursor.par->IsLetter(cursor.pos)
2686 || cursor.par->getFont(cursor.pos).latex() == LyXFont::ON))
2687 || (cursor.par->Last() == cursor.pos
2688 && cursor.par->Next())){
2689 if (cursor.pos == cursor.par->Last()) {
2690 cursor.par = cursor.par->Next();
2697 // Update the value if we changed paragraphs
2698 if (cursor.par != tmppar){
2699 SetCursor(cursor.par, cursor.pos);
2700 value = float(cursor.y)/float(height);
2703 /* Start the selection from here */
2704 sel_cursor = cursor;
2708 /* and find the end of the word
2709 (optional hyphens are part of a word) */
2710 while (cursor.pos < cursor.par->Last()
2711 && (cursor.par->IsLetter(cursor.pos))
2712 || (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET &&
2713 cursor.par->GetInset(cursor.pos) != 0 &&
2714 cursor.par->GetInset(cursor.pos)->Latex(latex, 0) == 0 &&
2718 // Finally, we copy the word to a string and return it
2721 if (sel_cursor.pos < cursor.pos) {
2722 str = new char [cursor.pos - sel_cursor.pos + 2];
2723 LyXParagraph::size_type i, j;
2724 for (i = sel_cursor.pos, j = 0; i < cursor.pos; ++i) {
2725 if (cursor.par->GetChar(i) != LyXParagraph::META_INSET)
2726 str[j++] = cursor.par->GetChar(i);
2734 // This one is also only for the spellchecker
2735 void LyXText::SelectSelectedWord()
2737 /* move cursor to the beginning */
2738 SetCursor(sel_cursor.par, sel_cursor.pos);
2740 /* set the sel cursor */
2741 sel_cursor = cursor;
2745 /* now find the end of the word */
2746 while (cursor.pos < cursor.par->Last()
2747 && (cursor.par->IsLetter(cursor.pos)
2748 || (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET &&
2749 cursor.par->GetInset(cursor.pos) != 0 &&
2750 cursor.par->GetInset(cursor.pos)->Latex(latex, 0) == 0 &&
2754 SetCursor(cursor.par, cursor.pos);
2756 /* finally set the selection */
2761 /* -------> Delete from cursor up to the end of the current or next word. */
2762 void LyXText::DeleteWordForward()
2764 LyXCursor tmpcursor = cursor;
2766 if (!cursor.par->Last())
2769 /* -------> Skip initial non-word stuff. */
2770 while ( cursor.pos < cursor.par->Last()
2771 && (cursor.par->IsSeparator(cursor.pos)
2772 || cursor.par->IsKomma(cursor.pos)) )
2775 SetCursorIntern(cursor.par, cursor.pos);
2776 selection = True; // to avoid deletion
2777 CursorRightOneWord();
2778 sel_cursor = cursor;
2782 /* -----> Great, CutSelection() gets rid of multiple spaces. */
2788 /* -------> Delete from cursor to start of current or prior word. */
2789 void LyXText::DeleteWordBackward()
2791 LyXCursor tmpcursor = cursor;
2792 if (!cursor.par->Last())
2795 selection = true; // to avoid deletion
2796 CursorLeftOneWord();
2797 sel_cursor = cursor;
2805 /* -------> Kill to end of line. */
2806 void LyXText::DeleteLineForward()
2808 LyXCursor tmpcursor = cursor;
2809 if (!cursor.par->Last())
2813 sel_cursor = cursor;
2816 if (selection == false) {
2817 DeleteWordForward();
2825 // Change the case of a word at cursor position. The meaning of action
2827 // 0 change to lowercase
2828 // 1 capitalize word
2829 // 2 change to uppercase
2830 // This function directly manipulates LyXParagraph::text because there
2831 // is no LyXParagraph::SetChar currently. I did what I could to ensure
2832 // that it is correct. I guess part of it should be moved to
2833 // LyXParagraph, but it will have to change for 1.1 anyway. At least
2834 // it does not access outside of the allocated array as the older
2835 // version did. (JMarc)
2836 void LyXText::ChangeWordCase(LyXText::TextCase action)
2838 LyXParagraph * tmppar = cursor.par->ParFromPos(cursor.pos);
2840 SetUndo(Undo::FINISH, tmppar->previous, tmppar->next);
2842 LyXParagraph::size_type tmppos =
2843 cursor.par->PositionInParFromPos(cursor.pos);
2844 while (tmppos < tmppar->size()) {
2845 unsigned char c = tmppar->text[tmppos];
2846 if (IsKommaChar(c) || IsLineSeparatorChar(c))
2848 if (c != LyXParagraph::META_INSET) {
2850 case text_lowercase:
2853 case text_capitalization:
2855 action = text_lowercase;
2857 case text_uppercase:
2863 tmppar->text[tmppos] = c;
2866 CheckParagraph(tmppar, tmppos);
2867 CursorRightOneWord();
2871 void LyXText::Delete()
2873 LyXCursor old_cursor = cursor;
2874 /* this is a very easy implementation*/
2876 /* just move to the right */
2877 CursorRightIntern();
2879 if (cursor.par->previous == old_cursor.par->previous
2880 && cursor.par != old_cursor.par)
2881 return; // delete-emty-paragraph-mechanism has done it
2883 /* if you had success make a backspace */
2884 if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) {
2885 LyXCursor tmpcursor = cursor;
2886 cursor = old_cursor; // to make sure undo gets the right cursor position
2887 SetUndo(Undo::DELETE,
2888 cursor.par->ParFromPos(cursor.pos)->previous,
2889 cursor.par->ParFromPos(cursor.pos)->next);
2896 void LyXText::Backspace()
2898 LyXParagraph * tmppar;
2899 Row * tmprow, * row;
2903 /* table stuff -- begin*/
2905 if (cursor.par->table) {
2909 /* table stuff -- end*/
2911 LyXFont rawtmpfont = current_font;
2912 LyXFont realtmpfont = real_current_font;
2914 // Get the font that is used to calculate the baselineskip
2915 int const lastpos = cursor.par->Last();
2916 LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2918 if (cursor.pos == 0) {
2919 /* we may paste some paragraphs */
2921 /* is it an empty paragraph? */
2924 || (lastpos == 1 && cursor.par->IsSeparator(0)))
2925 && !(cursor.par->Next()
2926 && cursor.par->footnoteflag ==
2927 LyXParagraph::NO_FOOTNOTE
2928 && cursor.par->Next()->footnoteflag ==
2929 LyXParagraph::OPEN_FOOTNOTE)) {
2931 if (cursor.par->previous) {
2932 tmppar = cursor.par->previous->FirstPhysicalPar();
2933 if (cursor.par->GetLayout() == tmppar->GetLayout()
2934 && cursor.par->footnoteflag == tmppar->footnoteflag
2935 && cursor.par->GetAlign() == tmppar->GetAlign()) {
2937 tmppar->line_bottom = cursor.par->line_bottom;
2938 tmppar->added_space_bottom = cursor.par->added_space_bottom;
2939 tmppar->pagebreak_bottom = cursor.par->pagebreak_bottom;
2944 /* the layout things can change the height of a row ! */
2945 tmpheight = cursor.row->height;
2946 SetHeightOfRow(cursor.row);
2947 if (cursor.row->height != tmpheight) {
2948 refresh_y = cursor.y - cursor.row->baseline;
2949 refresh_row = cursor.row;
2950 status = LyXText::NEED_MORE_REFRESH;
2955 if (cursor.par->ParFromPos(cursor.pos)->previous){
2956 SetUndo(Undo::DELETE,
2957 cursor.par->ParFromPos(cursor.pos)->previous->previous,
2958 cursor.par->ParFromPos(cursor.pos)->next);
2960 tmppar = cursor.par;
2961 tmprow = cursor.row;
2963 /* Pasting is not allowed, if the paragraphs have different
2964 layout. I think it is a real bug of all other
2965 word processors to allow it. It confuses the user.
2966 Even so with a footnote paragraph and a non-footnote
2967 paragraph. I will not allow pasting in this case,
2968 because the user would be confused if the footnote behaves
2969 different wether it is open or closed.
2971 Correction: Pasting is always allowed with standard-layout
2973 if (cursor.par != tmppar
2974 && (cursor.par->GetLayout() == tmppar->GetLayout()
2975 || !tmppar->GetLayout())
2976 && cursor.par->footnoteflag == tmppar->footnoteflag
2977 /* table stuff -- begin*/
2978 && !cursor.par->table /* no pasting of tables */
2979 /* table stuff -- end*/
2980 && cursor.par->GetAlign() == tmppar->GetAlign()) {
2982 cursor.par->PasteParagraph();
2985 cursor.par->IsSeparator(cursor.pos - 1)))
2986 cursor.par->InsertChar(cursor.pos, ' ');
2991 status = LyXText::NEED_MORE_REFRESH;
2992 refresh_row = cursor.row;
2993 refresh_y = cursor.y - cursor.row->baseline;
2995 /* remove the lost paragraph */
2996 RemoveParagraph(tmprow);
2999 AppendParagraph(cursor.row);
3000 UpdateCounters(cursor.row);
3002 /* the row may have changed, block, hfills etc. */
3003 SetCursor(cursor.par, cursor.pos);
3006 /* this is the code for a normal backspace, not pasting
3008 SetUndo(Undo::DELETE,
3009 cursor.par->ParFromPos(cursor.pos)->previous,
3010 cursor.par->ParFromPos(cursor.pos)->next);
3013 /* some insets are undeletable here */
3014 if (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
3015 if (!cursor.par->GetInset(cursor.pos)->Deletable())
3017 /* force complete redo when erasing display insets */
3018 /* this is a cruel mathod but save..... Matthias */
3019 if (cursor.par->GetInset(cursor.pos)->display()){
3020 cursor.par->Erase(cursor.pos);
3027 y = cursor.y - row->baseline;
3028 LyXParagraph::size_type z;
3029 /* remember that a space at the end of a row doesnt count
3030 * when calculating the fill */
3031 if (cursor.pos < RowLast(row) ||
3032 !cursor.par->IsLineSeparator(cursor.pos)) {
3033 row->fill += SingleWidth(cursor.par, cursor.pos);
3036 /* some special code when deleting a newline. This is similar
3037 * to the behavior when pasting paragraphs */
3038 if (cursor.pos && cursor.par->IsNewline(cursor.pos)) {
3039 cursor.par->Erase(cursor.pos);
3040 /* refresh the positions */
3042 while (tmprow->next && tmprow->next->par == row->par) {
3043 tmprow = tmprow->next;
3046 if (cursor.par->IsLineSeparator(cursor.pos - 1))
3049 if (cursor.pos < cursor.par->Last() && !cursor.par->IsSeparator(cursor.pos)) {
3050 cursor.par->InsertChar(cursor.pos, ' ');
3051 /* refresh the positions */
3053 while (tmprow->next && tmprow->next->par == row->par) {
3054 tmprow = tmprow->next;
3059 cursor.par->Erase(cursor.pos);
3061 /* refresh the positions */
3063 while (tmprow->next && tmprow->next->par == row->par) {
3064 tmprow = tmprow->next;
3068 /* delete superfluous blanks */
3069 if (cursor.pos < cursor.par->Last() - 1 &&
3070 (cursor.par->IsLineSeparator(cursor.pos))) {
3072 if (cursor.pos == BeginningOfMainBody(cursor.par)
3074 || cursor.par->IsLineSeparator(cursor.pos - 1)) {
3075 cursor.par->Erase(cursor.pos);
3076 /* refresh the positions */
3078 while (tmprow->next &&
3079 tmprow->next->par == row->par) {
3080 tmprow = tmprow->next;
3083 if (cursor.pos) /* move one character left */
3088 /* delete newlines at the beginning of paragraphs */
3089 while (cursor.par->Last() &&
3090 cursor.par->IsNewline(cursor.pos) &&
3091 cursor.pos == BeginningOfMainBody(cursor.par)) {
3092 cursor.par->Erase(cursor.pos);
3093 /* refresh the positions */
3095 while (tmprow->next &&
3096 tmprow->next->par == row->par) {
3097 tmprow = tmprow->next;
3103 /* is there a break one row above */
3104 if (row->previous && row->previous->par == row->par) {
3105 z = NextBreakPoint(row->previous, paperwidth);
3106 if ( z >= row->pos) {
3109 tmprow = row->previous;
3111 /* maybe the current row is now empty */
3112 if (row->pos >= row->par->Last()) {
3118 BreakAgainOneRow(row);
3119 if (row->next && row->next->par == row->par)
3120 need_break_row = row->next;
3125 /* set the dimensions of the row above */
3126 y -= tmprow->height;
3127 tmprow->fill = Fill(tmprow, paperwidth);
3128 SetHeightOfRow(tmprow);
3131 refresh_row = tmprow;
3132 status = LyXText::NEED_MORE_REFRESH;
3133 SetCursor(cursor.par, cursor.pos);
3134 current_font = rawtmpfont;
3135 real_current_font = realtmpfont;
3136 /* check, whether the last character's font has changed. */
3137 rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
3138 if (rawparfont != rawtmpfont)
3139 RedoHeightOfParagraph(cursor);
3144 /* break the cursor row again */
3145 z = NextBreakPoint(row, paperwidth);
3147 if ( z != RowLast(row) ||
3148 (row->next && row->next->par == row->par &&
3149 RowLast(row) == row->par->Last() - 1)){
3151 /* it can happen that a paragraph loses one row
3152 * without a real breakup. This is when a word
3153 * is to long to be broken. Well, I don t care this
3155 if (row->next && row->next->par == row->par &&
3156 RowLast(row) == row->par->Last() - 1)
3157 RemoveRow(row->next);
3161 status = LyXText::NEED_MORE_REFRESH;
3163 BreakAgainOneRow(row);
3165 SetCursor(cursor.par, cursor.pos);
3166 /* cursor MUST be in row now */
3168 if (row->next && row->next->par == row->par)
3169 need_break_row = row->next;
3173 /* set the dimensions of the row */
3174 row->fill = Fill(row, paperwidth);
3175 int tmpheight = row->height;
3176 SetHeightOfRow(row);
3177 if (tmpheight == row->height)
3178 status = LyXText::NEED_VERY_LITTLE_REFRESH;
3180 status = LyXText::NEED_MORE_REFRESH;
3183 SetCursor(cursor.par, cursor.pos);
3187 /* restore the current font
3188 * That is what a user expects! */
3189 current_font = rawtmpfont;
3190 real_current_font = realtmpfont;
3192 /* check, wether the last characters font has changed. */
3193 rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
3194 if (rawparfont != rawtmpfont) {
3195 RedoHeightOfParagraph(cursor);
3197 /* now the special right address boxes */
3198 if (textclasslist.Style(parameters->textclass,
3199 cursor.par->GetLayout()).margintype == MARGIN_RIGHT_ADDRESS_BOX) {
3200 RedoDrawingOfParagraph(cursor);
3206 void LyXText::GetVisibleRow(LyXScreen & scr, int offset,
3207 Row * row_ptr, long y)
3209 /* returns a printed row */
3210 LyXParagraph::size_type pos, pos_end;
3212 int y_top, y_bottom;
3213 float fill_separator, fill_hfill, fill_label_hfill;
3214 LyXParagraph * par, * firstpar;
3218 if (row_ptr->height <= 0) {
3219 lyxerr << "LYX_ERROR: row.height: " << row_ptr->height << endl;
3222 left_margin = LabelEnd(row_ptr);
3223 PrepareToPrint(row_ptr, x, fill_separator,
3224 fill_hfill, fill_label_hfill);
3226 LyXParagraph::size_type main_body =
3227 BeginningOfMainBody(row_ptr->par);
3228 /* initialize the pixmap */
3230 scr.fillRectangle(gc_clear,
3231 0, offset, paperwidth, row_ptr->height);
3232 // check for NOT FAST SELECTION
3233 if (!fast_selection && !mono_video && selection) {
3234 /* selection code */
3235 if (sel_start_cursor.row == row_ptr &&
3236 sel_end_cursor.row == row_ptr) {
3237 scr.fillRectangle(gc_selection, sel_start_cursor.x,
3243 else if (sel_start_cursor.row == row_ptr) {
3244 scr.fillRectangle(gc_selection, sel_start_cursor.x,
3246 paperwidth - sel_start_cursor.x,
3248 } else if (sel_end_cursor.row == row_ptr) {
3249 scr.fillRectangle(gc_selection, 0, offset,
3250 sel_end_cursor.x, row_ptr->height);
3251 } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
3252 scr.fillRectangle(gc_selection, 0, offset,
3253 paperwidth, row_ptr->height);
3256 } // end of NOT FAST SELECTION code
3258 if (row_ptr->par->appendix){
3259 scr.drawVerticalLine(gc_math, 1, offset, offset+row_ptr->height);
3260 scr.drawVerticalLine(gc_math, paperwidth-2 , offset, offset+row_ptr->height);
3263 if (row_ptr->par->pextra_type == LyXParagraph::PEXTRA_MINIPAGE) {
3264 /* draw a marker at the left margin! */
3265 LyXFont font = GetFont(row_ptr->par, 0);
3266 int asc = font.maxAscent();
3267 int x = (LYX_PAPER_MARGIN - font.width('|')) / 2;
3268 int y1 = (offset + row_ptr->baseline);
3269 int y2 = (offset + row_ptr->baseline) - asc;
3271 scr.drawVerticalLine(gc_minipage, x, y1, y2);
3273 if (row_ptr->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3274 LyXFont font(LyXFont::ALL_SANE);
3275 font.setSize(LyXFont::SIZE_FOOTNOTE);
3276 font.setColor(LyXFont::RED);
3278 int box_x = LYX_PAPER_MARGIN;
3279 box_x += font.textWidth(" wide-tab ", 10);
3280 if (row_ptr->previous &&
3281 row_ptr->previous->par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
3283 switch (row_ptr->par->footnotekind) {
3284 case LyXParagraph::MARGIN:
3287 case LyXParagraph::FIG:
3290 case LyXParagraph::TAB:
3293 case LyXParagraph::WIDE_FIG:
3296 case LyXParagraph::WIDE_TAB:
3299 case LyXParagraph::ALGORITHM:
3302 case LyXParagraph::FOOTNOTE:
3307 // Determine background color.
3308 gc_type back = gc_lighted;
3312 scr.fillRectangle(back, LYX_PAPER_MARGIN, offset+1,
3313 box_x - LYX_PAPER_MARGIN,
3314 int(font.maxAscent())+
3315 int(font.maxDescent()));
3317 scr.drawLine(gc_foot,
3320 paperwidth - 2*LYX_PAPER_MARGIN);
3322 scr.drawString(font, fs,
3323 offset + int(font.maxAscent())+1,
3325 scr.drawVerticalLine(gc_foot,
3329 + int(font.maxAscent())+
3330 int(font.maxDescent()));
3332 scr.drawLine(gc_foot,
3334 + int(font.maxAscent())
3335 + int(font.maxDescent()) + 1,
3336 LYX_PAPER_MARGIN, box_x - LYX_PAPER_MARGIN);
3339 /* draw the open floats in a red box */
3340 scr.drawVerticalLine(gc_foot,
3342 offset, offset + row_ptr->height);
3344 scr.drawVerticalLine(gc_foot,
3345 paperwidth - LYX_PAPER_MARGIN,
3347 offset + row_ptr->height);
3351 if (row_ptr->previous &&
3352 row_ptr->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3353 LyXFont font(LyXFont::ALL_SANE);
3354 font.setSize(LyXFont::SIZE_FOOTNOTE);
3356 int box_x = LYX_PAPER_MARGIN;
3357 box_x += font.textWidth(" wide-tab ", 10);
3359 scr.drawLine(gc_foot,
3362 paperwidth - LYX_PAPER_MARGIN - box_x);
3366 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
3367 row_ptr->par->GetLayout());
3368 firstpar = row_ptr->par->FirstPhysicalPar();
3371 y_bottom = row_ptr->height;
3373 /* is it a first row? */
3374 if (row_ptr->pos == 0
3375 && row_ptr->par == firstpar) {
3377 /* start of appendix? */
3378 if (row_ptr->par->start_of_appendix){
3379 scr.drawLine(gc_math,
3384 /* think about the margins */
3385 if (!row_ptr->previous)
3386 y_top += LYX_PAPER_MARGIN;
3388 if (row_ptr->par->pagebreak_top){ /* draw a top pagebreak */
3389 scr.drawOnOffLine(offset + y_top + 2 * DefaultHeight(),
3391 y_top += 3 * DefaultHeight();
3394 if (row_ptr->par->added_space_top.kind() == VSpace::VFILL) {
3395 /* draw a vfill top */
3396 scr.drawLine(gc_fill,
3398 0, LYX_PAPER_MARGIN);
3399 scr.drawLine(gc_fill,
3400 offset + y_top + 3 * DefaultHeight(),
3401 0, LYX_PAPER_MARGIN);
3402 scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2,
3404 offset + y_top + 3 *
3407 y_top += 3 * DefaultHeight();
3410 /* think about user added space */
3411 y_top += int(row_ptr->par->added_space_top.inPixels());
3413 /* think about the parskip */
3414 /* some parskips VERY EASY IMPLEMENTATION */
3415 if (parameters->paragraph_separation == BufferParams::PARSEP_SKIP) {
3416 if (layout.latextype == LATEX_PARAGRAPH
3417 && firstpar->GetDepth() == 0
3418 && firstpar->Previous())
3419 y_top += parameters->getDefSkip().inPixels();
3420 else if (firstpar->Previous()
3421 && textclasslist.Style(parameters->textclass,
3422 firstpar->Previous()->GetLayout()).latextype == LATEX_PARAGRAPH
3423 && firstpar->Previous()->GetDepth() == 0)
3424 // is it right to use defskip here, too? (AS)
3425 y_top += parameters->getDefSkip().inPixels();
3428 if (row_ptr->par->line_top) { /* draw a top line */
3429 y_top += GetFont(row_ptr->par, 0).ascent('x');
3431 scr.drawThickLine(offset + y_top,
3433 y_top += GetFont(row_ptr->par, 0).ascent('x');
3436 /* should we print a label? */
3437 if (layout.labeltype >= LABEL_STATIC
3438 && (layout.labeltype != LABEL_STATIC
3439 || layout.latextype != LATEX_ENVIRONMENT
3440 || row_ptr->par->IsFirstInSequence())) {
3441 font = GetFont(row_ptr->par, -2);
3442 if (!row_ptr->par->GetLabestring().empty()) {
3444 string tmpstring = row_ptr->par->GetLabestring();
3446 if (layout.labeltype == LABEL_COUNTER_CHAPTER) {
3447 if (parameters->secnumdepth >= 0){
3448 /* this is special code for the chapter layout. This is printed in
3449 * an extra row and has a pagebreak at the top. */
3450 maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue())
3451 + int(layout.parsep) * DefaultHeight();
3452 scr.drawString(font, tmpstring,
3453 offset + row_ptr->baseline
3454 - row_ptr->ascent_of_text - maxdesc,
3458 x -= font.stringWidth( layout.labelsep);
3459 x -= font.stringWidth( tmpstring);
3461 scr.drawString(font, tmpstring,
3462 offset + row_ptr->baseline, int(x));
3466 /* the labels at the top of an environment. More or less for bibliography */
3467 } else if (layout.labeltype == LABEL_TOP_ENVIRONMENT ||
3468 layout.labeltype == LABEL_BIBLIO ||
3469 layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) {
3470 if (row_ptr->par->IsFirstInSequence()) {
3471 font = GetFont(row_ptr->par, -2);
3472 if (!row_ptr->par->GetLabestring().empty()) {
3473 string tmpstring = row_ptr->par->GetLabestring();
3475 maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue()
3476 + (layout.labelbottomsep * DefaultHeight()));
3478 int top_label_x = int(x);
3479 if (layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT){
3480 top_label_x = int(x + (paperwidth - RightMargin(row_ptr) - x) / 2);
3481 top_label_x -= (font.stringWidth( tmpstring)/2);
3484 scr.drawString(font, tmpstring,
3485 offset + row_ptr->baseline
3486 - row_ptr->ascent_of_text - maxdesc,
3491 if (layout.labeltype == LABEL_BIBLIO) { // ale970302
3492 if (row_ptr->par->bibkey) {
3494 x -= font.stringWidth(layout.labelsep);
3495 font = GetFont(row_ptr->par, -1);
3496 x -= row_ptr->par->bibkey->Width(font);
3497 row_ptr->par->bibkey->Draw(font, scr,
3498 offset + row_ptr->baseline,
3505 /* is it a last row? */
3506 par = row_ptr->par->LastPhysicalPar();
3507 if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
3508 && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {
3510 /* think about the margins */
3512 y_bottom -= LYX_PAPER_MARGIN;
3514 /* draw a bottom pagebreak */
3515 if (firstpar->pagebreak_bottom) {
3516 scr.drawOnOffLine(offset + y_bottom - 2 *
3519 y_bottom -= 3 * DefaultHeight();
3522 if (firstpar->added_space_bottom.kind() == VSpace::VFILL) {
3523 /* draw a vfill bottom */
3524 scr.drawLine(gc_fill,
3525 offset + y_bottom - 3 * DefaultHeight(),
3526 0, LYX_PAPER_MARGIN);
3527 scr.drawLine(gc_fill, offset + y_bottom - 2,
3528 0, LYX_PAPER_MARGIN);
3529 scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2,
3530 offset + y_bottom - 3 * DefaultHeight(),
3531 offset + y_bottom - 2
3533 y_bottom -= 3* DefaultHeight();
3536 /* think about user added space */
3537 y_bottom -= int(firstpar->added_space_bottom.inPixels());
3539 if (firstpar->line_bottom) {
3540 /* draw a bottom line */
3541 y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
3543 scr.drawThickLine(offset + y_bottom,
3545 y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
3549 /* draw the text in the pixmap */
3550 pos_end = RowLast(row_ptr);
3553 /* table stuff -- begin*/
3554 if (row_ptr->par->table) {
3556 int cell = NumberOfCell(row_ptr->par, row_ptr->pos);
3558 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
3560 while (pos <= pos_end) {
3561 if (row_ptr->par->IsNewline(pos)) {
3563 x = x_old + row_ptr->par->table->WidthOfColumn(cell);
3564 /* draw the table lines, still very simple */
3565 on_off = !row_ptr->par->table->TopLine(cell);
3567 !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
3568 !row_ptr->par->table->IsContRow(cell))
3569 scr.drawTableLine(offset + row_ptr->baseline -
3570 row_ptr->ascent_of_text,
3571 int(x_old), int(x - x_old), on_off);
3572 on_off = !row_ptr->par->table->BottomLine(cell);
3573 if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
3574 row_ptr->par->table->VeryLastRow(cell))
3575 scr.drawTableLine(offset + y_bottom - 1,
3576 int(x_old), int(x - x_old), on_off);
3577 on_off = !row_ptr->par->table->LeftLine(cell);
3579 scr.drawVerticalTableLine(int(x_old),
3580 offset + row_ptr->baseline -
3581 row_ptr->ascent_of_text,
3582 offset + y_bottom - 1,
3584 on_off = !row_ptr->par->table->RightLine(cell);
3586 scr.drawVerticalTableLine(int(x) -
3587 row_ptr->par->table->AdditionalWidth(cell),
3588 offset + row_ptr->baseline -
3589 row_ptr->ascent_of_text,
3590 offset + y_bottom - 1,
3593 /* take care about the alignment and other spaces */
3595 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
3596 if (row_ptr->par->table->IsFirstCell(cell))
3597 cell--; // little hack, sorry
3599 } else if (row_ptr->par->IsHfill(pos)) {
3602 scr.drawVerticalLine(gc_fill, int(x),
3603 offset + row_ptr->baseline - DefaultHeight()/2,
3604 offset + row_ptr->baseline);
3608 if (row_ptr->par->IsSeparator(pos)) {
3610 x+= SingleWidth(row_ptr->par, pos);
3611 /* -------> Only draw protected spaces when not in
3612 * free-spacing mode. */
3613 if (row_ptr->par->GetChar(pos) == LyXParagraph::META_PROTECTED_SEPARATOR && !layout.free_spacing) {
3614 scr.drawVerticalLine(gc_fill, int(tmpx),
3615 offset + row_ptr->baseline - 3,
3616 offset + row_ptr->baseline - 1);
3617 scr.drawLine(gc_fill,
3618 offset + row_ptr->baseline - 1,
3621 scr.drawVerticalLine(gc_fill, int(x-2),
3622 offset + row_ptr->baseline - 3,
3623 offset + row_ptr->baseline - 1);
3624 /* what about underbars? */
3625 font = GetFont(row_ptr->par, pos);
3626 if (font.underbar() == LyXFont::ON
3627 && font.latex() != LyXFont::ON) {
3628 scr.drawLine(gc_copy,
3630 row_ptr->baseline + 2,
3637 Draw(row_ptr, pos, scr, offset, x);
3641 /* do not forget the very last cell. This has no NEWLINE so
3642 * ignored by the code above*/
3643 if (cell == row_ptr->par->table->GetNumberOfCells()-1){
3644 x = x_old + row_ptr->par->table->WidthOfColumn(cell);
3645 on_off = !row_ptr->par->table->TopLine(cell);
3647 !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
3648 !row_ptr->par->table->IsContRow(cell))
3650 scr.drawTableLine(offset + row_ptr->baseline -
3651 row_ptr->ascent_of_text,
3652 int(x_old), int(x - x_old), on_off);
3653 on_off = !row_ptr->par->table->BottomLine(cell);
3654 if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
3655 row_ptr->par->table->VeryLastRow(cell))
3657 scr.drawTableLine(offset + y_bottom - 1,
3658 int(x_old), int(x - x_old), on_off);
3659 on_off = !row_ptr->par->table->LeftLine(cell);
3661 scr.drawVerticalTableLine(int(x_old),
3662 offset + row_ptr->baseline -
3663 row_ptr->ascent_of_text,
3664 offset + y_bottom - 1,
3666 on_off = !row_ptr->par->table->RightLine(cell);
3668 scr.drawVerticalTableLine(int(x) -
3669 row_ptr->par->table->AdditionalWidth(cell),
3670 offset + row_ptr->baseline -
3671 row_ptr->ascent_of_text,
3672 offset + y_bottom - 1,
3676 /* table stuff -- end*/
3678 while (pos <= pos_end) {
3680 if (row_ptr->par->IsHfill(pos)) {
3682 scr.drawVerticalLine(gc_fill, int(x),
3683 offset + row_ptr->baseline - DefaultHeight()/2,
3684 offset + row_ptr->baseline);
3685 if (HfillExpansion(row_ptr, pos)) {
3686 if (pos >= main_body) {
3687 scr.drawOnOffLine(offset + row_ptr->baseline -
3693 scr.drawOnOffLine(offset + row_ptr->baseline -
3696 int(fill_label_hfill));
3697 x += fill_label_hfill;
3699 scr.drawVerticalLine(gc_fill, int(x),
3700 offset + row_ptr->baseline -
3702 offset + row_ptr->baseline);
3707 if (row_ptr->par->IsSeparator(pos)) {
3709 x+= SingleWidth(row_ptr->par, pos);
3710 if (pos >= main_body)
3712 /* -------> Only draw protected spaces when not in
3713 * free-spacing mode. */
3714 if (row_ptr->par->GetChar(pos) == LyXParagraph::META_PROTECTED_SEPARATOR && !layout.free_spacing) {
3716 scr.drawVerticalLine(gc_fill, int(tmpx),
3717 offset + row_ptr->baseline - 3,
3718 offset + row_ptr->baseline - 1);
3719 scr.drawLine(gc_fill,
3720 offset + row_ptr->baseline - 1,
3723 scr.drawVerticalLine(gc_fill, int(x-2),
3724 offset + row_ptr->baseline - 3,
3725 offset + row_ptr->baseline - 1);
3726 /* what about underbars? */
3727 font = GetFont(row_ptr->par, pos);
3728 if (font.underbar() == LyXFont::ON
3729 && font.latex() != LyXFont::ON) {
3730 scr.drawLine(gc_copy,
3731 offset + row_ptr->baseline + 2,
3738 Draw(row_ptr, pos, scr, offset, x);
3740 if (pos == main_body) {
3741 x += GetFont(row_ptr->par, -2).stringWidth(
3743 if (row_ptr->par->IsLineSeparator(pos - 1))
3744 x-= SingleWidth(row_ptr->par, pos - 1);
3745 if (x < left_margin)
3750 // check for FAST SELECTION
3751 if (fast_selection || mono_video){
3754 /* selection code */
3755 if (sel_start_cursor.row == row_ptr && sel_end_cursor.row == row_ptr) {
3756 scr.fillRectangle(gc_select, sel_start_cursor.x, offset,
3757 sel_end_cursor.x - sel_start_cursor.x,
3759 } else if (sel_start_cursor.row == row_ptr) {
3760 scr.fillRectangle(gc_select, sel_start_cursor.x, offset,
3761 paperwidth - sel_start_cursor.x,
3763 } else if (sel_end_cursor.row == row_ptr) {
3764 scr.fillRectangle(gc_select, 0, offset,
3767 } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
3768 scr.fillRectangle(gc_select, 0, offset,
3769 paperwidth, row_ptr->height);
3774 // end of FAST SELECTION code
3779 int LyXText::DefaultHeight()
3781 LyXFont font(LyXFont::ALL_SANE);
3782 return int(font.maxAscent() + font.maxDescent() * 1.5);
3786 /* returns the column near the specified x-coordinate of the row
3787 * x is set to the real beginning of this column */
3788 int LyXText::GetColumnNearX(Row * row, int& x)
3791 float fill_separator, fill_hfill, fill_label_hfill;
3793 int left_margin = LabelEnd(row);
3794 PrepareToPrint(row, tmpx, fill_separator,
3795 fill_hfill, fill_label_hfill);
3796 int main_body = BeginningOfMainBody(row->par);
3800 int last = RowLast(row);
3801 if (row->par->IsNewline(last))
3804 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
3805 row->par->GetLayout());
3806 /* table stuff -- begin */
3807 if (row->par->table) {
3808 if (!row->next || row->next->par != row->par)
3809 last = RowLast(row); /* the last row doesn't need a newline at the end*/
3810 int cell = NumberOfCell(row->par, row->pos);
3813 tmpx += row->par->table->GetBeginningOfTextInCell(cell);
3815 && tmpx + (SingleWidth(row->par, c)/2) <= x
3817 if (row->par->IsNewline(c)) {
3818 if (x_old + row->par->table->WidthOfColumn(cell) <= x){
3819 tmpx = x_old + row->par->table->WidthOfColumn(cell);
3822 tmpx += row->par->table->GetBeginningOfTextInCell(cell);
3827 tmpx += SingleWidth(row->par, c);
3832 /* table stuff -- end*/
3835 && tmpx + (SingleWidth(row->par, c)/2) <= x) {
3837 if (c && c == main_body
3838 && !row->par->IsLineSeparator(c - 1)) {
3839 tmpx += GetFont(row->par, -2)
3840 .stringWidth(layout.labelsep);
3841 if (tmpx < left_margin)
3845 tmpx += SingleWidth(row->par, c);
3846 if (HfillExpansion(row, c)) {
3850 tmpx += fill_label_hfill;
3852 else if (c >= main_body
3853 && row->par->IsSeparator(c)) {
3854 tmpx+= fill_separator;
3858 && row->par->IsLineSeparator(c - 1)) {
3859 tmpx += GetFont(row->par, -2)
3860 .stringWidth(layout.labelsep);
3861 tmpx-= SingleWidth(row->par, c - 1);
3862 if (tmpx < left_margin)
3866 /* make sure that a last space in a row doesnt count */
3867 if (c > 0 && c >= last
3868 && row->par->IsLineSeparator(c - 1)
3869 && !(!row->next || row->next->par != row->par)) {
3870 tmpx -= SingleWidth(row->par, c - 1);
3871 tmpx -= fill_separator;
3880 /* turn the selection into a new environment. If there is no selection,
3881 * create an empty environment */
3882 void LyXText::InsertFootnoteEnvironment(LyXParagraph::footnote_kind kind)
3884 /* no footnoteenvironment in a footnoteenvironment */
3885 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3886 WriteAlert(_("Impossible operation"),
3887 _("You can't insert a float in a float!"),
3891 /* no marginpars in minipages */
3892 if (kind == LyXParagraph::MARGIN
3893 && cursor.par->pextra_type == LyXParagraph::PEXTRA_MINIPAGE) {
3894 WriteAlert(_("Impossible operation"),
3895 _("You can't insert a marginpar in a minipage!"),
3900 /* this doesnt make sense, if there is no selection */
3901 bool dummy_selection = false;
3903 sel_start_cursor = cursor; /* dummy selection */
3904 sel_end_cursor = cursor;
3905 dummy_selection = true;
3908 LyXParagraph *tmppar;
3910 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
3911 WriteAlert(_("Impossible operation"), _("Cannot cut table."), _("Sorry."));
3915 /* a test to make sure there is not already a footnote
3916 * in the selection. */
3918 tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
3920 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos) &&
3921 tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
3922 tmppar = tmppar->next;
3924 if (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
3925 || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3926 WriteAlert(_("Impossible operation"),
3927 _("Float would include float!"),
3932 /* ok we have a selection. This is always between sel_start_cursor
3933 * and sel_end cursor */
3935 SetUndo(Undo::FINISH,
3936 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
3937 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
3939 if (sel_end_cursor.pos > 0
3940 && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1))
3941 sel_end_cursor.pos--; /* please break before a space at
3943 if (sel_start_cursor.par == sel_end_cursor.par
3944 && sel_start_cursor.pos > sel_end_cursor.pos)
3945 sel_start_cursor.pos--;
3947 sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
3949 sel_end_cursor.par = sel_end_cursor.par->Next();
3950 sel_end_cursor.pos = 0;
3952 // don't forget to insert a dummy layout paragraph if necessary
3953 if (sel_start_cursor.par->GetLayout() != sel_end_cursor.par->layout){
3954 sel_end_cursor.par->BreakParagraphConservative(0);
3955 sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
3956 sel_end_cursor.par = sel_end_cursor.par->next;
3959 sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
3961 cursor = sel_end_cursor;
3963 /* please break behind a space, if there is one. The space should
3965 if (sel_start_cursor.pos > 0
3966 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1))
3967 sel_start_cursor.pos--;
3968 if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)) {
3969 sel_start_cursor.par->Erase(sel_start_cursor.pos);
3972 sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
3973 tmppar = sel_start_cursor.par->Next();
3975 if (dummy_selection) {
3977 if (kind == LyXParagraph::TAB
3978 || kind == LyXParagraph::FIG
3979 || kind == LyXParagraph::WIDE_TAB
3980 || kind == LyXParagraph::WIDE_FIG
3981 || kind == LyXParagraph::ALGORITHM) {
3982 int lay = textclasslist.NumberOfLayout(parameters->textclass,
3984 if (lay == -1) // layout not found
3985 // use default layout "Standard" (0)
3987 tmppar->SetLayout(lay);
3991 if (sel_start_cursor.pos > 0) {
3992 /* the footnote-environment should begin with a standard layout.
3993 * Imagine you insert a footnote within an enumeration, you
3994 * certainly do not want an enumerated footnote! */
3998 /* this is a exception the user would sometimes expect, I hope */
3999 sel_start_cursor.par->Clear();
4003 while (tmppar != sel_end_cursor.par) {
4004 tmppar->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
4005 tmppar->footnotekind = kind;
4006 tmppar = tmppar->Next();
4009 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
4011 SetCursor(sel_start_cursor.par->Next(), 0);
4017 /* returns pointer to a specified row */
4018 Row * LyXText::GetRow(LyXParagraph * par, LyXParagraph::size_type pos, long &y)
4023 if (par == currentrow->par || par == currentrow->par->Previous()){
4024 // do not dereference par, it may have been deleted
4025 // already! (Matthias)
4026 while (currentrow->previous && currentrow->previous->par != par){
4027 currentrow = currentrow->previous;
4028 currentrow_y -= currentrow->height;
4030 while (currentrow->previous && currentrow->previous->par == par){
4031 currentrow = currentrow->previous;
4032 currentrow_y -= currentrow->height;
4035 tmprow = currentrow;
4037 /* find the first row of the specified paragraph */
4038 while (tmprow->next && (tmprow->par != par)) {
4039 y += tmprow->height;
4040 tmprow = tmprow->next;
4043 if (tmprow->par == par){
4044 /* now find the wanted row */
4045 while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par &&
4046 tmprow->next->pos <= pos) {
4047 y += tmprow->height;
4048 tmprow = tmprow->next;
4050 currentrow = tmprow;
4057 /* find the first row of the specified paragraph */
4058 while (tmprow->next && (tmprow->par != par)) {
4059 y += tmprow->height;
4060 tmprow = tmprow->next;
4063 /* now find the wanted row */
4064 while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par &&
4065 tmprow->next->pos <= pos) {
4066 y += tmprow->height;
4067 tmprow = tmprow->next;
4070 currentrow = tmprow;