1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-1999 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"
33 static const int LYX_PAPER_MARGIN = 20;
35 extern int mono_video;
36 extern int reverse_video;
37 extern int fast_selection;
38 extern BufferView * current_view;
39 //extern int UnlockInset(UpdatableInset * inset);
42 extern int bibitemMaxWidth(LyXFont const &);
44 int LyXText::SingleWidth(LyXParagraph * par,
45 LyXParagraph::size_type pos)
47 char c = par->GetChar(pos);
48 return SingleWidth(par, pos, c);
52 int LyXText::SingleWidth(LyXParagraph * par,
53 LyXParagraph::size_type pos, char c)
55 LyXFont font = GetFont(par, pos);
57 // The most common case is handled first (Asger)
61 } else if (IsHfillChar(c)) {
62 return 3; /* Because of the representation
63 * as vertical lines */
65 } else if (c == LyXParagraph::META_FOOTNOTE ||
66 c == LyXParagraph::META_MARGIN ||
67 c == LyXParagraph::META_FIG ||
68 c == LyXParagraph::META_TAB ||
69 c == LyXParagraph::META_WIDE_FIG ||
70 c == LyXParagraph::META_WIDE_TAB ||
71 c == LyXParagraph::META_ALGORITHM)
75 case LyXParagraph::META_MARGIN:
78 case LyXParagraph::META_FIG:
81 case LyXParagraph::META_TAB:
84 case LyXParagraph::META_ALGORITHM:
87 case LyXParagraph::META_WIDE_FIG:
90 case LyXParagraph::META_WIDE_TAB:
93 case LyXParagraph::META_FOOTNOTE:
99 return font.stringWidth(fs);
102 else if (c == LyXParagraph::META_INSET) {
103 Inset *tmpinset= par->GetInset(pos);
105 return par->GetInset(pos)->Width(font);
109 } else if (IsSeparatorChar(c))
111 else if (IsNewlineChar(c))
113 return font.width(c);
117 // Returns the paragraph position of the last character in the specified row
118 LyXParagraph::size_type LyXText::RowLast(Row * row)
121 return row->par->Last()-1;
122 else if (row->next->par != row->par)
123 return row->par->Last()-1;
125 return row->next->pos - 1;
129 void LyXText::Draw(Row * row, LyXParagraph::size_type & pos,
130 LyXScreen & scr, int offset, float & x)
132 char c = row->par->GetChar(pos);
134 if (IsNewlineChar(c)) {
136 // Draw end-of-line marker
138 LyXFont font = GetFont(row->par, pos);
139 int asc = font.maxAscent();
140 int wid = font.width('n');
141 int y = (offset + row->baseline);
143 p[0].x = int(x + wid*0.375); p[0].y = int(y - 0.875*asc*0.75);
144 p[1].x = int(x); p[1].y = int(y - 0.500*asc*0.75);
145 p[2].x = int(x + wid*0.375); p[2].y = int(y - 0.125*asc*0.75);
146 scr.drawLines(::getGC(gc_new_line), p, 3);
148 p[0].x = int(x); p[0].y = int(y - 0.500*asc*0.75);
149 p[1].x = int(x + wid); p[1].y = int(y - 0.500*asc*0.75);
150 p[2].x = int(x + wid); p[2].y = int(y - asc*0.75);
151 scr.drawLines(::getGC(gc_new_line), p, 3);
155 LyXFont font = GetFont(row->par, pos);
156 LyXFont font2 = font;
158 if (c == LyXParagraph::META_FOOTNOTE
159 || c == LyXParagraph::META_MARGIN
160 || c == LyXParagraph::META_FIG
161 || c == LyXParagraph::META_TAB
162 || c == LyXParagraph::META_WIDE_FIG
163 || c == LyXParagraph::META_WIDE_TAB
164 || c == LyXParagraph::META_ALGORITHM) {
167 case LyXParagraph::META_MARGIN:
169 // Draw a sign at the left margin!
170 scr.drawText(font, "!", 1, offset + row->baseline,
171 (LYX_PAPER_MARGIN - font.width('!'))/2);
173 case LyXParagraph::META_FIG:
176 case LyXParagraph::META_TAB:
179 case LyXParagraph::META_ALGORITHM:
182 case LyXParagraph::META_WIDE_FIG:
185 case LyXParagraph::META_WIDE_TAB:
188 case LyXParagraph::META_FOOTNOTE:
195 // calculate the position of the footnotemark
196 int y = (row->baseline - font2.maxAscent()
199 font.setColor(LyXFont::INSET);
203 // draw it and set new x position
204 x += scr.drawString(font, fs, offset + y, int(x));
206 scr.drawLine(gc_foot, offset + row->baseline,
207 int(tmpx), int(x - tmpx));
211 } else if (c == LyXParagraph::META_INSET) {
212 Inset * tmpinset = row->par->GetInset(pos);
214 tmpinset->Draw(font, scr, offset + row->baseline, x);
219 /* usual characters, no insets */
221 // Collect character that we can draw in one command
223 // This is dirty, but fast. Notice that it will never be too small.
224 // For the record, I'll note that Microsoft Word has a limit
225 // of 768 here. We have none :-) (Asger)
226 // Ok. I am the first to admit that the use of std::string will be
227 // a tiny bit slower than using a POD char array. However, I claim
228 // that this slowdown is so small that it is close to inperceptive.
229 // So IMHO we should go with the easier and clearer implementation.
230 // And even if 1024 is a large number here it might overflow, string
231 // will only overflow if the machine is out of memory...
232 static string textstring;
236 LyXParagraph::size_type last = RowLast(row);
239 && static_cast<char>(c = row->par->GetChar(pos)) > ' '
240 && font2 == GetFont(row->par, pos)) {
246 // If monochrome and LaTeX mode, provide reverse background
247 if (mono_video && font.latex() == LyXFont::ON) {
248 int a = font.maxAscent(), d = font.maxDescent();
249 scr.fillRectangle(gc_copy, int(tmpx), offset + row->baseline-a,
250 font.textWidth(textstring.c_str(),
251 textstring.length()), a+d);
253 // Draw text and set the new x position
254 x += scr.drawText(font, textstring.c_str(), textstring.length(),
255 offset + row->baseline,
258 // what about underbars?
259 if (font.underbar() == LyXFont::ON && font.latex() != LyXFont::ON) {
260 scr.drawLine(gc_copy, offset + row->baseline + 2,
261 int(tmpx), int(x - tmpx));
264 // If we want ulem.sty support, drawing
265 // routines should go here. (Asger)
266 // Why shouldn't LyXFont::drawText handle it internally?
270 /* Returns the left beginning of the text.
271 * This information cannot be taken from the layouts-objekt, because in
272 * LaTeX the beginning of the text fits in some cases (for example sections)
273 * exactly the label-width. */
274 int LyXText::LeftMargin(Row * row)
277 LyXParagraph * newpar;
279 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
280 row->par->GetLayout());
282 string parindent = layout.parindent;
284 /* table stuff -- begin*/
287 /* table stuff -- end*/
289 int x = LYX_PAPER_MARGIN;
291 x += textclasslist.TextClass(parameters->textclass).
292 defaultfont().signedStringWidth(textclasslist.TextClass(parameters->textclass).leftmargin());
294 if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
295 LyXFont font(LyXFont::ALL_SANE);
296 font.setSize(LyXFont::SIZE_SMALL);
297 x += font.textWidth("Mwide-figM", 10) + LYX_PAPER_MARGIN/2;
300 /* this is the way, LyX handles the LaTeX-Environments.
301 * I have had this idea very late, so it seems to be a
302 * later added hack and this is true */
303 if (!row->par->GetDepth()) {
304 if (!row->par->GetLayout()) {
305 /* find the previous same level paragraph */
306 if (row->par->FirstPhysicalPar()->Previous()) {
307 newpar = row->par->DepthHook(row->par->GetDepth());
308 if (newpar && textclasslist.Style(parameters->textclass,
309 newpar->GetLayout()).nextnoindent)
315 /* find the next level paragraph */
317 newpar = row->par->DepthHook(row->par->GetDepth()-1);
319 /* make a corresponding row. Needed to call LeftMargin() */
321 /* check wether it is a sufficent paragraph */
322 if (newpar && newpar->footnoteflag == row->par->footnoteflag
323 && textclasslist.Style(parameters->textclass,
324 newpar->GetLayout()).isEnvironment()) {
325 dummyrow.par = newpar;
326 dummyrow.pos = newpar->Last();
327 x = LeftMargin(&dummyrow);
330 /* this is no longer an error, because this function is used
331 * to clear impossible depths after changing a layout. Since there
332 * is always a redo, LeftMargin() is always called */
334 /* printf("LYX_ERROR (text, LeftMargin()) impossible depth \n");*/
335 row->par->FirstPhysicalPar()->depth = 0;
338 if (newpar && !row->par->GetLayout()) {
339 if (newpar->FirstPhysicalPar()->noindent)
342 parindent = textclasslist.Style(parameters->textclass,
343 newpar->GetLayout()).parindent;
348 labelfont = GetFont(row->par, -2);
349 switch (layout.margintype) {
351 if (!layout.leftmargin.empty()) {
352 x += textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.leftmargin);
354 if (!row->par->GetLabestring().empty()) {
355 x += labelfont.signedStringWidth(layout.labelindent);
356 x += labelfont.stringWidth(row->par->GetLabestring());
357 x += labelfont.stringWidth(layout.labelsep);
361 x += labelfont.signedStringWidth(layout.labelindent);
362 if (row->pos >= BeginningOfMainBody(row->par)) {
363 if (!row->par->GetLabelWidthString().empty()) {
364 x += labelfont.stringWidth(row->par->GetLabelWidthString());
365 x += labelfont.stringWidth(layout.labelsep);
370 x += ( textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.leftmargin) * 4
371 / (row->par->GetDepth() + 4));
373 case MARGIN_FIRST_DYNAMIC:
374 if (layout.labeltype == LABEL_MANUAL) {
375 if (row->pos >= BeginningOfMainBody(row->par)) {
376 x += labelfont.signedStringWidth(layout.leftmargin);
378 x += labelfont.signedStringWidth(layout.labelindent);
382 // Special case to fix problems with theorems (JMarc)
383 || (layout.labeltype == LABEL_STATIC
384 && layout.latextype == LATEX_ENVIRONMENT
385 && ! row->par->IsFirstInSequence())) {
386 x += labelfont.signedStringWidth(layout.leftmargin);
387 } else if (layout.labeltype != LABEL_TOP_ENVIRONMENT
388 && layout.labeltype != LABEL_BIBLIO
389 && layout.labeltype != LABEL_CENTERED_TOP_ENVIRONMENT) {
390 x += labelfont.signedStringWidth(layout.labelindent);
391 x += labelfont.stringWidth(layout.labelsep);
392 x += labelfont.stringWidth(row->par->GetLabestring());
397 case MARGIN_RIGHT_ADDRESS_BOX:
399 /* ok, a terrible hack. The left margin depends on the widest row
400 * in this paragraph. Do not care about footnotes, they are *NOT*
401 * allowed in the LaTeX realisation of this layout. */
403 /* find the first row of this paragraph */
405 while (tmprow->previous && tmprow->previous->par == row->par)
406 tmprow = tmprow->previous;
408 int minfill = tmprow->fill;
409 while (tmprow-> next && tmprow->next->par == row->par) {
410 tmprow = tmprow->next;
411 if (tmprow->fill < minfill)
412 minfill = tmprow->fill;
415 x += textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.leftmargin);
420 if (row->par->pextra_type == LyXParagraph::PEXTRA_INDENT) {
421 if (!row->par->pextra_widthp.empty()) {
422 x += paperwidth * atoi(row->par->pextra_widthp.c_str()) / 100;
423 } else if (!row->par->pextra_width.empty()) {
424 int xx = VSpace(row->par->pextra_width).inPixels();
427 xx = paperwidth * 80 / 100;
429 } else { // should not happen
430 LyXFont font(LyXFont::ALL_SANE);
431 x += font.stringWidth("XXXXXX");
436 if (row->par->FirstPhysicalPar()->align == LYX_ALIGN_LAYOUT)
437 align = layout.align;
439 align = row->par->FirstPhysicalPar()->align;
441 /* set the correct parindent */
443 if ((layout.labeltype == LABEL_NO_LABEL
444 || layout.labeltype == LABEL_TOP_ENVIRONMENT
445 || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT
446 || (layout.labeltype == LABEL_STATIC
447 && layout.latextype == LATEX_ENVIRONMENT
448 && ! row->par->IsFirstInSequence()))
449 && row->par == row->par->FirstPhysicalPar()
450 && align == LYX_ALIGN_BLOCK
451 && !row->par->noindent
452 && (row->par->layout ||
453 parameters->paragraph_separation == BufferParams::PARSEP_INDENT))
454 x += textclasslist.TextClass(parameters->textclass).defaultfont().stringWidth(parindent);
456 if (layout.labeltype == LABEL_BIBLIO) { // ale970405 Right width for bibitems
457 x += bibitemMaxWidth(textclasslist.TextClass(parameters->textclass).defaultfont());
465 int LyXText::RightMargin(Row *row)
467 LyXParagraph * newpar;
469 LyXLayout const & layout = textclasslist.Style(parameters->textclass, row->par->GetLayout());
471 int x = LYX_PAPER_MARGIN;
473 x += textclasslist.TextClass(parameters->textclass).
474 defaultfont().signedStringWidth(textclasslist.TextClass(parameters->textclass).rightmargin());
475 if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
476 x += LYX_PAPER_MARGIN/2;
479 /* this is the way, LyX handles the LaTeX-Environments.
480 * I have had this idea very late, so it seems to be a
481 * later added hack and this is true */
482 if (row->par->GetDepth()) {
483 /* find the next level paragraph */
488 newpar = newpar->FirstPhysicalPar()->Previous();
490 newpar = newpar->FirstPhysicalPar();
491 } while (newpar && newpar->GetDepth() >= row->par->GetDepth()
492 && newpar->footnoteflag == row->par->footnoteflag);
494 /* make a corresponding row. Needed to call LeftMargin() */
496 /* check wether it is a sufficent paragraph */
497 if (newpar && newpar->footnoteflag == row->par->footnoteflag
498 && textclasslist.Style(parameters->textclass,
499 newpar->GetLayout()).isEnvironment()) {
500 dummyrow.par = newpar;
502 x = RightMargin(&dummyrow);
505 /* this is no longer an error, because this function is used
506 * to clear impossible depths after changing a layout. Since there
507 * is always a redo, LeftMargin() is always called */
509 /* printf("LYX_ERROR (text, LeftMargin()) impossible depth \n");*/
510 row->par->FirstPhysicalPar()->depth = 0;
514 //lyxerr << "rightmargin: " << layout->rightmargin << endl;
515 x += (textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.rightmargin) * 4
516 / (row->par->GetDepth() + 4));
522 int LyXText::LabelEnd (Row * row)
524 if (textclasslist.Style(parameters->textclass, row->par->GetLayout()).margintype == MARGIN_MANUAL) {
527 tmprow.pos = row->par->Last();
528 return LeftMargin(&tmprow); /* just the beginning
529 * of the main body */
532 return 0; /* LabelEnd is only needed, if the
533 * layout fills a flushleft
538 /* table stuff -- begin*/
539 int LyXText::NumberOfCell(LyXParagraph * par,
540 LyXParagraph::size_type pos)
543 LyXParagraph::size_type tmp_pos = 0;
544 while (tmp_pos < pos) {
545 if (par->IsNewline(tmp_pos))
553 int LyXText::WidthOfCell(LyXParagraph * par, LyXParagraph::size_type & pos)
556 while (pos < par->Last() && !par->IsNewline(pos)) {
557 w += SingleWidth(par, pos);
560 if (par->IsNewline(pos))
566 bool LyXText::HitInTable(Row * row, int x)
569 float fill_separator, fill_hfill, fill_label_hfill;
570 if (!row->par->table)
572 PrepareToPrint(row, tmpx, fill_separator, fill_hfill, fill_label_hfill);
573 return (x > tmpx && x < tmpx + row->par->table->WidthOfTable());
577 bool LyXText::MouseHitInTable(int x, long y)
579 Row * row = GetRowNearY(y);
580 return HitInTable(row, x);
584 /* table stuff -- end*/
587 /* get the next breakpoint in a given paragraph */
588 LyXParagraph::size_type
589 LyXText::NextBreakPoint(Row * row, int width)
592 LyXParagraph::size_type last_separator = -1;
593 /* position of the last possible breakpoint
594 * -1 isn't a suitable value, but a flag */
597 LyXParagraph * par = row->par;
598 LyXParagraph::size_type i = 0;
599 LyXParagraph::size_type pos = row->pos;
601 /* table stuff -- begin*/
603 while (pos < par->size()
604 && (!par->IsNewline(pos)
605 || !par->table->IsFirstCell(NumberOfCell(par, pos+1)))) {
606 if (par->GetChar(pos) == LyXParagraph::META_INSET &&
607 par->GetInset(pos) && par->GetInset(pos)->display()){
608 par->GetInset(pos)->display(false);
614 /* table stuff -- end*/
616 left_margin = LabelEnd(row);
617 width -= RightMargin(row);
618 LyXParagraph::size_type main_body =
619 BeginningOfMainBody(par);
620 LyXLayout const & layout = textclasslist.Style(parameters->textclass, par->GetLayout());
624 if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX) {
625 /* special code for right address boxes, only newlines count */
626 while (i < par->Last()) {
627 if (par->IsNewline(i)) {
629 i = par->Last() - 1;/* this means break */
631 } else if (par->GetChar(i) == LyXParagraph::META_INSET &&
632 par->GetInset(i) && par->GetInset(i)->display()){
633 par->GetInset(i)->display(false);
638 // Last position is an invariant
639 LyXParagraph::size_type const last =
641 /* this is the usual handling */
643 while (x < width && i < last) {
645 if (IsNewlineChar(c)) {
647 x = width; /* this means break */
648 } else if (c == LyXParagraph::META_INSET &&
649 par->GetInset(i) && par->GetInset(i)->display()){
650 /* check wether a Display() inset is valid here .
651 if not, change it to non-display*/
652 if (layout.isCommand()
653 || (layout.labeltype == LABEL_MANUAL
654 && i < BeginningOfMainBody(par))){
655 /* display istn't allowd */
656 par->GetInset(i)->display(false);
657 x += SingleWidth(par, i, c);
659 /* inset is display. So break the line here */
663 if (IsLineSeparatorChar(par->GetChar(i+1)))
666 last_separator = last; // to avoid extra rows
668 last_separator = i - 1;
669 x = width; /* this means break */
672 if (IsLineSeparatorChar(c))
674 x += SingleWidth(par, i, c);
677 if (i == main_body) {
678 x += GetFont(par, -2).stringWidth(layout.labelsep);
679 if (par->IsLineSeparator(i - 1))
680 x-= SingleWidth(par, i - 1);
685 /* end of paragraph is always a suitable separator */
686 if (i == last && x < width)
690 /* well, if last_separator is still 0, the line isn't breakable.
691 * don't care and cut simply at the end */
692 if (last_separator < 0) {
696 /* manual labels cannot be broken in LaTeX, do not care */
697 if (main_body && last_separator < main_body)
698 last_separator = main_body - 1;
700 return last_separator;
704 /* returns the minimum space a row needs on the screen in pixel */
705 int LyXText::Fill(Row * row, int paper_width)
708 /* get the pure distance */
709 LyXParagraph::size_type last = RowLast(row);
710 /* table stuff -- begin*/
711 if (row->par->table) {
712 /* for tables FILL does calculate the widthes of each cell in
714 LyXParagraph::size_type pos = row->pos;
715 int cell = NumberOfCell(row->par, pos);
718 row->par->table->SetWidthOfCell(cell, WidthOfCell(row->par, pos));
720 } while (pos <= last && !row->par->table->IsFirstCell(cell));
721 /* don't forget the very last table cell without characters */
722 if (cell == row->par->table->GetNumberOfCells()-1)
723 row->par->table->SetWidthOfCell(cell, WidthOfCell(row->par, pos));
725 return 0; /* width of table cannot be returned since
726 * we cannot guarantee its correct value at
729 /* table stuff -- end*/
731 int left_margin = LabelEnd(row);
733 /* if the row ends with newline, this newline will not be relevant */
734 if (last >= 0 && row->par->IsNewline(last))
737 /* if the row ends with a space, this space will not be relevant */
738 if (last >= 0 && row->par->IsLineSeparator(last))
741 /* special handling of the right address boxes */
742 if (textclasslist.Style(parameters->textclass,
743 row->par->GetLayout()).margintype
744 == MARGIN_RIGHT_ADDRESS_BOX) {
745 int tmpfill = row->fill;
746 row->fill = 0; /* the minfill in MarginLeft() */
753 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
754 row->par->GetLayout());
755 LyXParagraph::size_type main_body =
756 BeginningOfMainBody(row->par);
757 LyXParagraph::size_type i = row->pos;
759 w += SingleWidth(row->par, i);
761 if (i == main_body) {
762 w += GetFont(row->par, -2).stringWidth(layout.labelsep);
763 if (row->par->IsLineSeparator(i - 1))
764 w -= SingleWidth(row->par, i - 1);
770 fill = paper_width - w - RightMargin(row);
775 /* returns the minimum space a manual label needs on the screen in pixel */
776 int LyXText::LabelFill(Row * row)
779 LyXParagraph::size_type last = BeginningOfMainBody(row->par) - 1;
780 /* -1 because a label ends either with a space that is in the label,
781 * or with the beginning of a footnote that is outside the label. */
783 // I don't understand this code in depth, but sometimes "last" is less than
784 // 0 and this causes a crash. This fix seems to work correctly, but I
785 // bet the real error is elsewhere. The bug is triggered when you have an
786 // open footnote in a paragraph environment with a manual label. (Asger)
787 if (last < 0) last = 0;
789 if (row->par->IsLineSeparator(last)) /* a sepearator at this end
796 w += SingleWidth(row->par, i);
801 if (!row->par->labelwidthstring.empty()) {
802 fill = GetFont(row->par, -2).stringWidth(row->par->labelwidthstring) - w;
812 /* returns the number of separators in the specified row. The separator
813 * on the very last column doesnt count */
814 int LyXText::NumberOfSeparators(Row *row)
816 int last = RowLast(row);
819 int main_body = BeginningOfMainBody(row->par);
822 for (; p < last; p++) {
823 if (row->par->IsSeparator(p)) {
831 /* returns the number of hfills in the specified row. The LyX-Hfill is
832 * a LaTeX \hfill so that the hfills at the beginning and at the end were
833 * ignored. This is *MUCH* more usefull than not to ignore! */
834 int LyXText::NumberOfHfills(Row * row)
836 int last = RowLast(row);
837 int first = row->pos;
838 if (first) { /* hfill *DO* count at the beginning
840 while(first <= last && row->par->IsHfill(first))
844 int main_body = BeginningOfMainBody(row->par);
845 if (first < main_body)
848 for (int p = first; p <= last; p++) { // last, because the end is ignored!
849 if (row->par->IsHfill(p)) {
857 /* like NumberOfHfills, but only those in the manual label! */
858 int LyXText::NumberOfLabelHfills(Row * row)
860 LyXParagraph::size_type last = RowLast(row);
861 LyXParagraph::size_type first = row->pos;
862 if (first) { /* hfill *DO* count at the beginning
864 while(first < last && row->par->IsHfill(first))
867 LyXParagraph::size_type main_body =
868 BeginningOfMainBody(row->par);
869 if (last > main_body)
873 for (LyXParagraph::size_type p = first;
874 p < last; ++p) { // last, because the end is ignored!
875 if (row->par->IsHfill(p)) {
883 /* returns true, if a expansion is needed.
884 * Rules are given by LaTeX */
885 bool LyXText::HfillExpansion(Row * row_ptr,
886 LyXParagraph::size_type pos)
888 /* by the way, is it a hfill? */
889 if (!row_ptr->par->IsHfill(pos))
892 /* at the end of a row it does not count */
893 if (pos >= RowLast(row_ptr))
896 /* at the beginning of a row it does not count, if it is not
897 * the first row of a paragaph */
901 /* in some labels it does not count */
902 if ( textclasslist.Style(parameters->textclass, row_ptr->par->GetLayout()).margintype != MARGIN_MANUAL &&
903 pos < BeginningOfMainBody(row_ptr->par))
906 /* if there is anything between the first char of the row and
907 * the sepcified position that is not a newline and not a hfill,
908 * the hfill will count, otherwise not */
909 LyXParagraph::size_type i = row_ptr->pos;
910 while (i < pos && (row_ptr->par->IsNewline(i)
911 || row_ptr->par->IsHfill(i)))
918 void LyXText::SetHeightOfRow(Row * row_ptr)
920 /* get the maximum ascent and the maximum descent */
921 int asc, maxasc, desc, maxdesc, pos_end, pos, labeladdon;
923 float layoutdesc = 0;
928 /* this must not happen before the currentrow for clear reasons.
929 so the trick is just to set the current row onto this row */
931 GetRow(row_ptr->par, row_ptr->pos, unused_y);
933 /* ok , let us initialize the maxasc and maxdesc value.
934 * This depends in LaTeX of the font of the last character
935 * in the paragraph. The hack below is necessary because
936 * of the possibility of open footnotes */
938 /* Correction: only the fontsize count. The other properties
939 are taken from the layoutfont. Nicer on the screen :) */
941 LyXParagraph * par = row_ptr->par->LastPhysicalPar();
942 LyXParagraph * firstpar = row_ptr->par->FirstPhysicalPar();
944 LyXLayout const & layout = textclasslist.Style(parameters->textclass, firstpar->GetLayout());
946 LyXFont font = GetFont(par, par->Last()-1);
947 LyXFont::FONT_SIZE size = font.size();
948 font = GetFont(par, -1);
951 LyXFont labelfont = GetFont(par, -2);
953 maxasc = int(font.maxAscent() *
954 layout.spacing.getValue() *
955 parameters->spacing.getValue());
956 maxdesc = int(font.maxDescent() *
957 layout.spacing.getValue() *
958 parameters->spacing.getValue());
960 pos_end = RowLast(row_ptr);
964 // Check if any insets are larger
965 for (pos = row_ptr->pos; pos <= pos_end; pos++) {
966 if (row_ptr->par->GetChar(pos) == LyXParagraph::META_INSET) {
967 tmpfont = GetFont(row_ptr->par, pos);
968 tmpinset = row_ptr->par->GetInset(pos);
970 asc = tmpinset->Ascent(tmpfont);
971 desc = tmpinset->Descent(tmpfont);
980 // Check if any custom fonts are larger (Asger)
981 // This is not completely correct, but we can live with the small,
982 // cosmetic error for now.
983 LyXFont::FONT_SIZE maxsize = row_ptr->par->HighestFontInRange(row_ptr->pos, pos_end);
984 if (maxsize > font.size()) {
985 font.setSize(maxsize);
987 asc = font.maxAscent();
988 desc = font.maxDescent();
995 /* table stuff -- begin*/
996 if (row_ptr->par->table){
997 // stretch the rows a bit
1001 /* table stuff -- end*/
1003 // This is nicer with box insets:
1007 row_ptr->ascent_of_text = maxasc;
1009 /* is it a top line? */
1010 if (row_ptr->pos == 0
1011 && row_ptr->par == firstpar) {
1013 /* some parksips VERY EASY IMPLEMENTATION */
1014 if (parameters->paragraph_separation == BufferParams::PARSEP_SKIP) {
1015 if (layout.isParagraph()
1016 && firstpar->GetDepth() == 0
1017 && firstpar->Previous())
1018 maxasc += parameters->getDefSkip().inPixels();
1019 else if (firstpar->Previous()
1020 && textclasslist.Style(parameters->textclass,
1021 firstpar->Previous()->GetLayout()).isParagraph()
1022 && firstpar->Previous()->GetDepth() == 0)
1023 // is it right to use defskip here too? (AS)
1024 maxasc += parameters->getDefSkip().inPixels();
1027 /* the paper margins */
1028 if (!row_ptr->par->previous)
1029 maxasc += LYX_PAPER_MARGIN;
1031 /* add the vertical spaces, that the user added */
1032 if (firstpar->added_space_top.kind() != VSpace::NONE)
1033 maxasc += int(firstpar->added_space_top.inPixels());
1035 /* do not forget the DTP-lines!
1036 * there height depends on the font of the nearest character */
1037 if (firstpar->line_top)
1038 maxasc += 2 * GetFont(firstpar, 0).ascent('x');
1040 /* and now the pagebreaks */
1041 if (firstpar->pagebreak_top)
1042 maxasc += 3 * DefaultHeight();
1044 /* this is special code for the chapter, since the label of this
1045 * layout is printed in an extra row */
1046 if (layout.labeltype == LABEL_COUNTER_CHAPTER
1047 && parameters->secnumdepth>= 0) {
1048 labeladdon = int(labelfont.maxDescent() *
1049 layout.spacing.getValue() *
1050 parameters->spacing.getValue())
1051 + int(labelfont.maxAscent() *
1052 layout.spacing.getValue() *
1053 parameters->spacing.getValue());
1056 /* special code for the top label */
1057 if ((layout.labeltype == LABEL_TOP_ENVIRONMENT
1058 || layout.labeltype == LABEL_BIBLIO
1059 || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)
1060 && row_ptr->par->IsFirstInSequence()
1061 && !row_ptr->par->GetLabestring().empty()) {
1063 (labelfont.maxAscent() *
1064 layout.spacing.getValue() *
1065 parameters->spacing.getValue())
1066 +(labelfont.maxDescent() *
1067 layout.spacing.getValue() *
1068 parameters->spacing.getValue())
1069 + layout.topsep * DefaultHeight()
1070 + layout.labelbottomsep * DefaultHeight());
1073 /* and now the layout spaces, for example before and after a section,
1074 * or between the items of a itemize or enumerate environment */
1076 if (!firstpar->pagebreak_top) {
1077 LyXParagraph *prev = row_ptr->par->Previous();
1079 prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth());
1080 if (prev && prev->GetLayout() == firstpar->GetLayout()
1081 && prev->GetDepth() == firstpar->GetDepth()
1082 && prev->GetLabelWidthString() == firstpar->GetLabelWidthString())
1084 layoutasc = (layout.itemsep * DefaultHeight());
1086 else if (row_ptr->previous) {
1087 tmptop = layout.topsep;
1089 if (row_ptr->previous->par->GetDepth() >= row_ptr->par->GetDepth())
1090 tmptop-= textclasslist.Style(parameters->textclass, row_ptr->previous->par->GetLayout()).bottomsep;
1093 layoutasc = (tmptop * DefaultHeight());
1095 else if (row_ptr->par->line_top){
1096 tmptop = layout.topsep;
1099 layoutasc = (tmptop * DefaultHeight());
1102 prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth()-1);
1104 maxasc += int(textclasslist.Style(parameters->textclass,
1105 prev->GetLayout()).parsep * DefaultHeight());
1108 if (firstpar->Previous()
1109 && firstpar->Previous()->GetDepth() == 0
1110 && firstpar->Previous()->GetLayout() != firstpar->GetLayout()) {
1113 else if (firstpar->Previous()){
1114 maxasc += int(layout.parsep * DefaultHeight());
1120 /* is it a bottom line? */
1121 if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
1122 && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {
1124 /* the paper margins */
1126 maxdesc += LYX_PAPER_MARGIN;
1128 /* add the vertical spaces, that the user added */
1129 if (firstpar->added_space_bottom.kind() != VSpace::NONE)
1130 maxdesc += int(firstpar->added_space_bottom.inPixels());
1132 /* do not forget the DTP-lines!
1133 * there height depends on the font of the nearest character */
1134 if (firstpar->line_bottom)
1135 maxdesc += 2 * (GetFont(par, par->Last()-1).ascent('x'));
1137 /* and now the pagebreaks */
1138 if (firstpar->pagebreak_bottom)
1139 maxdesc += 3 * DefaultHeight();
1141 /* and now the layout spaces, for example before and after a section,
1142 * or between the items of a itemize or enumerate environment */
1143 if (!firstpar->pagebreak_bottom && row_ptr->par->Next()) {
1144 LyXParagraph *nextpar = row_ptr->par->Next();
1145 LyXParagraph *comparepar = row_ptr->par;
1149 if (comparepar->GetDepth() > nextpar->GetDepth()) {
1150 usual = (textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1151 comparepar = comparepar->DepthHook(nextpar->GetDepth());
1152 if (comparepar->GetLayout()!= nextpar->GetLayout()
1153 || nextpar->GetLabelWidthString() !=
1154 comparepar->GetLabelWidthString())
1155 unusual = (textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1157 if (unusual > usual)
1158 layoutdesc = unusual;
1162 else if (comparepar->GetDepth() == nextpar->GetDepth()) {
1164 if (comparepar->GetLayout()!= nextpar->GetLayout()
1165 || nextpar->GetLabelWidthString() !=
1166 comparepar->GetLabelWidthString())
1167 layoutdesc = int(textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1172 /* incalculate the layout spaces */
1173 maxasc += int(layoutasc * 2 / (2 + firstpar->GetDepth()));
1174 maxdesc += int(layoutdesc * 2 / (2 + firstpar->GetDepth()));
1176 /* table stuff -- begin*/
1177 if (row_ptr->par->table){
1178 maxasc += row_ptr->par->table->
1179 AdditionalHeight(NumberOfCell(row_ptr->par, row_ptr->pos));
1181 /* table stuff -- end*/
1183 /* calculate the new height of the text */
1184 height -= row_ptr->height;
1186 row_ptr->height= maxasc+maxdesc+labeladdon;
1187 row_ptr->baseline= maxasc+labeladdon;
1189 height += row_ptr->height;
1193 /* Appends the implicit specified paragraph behind the specified row,
1194 * start at the implicit given position */
1195 void LyXText::AppendParagraph(Row * row)
1197 bool not_ready = true;
1199 // The last character position of a paragraph is an invariant so we can
1200 // safely get it here. (Asger)
1201 int lastposition = row->par->Last();
1204 // Get the next breakpoint
1205 int z = NextBreakPoint(row, paperwidth);
1209 // Insert the new row
1210 if (z < lastposition) {
1212 InsertRow(row, row->par, z);
1219 // Set the dimensions of the row
1220 tmprow->fill = Fill(tmprow, paperwidth);
1221 SetHeightOfRow(tmprow);
1223 } while (not_ready);
1227 void LyXText::BreakAgain(Row * row)
1229 bool not_ready = true;
1232 /* get the next breakpoint */
1233 LyXParagraph::size_type z =
1234 NextBreakPoint(row, paperwidth);
1237 if (z < row->par->Last() ) {
1238 if (!row->next || (row->next && row->next->par != row->par)) {
1239 /* insert a new row */
1241 InsertRow(row, row->par, z);
1248 not_ready = false; // the rest will not change
1254 /* if there are some rows too much, delete them */
1255 /* only if you broke the whole paragraph! */
1256 Row * tmprow2 = row;
1257 while (tmprow2->next && tmprow2->next->par == row->par) {
1258 tmprow2 = tmprow2->next;
1260 while (tmprow2 != row) {
1261 tmprow2 = tmprow2->previous;
1262 RemoveRow(tmprow2->next);
1267 /* set the dimensions of the row */
1268 tmprow->fill = Fill(tmprow, paperwidth);
1269 SetHeightOfRow(tmprow);
1270 } while (not_ready);
1274 /* this is just a little changed version of break again */
1275 void LyXText::BreakAgainOneRow(Row * row)
1277 /* get the next breakpoint */
1278 LyXParagraph::size_type z = NextBreakPoint(row, paperwidth);
1281 if (z < row->par->Last() ) {
1282 if (!row->next || (row->next && row->next->par != row->par)) {
1283 /* insert a new row */
1285 InsertRow(row, row->par, z);
1297 /* if there are some rows too much, delete them */
1298 /* only if you broke the whole paragraph! */
1299 Row * tmprow2 = row;
1300 while (tmprow2->next && tmprow2->next->par == row->par) {
1301 tmprow2 = tmprow2->next;
1303 while (tmprow2 != row) {
1304 tmprow2 = tmprow2->previous;
1305 RemoveRow(tmprow2->next);
1309 /* set the dimensions of the row */
1310 tmprow->fill = Fill(tmprow, paperwidth);
1311 SetHeightOfRow(tmprow);
1315 void LyXText::BreakParagraph(char keep_layout)
1317 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
1318 cursor.par->GetLayout());
1320 /* table stuff -- begin*/
1321 if (cursor.par->table) {
1322 // breaking of tables is only allowed at the beginning or the end */
1323 if (cursor.pos && cursor.pos < cursor.par->size() &&
1324 !cursor.par->table->ShouldBeVeryLastCell(NumberOfCell(cursor.par, cursor.pos)))
1325 return; /* no breaking of tables allowed */
1327 /* table stuff -- end*/
1329 /* this is only allowed, if the current paragraph is not empty or caption*/
1330 if ((cursor.par->Last() <= 0 && !cursor.par->IsDummy())
1332 layout.labeltype!= LABEL_SENSITIVE)
1335 SetUndo(Undo::INSERT,
1336 cursor.par->ParFromPos(cursor.pos)->previous,
1337 cursor.par->ParFromPos(cursor.pos)->next);
1339 /* table stuff -- begin*/
1340 if (cursor.par->table) {
1341 int cell = NumberOfCell(cursor.par, cursor.pos);
1342 if (cursor.par->table->ShouldBeVeryLastCell(cell))
1343 SetCursor(cursor.par, cursor.par->text.size());
1345 /* table stuff -- end*/
1346 /* please break alway behind a space */
1347 if (cursor.pos < cursor.par->Last()
1348 && cursor.par->IsLineSeparator(cursor.pos))
1351 /* break the paragraph */
1355 keep_layout = layout.isEnvironment();
1356 cursor.par->BreakParagraph(cursor.pos, keep_layout);
1358 /* table stuff -- begin*/
1359 if (cursor.par->table){
1360 // the table should stay with the contents
1362 cursor.par->Next()->table = cursor.par->table;
1363 cursor.par->table = 0;
1366 /* table stuff -- end*/
1368 /* well this is the caption hack since one caption is really enough */
1369 if (layout.labeltype == LABEL_SENSITIVE){
1371 cursor.par->SetLayout(0); /* set the new paragraph to standard-layout */
1373 cursor.par->Next()->SetLayout(0); /* set the new paragraph to standard-layout */
1377 /* if the cursor is at the beginning of a row without prior newline,
1379 * This touches only the screen-update. Otherwise we would may have
1380 * an empty row on the screen */
1381 if (cursor.pos && !cursor.row->par->IsNewline(cursor.row->pos -1) &&
1382 cursor.row->pos == cursor.pos) {
1386 status = LyXText::NEED_MORE_REFRESH;
1387 refresh_row = cursor.row;
1388 refresh_y = cursor.y - cursor.row->baseline;
1390 /* Do not forget the special right address boxes */
1391 if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX) {
1392 while (refresh_row->previous &&
1393 refresh_row->previous->par == refresh_row->par) {
1394 refresh_row = refresh_row->previous;
1395 refresh_y -= refresh_row->height;
1398 RemoveParagraph(cursor.row);
1400 /* set the dimensions of the cursor row */
1401 cursor.row->fill = Fill(cursor.row, paperwidth);
1403 SetHeightOfRow(cursor.row);
1405 while (!cursor.par->Next()->table && cursor.par->Next()->Last()
1406 && cursor.par->Next()->IsNewline(0))
1407 cursor.par->Next()->Erase(0);
1409 InsertParagraph(cursor.par->Next(), cursor.row);
1411 UpdateCounters(cursor.row->previous);
1413 /* this check is necessary. Otherwise the new empty paragraph will
1414 * be deleted automatically. And it is more friendly for the user! */
1416 SetCursor(cursor.par->Next(), 0);
1418 SetCursor(cursor.par, 0);
1420 if (cursor.row->next)
1421 BreakAgain(cursor.row->next);
1427 void LyXText::OpenFootnote()
1429 LyXParagraph * endpar,* tmppar;
1432 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
1434 /* if there is no footnote in this paragraph, just return. */
1436 || par->next->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1439 /* ok, move the cursor right before the footnote */
1441 /* just a little faster than using CursorRight() */
1442 for (cursor.pos= 0; cursor.par->ParFromPos(cursor.pos)!= par; cursor.pos++);
1443 /* now the cursor is at the beginning of the physical par */
1444 SetCursor(cursor.par,
1445 cursor.pos + cursor.par->ParFromPos(cursor.pos)->text.size());
1447 /* the cursor must be exactly before the footnote */
1448 par = cursor.par->ParFromPos(cursor.pos);
1450 status = LyXText::NEED_MORE_REFRESH;
1451 refresh_row = cursor.row;
1452 refresh_y = cursor.y - cursor.row->baseline;
1454 tmppar = cursor.par;
1455 endpar = cursor.par->Next();
1458 tmppar->OpenFootnote(cursor.pos);
1459 RemoveParagraph(row);
1460 /* set the dimensions of the cursor row */
1461 row->fill = Fill(row, paperwidth);
1462 SetHeightOfRow(row);
1463 tmppar = tmppar->Next();
1465 while (tmppar != endpar) {
1467 InsertParagraph(tmppar, row);
1468 while (row->next && row->next->par == tmppar)
1470 tmppar = tmppar->Next();
1473 SetCursor(par->next, 0);
1474 sel_cursor = cursor;
1478 /* table stuff -- begin*/
1480 void LyXText::TableFeatures(int feature, string val)
1482 if (!cursor.par->table)
1483 return; /* this should never happen */
1485 int actCell = NumberOfCell(cursor.par, cursor.pos);
1486 SetUndo(Undo::FINISH,
1487 cursor.par->ParFromPos(cursor.pos)->previous,
1488 cursor.par->ParFromPos(cursor.pos)->next);
1491 case LyXTable::SET_PWIDTH:
1492 cursor.par->table->SetPWidth(actCell, val);
1494 case LyXTable::SET_SPECIAL_COLUMN:
1495 case LyXTable::SET_SPECIAL_MULTI:
1496 cursor.par->table->SetAlignSpecial(actCell, val, feature);
1505 void LyXText::TableFeatures(int feature)
1508 int setAlign = LYX_ALIGN_LEFT;
1512 if (!cursor.par->table)
1513 return; /* this should never happen */
1515 int actCell = NumberOfCell(cursor.par, cursor.pos);
1516 SetUndo(Undo::FINISH,
1517 cursor.par->ParFromPos(cursor.pos)->previous,
1518 cursor.par->ParFromPos(cursor.pos)->next);
1521 case LyXTable::ALIGN_LEFT:
1522 setAlign= LYX_ALIGN_LEFT;
1524 case LyXTable::ALIGN_RIGHT:
1525 setAlign= LYX_ALIGN_RIGHT;
1527 case LyXTable::ALIGN_CENTER:
1528 setAlign= LYX_ALIGN_CENTER;
1534 case LyXTable::APPEND_ROW: {
1535 LyXParagraph::size_type pos = cursor.pos;
1537 /* move to the next row */
1538 int cell_org = actCell;
1539 int cell = cell_org;
1541 // if there is a ContRow following this row I have to add
1542 // the row after the ContRow's
1543 if ((pos < cursor.par->Last()) &&
1544 cursor.par->table->RowHasContRow(cell_org)) {
1545 while((pos < cursor.par->Last()) &&
1546 !cursor.par->table->IsContRow(cell)) {
1547 while (pos < cursor.par->Last() &&
1548 !cursor.par->IsNewline(pos))
1550 if (pos < cursor.par->Last())
1554 while((pos < cursor.par->Last()) &&
1555 cursor.par->table->IsContRow(cell)) {
1556 while (pos < cursor.par->Last() &&
1557 !cursor.par->IsNewline(pos))
1559 if (pos < cursor.par->Last())
1564 if (pos < cursor.par->Last())
1567 while (pos < cursor.par->Last() &&
1568 (cell == cell_org || !cursor.par->table->IsFirstCell(cell))){
1569 while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1571 if (pos < cursor.par->Last())
1576 /* insert the new cells */
1577 int number = cursor.par->table->NumberOfCellsInRow(cell_org);
1578 for (int i = 0; i < number; ++i)
1579 cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1581 /* append the row into the table */
1582 cursor.par->table->AppendRow(cell_org);
1586 case LyXTable::APPEND_CONT_ROW: {
1587 LyXParagraph::size_type pos = cursor.pos;
1588 /* move to the next row */
1589 int cell_org = actCell;
1590 int cell = cell_org;
1592 // if there is already a controw but not for this cell
1593 // the AppendContRow sets only the right values but does
1594 // not actually add a row
1595 if (cursor.par->table->RowHasContRow(cell_org) &&
1596 (cursor.par->table->CellHasContRow(cell_org)<0)) {
1597 cursor.par->table->AppendContRow(cell_org);
1601 while (pos < cursor.par->Last() &&
1603 || !cursor.par->table->IsFirstCell(cell))){
1604 while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1606 if (pos < cursor.par->Last())
1611 /* insert the new cells */
1612 int number = cursor.par->table->NumberOfCellsInRow(cell_org);
1614 for (i= 0; i<number; i++)
1615 cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1617 /* append the row into the table */
1618 cursor.par->table->AppendContRow(cell_org);
1622 case LyXTable::APPEND_COLUMN: {
1623 LyXParagraph::size_type pos = 0;
1624 int cell_org = actCell;
1627 if (pos && (cursor.par->IsNewline(pos-1))){
1628 if (cursor.par->table->AppendCellAfterCell(cell_org, cell)){
1629 cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1630 if (pos <= cursor.pos)
1637 } while (pos <= cursor.par->Last());
1638 /* remember that the very last cell doesn't end with a newline.
1639 This saves one byte memory per table ;-) */
1640 if (cursor.par->table->AppendCellAfterCell(cell_org, cell))
1641 cursor.par->InsertChar(cursor.par->Last(), LyXParagraph::META_NEWLINE);
1643 /* append the column into the table */
1644 cursor.par->table->AppendColumn(cell_org);
1649 case LyXTable::DELETE_ROW:
1650 if (current_view->the_locking_inset)
1651 current_view->unlockInset(current_view->the_locking_inset);
1652 RemoveTableRow(&cursor);
1656 case LyXTable::DELETE_COLUMN: {
1657 LyXParagraph::size_type pos = 0;
1658 int cell_org = actCell;
1660 if (current_view->the_locking_inset)
1661 current_view->unlockInset(current_view->the_locking_inset);
1663 if (!pos || (cursor.par->IsNewline(pos-1))){
1664 if (cursor.par->table->DeleteCellIfColumnIsDeleted(cell, cell_org)){
1666 while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1667 cursor.par->Erase(pos);
1668 if (pos < cursor.par->Last())
1669 cursor.par->Erase(pos);
1671 cursor.par->Erase(pos - 1); // the missing newline at the end of a table
1672 --pos; // because of pos++ below
1677 } while (pos <= cursor.par->Last());
1679 /* delete the column from the table */
1680 cursor.par->table->DeleteColumn(cell_org);
1682 /* set the cursor to the beginning of the table, where else? */
1687 case LyXTable::TOGGLE_LINE_TOP:
1688 lineSet = !cursor.par->table->TopLine(actCell);
1690 cursor.par->table->SetTopLine(actCell, lineSet);
1692 LyXParagraph::size_type i;
1694 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
1695 if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1696 cursor.par->table->SetTopLine(n, lineSet);
1704 case LyXTable::TOGGLE_LINE_BOTTOM:
1705 lineSet = !cursor.par->table->BottomLine(actCell);
1707 cursor.par->table->SetBottomLine(actCell, lineSet);
1709 LyXParagraph::size_type i;
1711 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
1712 if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1713 cursor.par->table->SetBottomLine(n, lineSet);
1721 case LyXTable::TOGGLE_LINE_LEFT:
1722 lineSet = !cursor.par->table->LeftLine(actCell);
1724 cursor.par->table->SetLeftLine(actCell, lineSet);
1726 LyXParagraph::size_type i;
1728 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
1729 if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1730 cursor.par->table->SetLeftLine(n, lineSet);
1738 case LyXTable::TOGGLE_LINE_RIGHT:
1739 lineSet = !cursor.par->table->RightLine(actCell);
1741 cursor.par->table->SetRightLine(actCell, lineSet);
1743 LyXParagraph::size_type i;
1745 for (i= sel_start_cursor.pos; i<= sel_end_cursor.pos; i++){
1746 if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1747 cursor.par->table->SetRightLine(n, lineSet);
1755 case LyXTable::ALIGN_LEFT:
1756 case LyXTable::ALIGN_RIGHT:
1757 case LyXTable::ALIGN_CENTER:
1759 cursor.par->table->SetAlignment(actCell, setAlign);
1761 LyXParagraph::size_type i;
1763 for (i= sel_start_cursor.pos; i<= sel_end_cursor.pos; i++){
1764 if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1765 cursor.par->table->SetAlignment(n, setAlign);
1773 case LyXTable::DELETE_TABLE:
1774 SetCursorIntern(cursor.par, 0);
1775 delete cursor.par->table;
1776 cursor.par->table = 0;
1777 // temporary: Should put table in simple_cut_buffer (with before and after
1778 // dummy-paragraph !!
1779 // not necessar anymore with UNDO :)
1780 for (LyXParagraph::size_type i =
1781 cursor.par->text.size() - 1; i >= 0; --i)
1782 cursor.par->Erase(i);
1786 case LyXTable::MULTICOLUMN: {
1788 // check wether we are completly in a multicol
1789 int multicol = cursor.par->table->IsMultiColumn(actCell);
1790 if (multicol && selection && sel_start_cursor.row == sel_end_cursor.row){
1791 multicol = NumberOfCell(sel_start_cursor.par, sel_start_cursor.pos)
1792 == NumberOfCell(sel_end_cursor.par, sel_end_cursor.pos);
1796 int newlines = cursor.par->table->UnsetMultiColumn(actCell);
1797 LyXParagraph::size_type pos = cursor.pos;
1798 while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1800 for (;newlines;newlines--)
1801 cursor.par->InsertChar(pos, LyXParagraph::META_NEWLINE);
1806 // selection must be in one row (or no selection)
1808 cursor.par->table->SetMultiColumn(NumberOfCell(cursor.par,
1815 if (sel_start_cursor.row == sel_end_cursor.row){
1816 LyXParagraph::size_type i;
1818 for (i = sel_start_cursor.pos;
1819 i < sel_end_cursor.pos; ++i){
1820 if (sel_start_cursor.par->IsNewline(i)){
1821 sel_start_cursor.par->Erase(i);
1822 // check for double-blanks
1823 if ((i && !sel_start_cursor.par->IsLineSeparator(i-1))
1825 (i < sel_start_cursor.par->Last()
1826 && !sel_start_cursor.par->IsLineSeparator(i)))
1827 sel_start_cursor.par->InsertChar(i, ' ');
1829 sel_end_cursor.pos--;
1836 SetMultiColumn(NumberOfCell(sel_start_cursor.par,
1837 sel_start_cursor.pos),
1839 cursor.pos = sel_start_cursor.pos;
1844 WriteAlert(_("Impossible Operation!"),
1845 _("Multicolumns can only be horizontally."),
1852 case LyXTable::SET_ALL_LINES:
1854 case LyXTable::UNSET_ALL_LINES:
1856 cursor.par->table->SetAllLines(NumberOfCell(cursor.par,
1860 LyXParagraph::size_type i;
1862 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
1863 if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1864 cursor.par->table->SetAllLines(n, setLines);
1871 case LyXTable::SET_LONGTABLE:
1872 cursor.par->table->SetLongTable(true);
1874 case LyXTable::UNSET_LONGTABLE:
1875 cursor.par->table->SetLongTable(false);
1877 case LyXTable::SET_ROTATE_TABLE:
1878 cursor.par->table->SetRotateTable(true);
1880 case LyXTable::UNSET_ROTATE_TABLE:
1881 cursor.par->table->SetRotateTable(false);
1883 case LyXTable::SET_ROTATE_CELL:
1885 cursor.par->table->SetRotateCell(actCell, true);
1887 LyXParagraph::size_type i;
1889 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
1890 if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1891 cursor.par->table->SetRotateCell(n, true);
1897 case LyXTable::UNSET_ROTATE_CELL:
1899 cursor.par->table->SetRotateCell(actCell, false);
1901 LyXParagraph::size_type i;
1903 for (i= sel_start_cursor.pos; i<= sel_end_cursor.pos; i++){
1904 if ((n= NumberOfCell(sel_start_cursor.par, i)) != m) {
1905 cursor.par->table->SetRotateCell(n, false);
1911 case LyXTable::SET_LINEBREAKS:
1912 what = !cursor.par->table->Linebreaks(cursor.par->table->FirstVirtualCell(actCell));
1914 cursor.par->table->SetLinebreaks(actCell, what);
1916 LyXParagraph::size_type i;
1918 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
1919 if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1920 cursor.par->table->SetLinebreaks(n, what);
1926 case LyXTable::SET_LTFIRSTHEAD:
1927 cursor.par->table->SetLTHead(actCell, true);
1929 case LyXTable::SET_LTHEAD:
1930 cursor.par->table->SetLTHead(actCell, false);
1932 case LyXTable::SET_LTFOOT:
1933 cursor.par->table->SetLTFoot(actCell, false);
1935 case LyXTable::SET_LTLASTFOOT:
1936 cursor.par->table->SetLTFoot(actCell, true);
1938 case LyXTable::SET_LTNEWPAGE:
1939 what = !cursor.par->table->LTNewPage(actCell);
1940 cursor.par->table->SetLTNewPage(actCell, what);
1946 void LyXText::InsertCharInTable(char c)
1951 bool jumped_over_space;
1953 /* first check, if there will be two blanks together or a blank at
1954 * the beginning of a paragraph.
1955 * I decided to handle blanks like normal characters, the main
1956 * difference are the special checks when calculating the row.fill
1957 * (blank does not count at the end of a row) and the check here */
1959 LyXFont realtmpfont = real_current_font;
1960 LyXFont rawtmpfont = current_font; /* store the current font.
1961 * This is because of the use
1962 * of cursor movements. The moving
1963 * cursor would refresh the
1966 // Get the font that is used to calculate the baselineskip
1967 LyXParagraph::size_type const lastpos =
1969 LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
1971 jumped_over_space = false;
1972 if (IsLineSeparatorChar(c)) {
1974 /* avoid double blanks but insert the new blank because
1975 * of a possible font change */
1976 if (cursor.pos < lastpos &&
1977 cursor.par->IsLineSeparator(cursor.pos))
1979 cursor.par->Erase(cursor.pos);
1980 jumped_over_space = true;
1982 else if ((cursor.pos > 0 &&
1983 cursor.par->IsLineSeparator(cursor.pos - 1))
1984 || (cursor.pos > 0 && cursor.par->IsNewline(cursor.pos - 1))
1985 || (cursor.pos == 0 &&
1986 !(cursor.par->Previous()
1987 && cursor.par->Previous()->footnoteflag
1988 == LyXParagraph::OPEN_FOOTNOTE)))
1991 else if (IsNewlineChar(c)) {
1992 if (!IsEmptyTableCell()) {
1993 TableFeatures(LyXTable::APPEND_CONT_ROW);
2000 y = cursor.y - row->baseline;
2001 if (c != LyXParagraph::META_INSET) /* in this case LyXText::InsertInset
2002 * already inserted the character */
2003 cursor.par->InsertChar(cursor.pos, c);
2004 SetCharFont(cursor.par, cursor.pos, rawtmpfont);
2006 if (!jumped_over_space) {
2007 /* refresh the positions */
2009 while (tmprow->next && tmprow->next->par == row->par) {
2010 tmprow = tmprow->next;
2017 CheckParagraphInTable(cursor.par, cursor.pos);
2019 current_font = rawtmpfont;
2020 real_current_font = realtmpfont;
2022 /* check, whether the last character's font has changed. */
2023 if (cursor.pos && cursor.pos == cursor.par->Last()
2024 && rawparfont != rawtmpfont)
2025 RedoHeightOfParagraph(cursor);
2029 void LyXText::CheckParagraphInTable(LyXParagraph * par,
2030 LyXParagraph::size_type pos)
2033 if (par->GetChar(pos) == LyXParagraph::META_INSET &&
2034 par->GetInset(pos) && par->GetInset(pos)->display()){
2035 par->GetInset(pos)->display(false);
2039 Row * row = GetRow(par, pos, y);
2041 int tmpheight = row->height;
2042 SetHeightOfRow(row);
2044 LyXParagraph::size_type tmp_pos = pos;
2045 /* update the table information */
2046 while (tmp_pos && !par->IsNewline(tmp_pos - 1))
2048 if (par->table->SetWidthOfCell(NumberOfCell(par, pos),
2049 WidthOfCell(par, tmp_pos))) {
2050 LyXCursor tmpcursor = cursor;
2051 SetCursorIntern(par, pos);
2052 /* make a complete redraw */
2053 RedoDrawingOfParagraph(cursor);
2057 /* redraw only the row */
2058 LyXCursor tmpcursor = cursor;
2059 SetCursorIntern(par, pos);
2061 refresh_x = cursor.x;
2063 refresh_pos = cursor.pos;
2066 if (tmpheight == row->height)
2067 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2069 status = LyXText::NEED_MORE_REFRESH;
2071 SetCursorIntern(cursor.par, cursor.pos);
2075 void LyXText::BackspaceInTable()
2077 Row * tmprow, * row;
2080 LyXFont rawtmpfont = current_font;
2081 LyXFont realtmpfont = real_current_font;
2083 // Get the font that is used to calculate the baselineskip
2084 int const lastpos = cursor.par->Last();
2085 LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2087 if (cursor.pos == 0) {
2088 /* no pasting of table paragraphs */
2093 /* this is the code for a normal backspace, not pasting
2095 SetUndo(Undo::DELETE,
2096 cursor.par->ParFromPos(cursor.pos)->previous,
2097 cursor.par->ParFromPos(cursor.pos)->next);
2101 /* some insets are undeletable here */
2102 if (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
2103 if (!cursor.par->GetInset(cursor.pos)->Deletable())
2108 y = cursor.y - row->baseline;
2110 /* some special code when deleting a newline. */
2111 if (cursor.par->IsNewline(cursor.pos)) {
2116 cursor.par->Erase(cursor.pos);
2118 /* refresh the positions */
2120 while (tmprow->next && tmprow->next->par == row->par) {
2121 tmprow = tmprow->next;
2125 /* delete superfluous blanks */
2126 if (cursor.pos < cursor.par->Last() - 1 &&
2127 (cursor.par->IsLineSeparator(cursor.pos))) {
2129 if (cursor.pos == BeginningOfMainBody(cursor.par)
2131 || cursor.par->IsLineSeparator(cursor.pos - 1)) {
2132 cursor.par->Erase(cursor.pos);
2133 /* refresh the positions */
2135 while (tmprow->next &&
2136 tmprow->next->par == row->par) {
2137 tmprow = tmprow->next;
2140 if (cursor.pos) /* move one character left */
2146 CheckParagraphInTable(cursor.par, cursor.pos);
2148 /* check, wether the last characters font has changed. */
2149 if (cursor.pos && cursor.pos == cursor.par->Last()
2150 && rawparfont != rawtmpfont)
2151 RedoHeightOfParagraph(cursor);
2153 /* restore the current font
2154 * That is what a user expects! */
2155 current_font = rawtmpfont;
2156 real_current_font = realtmpfont;
2158 SetCursorIntern(cursor.par, cursor.pos);
2161 /* table stuff -- end*/
2164 /* just a macro to make some thing easier. */
2165 void LyXText::RedoParagraph()
2167 LyXCursor tmpcursor = cursor;
2169 RedoParagraphs(cursor, cursor.par->Next());;
2170 SetCursorIntern(tmpcursor.par, tmpcursor.pos);
2174 /* insert a character, moves all the following breaks in the
2175 * same Paragraph one to the right and make a rebreak */
2176 void LyXText::InsertChar(char c)
2178 SetUndo(Undo::INSERT,
2179 cursor.par->ParFromPos(cursor.pos)->previous,
2180 cursor.par->ParFromPos(cursor.pos)->next);
2182 /* When the free-spacing option is set for the current layout,
2183 * all spaces are converted to protected spaces. */
2184 bool freeSpacingBo =
2185 textclasslist.Style(parameters->textclass,
2186 cursor.row->par->GetLayout()).free_spacing;
2188 if (freeSpacingBo && IsLineSeparatorChar(c)
2189 && (!cursor.pos || cursor.par->IsLineSeparator(cursor.pos-1)))
2190 c = LyXParagraph::META_PROTECTED_SEPARATOR;
2192 /* table stuff -- begin*/
2193 if (cursor.par->table) {
2194 InsertCharInTable(c);
2198 /* table stuff -- end*/
2200 /* first check, if there will be two blanks together or a blank at
2201 * the beginning of a paragraph.
2202 * I decided to handle blanks like normal characters, the main
2203 * difference are the special checks when calculating the row.fill
2204 * (blank does not count at the end of a row) and the check here */
2206 // The bug is triggered when we type in a description environment:
2207 // The current_font is not changed when we go from label to main text
2208 // and it should (along with realtmpfont) when we type the space.
2209 #ifdef WITH_WARNINGS
2210 #warning There is a bug here! (Asger)
2213 LyXFont realtmpfont = real_current_font;
2214 LyXFont rawtmpfont = current_font; /* store the current font.
2215 * This is because of the use
2216 * of cursor movements. The moving
2217 * cursor would refresh the
2220 // Get the font that is used to calculate the baselineskip
2221 LyXParagraph::size_type lastpos = cursor.par->Last();
2222 LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2224 bool jumped_over_space = false;
2226 if (IsLineSeparatorChar(c)) {
2228 if (cursor.pos < lastpos
2229 && cursor.par->IsLineSeparator(cursor.pos)) {
2230 /* the user inserted a space before a space. So we
2231 * will just make a CursorRight. BUT: The font of this
2232 * space should be set to current font. That is why
2233 * we need to rebreak perhaps. If there is a protected
2234 * blank at the end of a row we have to force
2237 current_view->owner()->getMiniBuffer()->Set(_("You cannot type two spaces this way. Please read the Tutorial."));
2238 if (cursor.pos == RowLast(cursor.row)
2239 && !IsLineSeparatorChar(c))
2240 cursor.row->fill = -1; /* force rebreak */
2242 cursor.par->Erase(cursor.pos);
2243 jumped_over_space = true;
2245 } else if ((cursor.pos > 0
2246 && cursor.par->IsLineSeparator(cursor.pos - 1))
2248 && cursor.par->IsNewline(cursor.pos - 1))
2250 && !(cursor.par->Previous()
2251 && cursor.par->Previous()->footnoteflag
2252 == LyXParagraph::OPEN_FOOTNOTE))) {
2253 if (cursor.pos == 0 )
2254 current_view->owner()->getMiniBuffer()->Set(_("You cannot insert a space at the beginning of a paragraph. Please read the Tutorial."));
2256 current_view->owner()->getMiniBuffer()->Set(_("You cannot type two spaces this way. Please read the Tutorial."));
2260 } else if (IsNewlineChar(c)) {
2261 if (cursor.par->FirstPhysicalPar() == cursor.par
2262 && cursor.pos <= BeginningOfMainBody(cursor.par)) {
2266 /* no newline at first position
2267 * of a paragraph or behind labels.
2268 * TeX does not allow that. */
2270 if (cursor.pos < cursor.par->Last() &&
2271 cursor.par->IsLineSeparator(cursor.pos))
2272 CursorRightIntern(); // newline always after a blank!
2273 cursor.row->fill = -1; // to force a new break
2276 /* the display inset stuff */
2277 if (cursor.row->par->GetChar(cursor.row->pos) == LyXParagraph::META_INSET
2278 && cursor.row->par->GetInset(cursor.row->pos)
2279 && cursor.row->par->GetInset(cursor.row->pos)->display())
2280 cursor.row->fill = -1; // to force a new break
2282 /* get the cursor row fist */
2283 /* this is a dumb solution, i will try to hold the cursor.row
2285 /* row = GetRow(cursor.par, cursor.pos, y);*/
2286 /* ok, heres a better way: */
2287 Row * row = cursor.row;
2288 long y = cursor.y - row->baseline;
2289 if (c != LyXParagraph::META_INSET) /* in this case LyXText::InsertInset
2290 * already insertet the character */
2291 cursor.par->InsertChar(cursor.pos, c);
2292 SetCharFont(cursor.par, cursor.pos, rawtmpfont);
2294 if (!jumped_over_space) {
2295 /* refresh the positions */
2297 while (tmprow->next && tmprow->next->par == row->par) {
2298 tmprow = tmprow->next;
2303 /* Is there a break one row above */
2304 if ((cursor.par->IsLineSeparator(cursor.pos)
2305 || cursor.par->IsNewline(cursor.pos)
2306 || cursor.row->fill == -1)
2307 && row->previous && row->previous->par == row->par) {
2308 LyXParagraph::size_type z = NextBreakPoint(row->previous,
2310 if ( z >= row->pos) {
2313 /* set the dimensions of the row above */
2314 row->previous->fill = Fill(row->previous, paperwidth);
2316 SetHeightOfRow(row->previous);
2318 y -= row->previous->height;
2320 refresh_row = row->previous;
2321 status = LyXText::NEED_MORE_REFRESH;
2323 BreakAgainOneRow(row);
2324 SetCursor(cursor.par, cursor.pos + 1);
2325 /* cursor MUST be in row now */
2327 if (row->next && row->next->par == row->par)
2328 need_break_row = row->next;
2332 current_font = rawtmpfont;
2333 real_current_font = realtmpfont;
2335 // check, wether the last characters font has changed.
2336 if (cursor.pos && cursor.pos == cursor.par->Last()
2337 && rawparfont != rawtmpfont)
2338 RedoHeightOfParagraph(cursor);
2345 /* recalculate the fill of the row */
2346 if (row->fill >= 0) /* needed because a newline
2347 * will set fill to -1. Otherwise
2348 * we would not get a rebreak! */
2349 row->fill = Fill(row, paperwidth);
2350 if (row->fill < 0 ) {
2353 refresh_x = cursor.x;
2354 refresh_pos = cursor.pos;
2355 status = LyXText::NEED_MORE_REFRESH;
2356 BreakAgainOneRow(row);
2357 /* will the cursor be in another row now? */
2358 if (RowLast(row) <= cursor.pos + 1 && row->next) {
2359 if (row->next && row->next->par == row->par)
2363 BreakAgainOneRow(row);
2365 SetCursor(cursor.par, cursor.pos + 1);
2366 if (row->next && row->next->par == row->par)
2367 need_break_row = row->next;
2371 current_font = rawtmpfont;
2372 real_current_font = realtmpfont;
2375 refresh_x = cursor.x;
2377 refresh_pos = cursor.pos;
2379 int tmpheight = row->height;
2380 SetHeightOfRow(row);
2381 if (tmpheight == row->height)
2382 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2384 status = LyXText::NEED_MORE_REFRESH;
2386 SetCursor(cursor.par, cursor.pos + 1);
2387 current_font = rawtmpfont;
2388 real_current_font = realtmpfont;
2391 /* check, wether the last characters font has changed. */
2392 if (cursor.pos && cursor.pos == cursor.par->Last()
2393 && rawparfont != rawtmpfont) {
2394 RedoHeightOfParagraph(cursor);
2396 /* now the special right address boxes */
2397 if (textclasslist.Style(parameters->textclass,
2398 cursor.par->GetLayout()).margintype
2399 == MARGIN_RIGHT_ADDRESS_BOX) {
2400 RedoDrawingOfParagraph(cursor);
2408 void LyXText::charInserted()
2410 // Here we could call FinishUndo for every 20 characters inserted.
2411 // This is from my experience how emacs does it.
2412 static unsigned int counter = 0;
2422 void LyXText::PrepareToPrint(Row * row, float & x, float & fill_separator,
2423 float & fill_hfill, float & fill_label_hfill)
2427 float w = row->fill;
2429 fill_label_hfill = 0;
2431 fill_label_hfill = 0;
2433 x = LeftMargin(row);
2435 /* is there a manual margin with a manual label */
2436 if (textclasslist.Style(parameters->textclass,
2437 row->par->GetLayout()).margintype == MARGIN_MANUAL
2438 && textclasslist.Style(parameters->textclass,
2439 row->par->GetLayout()).labeltype == LABEL_MANUAL) {
2441 nlh = NumberOfLabelHfills(row) + 1; /* one more since labels
2442 * are left aligned*/
2443 if (nlh && !row->par->GetLabelWidthString().empty()) {
2444 fill_label_hfill = LabelFill(row) / nlh;
2448 /* are there any hfills in the row? */
2449 nh = NumberOfHfills(row);
2451 /* table stuff -- begin*/
2452 if (row->par->table) {
2453 w = paperwidth - row->par->table->WidthOfTable()
2454 - x - RightMargin(row);
2455 nh = 0; /* ignore hfills in tables */
2457 /* table stuff -- end*/
2462 /* is it block, flushleft or flushright?
2463 * set x how you need it */
2465 if (row->par->FirstPhysicalPar()->align == LYX_ALIGN_LAYOUT)
2466 align = textclasslist.Style(parameters->textclass, row->par->GetLayout()).align;
2468 align = row->par->FirstPhysicalPar()->align;
2470 /* center displayed insets */
2471 if (row->par->GetChar(row->pos) == LyXParagraph::META_INSET
2472 && row->par->GetInset(row->pos)
2473 && row->par->GetInset(row->pos)->display())
2474 align = LYX_ALIGN_CENTER;
2477 case LYX_ALIGN_BLOCK:
2478 ns = NumberOfSeparators(row);
2479 if (ns && row->next && row->next->par == row->par &&
2480 !(row->next->par->IsNewline(row->next->pos-1))
2481 && !(row->next->par->GetChar(row->next->pos) == LyXParagraph::META_INSET
2482 && row->next->par->GetInset(row->next->pos)
2483 && row->next->par->GetInset(row->next->pos)->display())
2485 fill_separator = w / ns;
2487 case LYX_ALIGN_RIGHT:
2490 case LYX_ALIGN_CENTER:
2498 /* important for the screen */
2501 /* the cursor set functions have a special mechanism. When they
2502 * realize, that you left an empty paragraph, they will delete it.
2503 * They also delete the corresponding row */
2505 void LyXText::CursorRightOneWord()
2507 // treat floats, HFills and Insets as words
2508 LyXCursor tmpcursor = cursor;
2510 if (tmpcursor.pos == tmpcursor.par->Last()
2511 && tmpcursor.par->Next())
2513 tmpcursor.par = tmpcursor.par->Next();
2518 // Skip through initial nonword stuff.
2519 while ( tmpcursor.pos < tmpcursor.par->Last() &&
2520 ! tmpcursor.par->IsWord( tmpcursor.pos ) )
2522 // printf("Current pos1 %d", tmpcursor.pos) ;
2526 // Advance through word.
2527 while ( tmpcursor.pos < tmpcursor.par->Last() &&
2528 tmpcursor.par->IsWord( tmpcursor.pos ) )
2530 // printf("Current pos2 %d", tmpcursor.pos) ;
2535 SetCursor(tmpcursor.par, tmpcursor.pos);
2539 void LyXText::CursorTab()
2541 if (cursor.par->table) {
2542 int cell = NumberOfCell(cursor.par, cursor.pos);
2543 while(cursor.par->table->IsContRow(cell)) {
2545 cell = NumberOfCell(cursor.par, cursor.pos);
2547 if (cursor.par->table->ShouldBeVeryLastCell(cell))
2548 TableFeatures(LyXTable::APPEND_ROW);
2550 LyXCursor tmpcursor = cursor;
2551 while (tmpcursor.pos < tmpcursor.par->Last()
2552 && !tmpcursor.par->IsNewline(tmpcursor.pos))
2555 if (tmpcursor.pos == tmpcursor.par->Last()){
2556 if (tmpcursor.par->Next()) {
2557 tmpcursor.par = tmpcursor.par->Next();
2563 SetCursor(tmpcursor.par, tmpcursor.pos);
2564 if (cursor.par->table) {
2565 int cell = NumberOfCell(cursor.par, cursor.pos);
2566 while (cursor.par->table->IsContRow(cell) &&
2567 !cursor.par->table->ShouldBeVeryLastCell(cell)) {
2569 while (tmpcursor.pos < tmpcursor.par->Last()
2570 && !tmpcursor.par->IsNewline(tmpcursor.pos))
2573 if (tmpcursor.pos == tmpcursor.par->Last()){
2574 if (tmpcursor.par->Next()) {
2575 tmpcursor.par = tmpcursor.par->Next();
2581 SetCursor(tmpcursor.par, tmpcursor.pos);
2582 cell = NumberOfCell(cursor.par, cursor.pos);
2588 /* -------> Skip initial whitespace at end of word and move cursor to *start*
2589 of prior word, not to end of next prior word. */
2591 void LyXText::CursorLeftOneWord()
2593 // treat HFills, floats and Insets as words
2594 LyXCursor tmpcursor = cursor;
2595 while (tmpcursor.pos
2596 && (tmpcursor.par->IsSeparator(tmpcursor.pos - 1)
2597 || tmpcursor.par->IsKomma(tmpcursor.pos - 1))
2598 && !(tmpcursor.par->IsHfill(tmpcursor.pos - 1)
2599 || tmpcursor.par->IsFloat(tmpcursor.pos - 1)
2600 || tmpcursor.par->IsInset(tmpcursor.pos - 1)))
2604 && (tmpcursor.par->IsInset(tmpcursor.pos - 1)
2605 || tmpcursor.par->IsFloat(tmpcursor.pos - 1)
2606 || tmpcursor.par->IsHfill(tmpcursor.pos - 1))) {
2608 } else if (!tmpcursor.pos) {
2609 if (tmpcursor.par->Previous()){
2610 tmpcursor.par = tmpcursor.par->Previous();
2611 tmpcursor.pos = tmpcursor.par->Last();
2613 } else { // Here, tmpcursor != 0
2614 while (tmpcursor.pos > 0 &&
2615 tmpcursor.par->IsWord(tmpcursor.pos-1) )
2618 SetCursor(tmpcursor.par, tmpcursor.pos);
2621 /* -------> Select current word. This depends on behaviour of CursorLeftOneWord(), so it is
2624 void LyXText::SelectWord()
2626 /* Move cursor to the beginning, when not already there. */
2628 && !cursor.par->IsSeparator(cursor.pos-1)
2629 && !cursor.par->IsKomma(cursor.pos-1) )
2630 CursorLeftOneWord();
2632 /* set the sel cursor */
2633 sel_cursor = cursor;
2635 while ( cursor.pos < cursor.par->Last()
2636 && !cursor.par->IsSeparator(cursor.pos)
2637 && !cursor.par->IsKomma(cursor.pos) )
2639 SetCursor( cursor.par, cursor.pos );
2641 /* finally set the selection */
2646 /* -------> Select the word currently under the cursor when:
2647 1: no selection is currently set,
2648 2: the cursor is not at the borders of the word. */
2650 int LyXText::SelectWordWhenUnderCursor()
2652 if ( selection ) return 0;
2653 if ( cursor.pos < cursor.par->Last()
2654 && !cursor.par->IsSeparator(cursor.pos)
2655 && !cursor.par->IsKomma(cursor.pos)
2657 && !cursor.par->IsSeparator(cursor.pos -1)
2658 && !cursor.par->IsKomma(cursor.pos -1) ) {
2666 // This function is only used by the spellchecker for NextWord().
2667 // It doesn't handle LYX_ACCENTs and probably never will.
2668 char * LyXText::SelectNextWord(float & value)
2670 LyXParagraph * tmppar = cursor.par;
2672 // If this is not the very first word, skip rest of
2673 // current word because we are probably in the middle
2674 // of a word if there is text here.
2675 if (cursor.pos || cursor.par->previous) {
2676 while (cursor.pos < cursor.par->Last()
2677 && cursor.par->IsLetter(cursor.pos))
2680 // Now, skip until we have real text (will jump paragraphs)
2681 while ((cursor.par->Last() > cursor.pos
2682 && (!cursor.par->IsLetter(cursor.pos)
2683 || cursor.par->getFont(cursor.pos).latex() == LyXFont::ON))
2684 || (cursor.par->Last() == cursor.pos
2685 && cursor.par->Next())){
2686 if (cursor.pos == cursor.par->Last()) {
2687 cursor.par = cursor.par->Next();
2694 // Update the value if we changed paragraphs
2695 if (cursor.par != tmppar){
2696 SetCursor(cursor.par, cursor.pos);
2697 value = float(cursor.y)/float(height);
2700 /* Start the selection from here */
2701 sel_cursor = cursor;
2705 /* and find the end of the word
2706 (optional hyphens are part of a word) */
2707 while (cursor.pos < cursor.par->Last()
2708 && (cursor.par->IsLetter(cursor.pos))
2709 || (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET &&
2710 cursor.par->GetInset(cursor.pos) != 0 &&
2711 cursor.par->GetInset(cursor.pos)->Latex(latex, 0) == 0 &&
2715 // Finally, we copy the word to a string and return it
2718 if (sel_cursor.pos < cursor.pos) {
2719 str = new char [cursor.pos - sel_cursor.pos + 2];
2720 LyXParagraph::size_type i, j;
2721 for (i = sel_cursor.pos, j = 0; i < cursor.pos; ++i) {
2722 if (cursor.par->GetChar(i) != LyXParagraph::META_INSET)
2723 str[j++] = cursor.par->GetChar(i);
2731 // This one is also only for the spellchecker
2732 void LyXText::SelectSelectedWord()
2734 /* move cursor to the beginning */
2735 SetCursor(sel_cursor.par, sel_cursor.pos);
2737 /* set the sel cursor */
2738 sel_cursor = cursor;
2742 /* now find the end of the word */
2743 while (cursor.pos < cursor.par->Last()
2744 && (cursor.par->IsLetter(cursor.pos)
2745 || (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET &&
2746 cursor.par->GetInset(cursor.pos) != 0 &&
2747 cursor.par->GetInset(cursor.pos)->Latex(latex, 0) == 0 &&
2751 SetCursor(cursor.par, cursor.pos);
2753 /* finally set the selection */
2758 /* -------> Delete from cursor up to the end of the current or next word. */
2759 void LyXText::DeleteWordForward()
2761 LyXCursor tmpcursor = cursor;
2763 if (!cursor.par->Last())
2766 /* -------> Skip initial non-word stuff. */
2767 while ( cursor.pos < cursor.par->Last()
2768 && (cursor.par->IsSeparator(cursor.pos)
2769 || cursor.par->IsKomma(cursor.pos)) )
2772 SetCursorIntern(cursor.par, cursor.pos);
2773 selection = True; // to avoid deletion
2774 CursorRightOneWord();
2775 sel_cursor = cursor;
2779 /* -----> Great, CutSelection() gets rid of multiple spaces. */
2785 /* -------> Delete from cursor to start of current or prior word. */
2786 void LyXText::DeleteWordBackward()
2788 LyXCursor tmpcursor = cursor;
2789 if (!cursor.par->Last())
2792 selection = true; // to avoid deletion
2793 CursorLeftOneWord();
2794 sel_cursor = cursor;
2802 /* -------> Kill to end of line. */
2803 void LyXText::DeleteLineForward()
2805 LyXCursor tmpcursor = cursor;
2806 if (!cursor.par->Last())
2810 sel_cursor = cursor;
2813 if (selection == false) {
2814 DeleteWordForward();
2822 // Change the case of a word at cursor position. The meaning of action
2824 // 0 change to lowercase
2825 // 1 capitalize word
2826 // 2 change to uppercase
2827 // This function directly manipulates LyXParagraph::text because there
2828 // is no LyXParagraph::SetChar currently. I did what I could to ensure
2829 // that it is correct. I guess part of it should be moved to
2830 // LyXParagraph, but it will have to change for 1.1 anyway. At least
2831 // it does not access outside of the allocated array as the older
2832 // version did. (JMarc)
2833 void LyXText::ChangeWordCase(LyXText::TextCase action)
2835 LyXParagraph * tmppar = cursor.par->ParFromPos(cursor.pos);
2837 SetUndo(Undo::FINISH, tmppar->previous, tmppar->next);
2839 LyXParagraph::size_type tmppos =
2840 cursor.par->PositionInParFromPos(cursor.pos);
2841 while (tmppos < tmppar->size()) {
2842 unsigned char c = tmppar->text[tmppos];
2843 if (IsKommaChar(c) || IsLineSeparatorChar(c))
2845 if (c != LyXParagraph::META_INSET) {
2847 case text_lowercase:
2850 case text_capitalization:
2852 action = text_lowercase;
2854 case text_uppercase:
2860 tmppar->text[tmppos] = c;
2863 CheckParagraph(tmppar, tmppos);
2864 CursorRightOneWord();
2868 void LyXText::Delete()
2870 LyXCursor old_cursor = cursor;
2871 /* this is a very easy implementation*/
2873 /* just move to the right */
2874 CursorRightIntern();
2876 if (cursor.par->previous == old_cursor.par->previous
2877 && cursor.par != old_cursor.par)
2878 return; // delete-emty-paragraph-mechanism has done it
2880 /* if you had success make a backspace */
2881 if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) {
2882 LyXCursor tmpcursor = cursor;
2883 cursor = old_cursor; // to make sure undo gets the right cursor position
2884 SetUndo(Undo::DELETE,
2885 cursor.par->ParFromPos(cursor.pos)->previous,
2886 cursor.par->ParFromPos(cursor.pos)->next);
2893 void LyXText::Backspace()
2895 LyXParagraph * tmppar;
2896 Row * tmprow, * row;
2900 /* table stuff -- begin*/
2902 if (cursor.par->table) {
2906 /* table stuff -- end*/
2908 LyXFont rawtmpfont = current_font;
2909 LyXFont realtmpfont = real_current_font;
2911 // Get the font that is used to calculate the baselineskip
2912 int const lastpos = cursor.par->Last();
2913 LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2915 if (cursor.pos == 0) {
2916 /* we may paste some paragraphs */
2918 /* is it an empty paragraph? */
2921 || (lastpos == 1 && cursor.par->IsSeparator(0)))
2922 && !(cursor.par->Next()
2923 && cursor.par->footnoteflag ==
2924 LyXParagraph::NO_FOOTNOTE
2925 && cursor.par->Next()->footnoteflag ==
2926 LyXParagraph::OPEN_FOOTNOTE)) {
2928 if (cursor.par->previous) {
2929 tmppar = cursor.par->previous->FirstPhysicalPar();
2930 if (cursor.par->GetLayout() == tmppar->GetLayout()
2931 && cursor.par->footnoteflag == tmppar->footnoteflag
2932 && cursor.par->GetAlign() == tmppar->GetAlign()) {
2934 tmppar->line_bottom = cursor.par->line_bottom;
2935 tmppar->added_space_bottom = cursor.par->added_space_bottom;
2936 tmppar->pagebreak_bottom = cursor.par->pagebreak_bottom;
2941 /* the layout things can change the height of a row ! */
2942 tmpheight = cursor.row->height;
2943 SetHeightOfRow(cursor.row);
2944 if (cursor.row->height != tmpheight) {
2945 refresh_y = cursor.y - cursor.row->baseline;
2946 refresh_row = cursor.row;
2947 status = LyXText::NEED_MORE_REFRESH;
2952 if (cursor.par->ParFromPos(cursor.pos)->previous){
2953 SetUndo(Undo::DELETE,
2954 cursor.par->ParFromPos(cursor.pos)->previous->previous,
2955 cursor.par->ParFromPos(cursor.pos)->next);
2957 tmppar = cursor.par;
2958 tmprow = cursor.row;
2960 /* Pasting is not allowed, if the paragraphs have different
2961 layout. I think it is a real bug of all other
2962 word processors to allow it. It confuses the user.
2963 Even so with a footnote paragraph and a non-footnote
2964 paragraph. I will not allow pasting in this case,
2965 because the user would be confused if the footnote behaves
2966 different wether it is open or closed.
2968 Correction: Pasting is always allowed with standard-layout
2970 if (cursor.par != tmppar
2971 && (cursor.par->GetLayout() == tmppar->GetLayout()
2972 || !tmppar->GetLayout())
2973 && cursor.par->footnoteflag == tmppar->footnoteflag
2974 /* table stuff -- begin*/
2975 && !cursor.par->table /* no pasting of tables */
2976 /* table stuff -- end*/
2977 && cursor.par->GetAlign() == tmppar->GetAlign()) {
2979 cursor.par->PasteParagraph();
2982 cursor.par->IsSeparator(cursor.pos - 1)))
2983 cursor.par->InsertChar(cursor.pos, ' ');
2988 status = LyXText::NEED_MORE_REFRESH;
2989 refresh_row = cursor.row;
2990 refresh_y = cursor.y - cursor.row->baseline;
2992 /* remove the lost paragraph */
2993 RemoveParagraph(tmprow);
2996 AppendParagraph(cursor.row);
2997 UpdateCounters(cursor.row);
2999 /* the row may have changed, block, hfills etc. */
3000 SetCursor(cursor.par, cursor.pos);
3003 /* this is the code for a normal backspace, not pasting
3005 SetUndo(Undo::DELETE,
3006 cursor.par->ParFromPos(cursor.pos)->previous,
3007 cursor.par->ParFromPos(cursor.pos)->next);
3010 /* some insets are undeletable here */
3011 if (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
3012 if (!cursor.par->GetInset(cursor.pos)->Deletable())
3014 /* force complete redo when erasing display insets */
3015 /* this is a cruel mathod but save..... Matthias */
3016 if (cursor.par->GetInset(cursor.pos)->display()){
3017 cursor.par->Erase(cursor.pos);
3024 y = cursor.y - row->baseline;
3025 LyXParagraph::size_type z;
3026 /* remember that a space at the end of a row doesnt count
3027 * when calculating the fill */
3028 if (cursor.pos < RowLast(row) ||
3029 !cursor.par->IsLineSeparator(cursor.pos)) {
3030 row->fill += SingleWidth(cursor.par, cursor.pos);
3033 /* some special code when deleting a newline. This is similar
3034 * to the behavior when pasting paragraphs */
3035 if (cursor.pos && cursor.par->IsNewline(cursor.pos)) {
3036 cursor.par->Erase(cursor.pos);
3037 /* refresh the positions */
3039 while (tmprow->next && tmprow->next->par == row->par) {
3040 tmprow = tmprow->next;
3043 if (cursor.par->IsLineSeparator(cursor.pos - 1))
3046 if (cursor.pos < cursor.par->Last() && !cursor.par->IsSeparator(cursor.pos)) {
3047 cursor.par->InsertChar(cursor.pos, ' ');
3048 /* refresh the positions */
3050 while (tmprow->next && tmprow->next->par == row->par) {
3051 tmprow = tmprow->next;
3056 cursor.par->Erase(cursor.pos);
3058 /* refresh the positions */
3060 while (tmprow->next && tmprow->next->par == row->par) {
3061 tmprow = tmprow->next;
3065 /* delete superfluous blanks */
3066 if (cursor.pos < cursor.par->Last() - 1 &&
3067 (cursor.par->IsLineSeparator(cursor.pos))) {
3069 if (cursor.pos == BeginningOfMainBody(cursor.par)
3071 || cursor.par->IsLineSeparator(cursor.pos - 1)) {
3072 cursor.par->Erase(cursor.pos);
3073 /* refresh the positions */
3075 while (tmprow->next &&
3076 tmprow->next->par == row->par) {
3077 tmprow = tmprow->next;
3080 if (cursor.pos) /* move one character left */
3085 /* delete newlines at the beginning of paragraphs */
3086 while (cursor.par->Last() &&
3087 cursor.par->IsNewline(cursor.pos) &&
3088 cursor.pos == BeginningOfMainBody(cursor.par)) {
3089 cursor.par->Erase(cursor.pos);
3090 /* refresh the positions */
3092 while (tmprow->next &&
3093 tmprow->next->par == row->par) {
3094 tmprow = tmprow->next;
3100 /* is there a break one row above */
3101 if (row->previous && row->previous->par == row->par) {
3102 z = NextBreakPoint(row->previous, paperwidth);
3103 if ( z >= row->pos) {
3106 tmprow = row->previous;
3108 /* maybe the current row is now empty */
3109 if (row->pos >= row->par->Last()) {
3115 BreakAgainOneRow(row);
3116 if (row->next && row->next->par == row->par)
3117 need_break_row = row->next;
3122 /* set the dimensions of the row above */
3123 y -= tmprow->height;
3124 tmprow->fill = Fill(tmprow, paperwidth);
3125 SetHeightOfRow(tmprow);
3128 refresh_row = tmprow;
3129 status = LyXText::NEED_MORE_REFRESH;
3130 SetCursor(cursor.par, cursor.pos);
3131 current_font = rawtmpfont;
3132 real_current_font = realtmpfont;
3133 /* check, whether the last character's font has changed. */
3134 rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
3135 if (rawparfont != rawtmpfont)
3136 RedoHeightOfParagraph(cursor);
3141 /* break the cursor row again */
3142 z = NextBreakPoint(row, paperwidth);
3144 if ( z != RowLast(row) ||
3145 (row->next && row->next->par == row->par &&
3146 RowLast(row) == row->par->Last() - 1)){
3148 /* it can happen that a paragraph loses one row
3149 * without a real breakup. This is when a word
3150 * is to long to be broken. Well, I don t care this
3152 if (row->next && row->next->par == row->par &&
3153 RowLast(row) == row->par->Last() - 1)
3154 RemoveRow(row->next);
3158 status = LyXText::NEED_MORE_REFRESH;
3160 BreakAgainOneRow(row);
3162 SetCursor(cursor.par, cursor.pos);
3163 /* cursor MUST be in row now */
3165 if (row->next && row->next->par == row->par)
3166 need_break_row = row->next;
3170 /* set the dimensions of the row */
3171 row->fill = Fill(row, paperwidth);
3172 int tmpheight = row->height;
3173 SetHeightOfRow(row);
3174 if (tmpheight == row->height)
3175 status = LyXText::NEED_VERY_LITTLE_REFRESH;
3177 status = LyXText::NEED_MORE_REFRESH;
3180 SetCursor(cursor.par, cursor.pos);
3184 /* restore the current font
3185 * That is what a user expects! */
3186 current_font = rawtmpfont;
3187 real_current_font = realtmpfont;
3189 /* check, wether the last characters font has changed. */
3190 rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
3191 if (rawparfont != rawtmpfont) {
3192 RedoHeightOfParagraph(cursor);
3194 /* now the special right address boxes */
3195 if (textclasslist.Style(parameters->textclass,
3196 cursor.par->GetLayout()).margintype == MARGIN_RIGHT_ADDRESS_BOX) {
3197 RedoDrawingOfParagraph(cursor);
3203 void LyXText::GetVisibleRow(LyXScreen & scr, int offset,
3204 Row * row_ptr, long y)
3206 /* returns a printed row */
3207 LyXParagraph::size_type pos, pos_end;
3209 int y_top, y_bottom;
3210 float fill_separator, fill_hfill, fill_label_hfill;
3211 LyXParagraph * par, * firstpar;
3215 if (row_ptr->height <= 0) {
3216 lyxerr << "LYX_ERROR: row.height: " << row_ptr->height << endl;
3219 left_margin = LabelEnd(row_ptr);
3220 PrepareToPrint(row_ptr, x, fill_separator,
3221 fill_hfill, fill_label_hfill);
3223 LyXParagraph::size_type main_body =
3224 BeginningOfMainBody(row_ptr->par);
3225 /* initialize the pixmap */
3227 scr.fillRectangle(gc_clear,
3228 0, offset, paperwidth, row_ptr->height);
3229 // check for NOT FAST SELECTION
3230 if (!fast_selection && !mono_video && selection) {
3231 /* selection code */
3232 if (sel_start_cursor.row == row_ptr &&
3233 sel_end_cursor.row == row_ptr) {
3234 scr.fillRectangle(gc_selection, sel_start_cursor.x,
3240 else if (sel_start_cursor.row == row_ptr) {
3241 scr.fillRectangle(gc_selection, sel_start_cursor.x,
3243 paperwidth - sel_start_cursor.x,
3245 } else if (sel_end_cursor.row == row_ptr) {
3246 scr.fillRectangle(gc_selection, 0, offset,
3247 sel_end_cursor.x, row_ptr->height);
3248 } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
3249 scr.fillRectangle(gc_selection, 0, offset,
3250 paperwidth, row_ptr->height);
3253 } // end of NOT FAST SELECTION code
3255 if (row_ptr->par->appendix){
3256 scr.drawVerticalLine(gc_math, 1, offset, offset+row_ptr->height);
3257 scr.drawVerticalLine(gc_math, paperwidth-2 , offset, offset+row_ptr->height);
3260 if (row_ptr->par->pextra_type == LyXParagraph::PEXTRA_MINIPAGE) {
3261 /* draw a marker at the left margin! */
3262 LyXFont font = GetFont(row_ptr->par, 0);
3263 int asc = font.maxAscent();
3264 int x = (LYX_PAPER_MARGIN - font.width('|')) / 2;
3265 int y1 = (offset + row_ptr->baseline);
3266 int y2 = (offset + row_ptr->baseline) - asc;
3268 scr.drawVerticalLine(gc_minipage, x, y1, y2);
3270 if (row_ptr->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3271 LyXFont font(LyXFont::ALL_SANE);
3272 font.setSize(LyXFont::SIZE_FOOTNOTE);
3273 font.setColor(LyXFont::RED);
3275 int box_x = LYX_PAPER_MARGIN;
3276 box_x += font.textWidth(" wide-tab ", 10);
3277 if (row_ptr->previous &&
3278 row_ptr->previous->par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
3280 switch (row_ptr->par->footnotekind) {
3281 case LyXParagraph::MARGIN:
3284 case LyXParagraph::FIG:
3287 case LyXParagraph::TAB:
3290 case LyXParagraph::WIDE_FIG:
3293 case LyXParagraph::WIDE_TAB:
3296 case LyXParagraph::ALGORITHM:
3299 case LyXParagraph::FOOTNOTE:
3304 // Determine background color.
3305 gc_type back = gc_lighted;
3309 scr.fillRectangle(back, LYX_PAPER_MARGIN, offset+1,
3310 box_x - LYX_PAPER_MARGIN,
3311 int(font.maxAscent())+
3312 int(font.maxDescent()));
3314 scr.drawLine(gc_foot,
3317 paperwidth - 2*LYX_PAPER_MARGIN);
3319 scr.drawString(font, fs,
3320 offset + int(font.maxAscent())+1,
3322 scr.drawVerticalLine(gc_foot,
3326 + int(font.maxAscent())+
3327 int(font.maxDescent()));
3329 scr.drawLine(gc_foot,
3331 + int(font.maxAscent())
3332 + int(font.maxDescent()) + 1,
3333 LYX_PAPER_MARGIN, box_x - LYX_PAPER_MARGIN);
3336 /* draw the open floats in a red box */
3337 scr.drawVerticalLine(gc_foot,
3339 offset, offset + row_ptr->height);
3341 scr.drawVerticalLine(gc_foot,
3342 paperwidth - LYX_PAPER_MARGIN,
3344 offset + row_ptr->height);
3348 if (row_ptr->previous &&
3349 row_ptr->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3350 LyXFont font(LyXFont::ALL_SANE);
3351 font.setSize(LyXFont::SIZE_FOOTNOTE);
3353 int box_x = LYX_PAPER_MARGIN;
3354 box_x += font.textWidth(" wide-tab ", 10);
3356 scr.drawLine(gc_foot,
3359 paperwidth - LYX_PAPER_MARGIN - box_x);
3363 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
3364 row_ptr->par->GetLayout());
3365 firstpar = row_ptr->par->FirstPhysicalPar();
3368 y_bottom = row_ptr->height;
3370 /* is it a first row? */
3371 if (row_ptr->pos == 0
3372 && row_ptr->par == firstpar) {
3374 /* start of appendix? */
3375 if (row_ptr->par->start_of_appendix){
3376 scr.drawLine(gc_math,
3381 /* think about the margins */
3382 if (!row_ptr->previous)
3383 y_top += LYX_PAPER_MARGIN;
3385 if (row_ptr->par->pagebreak_top){ /* draw a top pagebreak */
3386 scr.drawOnOffLine(offset + y_top + 2 * DefaultHeight(),
3388 y_top += 3 * DefaultHeight();
3391 if (row_ptr->par->added_space_top.kind() == VSpace::VFILL) {
3392 /* draw a vfill top */
3393 scr.drawLine(gc_fill,
3395 0, LYX_PAPER_MARGIN);
3396 scr.drawLine(gc_fill,
3397 offset + y_top + 3 * DefaultHeight(),
3398 0, LYX_PAPER_MARGIN);
3399 scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2,
3401 offset + y_top + 3 *
3404 y_top += 3 * DefaultHeight();
3407 /* think about user added space */
3408 y_top += int(row_ptr->par->added_space_top.inPixels());
3410 /* think about the parskip */
3411 /* some parskips VERY EASY IMPLEMENTATION */
3412 if (parameters->paragraph_separation == BufferParams::PARSEP_SKIP) {
3413 if (layout.latextype == LATEX_PARAGRAPH
3414 && firstpar->GetDepth() == 0
3415 && firstpar->Previous())
3416 y_top += parameters->getDefSkip().inPixels();
3417 else if (firstpar->Previous()
3418 && textclasslist.Style(parameters->textclass,
3419 firstpar->Previous()->GetLayout()).latextype == LATEX_PARAGRAPH
3420 && firstpar->Previous()->GetDepth() == 0)
3421 // is it right to use defskip here, too? (AS)
3422 y_top += parameters->getDefSkip().inPixels();
3425 if (row_ptr->par->line_top) { /* draw a top line */
3426 y_top += GetFont(row_ptr->par, 0).ascent('x');
3428 scr.drawThickLine(offset + y_top,
3430 y_top += GetFont(row_ptr->par, 0).ascent('x');
3433 /* should we print a label? */
3434 if (layout.labeltype >= LABEL_STATIC
3435 && (layout.labeltype != LABEL_STATIC
3436 || layout.latextype != LATEX_ENVIRONMENT
3437 || row_ptr->par->IsFirstInSequence())) {
3438 font = GetFont(row_ptr->par, -2);
3439 if (!row_ptr->par->GetLabestring().empty()) {
3441 string tmpstring = row_ptr->par->GetLabestring();
3443 if (layout.labeltype == LABEL_COUNTER_CHAPTER) {
3444 if (parameters->secnumdepth >= 0){
3445 /* this is special code for the chapter layout. This is printed in
3446 * an extra row and has a pagebreak at the top. */
3447 maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue())
3448 + int(layout.parsep) * DefaultHeight();
3449 scr.drawString(font, tmpstring,
3450 offset + row_ptr->baseline
3451 - row_ptr->ascent_of_text - maxdesc,
3455 x -= font.stringWidth( layout.labelsep);
3456 x -= font.stringWidth( tmpstring);
3458 scr.drawString(font, tmpstring,
3459 offset + row_ptr->baseline, int(x));
3463 /* the labels at the top of an environment. More or less for bibliography */
3464 } else if (layout.labeltype == LABEL_TOP_ENVIRONMENT ||
3465 layout.labeltype == LABEL_BIBLIO ||
3466 layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) {
3467 if (row_ptr->par->IsFirstInSequence()) {
3468 font = GetFont(row_ptr->par, -2);
3469 if (!row_ptr->par->GetLabestring().empty()) {
3470 string tmpstring = row_ptr->par->GetLabestring();
3472 maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue()
3473 + (layout.labelbottomsep * DefaultHeight()));
3475 int top_label_x = int(x);
3476 if (layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT){
3477 top_label_x = int(x + (paperwidth - RightMargin(row_ptr) - x) / 2);
3478 top_label_x -= (font.stringWidth( tmpstring)/2);
3481 scr.drawString(font, tmpstring,
3482 offset + row_ptr->baseline
3483 - row_ptr->ascent_of_text - maxdesc,
3488 if (layout.labeltype == LABEL_BIBLIO) { // ale970302
3489 if (row_ptr->par->bibkey) {
3491 x -= font.stringWidth(layout.labelsep);
3492 font = GetFont(row_ptr->par, -1);
3493 x -= row_ptr->par->bibkey->Width(font);
3494 row_ptr->par->bibkey->Draw(font, scr,
3495 offset + row_ptr->baseline,
3502 /* is it a last row? */
3503 par = row_ptr->par->LastPhysicalPar();
3504 if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
3505 && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {
3507 /* think about the margins */
3509 y_bottom -= LYX_PAPER_MARGIN;
3511 /* draw a bottom pagebreak */
3512 if (firstpar->pagebreak_bottom) {
3513 scr.drawOnOffLine(offset + y_bottom - 2 *
3516 y_bottom -= 3 * DefaultHeight();
3519 if (firstpar->added_space_bottom.kind() == VSpace::VFILL) {
3520 /* draw a vfill bottom */
3521 scr.drawLine(gc_fill,
3522 offset + y_bottom - 3 * DefaultHeight(),
3523 0, LYX_PAPER_MARGIN);
3524 scr.drawLine(gc_fill, offset + y_bottom - 2,
3525 0, LYX_PAPER_MARGIN);
3526 scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2,
3527 offset + y_bottom - 3 * DefaultHeight(),
3528 offset + y_bottom - 2
3530 y_bottom -= 3* DefaultHeight();
3533 /* think about user added space */
3534 y_bottom -= int(firstpar->added_space_bottom.inPixels());
3536 if (firstpar->line_bottom) {
3537 /* draw a bottom line */
3538 y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
3540 scr.drawThickLine(offset + y_bottom,
3542 y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
3546 /* draw the text in the pixmap */
3547 pos_end = RowLast(row_ptr);
3550 /* table stuff -- begin*/
3551 if (row_ptr->par->table) {
3553 int cell = NumberOfCell(row_ptr->par, row_ptr->pos);
3555 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
3557 while (pos <= pos_end) {
3558 if (row_ptr->par->IsNewline(pos)) {
3560 x = x_old + row_ptr->par->table->WidthOfColumn(cell);
3561 /* draw the table lines, still very simple */
3562 on_off = !row_ptr->par->table->TopLine(cell);
3564 !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
3565 !row_ptr->par->table->IsContRow(cell))
3566 scr.drawTableLine(offset + row_ptr->baseline -
3567 row_ptr->ascent_of_text,
3568 int(x_old), int(x - x_old), on_off);
3569 on_off = !row_ptr->par->table->BottomLine(cell);
3570 if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
3571 row_ptr->par->table->VeryLastRow(cell))
3572 scr.drawTableLine(offset + y_bottom - 1,
3573 int(x_old), int(x - x_old), on_off);
3574 on_off = !row_ptr->par->table->LeftLine(cell);
3576 scr.drawVerticalTableLine(int(x_old),
3577 offset + row_ptr->baseline -
3578 row_ptr->ascent_of_text,
3579 offset + y_bottom - 1,
3581 on_off = !row_ptr->par->table->RightLine(cell);
3583 scr.drawVerticalTableLine(int(x) -
3584 row_ptr->par->table->AdditionalWidth(cell),
3585 offset + row_ptr->baseline -
3586 row_ptr->ascent_of_text,
3587 offset + y_bottom - 1,
3590 /* take care about the alignment and other spaces */
3592 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
3593 if (row_ptr->par->table->IsFirstCell(cell))
3594 cell--; // little hack, sorry
3596 } else if (row_ptr->par->IsHfill(pos)) {
3599 scr.drawVerticalLine(gc_fill, int(x),
3600 offset + row_ptr->baseline - DefaultHeight()/2,
3601 offset + row_ptr->baseline);
3605 if (row_ptr->par->IsSeparator(pos)) {
3607 x+= SingleWidth(row_ptr->par, pos);
3608 /* -------> Only draw protected spaces when not in
3609 * free-spacing mode. */
3610 if (row_ptr->par->GetChar(pos) == LyXParagraph::META_PROTECTED_SEPARATOR && !layout.free_spacing) {
3611 scr.drawVerticalLine(gc_fill, int(tmpx),
3612 offset + row_ptr->baseline - 3,
3613 offset + row_ptr->baseline - 1);
3614 scr.drawLine(gc_fill,
3615 offset + row_ptr->baseline - 1,
3618 scr.drawVerticalLine(gc_fill, int(x-2),
3619 offset + row_ptr->baseline - 3,
3620 offset + row_ptr->baseline - 1);
3621 /* what about underbars? */
3622 font = GetFont(row_ptr->par, pos);
3623 if (font.underbar() == LyXFont::ON
3624 && font.latex() != LyXFont::ON) {
3625 scr.drawLine(gc_copy,
3627 row_ptr->baseline + 2,
3634 Draw(row_ptr, pos, scr, offset, x);
3638 /* do not forget the very last cell. This has no NEWLINE so
3639 * ignored by the code above*/
3640 if (cell == row_ptr->par->table->GetNumberOfCells()-1){
3641 x = x_old + row_ptr->par->table->WidthOfColumn(cell);
3642 on_off = !row_ptr->par->table->TopLine(cell);
3644 !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
3645 !row_ptr->par->table->IsContRow(cell))
3647 scr.drawTableLine(offset + row_ptr->baseline -
3648 row_ptr->ascent_of_text,
3649 int(x_old), int(x - x_old), on_off);
3650 on_off = !row_ptr->par->table->BottomLine(cell);
3651 if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
3652 row_ptr->par->table->VeryLastRow(cell))
3654 scr.drawTableLine(offset + y_bottom - 1,
3655 int(x_old), int(x - x_old), on_off);
3656 on_off = !row_ptr->par->table->LeftLine(cell);
3658 scr.drawVerticalTableLine(int(x_old),
3659 offset + row_ptr->baseline -
3660 row_ptr->ascent_of_text,
3661 offset + y_bottom - 1,
3663 on_off = !row_ptr->par->table->RightLine(cell);
3665 scr.drawVerticalTableLine(int(x) -
3666 row_ptr->par->table->AdditionalWidth(cell),
3667 offset + row_ptr->baseline -
3668 row_ptr->ascent_of_text,
3669 offset + y_bottom - 1,
3673 /* table stuff -- end*/
3675 while (pos <= pos_end) {
3677 if (row_ptr->par->IsHfill(pos)) {
3679 scr.drawVerticalLine(gc_fill, int(x),
3680 offset + row_ptr->baseline - DefaultHeight()/2,
3681 offset + row_ptr->baseline);
3682 if (HfillExpansion(row_ptr, pos)) {
3683 if (pos >= main_body) {
3684 scr.drawOnOffLine(offset + row_ptr->baseline -
3690 scr.drawOnOffLine(offset + row_ptr->baseline -
3693 int(fill_label_hfill));
3694 x += fill_label_hfill;
3696 scr.drawVerticalLine(gc_fill, int(x),
3697 offset + row_ptr->baseline -
3699 offset + row_ptr->baseline);
3704 if (row_ptr->par->IsSeparator(pos)) {
3706 x+= SingleWidth(row_ptr->par, pos);
3707 if (pos >= main_body)
3709 /* -------> Only draw protected spaces when not in
3710 * free-spacing mode. */
3711 if (row_ptr->par->GetChar(pos) == LyXParagraph::META_PROTECTED_SEPARATOR && !layout.free_spacing) {
3713 scr.drawVerticalLine(gc_fill, int(tmpx),
3714 offset + row_ptr->baseline - 3,
3715 offset + row_ptr->baseline - 1);
3716 scr.drawLine(gc_fill,
3717 offset + row_ptr->baseline - 1,
3720 scr.drawVerticalLine(gc_fill, int(x-2),
3721 offset + row_ptr->baseline - 3,
3722 offset + row_ptr->baseline - 1);
3723 /* what about underbars? */
3724 font = GetFont(row_ptr->par, pos);
3725 if (font.underbar() == LyXFont::ON
3726 && font.latex() != LyXFont::ON) {
3727 scr.drawLine(gc_copy,
3728 offset + row_ptr->baseline + 2,
3735 Draw(row_ptr, pos, scr, offset, x);
3737 if (pos == main_body) {
3738 x += GetFont(row_ptr->par, -2).stringWidth(
3740 if (row_ptr->par->IsLineSeparator(pos - 1))
3741 x-= SingleWidth(row_ptr->par, pos - 1);
3742 if (x < left_margin)
3747 // check for FAST SELECTION
3748 if (fast_selection || mono_video){
3751 /* selection code */
3752 if (sel_start_cursor.row == row_ptr && sel_end_cursor.row == row_ptr) {
3753 scr.fillRectangle(gc_select, sel_start_cursor.x, offset,
3754 sel_end_cursor.x - sel_start_cursor.x,
3756 } else if (sel_start_cursor.row == row_ptr) {
3757 scr.fillRectangle(gc_select, sel_start_cursor.x, offset,
3758 paperwidth - sel_start_cursor.x,
3760 } else if (sel_end_cursor.row == row_ptr) {
3761 scr.fillRectangle(gc_select, 0, offset,
3764 } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
3765 scr.fillRectangle(gc_select, 0, offset,
3766 paperwidth, row_ptr->height);
3771 // end of FAST SELECTION code
3776 int LyXText::DefaultHeight()
3778 LyXFont font(LyXFont::ALL_SANE);
3779 return int(font.maxAscent() + font.maxDescent() * 1.5);
3783 /* returns the column near the specified x-coordinate of the row
3784 * x is set to the real beginning of this column */
3785 int LyXText::GetColumnNearX(Row * row, int& x)
3788 float fill_separator, fill_hfill, fill_label_hfill;
3790 int left_margin = LabelEnd(row);
3791 PrepareToPrint(row, tmpx, fill_separator,
3792 fill_hfill, fill_label_hfill);
3793 int main_body = BeginningOfMainBody(row->par);
3797 int last = RowLast(row);
3798 if (row->par->IsNewline(last))
3801 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
3802 row->par->GetLayout());
3803 /* table stuff -- begin */
3804 if (row->par->table) {
3805 if (!row->next || row->next->par != row->par)
3806 last = RowLast(row); /* the last row doesn't need a newline at the end*/
3807 int cell = NumberOfCell(row->par, row->pos);
3810 tmpx += row->par->table->GetBeginningOfTextInCell(cell);
3812 && tmpx + (SingleWidth(row->par, c)/2) <= x
3814 if (row->par->IsNewline(c)) {
3815 if (x_old + row->par->table->WidthOfColumn(cell) <= x){
3816 tmpx = x_old + row->par->table->WidthOfColumn(cell);
3819 tmpx += row->par->table->GetBeginningOfTextInCell(cell);
3824 tmpx += SingleWidth(row->par, c);
3829 /* table stuff -- end*/
3832 && tmpx + (SingleWidth(row->par, c)/2) <= x) {
3834 if (c && c == main_body
3835 && !row->par->IsLineSeparator(c - 1)) {
3836 tmpx += GetFont(row->par, -2)
3837 .stringWidth(layout.labelsep);
3838 if (tmpx < left_margin)
3842 tmpx += SingleWidth(row->par, c);
3843 if (HfillExpansion(row, c)) {
3847 tmpx += fill_label_hfill;
3849 else if (c >= main_body
3850 && row->par->IsSeparator(c)) {
3851 tmpx+= fill_separator;
3855 && row->par->IsLineSeparator(c - 1)) {
3856 tmpx += GetFont(row->par, -2)
3857 .stringWidth(layout.labelsep);
3858 tmpx-= SingleWidth(row->par, c - 1);
3859 if (tmpx < left_margin)
3863 /* make sure that a last space in a row doesnt count */
3864 if (c > 0 && c >= last
3865 && row->par->IsLineSeparator(c - 1)
3866 && !(!row->next || row->next->par != row->par)) {
3867 tmpx -= SingleWidth(row->par, c - 1);
3868 tmpx -= fill_separator;
3877 /* turn the selection into a new environment. If there is no selection,
3878 * create an empty environment */
3879 void LyXText::InsertFootnoteEnvironment(LyXParagraph::footnote_kind kind)
3881 /* no footnoteenvironment in a footnoteenvironment */
3882 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3883 WriteAlert(_("Impossible operation"),
3884 _("You can't insert a float in a float!"),
3888 /* no marginpars in minipages */
3889 if (kind == LyXParagraph::MARGIN
3890 && cursor.par->pextra_type == LyXParagraph::PEXTRA_MINIPAGE) {
3891 WriteAlert(_("Impossible operation"),
3892 _("You can't insert a marginpar in a minipage!"),
3897 /* this doesnt make sense, if there is no selection */
3898 bool dummy_selection = false;
3900 sel_start_cursor = cursor; /* dummy selection */
3901 sel_end_cursor = cursor;
3902 dummy_selection = true;
3905 LyXParagraph *tmppar;
3907 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
3908 WriteAlert(_("Impossible operation"), _("Cannot cut table."), _("Sorry."));
3912 /* a test to make sure there is not already a footnote
3913 * in the selection. */
3915 tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
3917 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos) &&
3918 tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
3919 tmppar = tmppar->next;
3921 if (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
3922 || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
3923 WriteAlert(_("Impossible operation"),
3924 _("Float would include float!"),
3929 /* ok we have a selection. This is always between sel_start_cursor
3930 * and sel_end cursor */
3932 SetUndo(Undo::FINISH,
3933 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
3934 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
3936 if (sel_end_cursor.pos > 0
3937 && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1))
3938 sel_end_cursor.pos--; /* please break before a space at
3940 if (sel_start_cursor.par == sel_end_cursor.par
3941 && sel_start_cursor.pos > sel_end_cursor.pos)
3942 sel_start_cursor.pos--;
3944 sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
3946 sel_end_cursor.par = sel_end_cursor.par->Next();
3947 sel_end_cursor.pos = 0;
3949 // don't forget to insert a dummy layout paragraph if necessary
3950 if (sel_start_cursor.par->GetLayout() != sel_end_cursor.par->layout){
3951 sel_end_cursor.par->BreakParagraphConservative(0);
3952 sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
3953 sel_end_cursor.par = sel_end_cursor.par->next;
3956 sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
3958 cursor = sel_end_cursor;
3960 /* please break behind a space, if there is one. The space should
3962 if (sel_start_cursor.pos > 0
3963 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1))
3964 sel_start_cursor.pos--;
3965 if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)) {
3966 sel_start_cursor.par->Erase(sel_start_cursor.pos);
3969 sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
3970 tmppar = sel_start_cursor.par->Next();
3972 if (dummy_selection) {
3974 if (kind == LyXParagraph::TAB
3975 || kind == LyXParagraph::FIG
3976 || kind == LyXParagraph::WIDE_TAB
3977 || kind == LyXParagraph::WIDE_FIG
3978 || kind == LyXParagraph::ALGORITHM) {
3979 int lay = textclasslist.NumberOfLayout(parameters->textclass,
3981 if (lay == -1) // layout not found
3982 // use default layout "Standard" (0)
3984 tmppar->SetLayout(lay);
3988 if (sel_start_cursor.pos > 0) {
3989 /* the footnote-environment should begin with a standard layout.
3990 * Imagine you insert a footnote within an enumeration, you
3991 * certainly do not want an enumerated footnote! */
3995 /* this is a exception the user would sometimes expect, I hope */
3996 sel_start_cursor.par->Clear();
4000 while (tmppar != sel_end_cursor.par) {
4001 tmppar->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
4002 tmppar->footnotekind = kind;
4003 tmppar = tmppar->Next();
4006 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
4008 SetCursor(sel_start_cursor.par->Next(), 0);
4014 /* returns pointer to a specified row */
4015 Row * LyXText::GetRow(LyXParagraph * par, LyXParagraph::size_type pos, long &y)
4020 if (par == currentrow->par || par == currentrow->par->Previous()){
4021 // do not dereference par, it may have been deleted
4022 // already! (Matthias)
4023 while (currentrow->previous && currentrow->previous->par != par){
4024 currentrow = currentrow->previous;
4025 currentrow_y -= currentrow->height;
4027 while (currentrow->previous && currentrow->previous->par == par){
4028 currentrow = currentrow->previous;
4029 currentrow_y -= currentrow->height;
4032 tmprow = currentrow;
4034 /* find the first row of the specified paragraph */
4035 while (tmprow->next && (tmprow->par != par)) {
4036 y += tmprow->height;
4037 tmprow = tmprow->next;
4040 if (tmprow->par == par){
4041 /* now find the wanted row */
4042 while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par &&
4043 tmprow->next->pos <= pos) {
4044 y += tmprow->height;
4045 tmprow = tmprow->next;
4047 currentrow = tmprow;
4054 /* find the first row of the specified paragraph */
4055 while (tmprow->next && (tmprow->par != par)) {
4056 y += tmprow->height;
4057 tmprow = tmprow->next;
4060 /* now find the wanted row */
4061 while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par &&
4062 tmprow->next->pos <= pos) {
4063 y += tmprow->height;
4064 tmprow = tmprow->next;
4067 currentrow = tmprow;