1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright (C) 1995 Matthias Ettrich
7 * Copyright (C) 1995-1998 The LyX Team.
9 *======================================================*/
16 #pragma implementation "table.h"
20 #include "lyxparagraph.h"
22 #include "support/textutils.h"
23 #include "lyx_gui_misc.h"
26 #include "bufferparams.h"
28 #include "lyxscreen.h"
29 #include "minibuffer.h"
32 static const int LYX_PAPER_MARGIN = 20;
34 extern int mono_video;
35 extern int reverse_video;
36 extern int fast_selection;
37 extern BufferView * current_view;
38 extern int UnlockInset(UpdatableInset * inset);
41 extern int bibitemMaxWidth(LyXFont const &);
44 extern MiniBuffer * minibuffer;
47 int LyXText::SingleWidth(LyXParagraph * par,
48 LyXParagraph::size_type pos)
50 int LyXText::SingleWidth(LyXParagraph * par, int pos)
53 char c = par->GetChar(pos);
54 return SingleWidth(par, pos, c);
59 int LyXText::SingleWidth(LyXParagraph * par,
60 LyXParagraph::size_type pos, char c)
62 int LyXText::SingleWidth(LyXParagraph * par, int pos, char c)
65 LyXFont font = GetFont(par, pos);
67 // The most common case is handled first (Asger)
71 } else if (IsHfillChar(c)) {
72 return 3; /* because of the representation
73 * as vertical lines */
75 } else if (c == LYX_META_FOOTNOTE ||
76 c == LYX_META_MARGIN ||
79 c == LYX_META_WIDE_FIG ||
80 c == LYX_META_WIDE_TAB ||
81 c == LYX_META_ALGORITHM)
94 case LYX_META_ALGORITHM:
97 case LYX_META_WIDE_FIG:
100 case LYX_META_WIDE_TAB:
103 case LYX_META_FOOTNOTE:
109 return font.stringWidth(fs);
112 else if (c == LYX_META_INSET) {
113 Inset *tmpinset=par->GetInset(pos);
115 return par->GetInset(pos)->Width(font);
119 } else if (IsSeparatorChar(c))
121 else if (IsNewlineChar(c))
123 return font.width(c);
127 /* returns the paragraph position of the last character in the
130 LyXParagraph::size_type LyXText::RowLast(Row * row)
132 int LyXText::RowLast(Row * row)
136 return row->par->Last()-1;
137 else if (row->next->par != row->par)
138 return row->par->Last()-1;
140 return row->next->pos - 1;
144 void LyXText::Draw(Row * row, LyXParagraph::size_type & pos,
145 LyXScreen & scr, int offset, float & x)
147 void LyXText::Draw(Row * row, int & pos,
148 LyXScreen & scr, int offset, float & x)
151 char c = row->par->GetChar(pos);
153 if (IsNewlineChar(c)) {
155 // Draw end-of-line marker
157 LyXFont font = GetFont(row->par, pos);
158 int asc = font.maxAscent();
159 int wid = font.width('n');
160 int y = (offset + row->baseline);
162 p[0].x = int(x + wid*0.375); p[0].y = int(y - 0.875*asc*0.75);
163 p[1].x = int(x); p[1].y = int(y - 0.500*asc*0.75);
164 p[2].x = int(x + wid*0.375); p[2].y = int(y - 0.125*asc*0.75);
165 scr.drawLines(::getGC(gc_new_line),p, 3);
167 p[0].x = int(x); p[0].y = int(y - 0.500*asc*0.75);
168 p[1].x = int(x + wid); p[1].y = int(y - 0.500*asc*0.75);
169 p[2].x = int(x + wid); p[2].y = int(y - asc*0.75);
170 scr.drawLines(::getGC(gc_new_line),p, 3);
174 LyXFont font = GetFont(row->par, pos);
175 LyXFont font2 = font;
177 if (c == LYX_META_FOOTNOTE ||
178 c == LYX_META_MARGIN ||
181 c == LYX_META_WIDE_FIG ||
182 c == LYX_META_WIDE_TAB ||
183 c == LYX_META_ALGORITHM) {
186 case LYX_META_MARGIN:
188 /* draw a sign at the left margin! */
189 scr.drawText(font, "!", 1, offset + row->baseline,
190 (LYX_PAPER_MARGIN - font.width('!'))/2);
198 case LYX_META_ALGORITHM:
201 case LYX_META_WIDE_FIG:
204 case LYX_META_WIDE_TAB:
207 case LYX_META_FOOTNOTE:
214 /* calculate the position of the footnotemark */
215 int y = (row->baseline - font2.maxAscent()
218 font.setColor(LyXFont::INSET);
222 /* draw it and set new x position */
223 x += scr.drawString(font, fs, offset + y, int(x));
225 scr.drawLine(gc_foot, offset + row->baseline,
226 int(tmpx), int(x - tmpx));
230 } else if (c == LYX_META_INSET) {
231 Inset *tmpinset = row->par->GetInset(pos);
233 tmpinset->Draw(font, scr, offset + row->baseline, x);
238 /* usual characters, no insets */
240 // Collect character that we can draw in one command
242 // This is dirty, but fast. Notice that it will never be too small.
243 // For the record, I'll note that Microsoft Word has a limit
244 // of 768 here. We have none :-) (Asger)
246 static char textstring[1024];
248 // Ok. I am the first to admit that the use of std::string will be
249 // a tiny bit slower. However, I claim that this slowdown is so
250 // small that it is close to inperceptive. So IMHO we should go
251 // with the easier and clearer implementation. And even if 1024
252 // is a large number here it might overflow, string will only
253 // overflow if the machine is out of memory...
254 static string textstring;
260 LyXParagraph::size_type last = RowLast(row);
262 int last = RowLast(row);
265 // Prevent crash in the extremely unlikely event
266 // that our array is too small
267 if (last > pos+1020) last = pos + 1020;
275 while (pos <= last &&
276 static_cast<char>(c = row->par->GetChar(pos)) > ' ' &&
277 font2 == GetFont(row->par, pos)) {
290 // If monochrome and LaTeX mode, provide reverse background
291 if (mono_video && font.latex() == LyXFont::ON) {
292 int a=font.maxAscent(), d=font.maxDescent();
294 scr.fillRectangle(gc_copy, int(tmpx), offset + row->baseline-a,
295 font.textWidth(textstring, i), a+d);
297 scr.fillRectangle(gc_copy, int(tmpx), offset + row->baseline-a,
298 font.textWidth(textstring.c_str(),
299 textstring.length()), a+d);
303 /* Draw text and set the new x position */
304 x += scr.drawText(font, textstring, i, offset + row->baseline,
307 /* Draw text and set the new x position */
308 x += scr.drawText(font, textstring.c_str(), textstring.length(),
309 offset + row->baseline,
313 /* what about underbars? */
314 if (font.underbar() == LyXFont::ON && font.latex() != LyXFont::ON) {
315 scr.drawLine(gc_copy, offset + row->baseline + 2,
316 int(tmpx), int(x - tmpx));
319 // If we want ulem.sty support, drawing
320 // routines should go here. (Asger)
321 // Why shouldn't LyXFont::drawText handle it internally?
325 /* Returns the left beginning of the text.
326 * This information cannot be taken from the layouts-objekt, because in
327 * LaTeX the beginning of the text fits in some cases (for example sections)
328 * exactly the label-width. */
329 int LyXText::LeftMargin(Row * row)
332 LyXParagraph * newpar;
334 LyXLayout const & layout = textclasslist.Style(parameters->textclass, row->par->GetLayout());
336 string parindent = layout.parindent;
338 /* table stuff -- begin*/
341 /* table stuff -- end*/
343 int x = LYX_PAPER_MARGIN;
345 x += textclasslist.TextClass(parameters->textclass).
346 defaultfont().signedStringWidth(textclasslist.TextClass(parameters->textclass).leftmargin());
348 if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
349 LyXFont font(LyXFont::ALL_SANE);
350 font.setSize(LyXFont::SIZE_SMALL);
351 x += font.textWidth("Mwide-figM", 10) + LYX_PAPER_MARGIN/2;
354 /* this is the way, LyX handles the LaTeX-Environments.
355 * I have had this idea very late, so it seems to be a
356 * later added hack and this is true */
357 if (!row->par->GetDepth()) {
358 if (!row->par->GetLayout()) {
359 /* find the previous same level paragraph */
360 if (row->par->FirstPhysicalPar()->Previous()) {
361 newpar = row->par->DepthHook(row->par->GetDepth());
362 if (newpar && textclasslist.Style(parameters->textclass, newpar->GetLayout()).nextnoindent)
368 /* find the next level paragraph */
370 newpar = row->par->DepthHook(row->par->GetDepth()-1);
372 /* make a corresponding row. Needed to call LeftMargin() */
374 /* check wether it is a sufficent paragraph */
375 if (newpar && newpar->footnoteflag == row->par->footnoteflag
376 && textclasslist.Style(parameters->textclass,
377 newpar->GetLayout()).isEnvironment()) {
378 dummyrow.par = newpar;
379 dummyrow.pos = newpar->Last();
380 x = LeftMargin(&dummyrow);
383 /* this is no longer an error, because this function is used
384 * to clear impossible depths after changing a layout. Since there
385 * is always a redo, LeftMargin() is always called */
387 /* printf("LYX_ERROR (text, LeftMargin()) impossible depth \n");*/
388 row->par->FirstPhysicalPar()->depth = 0;
391 if (newpar && !row->par->GetLayout()) {
392 if (newpar->FirstPhysicalPar()->noindent)
395 parindent = textclasslist.Style(parameters->textclass,
396 newpar->GetLayout()).parindent;
401 labelfont = GetFont(row->par, -2);
402 switch (layout.margintype) {
404 if (!layout.leftmargin.empty()) {
405 x += textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.leftmargin);
407 if (!row->par->GetLabestring().empty()) {
408 x += labelfont.signedStringWidth(layout.labelindent);
409 x += labelfont.stringWidth(row->par->GetLabestring());
410 x += labelfont.stringWidth(layout.labelsep);
414 x += labelfont.signedStringWidth(layout.labelindent);
415 if (row->pos >= BeginningOfMainBody(row->par)) {
416 if (!row->par->GetLabelWidthString().empty()) {
417 x += labelfont.stringWidth(row->par->GetLabelWidthString());
418 x += labelfont.stringWidth(layout.labelsep);
423 x += ( textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.leftmargin) * 4
424 / (row->par->GetDepth() + 4));
426 case MARGIN_FIRST_DYNAMIC:
427 if (layout.labeltype == LABEL_MANUAL) {
428 if (row->pos >= BeginningOfMainBody(row->par)) {
429 x += labelfont.signedStringWidth(layout.leftmargin);
431 x += labelfont.signedStringWidth(layout.labelindent);
435 // Special case to fix problems with theorems (JMarc)
436 || (layout.labeltype == LABEL_STATIC
437 && layout.latextype == LATEX_ENVIRONMENT
438 && ! row->par->IsFirstInSequence())) {
439 x += labelfont.signedStringWidth(layout.leftmargin);
440 } else if (layout.labeltype != LABEL_TOP_ENVIRONMENT
441 && layout.labeltype != LABEL_BIBLIO
442 && layout.labeltype != LABEL_CENTERED_TOP_ENVIRONMENT) {
443 x += labelfont.signedStringWidth(layout.labelindent);
444 x += labelfont.stringWidth(layout.labelsep);
445 x += labelfont.stringWidth(row->par->GetLabestring());
450 case MARGIN_RIGHT_ADDRESS_BOX:
452 /* ok, a terrible hack. The left margin depends on the widest row
453 * in this paragraph. Do not care about footnotes, they are *NOT*
454 * allowed in the LaTeX realisation of this layout. */
456 /* find the first row of this paragraph */
458 while (tmprow->previous && tmprow->previous->par == row->par)
459 tmprow = tmprow->previous;
461 int minfill = tmprow->fill;
462 while (tmprow-> next && tmprow->next->par == row->par) {
463 tmprow = tmprow->next;
464 if (tmprow->fill < minfill)
465 minfill = tmprow->fill;
468 x += textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.leftmargin);
473 if (row->par->pextra_type == PEXTRA_INDENT) {
474 if (!row->par->pextra_widthp.empty()) {
475 x += paperwidth * atoi(row->par->pextra_widthp.c_str()) / 100;
476 } else if (!row->par->pextra_width.empty()) {
477 int xx = VSpace(row->par->pextra_width).inPixels();
480 xx = paperwidth * 80 / 100;
482 } else { // should not happen
483 LyXFont font(LyXFont::ALL_SANE);
484 x += font.stringWidth("XXXXXX");
489 if (row->par->FirstPhysicalPar()->align == LYX_ALIGN_LAYOUT)
490 align = layout.align;
492 align = row->par->FirstPhysicalPar()->align;
494 /* set the correct parindent */
496 if ((layout.labeltype == LABEL_NO_LABEL
497 || layout.labeltype == LABEL_TOP_ENVIRONMENT
498 || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT
499 || (layout.labeltype == LABEL_STATIC
500 && layout.latextype == LATEX_ENVIRONMENT
501 && ! row->par->IsFirstInSequence()))
502 && row->par == row->par->FirstPhysicalPar()
503 && align == LYX_ALIGN_BLOCK
504 && !row->par->noindent
505 && (row->par->layout ||
506 parameters->paragraph_separation == LYX_PARSEP_INDENT))
507 x += textclasslist.TextClass(parameters->textclass).defaultfont().stringWidth(parindent);
509 if (layout.labeltype==LABEL_BIBLIO) { // ale970405 Right width for bibitems
510 x += bibitemMaxWidth(textclasslist.TextClass(parameters->textclass).defaultfont());
518 int LyXText::RightMargin(Row *row)
520 LyXParagraph * newpar;
522 LyXLayout const & layout = textclasslist.Style(parameters->textclass, row->par->GetLayout());
524 int x = LYX_PAPER_MARGIN;
526 x += textclasslist.TextClass(parameters->textclass).
527 defaultfont().signedStringWidth(textclasslist.TextClass(parameters->textclass).rightmargin());
528 if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
529 x += LYX_PAPER_MARGIN/2;
532 /* this is the way, LyX handles the LaTeX-Environments.
533 * I have had this idea very late, so it seems to be a
534 * later added hack and this is true */
535 if (row->par->GetDepth()) {
536 /* find the next level paragraph */
541 newpar = newpar->FirstPhysicalPar()->Previous();
543 newpar = newpar->FirstPhysicalPar();
544 } while (newpar && newpar->GetDepth() >= row->par->GetDepth()
545 && newpar->footnoteflag == row->par->footnoteflag);
547 /* make a corresponding row. Needed to call LeftMargin() */
549 /* check wether it is a sufficent paragraph */
550 if (newpar && newpar->footnoteflag == row->par->footnoteflag
551 && textclasslist.Style(parameters->textclass,
552 newpar->GetLayout()).isEnvironment()) {
553 dummyrow.par = newpar;
555 x = RightMargin(&dummyrow);
558 /* this is no longer an error, because this function is used
559 * to clear impossible depths after changing a layout. Since there
560 * is always a redo, LeftMargin() is always called */
562 /* printf("LYX_ERROR (text, LeftMargin()) impossible depth \n");*/
563 row->par->FirstPhysicalPar()->depth = 0;
567 //lyxerr << "rightmargin: " << layout->rightmargin << endl;
568 x += (textclasslist.TextClass(parameters->textclass).defaultfont().signedStringWidth(layout.rightmargin) * 4
569 / (row->par->GetDepth() + 4));
575 int LyXText::LabelEnd (Row * row)
577 if (textclasslist.Style(parameters->textclass, row->par->GetLayout()).margintype == MARGIN_MANUAL) {
580 tmprow.pos = row->par->Last();
581 return LeftMargin(&tmprow); /* just the beginning
582 * of the main body */
585 return 0; /* LabelEnd is only needed, if the
586 * layout fills a flushleft
591 /* table stuff -- begin*/
593 int LyXText::NumberOfCell(LyXParagraph * par,
594 LyXParagraph::size_type pos)
596 int LyXText::NumberOfCell(LyXParagraph * par, int pos)
601 LyXParagraph::size_type tmp_pos = 0;
605 while (tmp_pos < pos) {
606 if (par->IsNewline(tmp_pos))
614 int LyXText::WidthOfCell(LyXParagraph * par, LyXParagraph::size_type & pos)
616 int LyXText::WidthOfCell(LyXParagraph * par, int & pos)
620 while (pos < par->Last() && !par->IsNewline(pos)) {
621 w += SingleWidth(par, pos);
624 if (par->IsNewline(pos))
630 char LyXText::HitInTable(Row * row, int x)
633 float fill_separator, fill_hfill, fill_label_hfill;
634 if (!row->par->table)
636 PrepareToPrint(row, tmpx, fill_separator, fill_hfill, fill_label_hfill);
637 return (x > tmpx && x < tmpx + row->par->table->WidthOfTable());
641 bool LyXText::MouseHitInTable(int x, long y)
643 Row * row = GetRowNearY(y);
644 return HitInTable(row, x);
648 /* table stuff -- end*/
651 /* get the next breakpoint in a given paragraph */
653 LyXParagraph::size_type
654 LyXText::NextBreakPoint(Row * row, int width)
656 int LyXText::NextBreakPoint(Row * row, int width)
661 LyXParagraph::size_type last_separator = -1;
662 /* position of the last possible breakpoint
663 * -1 isn't a suitable value, but a flag */
665 int last_separator = -1; /* position of the last possible breakpoint
666 * -1 isn't a suitable value, but a flag */
670 LyXParagraph * par = row->par;
672 LyXParagraph::size_type i = 0;
673 LyXParagraph::size_type pos = row->pos;
679 /* table stuff -- begin*/
682 while (pos < par->size()
686 && (!par->IsNewline(pos)
687 || !par->table->IsFirstCell(NumberOfCell(par, pos+1)))) {
688 if (par->GetChar(pos) == LYX_META_INSET &&
689 par->GetInset(pos) && par->GetInset(pos)->Display()){
690 par->GetInset(pos)->SetDisplay(false);
696 /* table stuff -- end*/
698 left_margin = LabelEnd(row);
699 width -= RightMargin(row);
701 LyXParagraph::size_type main_body =
702 BeginningOfMainBody(par);
704 int main_body = BeginningOfMainBody(par);
706 LyXLayout const & layout = textclasslist.Style(parameters->textclass, par->GetLayout());
710 if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX) {
711 /* special code for right address boxes, only newlines count */
712 while (i < par->Last()) {
713 if (par->IsNewline(i)) {
715 i = par->Last() - 1;/* this means break */
717 } else if (par->GetChar(i) == LYX_META_INSET &&
718 par->GetInset(i) && par->GetInset(i)->Display()){
719 par->GetInset(i)->SetDisplay(false);
724 // Last position is an invariant
726 LyXParagraph::size_type const last =
729 int const last = par->Last();
731 /* this is the usual handling */
733 while (x < width && i < last) {
735 if (IsNewlineChar(c)) {
737 x = width; /* this means break */
738 } else if (c == LYX_META_INSET &&
739 par->GetInset(i) && par->GetInset(i)->Display()){
740 /* check wether a Display() inset is valid here .
741 if not, change it to non-display*/
742 if (layout.isCommand()
743 || (layout.labeltype == LABEL_MANUAL
744 && i < BeginningOfMainBody(par))){
745 /* display istn't allowd */
746 par->GetInset(i)->SetDisplay(false);
747 x += SingleWidth(par, i, c);
749 /* inset is display. So break the line here */
753 if (IsLineSeparatorChar(par->GetChar(i+1)))
756 last_separator = last; // to avoid extra rows
758 last_separator = i - 1;
759 x = width; /* this means break */
762 if (IsLineSeparatorChar(c))
764 x += SingleWidth(par, i, c);
767 if (i == main_body) {
768 x += GetFont(par, -2).stringWidth(layout.labelsep);
769 if (par->IsLineSeparator(i - 1))
770 x-= SingleWidth(par, i - 1);
775 /* end of paragraph is always a suitable separator */
776 if (i == last && x < width)
780 /* well, if last_separator is still 0, the line isn't breakable.
781 * don't care and cut simply at the end */
782 if (last_separator < 0) {
786 /* manual labels cannot be broken in LaTeX, do not care */
787 if (main_body && last_separator < main_body)
788 last_separator = main_body - 1;
790 return last_separator;
794 /* returns the minimum space a row needs on the screen in pixel */
795 int LyXText::Fill(Row * row, int paperwidth)
798 /* get the pure distance */
800 LyXParagraph::size_type last = RowLast(row);
802 int last = RowLast(row);
804 /* table stuff -- begin*/
805 if (row->par->table) {
806 /* for tables FILL does calculate the widthes of each cell in
809 LyXParagraph::size_type pos = row->pos;
813 int cell = NumberOfCell(row->par, pos);
816 row->par->table->SetWidthOfCell(cell, WidthOfCell(row->par, pos));
818 } while (pos <= last && !row->par->table->IsFirstCell(cell));
819 /* don't forget the very last table cell without characters */
820 if (cell == row->par->table->GetNumberOfCells()-1)
821 row->par->table->SetWidthOfCell(cell, WidthOfCell(row->par, pos));
823 return 0; /* width of table cannot be returned since
824 * we cannot guarantee its correct value at
827 /* table stuff -- end*/
829 int left_margin = LabelEnd(row);
831 /* if the row ends with newline, this newline will not be relevant */
832 if (last >= 0 && row->par->IsNewline(last))
835 /* if the row ends with a space, this space will not be relevant */
836 if (last >= 0 && row->par->IsLineSeparator(last))
839 /* special handling of the right address boxes */
840 if (textclasslist.Style(parameters->textclass,
841 row->par->GetLayout()).margintype
842 == MARGIN_RIGHT_ADDRESS_BOX) {
843 int tmpfill = row->fill;
844 row->fill = 0; /* the minfill in MarginLeft() */
851 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
852 row->par->GetLayout());
854 LyXParagraph::size_type main_body =
855 BeginningOfMainBody(row->par);
856 LyXParagraph::size_type i = row->pos;
859 int main_body = BeginningOfMainBody(row->par);
863 w += SingleWidth(row->par, i);
865 if (i == main_body) {
866 w += GetFont(row->par, -2).stringWidth(layout.labelsep);
867 if (row->par->IsLineSeparator(i - 1))
868 w -= SingleWidth(row->par, i - 1);
874 fill = paperwidth - w - RightMargin(row);
879 /* returns the minimum space a manual label needs on the screen in pixel */
880 int LyXText::LabelFill(Row * row)
884 LyXParagraph::size_type last = BeginningOfMainBody(row->par) - 1;
886 int last = BeginningOfMainBody(row->par) - 1;
888 /* -1 because a label ends either with a space that is in the label,
889 * or with the beginning of a footnote that is outside the label. */
891 // I don't understand this code in depth, but sometimes "last" is less than
892 // 0 and this causes a crash. This fix seems to work correctly, but I
893 // bet the real error is elsewhere. The bug is triggered when you have an
894 // open footnote in a paragraph environment with a manual label. (Asger)
895 if (last < 0) last = 0;
897 if (row->par->IsLineSeparator(last)) /* a sepearator at this end
904 w += SingleWidth(row->par, i);
909 if (!row->par->labelwidthstring.empty()) {
910 fill = GetFont(row->par, -2).stringWidth(row->par->labelwidthstring) - w;
920 /* returns the number of separators in the specified row. The separator
921 * on the very last column doesnt count */
922 int LyXText::NumberOfSeparators(Row *row)
924 int last = RowLast(row);
927 int main_body = BeginningOfMainBody(row->par);
930 for (; p < last; p++) {
931 if (row->par->IsSeparator(p)) {
939 /* returns the number of hfills in the specified row. The LyX-Hfill is
940 * a LaTeX \hfill so that the hfills at the beginning and at the end were
941 * ignored. This is *MUCH* more usefull than not to ignore! */
942 int LyXText::NumberOfHfills(Row * row)
944 int last = RowLast(row);
945 int first = row->pos;
946 if (first) { /* hfill *DO* count at the beginning
948 while(first <= last && row->par->IsHfill(first))
952 int main_body = BeginningOfMainBody(row->par);
953 if (first < main_body)
956 for (int p = first; p <= last; p++) { // last, because the end is ignored!
957 if (row->par->IsHfill(p)) {
965 /* like NumberOfHfills, but only those in the manual label! */
966 int LyXText::NumberOfLabelHfills(Row * row)
969 LyXParagraph::size_type last = RowLast(row);
970 LyXParagraph::size_type first = row->pos;
972 int last = RowLast(row);
973 int first = row->pos;
975 if (first) { /* hfill *DO* count at the beginning
977 while(first < last && row->par->IsHfill(first))
981 LyXParagraph::size_type main_body =
982 BeginningOfMainBody(row->par);
984 int main_body = BeginningOfMainBody(row->par);
986 if (last > main_body)
991 for (LyXParagraph::size_type p = first;
992 p < last; ++p) { // last, because the end is ignored!
994 for (int p = first; p < last; p++) { // last, because the end is ignored!
996 if (row->par->IsHfill(p)) {
1004 /* returns true, if a expansion is needed.
1005 * Rules are given by LaTeX */
1007 bool LyXText::HfillExpansion(Row * row_ptr,
1008 LyXParagraph::size_type pos)
1010 bool LyXText::HfillExpansion(Row * row_ptr, int pos)
1013 /* by the way, is it a hfill? */
1014 if (!row_ptr->par->IsHfill(pos))
1017 /* at the end of a row it does not count */
1018 if (pos >= RowLast(row_ptr))
1021 /* at the beginning of a row it does not count, if it is not
1022 * the first row of a paragaph */
1026 /* in some labels it does not count */
1027 if ( textclasslist.Style(parameters->textclass, row_ptr->par->GetLayout()).margintype != MARGIN_MANUAL &&
1028 pos < BeginningOfMainBody(row_ptr->par))
1031 /* if there is anything between the first char of the row and
1032 * the sepcified position that is not a newline and not a hfill,
1033 * the hfill will count, otherwise not */
1035 LyXParagraph::size_type i = row_ptr->pos;
1037 int i = row_ptr->pos;
1039 while (i < pos && (row_ptr->par->IsNewline(i)
1040 || row_ptr->par->IsHfill(i)))
1047 void LyXText::SetHeightOfRow(Row * row_ptr)
1049 /* get the maximum ascent and the maximum descent */
1050 int asc, maxasc, desc, maxdesc, pos_end, pos, labeladdon;
1051 float layoutasc = 0;
1052 float layoutdesc = 0;
1057 /* this must not happen before the currentrow for clear reasons.
1058 so the trick is just to set the current row onto this row */
1060 GetRow(row_ptr->par, row_ptr->pos, unused_y);
1062 /* ok , let us initialize the maxasc and maxdesc value.
1063 * This depends in LaTeX of the font of the last character
1064 * in the paragraph. The hack below is necessary because
1065 * of the possibility of open footnotes */
1067 /* Correction: only the fontsize count. The other properties
1068 are taken from the layoutfont. Nicer on the screen :) */
1070 LyXParagraph * par = row_ptr->par->LastPhysicalPar();
1071 LyXParagraph * firstpar = row_ptr->par->FirstPhysicalPar();
1073 LyXLayout const & layout = textclasslist.Style(parameters->textclass, firstpar->GetLayout());
1075 LyXFont font = GetFont(par, par->Last()-1);
1076 LyXFont::FONT_SIZE size = font.size();
1077 font = GetFont(par, -1);
1080 LyXFont labelfont = GetFont(par, -2);
1082 maxasc = int(font.maxAscent() *
1083 layout.spacing.getValue() *
1084 parameters->spacing.getValue());
1085 maxdesc = int(font.maxDescent() *
1086 layout.spacing.getValue() *
1087 parameters->spacing.getValue());
1089 pos_end = RowLast(row_ptr);
1093 // Check if any insets are larger
1094 for (pos = row_ptr->pos; pos <= pos_end; pos++) {
1095 if (row_ptr->par->GetChar(pos) == LYX_META_INSET) {
1096 tmpfont = GetFont(row_ptr->par, pos);
1097 tmpinset = row_ptr->par->GetInset(pos);
1099 asc = tmpinset->Ascent(tmpfont);
1100 desc = tmpinset->Descent(tmpfont);
1109 // Check if any custom fonts are larger (Asger)
1110 // This is not completely correct, but we can live with the small,
1111 // cosmetic error for now.
1112 LyXFont::FONT_SIZE maxsize = row_ptr->par->HighestFontInRange(row_ptr->pos, pos_end);
1113 if (maxsize > font.size()) {
1114 font.setSize(maxsize);
1116 asc = font.maxAscent();
1117 desc = font.maxDescent();
1124 /* table stuff -- begin*/
1125 if (row_ptr->par->table){
1126 // stretch the rows a bit
1130 /* table stuff -- end*/
1132 // This is nicer with box insets:
1136 row_ptr->ascent_of_text = maxasc;
1138 /* is it a top line? */
1139 if (row_ptr->pos == 0
1140 && row_ptr->par == firstpar) {
1142 /* some parksips VERY EASY IMPLEMENTATION */
1143 if (parameters->paragraph_separation == LYX_PARSEP_SKIP) {
1144 if (layout.isParagraph()
1145 && firstpar->GetDepth() == 0
1146 && firstpar->Previous())
1147 maxasc += parameters->getDefSkip().inPixels();
1148 else if (firstpar->Previous()
1149 && textclasslist.Style(parameters->textclass,
1150 firstpar->Previous()->GetLayout()).isParagraph()
1151 && firstpar->Previous()->GetDepth() == 0)
1152 // is it right to use defskip here too? (AS)
1153 maxasc += parameters->getDefSkip().inPixels();
1156 /* the paper margins */
1157 if (!row_ptr->par->previous)
1158 maxasc += LYX_PAPER_MARGIN;
1160 /* add the vertical spaces, that the user added */
1161 if (firstpar->added_space_top.kind() != VSpace::NONE)
1162 maxasc += int(firstpar->added_space_top.inPixels());
1164 /* do not forget the DTP-lines!
1165 * there height depends on the font of the nearest character */
1166 if (firstpar->line_top)
1167 maxasc += 2 * GetFont(firstpar, 0).ascent('x');
1169 /* and now the pagebreaks */
1170 if (firstpar->pagebreak_top)
1171 maxasc += 3 * DefaultHeight();
1173 /* this is special code for the chapter, since the label of this
1174 * layout is printed in an extra row */
1175 if (layout.labeltype == LABEL_COUNTER_CHAPTER
1176 && parameters->secnumdepth>=0) {
1177 labeladdon = int(labelfont.maxDescent() *
1178 layout.spacing.getValue() *
1179 parameters->spacing.getValue())
1180 + int(labelfont.maxAscent() *
1181 layout.spacing.getValue() *
1182 parameters->spacing.getValue());
1185 /* special code for the top label */
1186 if ((layout.labeltype == LABEL_TOP_ENVIRONMENT
1187 || layout.labeltype == LABEL_BIBLIO
1188 || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)
1189 && row_ptr->par->IsFirstInSequence()
1190 && !row_ptr->par->GetLabestring().empty()) {
1192 (labelfont.maxAscent() *
1193 layout.spacing.getValue() *
1194 parameters->spacing.getValue())
1195 +(labelfont.maxDescent() *
1196 layout.spacing.getValue() *
1197 parameters->spacing.getValue())
1198 + layout.topsep * DefaultHeight()
1199 + layout.labelbottomsep * DefaultHeight());
1202 /* and now the layout spaces, for example before and after a section,
1203 * or between the items of a itemize or enumerate environment */
1205 if (!firstpar->pagebreak_top) {
1206 LyXParagraph *prev = row_ptr->par->Previous();
1208 prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth());
1209 if (prev && prev->GetLayout() == firstpar->GetLayout()
1210 && prev->GetDepth() == firstpar->GetDepth()
1211 && prev->GetLabelWidthString() == firstpar->GetLabelWidthString())
1213 layoutasc = (layout.itemsep * DefaultHeight());
1215 else if (row_ptr->previous) {
1216 tmptop = layout.topsep;
1218 if (row_ptr->previous->par->GetDepth() >= row_ptr->par->GetDepth())
1219 tmptop-=textclasslist.Style(parameters->textclass, row_ptr->previous->par->GetLayout()).bottomsep;
1222 layoutasc = (tmptop * DefaultHeight());
1224 else if (row_ptr->par->line_top){
1225 tmptop = layout.topsep;
1228 layoutasc = (tmptop * DefaultHeight());
1231 prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth()-1);
1233 maxasc += int(textclasslist.Style(parameters->textclass,
1234 prev->GetLayout()).parsep * DefaultHeight());
1237 if (firstpar->Previous()
1238 && firstpar->Previous()->GetDepth() == 0
1239 && firstpar->Previous()->GetLayout() != firstpar->GetLayout()) {
1242 else if (firstpar->Previous()){
1243 maxasc += int(layout.parsep * DefaultHeight());
1249 /* is it a bottom line? */
1250 if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
1251 && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {
1253 /* the paper margins */
1255 maxdesc += LYX_PAPER_MARGIN;
1257 /* add the vertical spaces, that the user added */
1258 if (firstpar->added_space_bottom.kind() != VSpace::NONE)
1259 maxdesc += int(firstpar->added_space_bottom.inPixels());
1261 /* do not forget the DTP-lines!
1262 * there height depends on the font of the nearest character */
1263 if (firstpar->line_bottom)
1264 maxdesc += 2 * (GetFont(par, par->Last()-1).ascent('x'));
1266 /* and now the pagebreaks */
1267 if (firstpar->pagebreak_bottom)
1268 maxdesc += 3 * DefaultHeight();
1270 /* and now the layout spaces, for example before and after a section,
1271 * or between the items of a itemize or enumerate environment */
1272 if (!firstpar->pagebreak_bottom && row_ptr->par->Next()) {
1273 LyXParagraph *nextpar = row_ptr->par->Next();
1274 LyXParagraph *comparepar = row_ptr->par;
1278 if (comparepar->GetDepth() > nextpar->GetDepth()) {
1279 usual = (textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1280 comparepar = comparepar->DepthHook(nextpar->GetDepth());
1281 if (comparepar->GetLayout()!=nextpar->GetLayout()
1282 || nextpar->GetLabelWidthString() !=
1283 comparepar->GetLabelWidthString())
1284 unusual = (textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1286 if (unusual > usual)
1287 layoutdesc = unusual;
1291 else if (comparepar->GetDepth() == nextpar->GetDepth()) {
1293 if (comparepar->GetLayout()!= nextpar->GetLayout()
1294 || nextpar->GetLabelWidthString() !=
1295 comparepar->GetLabelWidthString())
1296 layoutdesc = int(textclasslist.Style(parameters->textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1301 /* incalculate the layout spaces */
1302 maxasc += int(layoutasc * 2 / (2 + firstpar->GetDepth()));
1303 maxdesc += int(layoutdesc * 2 / (2 + firstpar->GetDepth()));
1305 /* table stuff -- begin*/
1306 if (row_ptr->par->table){
1307 maxasc += row_ptr->par->table->
1308 AdditionalHeight(NumberOfCell(row_ptr->par, row_ptr->pos));
1310 /* table stuff -- end*/
1312 /* calculate the new height of the text */
1313 height -= row_ptr->height;
1315 row_ptr->height=maxasc+maxdesc+labeladdon;
1316 row_ptr->baseline=maxasc+labeladdon;
1318 height += row_ptr->height;
1322 /* Appends the implicit specified paragraph behind the specified row,
1323 * start at the implicit given position */
1324 void LyXText::AppendParagraph(Row * row)
1326 bool not_ready = true;
1328 // The last character position of a paragraph is an invariant so we can
1329 // safely get it here. (Asger)
1330 int lastposition = row->par->Last();
1333 // Get the next breakpoint
1334 int z = NextBreakPoint(row, paperwidth);
1338 // Insert the new row
1339 if (z < lastposition) {
1341 InsertRow(row, row->par, z);
1348 // Set the dimensions of the row
1349 tmprow->fill = Fill(tmprow, paperwidth);
1350 SetHeightOfRow(tmprow);
1352 } while (not_ready);
1356 void LyXText::BreakAgain(Row * row)
1358 bool not_ready = true;
1361 /* get the next breakpoint */
1363 LyXParagraph::size_type z =
1364 NextBreakPoint(row, paperwidth);
1366 int z = NextBreakPoint(row, paperwidth);
1370 if (z < row->par->Last() ) {
1371 if (!row->next || (row->next && row->next->par != row->par)) {
1372 /* insert a new row */
1374 InsertRow(row, row->par, z);
1381 not_ready = false; // the rest will not change
1387 /* if there are some rows too much, delete them */
1388 /* only if you broke the whole paragraph! */
1389 Row * tmprow2 = row;
1390 while (tmprow2->next && tmprow2->next->par == row->par) {
1391 tmprow2 = tmprow2->next;
1393 while (tmprow2 != row) {
1394 tmprow2 = tmprow2->previous;
1395 RemoveRow(tmprow2->next);
1400 /* set the dimensions of the row */
1401 tmprow->fill = Fill(tmprow, paperwidth);
1402 SetHeightOfRow(tmprow);
1403 } while (not_ready);
1407 /* this is just a little changed version of break again */
1408 void LyXText::BreakAgainOneRow(Row * row)
1410 /* get the next breakpoint */
1412 LyXParagraph::size_type z = NextBreakPoint(row, paperwidth);
1414 int z = NextBreakPoint(row, paperwidth);
1418 if (z < row->par->Last() ) {
1419 if (!row->next || (row->next && row->next->par != row->par)) {
1420 /* insert a new row */
1422 InsertRow(row, row->par, z);
1434 /* if there are some rows too much, delete them */
1435 /* only if you broke the whole paragraph! */
1436 Row * tmprow2 = row;
1437 while (tmprow2->next && tmprow2->next->par == row->par) {
1438 tmprow2 = tmprow2->next;
1440 while (tmprow2 != row) {
1441 tmprow2 = tmprow2->previous;
1442 RemoveRow(tmprow2->next);
1446 /* set the dimensions of the row */
1447 tmprow->fill = Fill(tmprow, paperwidth);
1448 SetHeightOfRow(tmprow);
1452 void LyXText::BreakParagraph(char keep_layout)
1454 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
1455 cursor.par->GetLayout());
1457 /* table stuff -- begin*/
1458 if (cursor.par->table) {
1459 // breaking of tables is only allowed at the beginning or the end */
1461 if (cursor.pos && cursor.pos < cursor.par->size() &&
1463 if (cursor.pos && cursor.pos < cursor.par->last &&
1465 !cursor.par->table->ShouldBeVeryLastCell(NumberOfCell(cursor.par, cursor.pos)))
1466 return; /* no breaking of tables allowed */
1468 /* table stuff -- end*/
1470 /* this is only allowed, if the current paragraph is not empty or caption*/
1471 if ((cursor.par->Last() <= 0 && !cursor.par->IsDummy())
1473 layout.labeltype!=LABEL_SENSITIVE)
1476 SetUndo(Undo::INSERT,
1477 cursor.par->ParFromPos(cursor.pos)->previous,
1478 cursor.par->ParFromPos(cursor.pos)->next);
1480 /* table stuff -- begin*/
1481 if (cursor.par->table) {
1482 int cell = NumberOfCell(cursor.par, cursor.pos);
1483 if (cursor.par->table->ShouldBeVeryLastCell(cell))
1485 SetCursor(cursor.par, cursor.par->text.size());
1487 SetCursor(cursor.par, cursor.par->last);
1490 /* table stuff -- end*/
1491 /* please break alway behind a space */
1492 if (cursor.pos < cursor.par->Last()
1493 && cursor.par->IsLineSeparator(cursor.pos))
1496 /* break the paragraph */
1500 keep_layout = layout.isEnvironment();
1501 cursor.par->BreakParagraph(cursor.pos, keep_layout);
1503 /* table stuff -- begin*/
1504 if (cursor.par->table){
1505 // the table should stay with the contents
1507 cursor.par->Next()->table = cursor.par->table;
1508 cursor.par->table = 0;
1511 /* table stuff -- end*/
1513 /* well this is the caption hack since one caption is really enough */
1514 if (layout.labeltype == LABEL_SENSITIVE){
1516 cursor.par->SetLayout(0); /* set the new paragraph to standard-layout */
1518 cursor.par->Next()->SetLayout(0); /* set the new paragraph to standard-layout */
1522 /* if the cursor is at the beginning of a row without prior newline,
1524 * This touches only the screen-update. Otherwise we would may have
1525 * an empty row on the screen */
1526 if (cursor.pos && !cursor.row->par->IsNewline(cursor.row->pos -1) &&
1527 cursor.row->pos == cursor.pos) {
1531 status = LyXText::NEED_MORE_REFRESH;
1532 refresh_row = cursor.row;
1533 refresh_y = cursor.y - cursor.row->baseline;
1535 /* Do not forget the special right address boxes */
1536 if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX) {
1537 while (refresh_row->previous &&
1538 refresh_row->previous->par == refresh_row->par) {
1539 refresh_row = refresh_row->previous;
1540 refresh_y -= refresh_row->height;
1543 RemoveParagraph(cursor.row);
1545 /* set the dimensions of the cursor row */
1546 cursor.row->fill = Fill(cursor.row, paperwidth);
1548 SetHeightOfRow(cursor.row);
1550 while (!cursor.par->Next()->table && cursor.par->Next()->Last()
1551 && cursor.par->Next()->IsNewline(0))
1552 cursor.par->Next()->Erase(0);
1554 InsertParagraph(cursor.par->Next(), cursor.row);
1556 UpdateCounters(cursor.row->previous);
1558 /* this check is necessary. Otherwise the new empty paragraph will
1559 * be deleted automatically. And it is more friendly for the user! */
1561 SetCursor(cursor.par->Next(), 0);
1563 SetCursor(cursor.par, 0);
1565 if (cursor.row->next)
1566 BreakAgain(cursor.row->next);
1572 void LyXText::OpenFootnote()
1574 LyXParagraph * endpar,* tmppar;
1577 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
1579 /* if there is no footnote in this paragraph, just return. */
1581 || par->next->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1584 /* ok, move the cursor right before the footnote */
1586 /* just a little faster than using CursorRight() */
1587 for (cursor.pos=0; cursor.par->ParFromPos(cursor.pos)!=par; cursor.pos++);
1588 /* now the cursor is at the beginning of the physical par */
1590 SetCursor(cursor.par,
1591 cursor.pos + cursor.par->ParFromPos(cursor.pos)->text.size());
1593 SetCursor(cursor.par, cursor.pos + cursor.par->ParFromPos(cursor.pos)->last);
1596 /* the cursor must be exactly before the footnote */
1597 par = cursor.par->ParFromPos(cursor.pos);
1599 status = LyXText::NEED_MORE_REFRESH;
1600 refresh_row = cursor.row;
1601 refresh_y = cursor.y - cursor.row->baseline;
1603 tmppar = cursor.par;
1604 endpar = cursor.par->Next();
1607 tmppar->OpenFootnote(cursor.pos);
1608 RemoveParagraph(row);
1609 /* set the dimensions of the cursor row */
1610 row->fill = Fill(row, paperwidth);
1611 SetHeightOfRow(row);
1612 tmppar = tmppar->Next();
1614 while (tmppar != endpar) {
1616 InsertParagraph(tmppar, row);
1617 while (row->next && row->next->par == tmppar)
1619 tmppar = tmppar->Next();
1622 SetCursor(par->next, 0);
1623 sel_cursor = cursor;
1627 /* table stuff -- begin*/
1629 void LyXText::TableFeatures(int feature, string val)
1631 if (!cursor.par->table)
1632 return; /* this should never happen */
1634 int actCell = NumberOfCell(cursor.par, cursor.pos);
1635 SetUndo(Undo::FINISH,
1636 cursor.par->ParFromPos(cursor.pos)->previous,
1637 cursor.par->ParFromPos(cursor.pos)->next);
1640 case LyXTable::SET_PWIDTH:
1641 cursor.par->table->SetPWidth(actCell,val);
1643 case LyXTable::SET_SPECIAL_COLUMN:
1644 case LyXTable::SET_SPECIAL_MULTI:
1645 cursor.par->table->SetAlignSpecial(actCell,val,feature);
1654 void LyXText::TableFeatures(int feature)
1657 int setAlign = LYX_ALIGN_LEFT;
1661 if (!cursor.par->table)
1662 return; /* this should never happen */
1664 int actCell = NumberOfCell(cursor.par, cursor.pos);
1665 SetUndo(Undo::FINISH,
1666 cursor.par->ParFromPos(cursor.pos)->previous,
1667 cursor.par->ParFromPos(cursor.pos)->next);
1670 case LyXTable::ALIGN_LEFT:
1671 setAlign=LYX_ALIGN_LEFT;
1673 case LyXTable::ALIGN_RIGHT:
1674 setAlign=LYX_ALIGN_RIGHT;
1676 case LyXTable::ALIGN_CENTER:
1677 setAlign=LYX_ALIGN_CENTER;
1683 case LyXTable::APPEND_ROW: {
1685 LyXParagraph::size_type pos = cursor.pos;
1687 int pos = cursor.pos;
1689 /* move to the next row */
1690 int cell_org = actCell;
1691 int cell = cell_org;
1693 // if there is a ContRow following this row I have to add
1694 // the row after the ContRow's
1695 if ((pos < cursor.par->Last()) &&
1696 cursor.par->table->RowHasContRow(cell_org)) {
1697 while((pos < cursor.par->Last()) &&
1698 !cursor.par->table->IsContRow(cell)) {
1699 while (pos < cursor.par->Last() &&
1700 !cursor.par->IsNewline(pos))
1702 if (pos < cursor.par->Last())
1706 while((pos < cursor.par->Last()) &&
1707 cursor.par->table->IsContRow(cell)) {
1708 while (pos < cursor.par->Last() &&
1709 !cursor.par->IsNewline(pos))
1711 if (pos < cursor.par->Last())
1716 if (pos < cursor.par->Last())
1719 while (pos < cursor.par->Last() &&
1720 (cell == cell_org || !cursor.par->table->IsFirstCell(cell))){
1721 while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1723 if (pos < cursor.par->Last())
1728 /* insert the new cells */
1729 int number = cursor.par->table->NumberOfCellsInRow(cell_org);
1730 for (int i = 0; i < number; ++i)
1731 cursor.par->InsertChar(pos, LYX_META_NEWLINE);
1733 /* append the row into the table */
1734 cursor.par->table->AppendRow(cell_org);
1738 case LyXTable::APPEND_CONT_ROW: {
1740 LyXParagraph::size_type pos = cursor.pos;
1742 int pos = cursor.pos;
1744 /* move to the next row */
1745 int cell_org = actCell;
1746 int cell = cell_org;
1748 // if there is already a controw but not for this cell
1749 // the AppendContRow sets only the right values but does
1750 // not actually add a row
1751 if (cursor.par->table->RowHasContRow(cell_org) &&
1752 (cursor.par->table->CellHasContRow(cell_org)<0)) {
1753 cursor.par->table->AppendContRow(cell_org);
1757 while (pos < cursor.par->Last() &&
1759 || !cursor.par->table->IsFirstCell(cell))){
1760 while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1762 if (pos < cursor.par->Last())
1767 /* insert the new cells */
1768 int number = cursor.par->table->NumberOfCellsInRow(cell_org);
1770 for (i=0; i<number; i++)
1771 cursor.par->InsertChar(pos, LYX_META_NEWLINE);
1773 /* append the row into the table */
1774 cursor.par->table->AppendContRow(cell_org);
1778 case LyXTable::APPEND_COLUMN: {
1780 LyXParagraph::size_type pos = 0;
1784 int cell_org = actCell;
1787 if (pos && (cursor.par->IsNewline(pos-1))){
1788 if (cursor.par->table->AppendCellAfterCell(cell_org, cell)){
1789 cursor.par->InsertChar(pos, LYX_META_NEWLINE);
1790 if (pos <= cursor.pos)
1797 } while (pos <= cursor.par->Last());
1798 /* remember that the very last cell doesn't end with a newline.
1799 This saves one byte memory per table ;-) */
1800 if (cursor.par->table->AppendCellAfterCell(cell_org, cell))
1801 cursor.par->InsertChar(cursor.par->Last(), LYX_META_NEWLINE);
1803 /* append the column into the table */
1804 cursor.par->table->AppendColumn(cell_org);
1809 case LyXTable::DELETE_ROW:
1810 if (current_view->currentBuffer()->the_locking_inset)
1811 UnlockInset(current_view->currentBuffer()->the_locking_inset);
1812 RemoveTableRow(&cursor);
1816 case LyXTable::DELETE_COLUMN: {
1818 LyXParagraph::size_type pos = 0;
1822 int cell_org = actCell;
1824 if (current_view->currentBuffer()->the_locking_inset)
1825 UnlockInset(current_view->currentBuffer()->the_locking_inset);
1827 if (!pos || (cursor.par->IsNewline(pos-1))){
1828 if (cursor.par->table->DeleteCellIfColumnIsDeleted(cell, cell_org)){
1830 while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1831 cursor.par->Erase(pos);
1832 if (pos < cursor.par->Last())
1833 cursor.par->Erase(pos);
1835 cursor.par->Erase(pos - 1); // the missing newline at the end of a table
1836 --pos; // because of pos++ below
1841 } while (pos <= cursor.par->Last());
1843 /* delete the column from the table */
1844 cursor.par->table->DeleteColumn(cell_org);
1846 /* set the cursor to the beginning of the table, where else? */
1851 case LyXTable::TOGGLE_LINE_TOP:
1852 lineSet = !cursor.par->table->TopLine(actCell);
1854 cursor.par->table->SetTopLine(actCell,lineSet);
1857 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->SetTopLine(n, lineSet);
1872 case LyXTable::TOGGLE_LINE_BOTTOM:
1873 lineSet = !cursor.par->table->BottomLine(actCell);
1875 cursor.par->table->SetBottomLine(actCell,lineSet);
1878 LyXParagraph::size_type i;
1881 int i, n = -1, m = -2;
1883 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
1884 if ((n = NumberOfCell(sel_start_cursor.par, i)) != m) {
1885 cursor.par->table->SetBottomLine(n, lineSet);
1893 case LyXTable::TOGGLE_LINE_LEFT:
1894 lineSet = !cursor.par->table->LeftLine(actCell);
1896 cursor.par->table->SetLeftLine(actCell,lineSet);
1899 LyXParagraph::size_type i;
1904 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
1905 if ((n=NumberOfCell(sel_start_cursor.par,i)) != m) {
1906 cursor.par->table->SetLeftLine(n,lineSet);
1914 case LyXTable::TOGGLE_LINE_RIGHT:
1915 lineSet = !cursor.par->table->RightLine(actCell);
1917 cursor.par->table->SetRightLine(actCell,lineSet);
1920 LyXParagraph::size_type i;
1925 for (i=sel_start_cursor.pos; i<=sel_end_cursor.pos; i++){
1926 if ((n=NumberOfCell(sel_start_cursor.par,i)) != m) {
1927 cursor.par->table->SetRightLine(n,lineSet);
1935 case LyXTable::ALIGN_LEFT:
1936 case LyXTable::ALIGN_RIGHT:
1937 case LyXTable::ALIGN_CENTER:
1939 cursor.par->table->SetAlignment(actCell,setAlign);
1942 LyXParagraph::size_type i;
1947 for (i=sel_start_cursor.pos; i<=sel_end_cursor.pos; i++){
1948 if ((n=NumberOfCell(sel_start_cursor.par,i)) != m) {
1949 cursor.par->table->SetAlignment(n,setAlign);
1957 case LyXTable::DELETE_TABLE:
1958 SetCursorIntern(cursor.par, 0);
1959 delete cursor.par->table;
1960 cursor.par->table = 0;
1961 // temporary: Should put table in simple_cut_buffer (with before and after
1962 // dummy-paragraph !!
1963 // not necessar anymore with UNDO :)
1965 for (LyXParagraph::size_type i =
1966 cursor.par->text.size() - 1; i >= 0; --i)
1968 for (int i = cursor.par->last-1; i>=0; i--)
1970 cursor.par->Erase(i);
1974 case LyXTable::MULTICOLUMN: {
1976 // check wether we are completly in a multicol
1977 int multicol = cursor.par->table->IsMultiColumn(actCell);
1978 if (multicol && selection && sel_start_cursor.row == sel_end_cursor.row){
1979 multicol = NumberOfCell(sel_start_cursor.par, sel_start_cursor.pos)
1980 == NumberOfCell(sel_end_cursor.par, sel_end_cursor.pos);
1984 int newlines = cursor.par->table->UnsetMultiColumn(actCell);
1986 LyXParagraph::size_type pos = cursor.pos;
1988 int pos = cursor.pos;
1990 while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
1992 for (;newlines;newlines--)
1993 cursor.par->InsertChar(pos, LYX_META_NEWLINE);
1998 // selection must be in one row (or no selection)
2000 cursor.par->table->SetMultiColumn(NumberOfCell(cursor.par,
2007 if (sel_start_cursor.row == sel_end_cursor.row){
2009 LyXParagraph::size_type i;
2014 for (i = sel_start_cursor.pos;
2015 i < sel_end_cursor.pos; ++i){
2016 if (sel_start_cursor.par->IsNewline(i)){
2017 sel_start_cursor.par->Erase(i);
2018 // check for double-blanks
2019 if ((i && !sel_start_cursor.par->IsLineSeparator(i-1))
2021 (i < sel_start_cursor.par->Last()
2022 && !sel_start_cursor.par->IsLineSeparator(i)))
2023 sel_start_cursor.par->InsertChar(i, ' ');
2025 sel_end_cursor.pos--;
2032 SetMultiColumn(NumberOfCell(sel_start_cursor.par,
2033 sel_start_cursor.pos),
2035 cursor.pos = sel_start_cursor.pos;
2040 WriteAlert(_("Impossible Operation!"),
2041 _("Multicolumns can only be horizontally."),
2048 case LyXTable::SET_ALL_LINES:
2050 case LyXTable::UNSET_ALL_LINES:
2052 cursor.par->table->SetAllLines(NumberOfCell(cursor.par,
2057 LyXParagraph::size_type i;
2062 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
2063 if ((n=NumberOfCell(sel_start_cursor.par,i)) != m) {
2064 cursor.par->table->SetAllLines(n,setLines);
2071 case LyXTable::SET_LONGTABLE:
2072 cursor.par->table->SetLongTable(true);
2074 case LyXTable::UNSET_LONGTABLE:
2075 cursor.par->table->SetLongTable(false);
2077 case LyXTable::SET_ROTATE_TABLE:
2078 cursor.par->table->SetRotateTable(true);
2080 case LyXTable::UNSET_ROTATE_TABLE:
2081 cursor.par->table->SetRotateTable(false);
2083 case LyXTable::SET_ROTATE_CELL:
2085 cursor.par->table->SetRotateCell(actCell,true);
2088 LyXParagraph::size_type i;
2093 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i){
2094 if ((n = NumberOfCell(sel_start_cursor.par,i)) != m) {
2095 cursor.par->table->SetRotateCell(n,true);
2101 case LyXTable::UNSET_ROTATE_CELL:
2103 cursor.par->table->SetRotateCell(actCell,false);
2106 LyXParagraph::size_type i;
2109 int i, n = -1, m = -2;
2111 for (i=sel_start_cursor.pos; i<=sel_end_cursor.pos; i++){
2112 if ((n=NumberOfCell(sel_start_cursor.par,i)) != m) {
2113 cursor.par->table->SetRotateCell(n,false);
2119 case LyXTable::SET_LINEBREAKS:
2120 what = !cursor.par->table->Linebreaks(cursor.par->table->FirstVirtualCell(actCell));
2122 cursor.par->table->SetLinebreaks(actCell,what);
2125 LyXParagraph::size_type i;
2128 int i, n = -1, m = -2;
2130 for (i = sel_start_cursor.pos; i <= sel_end_cursor.pos; ++i) {
2131 if ((n = NumberOfCell(sel_start_cursor.par,i)) != m) {
2132 cursor.par->table->SetLinebreaks(n,what);
2138 case LyXTable::SET_LTFIRSTHEAD:
2139 cursor.par->table->SetLTHead(actCell,true);
2141 case LyXTable::SET_LTHEAD:
2142 cursor.par->table->SetLTHead(actCell,false);
2144 case LyXTable::SET_LTFOOT:
2145 cursor.par->table->SetLTFoot(actCell,false);
2147 case LyXTable::SET_LTLASTFOOT:
2148 cursor.par->table->SetLTFoot(actCell,true);
2150 case LyXTable::SET_LTNEWPAGE:
2151 what = !cursor.par->table->LTNewPage(actCell);
2152 cursor.par->table->SetLTNewPage(actCell,what);
2158 void LyXText::InsertCharInTable(char c)
2163 bool jumped_over_space;
2165 /* first check, if there will be two blanks together or a blank at
2166 * the beginning of a paragraph.
2167 * I decided to handle blanks like normal characters, the main
2168 * difference are the special checks when calculating the row.fill
2169 * (blank does not count at the end of a row) and the check here */
2171 LyXFont realtmpfont = real_current_font;
2172 LyXFont rawtmpfont = current_font; /* store the current font.
2173 * This is because of the use
2174 * of cursor movements. The moving
2175 * cursor would refresh the
2178 // Get the font that is used to calculate the baselineskip
2180 LyXParagraph::size_type const lastpos =
2183 int const lastpos = cursor.par->Last();
2185 LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2187 jumped_over_space = false;
2188 if (IsLineSeparatorChar(c)) {
2190 /* avoid double blanks but insert the new blank because
2191 * of a possible font change */
2192 if (cursor.pos < lastpos &&
2193 cursor.par->IsLineSeparator(cursor.pos))
2195 cursor.par->Erase(cursor.pos);
2196 jumped_over_space = true;
2198 else if ((cursor.pos > 0 &&
2199 cursor.par->IsLineSeparator(cursor.pos - 1))
2200 || (cursor.pos > 0 && cursor.par->IsNewline(cursor.pos - 1))
2201 || (cursor.pos == 0 &&
2202 !(cursor.par->Previous()
2203 && cursor.par->Previous()->footnoteflag
2204 == LyXParagraph::OPEN_FOOTNOTE)))
2207 else if (IsNewlineChar(c)) {
2208 if (!IsEmptyTableCell()) {
2209 TableFeatures(LyXTable::APPEND_CONT_ROW);
2216 y = cursor.y - row->baseline;
2217 if (c != LYX_META_INSET) /* in this case LyXText::InsertInset
2218 * already inserted the character */
2219 cursor.par->InsertChar(cursor.pos, c);
2220 SetCharFont(cursor.par, cursor.pos, rawtmpfont);
2222 if (!jumped_over_space) {
2223 /* refresh the positions */
2225 while (tmprow->next && tmprow->next->par == row->par) {
2226 tmprow = tmprow->next;
2233 CheckParagraphInTable(cursor.par, cursor.pos);
2235 current_font = rawtmpfont;
2236 real_current_font = realtmpfont;
2238 /* check, whether the last character's font has changed. */
2239 if (cursor.pos && cursor.pos == cursor.par->Last()
2240 && rawparfont != rawtmpfont)
2241 RedoHeightOfParagraph(cursor);
2245 void LyXText::CheckParagraphInTable(LyXParagraph * par,
2246 LyXParagraph::size_type pos)
2248 void LyXText::CheckParagraphInTable(LyXParagraph * par, int pos)
2252 if (par->GetChar(pos) == LYX_META_INSET &&
2253 par->GetInset(pos) && par->GetInset(pos)->Display()){
2254 par->GetInset(pos)->SetDisplay(false);
2258 Row * row = GetRow(par, pos, y);
2260 int tmpheight = row->height;
2261 SetHeightOfRow(row);
2264 LyXParagraph::size_type tmp_pos = pos;
2268 /* update the table information */
2269 while (tmp_pos && !par->IsNewline(tmp_pos - 1))
2271 if (par->table->SetWidthOfCell(NumberOfCell(par, pos),
2272 WidthOfCell(par, tmp_pos))) {
2273 LyXCursor tmpcursor = cursor;
2274 SetCursorIntern(par, pos);
2275 /* make a complete redraw */
2276 RedoDrawingOfParagraph(cursor);
2280 /* redraw only the row */
2281 LyXCursor tmpcursor = cursor;
2282 SetCursorIntern(par, pos);
2284 refresh_x = cursor.x;
2286 refresh_pos = cursor.pos;
2289 if (tmpheight == row->height)
2290 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2292 status = LyXText::NEED_MORE_REFRESH;
2294 SetCursorIntern(cursor.par, cursor.pos);
2298 void LyXText::BackspaceInTable()
2300 Row * tmprow, * row;
2303 LyXFont rawtmpfont = current_font;
2304 LyXFont realtmpfont = real_current_font;
2306 // Get the font that is used to calculate the baselineskip
2307 int const lastpos = cursor.par->Last();
2308 LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2310 if (cursor.pos == 0) {
2311 /* no pasting of table paragraphs */
2316 /* this is the code for a normal backspace, not pasting
2318 SetUndo(Undo::DELETE,
2319 cursor.par->ParFromPos(cursor.pos)->previous,
2320 cursor.par->ParFromPos(cursor.pos)->next);
2324 /* some insets are undeletable here */
2325 if (cursor.par->GetChar(cursor.pos)==LYX_META_INSET) {
2326 if (!cursor.par->GetInset(cursor.pos)->Deletable())
2331 y = cursor.y - row->baseline;
2333 /* some special code when deleting a newline. */
2334 if (cursor.par->IsNewline(cursor.pos)) {
2339 cursor.par->Erase(cursor.pos);
2341 /* refresh the positions */
2343 while (tmprow->next && tmprow->next->par == row->par) {
2344 tmprow = tmprow->next;
2348 /* delete superfluous blanks */
2349 if (cursor.pos < cursor.par->Last() - 1 &&
2350 (cursor.par->IsLineSeparator(cursor.pos))) {
2352 if (cursor.pos == BeginningOfMainBody(cursor.par)
2354 || cursor.par->IsLineSeparator(cursor.pos - 1)) {
2355 cursor.par->Erase(cursor.pos);
2356 /* refresh the positions */
2358 while (tmprow->next &&
2359 tmprow->next->par == row->par) {
2360 tmprow = tmprow->next;
2363 if (cursor.pos) /* move one character left */
2369 CheckParagraphInTable(cursor.par, cursor.pos);
2371 /* check, wether the last characters font has changed. */
2372 if (cursor.pos && cursor.pos == cursor.par->Last()
2373 && rawparfont != rawtmpfont)
2374 RedoHeightOfParagraph(cursor);
2376 /* restore the current font
2377 * That is what a user expects! */
2378 current_font = rawtmpfont;
2379 real_current_font = realtmpfont;
2381 SetCursorIntern(cursor.par, cursor.pos);
2384 /* table stuff -- end*/
2387 /* just a macro to make some thing easier. */
2388 void LyXText::RedoParagraph()
2390 LyXCursor tmpcursor = cursor;
2392 RedoParagraphs(cursor, cursor.par->Next());;
2393 SetCursorIntern(tmpcursor.par, tmpcursor.pos);
2397 /* insert a character, moves all the following breaks in the
2398 * same Paragraph one to the right and make a rebreak */
2399 void LyXText::InsertChar(char c)
2404 bool jumped_over_space;
2405 LyXFont realtmpfont;
2408 LyXParagraph::size_type z;
2409 LyXParagraph::size_type lastpos;
2416 SetUndo(Undo::INSERT,
2417 cursor.par->ParFromPos(cursor.pos)->previous,
2418 cursor.par->ParFromPos(cursor.pos)->next);
2420 /* When the free-spacing option is set for the current layout,
2421 * all spaces are converted to protected spaces. */
2422 bool freeSpacingBo =
2423 textclasslist.Style(parameters->textclass,
2424 cursor.row->par->GetLayout()).free_spacing;
2426 if (freeSpacingBo && IsLineSeparatorChar(c)
2427 && (!cursor.pos || cursor.par->IsLineSeparator(cursor.pos-1)))
2428 c = LYX_META_PROTECTED_SEPARATOR;
2430 /* table stuff -- begin*/
2431 if (cursor.par->table) {
2432 InsertCharInTable(c);
2435 /* table stuff -- end*/
2437 /* first check, if there will be two blanks together or a blank at
2438 * the beginning of a paragraph.
2439 * I decided to handle blanks like normal characters, the main
2440 * difference are the special checks when calculating the row.fill
2441 * (blank does not count at the end of a row) and the check here */
2443 // The bug is triggered when we type in a description environment:
2444 // The current_font is not changed when we go from label to main text
2445 // and it should (along with realtmpfont) when we type the space.
2446 #ifdef WITH_WARNINGS
2447 #warning There is a bug here! (Asger)
2450 realtmpfont = real_current_font;
2451 rawtmpfont = current_font; /* store the current font.
2452 * This is because of the use
2453 * of cursor movements. The moving
2454 * cursor would refresh the
2457 // Get the font that is used to calculate the baselineskip
2458 lastpos = cursor.par->Last();
2459 rawparfont = cursor.par->GetFontSettings(lastpos - 1);
2461 jumped_over_space = false;
2463 if (IsLineSeparatorChar(c)) {
2465 if (cursor.pos < lastpos
2466 && cursor.par->IsLineSeparator(cursor.pos)) {
2467 /* the user inserted a space before a space. So we
2468 * will just make a CursorRight. BUT: The font of this
2469 * space should be set to current font. That is why
2470 * we need to rebreak perhaps. If there is a protected
2471 * blank at the end of a row we have to force
2474 minibuffer->Set(_("You cannot type two spaces this way. Please read the Tutorial."));
2475 if (cursor.pos == RowLast(cursor.row)
2476 && !IsLineSeparatorChar(c))
2477 cursor.row->fill = -1; /* force rebreak */
2479 cursor.par->Erase(cursor.pos);
2480 jumped_over_space = true;
2482 } else if ((cursor.pos > 0
2483 && cursor.par->IsLineSeparator(cursor.pos - 1))
2485 && cursor.par->IsNewline(cursor.pos - 1))
2487 && !(cursor.par->Previous()
2488 && cursor.par->Previous()->footnoteflag
2489 == LyXParagraph::OPEN_FOOTNOTE))) {
2490 if (cursor.pos == 0 )
2491 minibuffer->Set(_("You cannot insert a space at the beginning of a paragraph. Please read the Tutorial."));
2493 minibuffer->Set(_("You cannot type two spaces this way. Please read the Tutorial."));
2496 } else if (IsNewlineChar(c)) {
2497 if (cursor.par->FirstPhysicalPar() == cursor.par
2498 && cursor.pos <= BeginningOfMainBody(cursor.par))
2500 /* no newline at first position
2501 * of a paragraph or behind labels.
2502 * TeX does not allow that. */
2504 if (cursor.pos < cursor.par->Last() &&
2505 cursor.par->IsLineSeparator(cursor.pos))
2506 CursorRightIntern(); // newline always after a blank!
2507 cursor.row->fill = -1; // to force a new break
2510 /* the display inset stuff */
2511 if (cursor.row->par->GetChar(cursor.row->pos) == LYX_META_INSET
2512 && cursor.row->par->GetInset(cursor.row->pos)
2513 && cursor.row->par->GetInset(cursor.row->pos)->Display())
2514 cursor.row->fill = -1; // to force a new break
2516 /* get the cursor row fist */
2517 /* this is a dumb solution, i will try to hold the cursor.row
2519 /* row = GetRow(cursor.par, cursor.pos, y);*/
2520 /* ok, heres a better way: */
2522 y = cursor.y - row->baseline;
2523 if (c != LYX_META_INSET) /* in this case LyXText::InsertInset
2524 * already insertet the character */
2525 cursor.par->InsertChar(cursor.pos, c);
2526 SetCharFont(cursor.par, cursor.pos, rawtmpfont);
2528 if (!jumped_over_space) {
2529 /* refresh the positions */
2531 while (tmprow->next && tmprow->next->par == row->par) {
2532 tmprow = tmprow->next;
2537 /* Is there a break one row above */
2538 if ((cursor.par->IsLineSeparator(cursor.pos)
2539 || cursor.par->IsNewline(cursor.pos)
2540 || cursor.row->fill == -1)
2541 && row->previous && row->previous->par == row->par) {
2542 z = NextBreakPoint(row->previous, paperwidth);
2543 if ( z >= row->pos) {
2546 /* set the dimensions of the row above */
2547 row->previous->fill = Fill(row->previous, paperwidth);
2549 SetHeightOfRow(row->previous);
2551 y -= row->previous->height;
2553 refresh_row = row->previous;
2554 status = LyXText::NEED_MORE_REFRESH;
2556 BreakAgainOneRow(row);
2557 SetCursor(cursor.par, cursor.pos + 1);
2558 /* cursor MUST be in row now */
2560 if (row->next && row->next->par == row->par)
2561 need_break_row = row->next;
2565 current_font = rawtmpfont;
2566 real_current_font = realtmpfont;
2568 // check, wether the last characters font has changed.
2569 if (cursor.pos && cursor.pos == cursor.par->Last()
2570 && rawparfont != rawtmpfont)
2571 RedoHeightOfParagraph(cursor);
2577 /* recalculate the fill of the row */
2578 if (row->fill >= 0) /* needed because a newline
2579 * will set fill to -1. Otherwise
2580 * we would not get a rebreak! */
2581 row->fill = Fill(row, paperwidth);
2582 if (row->fill < 0 ) {
2585 refresh_x = cursor.x;
2586 refresh_pos = cursor.pos;
2587 status = LyXText::NEED_MORE_REFRESH;
2588 BreakAgainOneRow(row);
2589 /* will the cursor be in another row now? */
2590 if (RowLast(row) <= cursor.pos + 1 && row->next) {
2591 if (row->next && row->next->par == row->par)
2595 BreakAgainOneRow(row);
2597 SetCursor(cursor.par, cursor.pos + 1);
2598 if (row->next && row->next->par == row->par)
2599 need_break_row = row->next;
2603 current_font = rawtmpfont;
2604 real_current_font = realtmpfont;
2607 refresh_x = cursor.x;
2609 refresh_pos = cursor.pos;
2611 int tmpheight = row->height;
2612 SetHeightOfRow(row);
2613 if (tmpheight == row->height)
2614 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2616 status = LyXText::NEED_MORE_REFRESH;
2618 SetCursor(cursor.par, cursor.pos + 1);
2619 current_font = rawtmpfont;
2620 real_current_font = realtmpfont;
2623 /* check, wether the last characters font has changed. */
2624 if (cursor.pos && cursor.pos == cursor.par->Last()
2625 && rawparfont != rawtmpfont) {
2626 RedoHeightOfParagraph(cursor);
2628 /* now the special right address boxes */
2629 if (textclasslist.Style(parameters->textclass,
2630 cursor.par->GetLayout()).margintype
2631 == MARGIN_RIGHT_ADDRESS_BOX) {
2632 RedoDrawingOfParagraph(cursor);
2637 // Here we could call FinishUndo for every 20 characters inserted.
2638 // This is from my experience how emacs does it.
2639 static unsigned short counter = 0;
2650 void LyXText::PrepareToPrint(Row * row, float & x, float & fill_separator,
2651 float & fill_hfill, float & fill_label_hfill)
2655 float w = row->fill;
2657 fill_label_hfill = 0;
2659 fill_label_hfill = 0;
2661 x = LeftMargin(row);
2663 /* is there a manual margin with a manual label */
2664 if (textclasslist.Style(parameters->textclass,
2665 row->par->GetLayout()).margintype == MARGIN_MANUAL
2666 && textclasslist.Style(parameters->textclass,
2667 row->par->GetLayout()).labeltype == LABEL_MANUAL) {
2669 nlh = NumberOfLabelHfills(row) + 1; /* one more since labels
2670 * are left aligned*/
2671 if (nlh && !row->par->GetLabelWidthString().empty()) {
2672 fill_label_hfill = LabelFill(row) / nlh;
2676 /* are there any hfills in the row? */
2677 nh = NumberOfHfills(row);
2679 /* table stuff -- begin*/
2680 if (row->par->table) {
2681 w = paperwidth - row->par->table->WidthOfTable()
2682 - x - RightMargin(row);
2683 nh = 0; /* ignore hfills in tables */
2685 /* table stuff -- end*/
2690 /* is it block, flushleft or flushright?
2691 * set x how you need it */
2693 if (row->par->FirstPhysicalPar()->align == LYX_ALIGN_LAYOUT)
2694 align = textclasslist.Style(parameters->textclass, row->par->GetLayout()).align;
2696 align = row->par->FirstPhysicalPar()->align;
2698 /* center displayed insets */
2699 if (row->par->GetChar(row->pos) == LYX_META_INSET
2700 && row->par->GetInset(row->pos)
2701 && row->par->GetInset(row->pos)->Display())
2702 align = LYX_ALIGN_CENTER;
2705 case LYX_ALIGN_BLOCK:
2706 ns = NumberOfSeparators(row);
2707 if (ns && row->next && row->next->par == row->par &&
2708 !(row->next->par->IsNewline(row->next->pos-1))
2709 && !(row->next->par->GetChar(row->next->pos) == LYX_META_INSET
2710 && row->next->par->GetInset(row->next->pos)
2711 && row->next->par->GetInset(row->next->pos)->Display())
2713 fill_separator = w / ns;
2715 case LYX_ALIGN_RIGHT:
2718 case LYX_ALIGN_CENTER:
2726 /* important for the screen */
2729 /* the cursor set functions have a special mechanism. When they
2730 * realize, that you left an empty paragraph, they will delete it.
2731 * They also delete the corresponding row */
2733 void LyXText::CursorRightOneWord()
2735 // treat floats, HFills and Insets as words
2736 LyXCursor tmpcursor = cursor;
2738 if (tmpcursor.pos == tmpcursor.par->Last()
2739 && tmpcursor.par->Next())
2741 tmpcursor.par = tmpcursor.par->Next();
2746 // Skip through initial nonword stuff.
2747 while ( tmpcursor.pos < tmpcursor.par->Last() &&
2748 ! tmpcursor.par->IsWord( tmpcursor.pos ) )
2750 // printf("Current pos1 %d",tmpcursor.pos) ;
2754 // Advance through word.
2755 while ( tmpcursor.pos < tmpcursor.par->Last() &&
2756 tmpcursor.par->IsWord( tmpcursor.pos ) )
2758 // printf("Current pos2 %d",tmpcursor.pos) ;
2763 SetCursor(tmpcursor.par, tmpcursor.pos);
2767 void LyXText::CursorTab()
2769 if (cursor.par->table) {
2770 int cell = NumberOfCell(cursor.par, cursor.pos);
2771 while(cursor.par->table->IsContRow(cell)) {
2773 cell = NumberOfCell(cursor.par, cursor.pos);
2775 if (cursor.par->table->ShouldBeVeryLastCell(cell))
2776 TableFeatures(LyXTable::APPEND_ROW);
2778 LyXCursor tmpcursor = cursor;
2779 while (tmpcursor.pos < tmpcursor.par->Last()
2780 && !tmpcursor.par->IsNewline(tmpcursor.pos))
2783 if (tmpcursor.pos == tmpcursor.par->Last()){
2784 if (tmpcursor.par->Next()) {
2785 tmpcursor.par = tmpcursor.par->Next();
2791 SetCursor(tmpcursor.par, tmpcursor.pos);
2792 if (cursor.par->table) {
2793 int cell = NumberOfCell(cursor.par, cursor.pos);
2794 while (cursor.par->table->IsContRow(cell) &&
2795 !cursor.par->table->ShouldBeVeryLastCell(cell)) {
2797 while (tmpcursor.pos < tmpcursor.par->Last()
2798 && !tmpcursor.par->IsNewline(tmpcursor.pos))
2801 if (tmpcursor.pos == tmpcursor.par->Last()){
2802 if (tmpcursor.par->Next()) {
2803 tmpcursor.par = tmpcursor.par->Next();
2809 SetCursor(tmpcursor.par, tmpcursor.pos);
2810 cell = NumberOfCell(cursor.par, cursor.pos);
2816 /* -------> Skip initial whitespace at end of word and move cursor to *start*
2817 of prior word, not to end of next prior word. */
2819 void LyXText::CursorLeftOneWord()
2821 // treat HFills, floats and Insets as words
2822 LyXCursor tmpcursor = cursor;
2823 while (tmpcursor.pos
2824 && (tmpcursor.par->IsSeparator(tmpcursor.pos - 1)
2825 || tmpcursor.par->IsKomma(tmpcursor.pos - 1))
2826 && !(tmpcursor.par->IsHfill(tmpcursor.pos - 1)
2827 || tmpcursor.par->IsFloat(tmpcursor.pos - 1)
2828 || tmpcursor.par->IsInset(tmpcursor.pos - 1)))
2832 && (tmpcursor.par->IsInset(tmpcursor.pos - 1)
2833 || tmpcursor.par->IsFloat(tmpcursor.pos - 1)
2834 || tmpcursor.par->IsHfill(tmpcursor.pos - 1))) {
2836 } else if (!tmpcursor.pos) {
2837 if (tmpcursor.par->Previous()){
2838 tmpcursor.par = tmpcursor.par->Previous();
2839 tmpcursor.pos = tmpcursor.par->Last();
2841 } else { // Here, tmpcursor != 0
2842 while (tmpcursor.pos > 0 &&
2843 tmpcursor.par->IsWord(tmpcursor.pos-1) )
2846 SetCursor(tmpcursor.par, tmpcursor.pos);
2849 /* -------> Select current word. This depends on behaviour of CursorLeftOneWord(), so it is
2852 void LyXText::SelectWord()
2854 /* Move cursor to the beginning, when not already there. */
2856 && !cursor.par->IsSeparator(cursor.pos-1)
2857 && !cursor.par->IsKomma(cursor.pos-1) )
2858 CursorLeftOneWord();
2860 /* set the sel cursor */
2861 sel_cursor = cursor;
2863 while ( cursor.pos < cursor.par->Last()
2864 && !cursor.par->IsSeparator(cursor.pos)
2865 && !cursor.par->IsKomma(cursor.pos) )
2867 SetCursor( cursor.par, cursor.pos );
2869 /* finally set the selection */
2874 /* -------> Select the word currently under the cursor when:
2875 1: no selection is currently set,
2876 2: the cursor is not at the borders of the word. */
2878 int LyXText::SelectWordWhenUnderCursor()
2880 if ( selection ) return 0;
2881 if ( cursor.pos < cursor.par->Last()
2882 && !cursor.par->IsSeparator(cursor.pos)
2883 && !cursor.par->IsKomma(cursor.pos)
2885 && !cursor.par->IsSeparator(cursor.pos -1)
2886 && !cursor.par->IsKomma(cursor.pos -1) ) {
2894 // This function is only used by the spellchecker for NextWord().
2895 // It doesn't handle LYX_ACCENTs and probably never will.
2896 char * LyXText::SelectNextWord(float & value)
2898 LyXParagraph * tmppar = cursor.par;
2900 // If this is not the very first word, skip rest of
2901 // current word because we are probably in the middle
2902 // of a word if there is text here.
2903 if (cursor.pos || cursor.par->previous) {
2904 while (cursor.pos < cursor.par->Last()
2905 && cursor.par->IsLetter(cursor.pos))
2908 // Now, skip until we have real text (will jump paragraphs)
2909 while ((cursor.par->Last() > cursor.pos
2910 && (!cursor.par->IsLetter(cursor.pos)
2911 || cursor.par->getFont(cursor.pos).latex() == LyXFont::ON))
2912 || (cursor.par->Last() == cursor.pos
2913 && cursor.par->Next())){
2914 if (cursor.pos == cursor.par->Last()) {
2915 cursor.par = cursor.par->Next();
2922 // Update the value if we changed paragraphs
2923 if (cursor.par != tmppar){
2924 SetCursor(cursor.par, cursor.pos);
2925 value = float(cursor.y)/float(height);
2928 /* Start the selection from here */
2929 sel_cursor = cursor;
2933 /* and find the end of the word
2934 (optional hyphens are part of a word) */
2935 while (cursor.pos < cursor.par->Last()
2936 && (cursor.par->IsLetter(cursor.pos))
2937 || (cursor.par->GetChar(cursor.pos) == LYX_META_INSET &&
2938 cursor.par->GetInset(cursor.pos) != 0 &&
2939 cursor.par->GetInset(cursor.pos)->Latex(latex,0)==0 &&
2943 // Finally, we copy the word to a string and return it
2946 if (sel_cursor.pos < cursor.pos) {
2947 str = new char [cursor.pos - sel_cursor.pos + 2];
2949 LyXParagraph::size_type i, j;
2953 for (i = sel_cursor.pos, j = 0; i < cursor.pos; ++i) {
2954 if (cursor.par->GetChar(i) != LYX_META_INSET)
2955 str[j++] = cursor.par->GetChar(i);
2963 // This one is also only for the spellchecker
2964 void LyXText::SelectSelectedWord()
2966 /* move cursor to the beginning */
2967 SetCursor(sel_cursor.par, sel_cursor.pos);
2969 /* set the sel cursor */
2970 sel_cursor = cursor;
2974 /* now find the end of the word */
2975 while (cursor.pos < cursor.par->Last()
2976 && (cursor.par->IsLetter(cursor.pos)
2977 || (cursor.par->GetChar(cursor.pos) == LYX_META_INSET &&
2978 cursor.par->GetInset(cursor.pos) != 0 &&
2979 cursor.par->GetInset(cursor.pos)->Latex(latex,0)==0 &&
2983 SetCursor(cursor.par, cursor.pos);
2985 /* finally set the selection */
2990 /* -------> Delete from cursor up to the end of the current or next word. */
2991 void LyXText::DeleteWordForward()
2993 LyXCursor tmpcursor = cursor;
2995 if (!cursor.par->Last())
2998 /* -------> Skip initial non-word stuff. */
2999 while ( cursor.pos < cursor.par->Last()
3000 && (cursor.par->IsSeparator(cursor.pos)
3001 || cursor.par->IsKomma(cursor.pos)) )
3004 SetCursorIntern(cursor.par, cursor.pos);
3005 selection = True; // to avoid deletion
3006 CursorRightOneWord();
3007 sel_cursor = cursor;
3011 /* -----> Great, CutSelection() gets rid of multiple spaces. */
3017 /* -------> Delete from cursor to start of current or prior word. */
3018 void LyXText::DeleteWordBackward()
3020 LyXCursor tmpcursor = cursor;
3021 if (!cursor.par->Last())
3024 selection = true; // to avoid deletion
3025 CursorLeftOneWord();
3026 sel_cursor = cursor;
3034 /* -------> Kill to end of line. */
3035 void LyXText::DeleteLineForward()
3037 LyXCursor tmpcursor = cursor;
3038 if (!cursor.par->Last())
3042 sel_cursor = cursor;
3045 if (selection == false) {
3046 DeleteWordForward();
3054 // Change the case of a word at cursor position. The meaning of action
3056 // 0 change to lowercase
3057 // 1 capitalize word
3058 // 2 change to uppercase
3059 // This function directly manipulates LyXParagraph::text because there
3060 // is no LyXParagraph::SetChar currently. I did what I could to ensure
3061 // that it is correct. I guess part of it should be moved to
3062 // LyXParagraph, but it will have to change for 1.1 anyway. At least
3063 // it does not access outside of the allocated array as the older
3064 // version did. (JMarc)
3065 void LyXText::ChangeWordCase(LyXText::TextCase action)
3067 LyXParagraph * tmppar = cursor.par->ParFromPos(cursor.pos);
3069 SetUndo(Undo::FINISH, tmppar->previous, tmppar->next);
3072 LyXParagraph::size_type tmppos =
3073 cursor.par->PositionInParFromPos(cursor.pos);
3074 while (tmppos < tmppar->size()) {
3076 int tmppos = cursor.par->PositionInParFromPos(cursor.pos);
3077 while (tmppos < tmppar->last) {
3079 unsigned char c = tmppar->text[tmppos];
3080 if (IsKommaChar(c) || IsLineSeparatorChar(c))
3082 if (c != LYX_META_INSET) {
3084 case text_lowercase:
3087 case text_capitalization:
3089 action = text_lowercase;
3091 case text_uppercase:
3097 tmppar->text[tmppos] = c;
3100 CheckParagraph(tmppar, tmppos);
3101 CursorRightOneWord();
3105 void LyXText::Delete()
3107 LyXCursor old_cursor = cursor;
3108 /* this is a very easy implementation*/
3110 /* just move to the right */
3111 CursorRightIntern();
3113 if (cursor.par->previous == old_cursor.par->previous
3114 && cursor.par != old_cursor.par)
3115 return; // delete-emty-paragraph-mechanism has done it
3117 /* if you had success make a backspace */
3118 if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) {
3119 LyXCursor tmpcursor = cursor;
3120 cursor = old_cursor; // to make sure undo gets the right cursor position
3121 SetUndo(Undo::DELETE,
3122 cursor.par->ParFromPos(cursor.pos)->previous,
3123 cursor.par->ParFromPos(cursor.pos)->next);
3130 void LyXText::Backspace()
3132 LyXParagraph * tmppar;
3133 Row * tmprow, * row;
3137 /* table stuff -- begin*/
3139 if (cursor.par->table) {
3143 /* table stuff -- end*/
3145 LyXFont rawtmpfont = current_font;
3146 LyXFont realtmpfont = real_current_font;
3148 // Get the font that is used to calculate the baselineskip
3149 int const lastpos = cursor.par->Last();
3150 LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
3152 if (cursor.pos == 0) {
3153 /* we may paste some paragraphs */
3155 /* is it an empty paragraph? */
3158 || (lastpos == 1 && cursor.par->IsSeparator(0)))
3159 && !(cursor.par->Next()
3160 && cursor.par->footnoteflag ==
3161 LyXParagraph::NO_FOOTNOTE
3162 && cursor.par->Next()->footnoteflag ==
3163 LyXParagraph::OPEN_FOOTNOTE)) {
3165 if (cursor.par->previous) {
3166 tmppar = cursor.par->previous->FirstPhysicalPar();
3167 if (cursor.par->GetLayout() == tmppar->GetLayout()
3168 && cursor.par->footnoteflag == tmppar->footnoteflag
3169 && cursor.par->GetAlign() == tmppar->GetAlign()) {
3171 tmppar->line_bottom = cursor.par->line_bottom;
3172 tmppar->added_space_bottom = cursor.par->added_space_bottom;
3173 tmppar->pagebreak_bottom = cursor.par->pagebreak_bottom;
3178 /* the layout things can change the height of a row ! */
3179 tmpheight = cursor.row->height;
3180 SetHeightOfRow(cursor.row);
3181 if (cursor.row->height != tmpheight) {
3182 refresh_y = cursor.y - cursor.row->baseline;
3183 refresh_row = cursor.row;
3184 status = LyXText::NEED_MORE_REFRESH;
3189 if (cursor.par->ParFromPos(cursor.pos)->previous){
3190 SetUndo(Undo::DELETE,
3191 cursor.par->ParFromPos(cursor.pos)->previous->previous,
3192 cursor.par->ParFromPos(cursor.pos)->next);
3194 tmppar = cursor.par;
3195 tmprow = cursor.row;
3197 /* Pasting is not allowed, if the paragraphs have different
3198 layout. I think it is a real bug of all other
3199 word processors to allow it. It confuses the user.
3200 Even so with a footnote paragraph and a non-footnote
3201 paragraph. I will not allow pasting in this case,
3202 because the user would be confused if the footnote behaves
3203 different wether it is open or closed.
3205 Correction: Pasting is always allowed with standard-layout
3207 if (cursor.par != tmppar
3208 && (cursor.par->GetLayout() == tmppar->GetLayout()
3209 || !tmppar->GetLayout())
3210 && cursor.par->footnoteflag == tmppar->footnoteflag
3211 /* table stuff -- begin*/
3212 && !cursor.par->table /* no pasting of tables */
3213 /* table stuff -- end*/
3214 && cursor.par->GetAlign() == tmppar->GetAlign()) {
3216 cursor.par->PasteParagraph();
3219 cursor.par->IsSeparator(cursor.pos - 1)))
3220 cursor.par->InsertChar(cursor.pos, ' ');
3225 status = LyXText::NEED_MORE_REFRESH;
3226 refresh_row = cursor.row;
3227 refresh_y = cursor.y - cursor.row->baseline;
3229 /* remove the lost paragraph */
3230 RemoveParagraph(tmprow);
3233 AppendParagraph(cursor.row);
3234 UpdateCounters(cursor.row);
3236 /* the row may have changed, block, hfills etc. */
3237 SetCursor(cursor.par, cursor.pos);
3240 /* this is the code for a normal backspace, not pasting
3242 SetUndo(Undo::DELETE,
3243 cursor.par->ParFromPos(cursor.pos)->previous,
3244 cursor.par->ParFromPos(cursor.pos)->next);
3247 /* some insets are undeletable here */
3248 if (cursor.par->GetChar(cursor.pos)==LYX_META_INSET) {
3249 if (!cursor.par->GetInset(cursor.pos)->Deletable())
3251 /* force complete redo when erasing display insets */
3252 /* this is a cruel mathod but save..... Matthias */
3253 if (cursor.par->GetInset(cursor.pos)->Display()){
3254 cursor.par->Erase(cursor.pos);
3261 y = cursor.y - row->baseline;
3263 LyXParagraph::size_type z;
3267 /* remember that a space at the end of a row doesnt count
3268 * when calculating the fill */
3269 if (cursor.pos < RowLast(row) ||
3270 !cursor.par->IsLineSeparator(cursor.pos)) {
3271 row->fill += SingleWidth(cursor.par, cursor.pos);
3274 /* some special code when deleting a newline. This is similar
3275 * to the behavior when pasting paragraphs */
3276 if (cursor.pos && cursor.par->IsNewline(cursor.pos)) {
3277 cursor.par->Erase(cursor.pos);
3278 /* refresh the positions */
3280 while (tmprow->next && tmprow->next->par == row->par) {
3281 tmprow = tmprow->next;
3284 if (cursor.par->IsLineSeparator(cursor.pos - 1))
3287 if (cursor.pos < cursor.par->Last() && !cursor.par->IsSeparator(cursor.pos)) {
3288 cursor.par->InsertChar(cursor.pos, ' ');
3289 /* refresh the positions */
3291 while (tmprow->next && tmprow->next->par == row->par) {
3292 tmprow = tmprow->next;
3297 cursor.par->Erase(cursor.pos);
3299 /* refresh the positions */
3301 while (tmprow->next && tmprow->next->par == row->par) {
3302 tmprow = tmprow->next;
3306 /* delete superfluous blanks */
3307 if (cursor.pos < cursor.par->Last() - 1 &&
3308 (cursor.par->IsLineSeparator(cursor.pos))) {
3310 if (cursor.pos == BeginningOfMainBody(cursor.par)
3312 || cursor.par->IsLineSeparator(cursor.pos - 1)) {
3313 cursor.par->Erase(cursor.pos);
3314 /* refresh the positions */
3316 while (tmprow->next &&
3317 tmprow->next->par == row->par) {
3318 tmprow = tmprow->next;
3321 if (cursor.pos) /* move one character left */
3326 /* delete newlines at the beginning of paragraphs */
3327 while (cursor.par->Last() &&
3328 cursor.par->IsNewline(cursor.pos) &&
3329 cursor.pos == BeginningOfMainBody(cursor.par)) {
3330 cursor.par->Erase(cursor.pos);
3331 /* refresh the positions */
3333 while (tmprow->next &&
3334 tmprow->next->par == row->par) {
3335 tmprow = tmprow->next;
3341 /* is there a break one row above */
3342 if (row->previous && row->previous->par == row->par) {
3343 z = NextBreakPoint(row->previous, paperwidth);
3344 if ( z >= row->pos) {
3347 tmprow = row->previous;
3349 /* maybe the current row is now empty */
3350 if (row->pos >= row->par->Last()) {
3356 BreakAgainOneRow(row);
3357 if (row->next && row->next->par == row->par)
3358 need_break_row = row->next;
3363 /* set the dimensions of the row above */
3364 y -= tmprow->height;
3365 tmprow->fill = Fill(tmprow, paperwidth);
3366 SetHeightOfRow(tmprow);
3369 refresh_row = tmprow;
3370 status = LyXText::NEED_MORE_REFRESH;
3371 SetCursor(cursor.par, cursor.pos);
3372 current_font = rawtmpfont;
3373 real_current_font = realtmpfont;
3374 /* check, whether the last character's font has changed. */
3375 rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
3376 if (rawparfont != rawtmpfont)
3377 RedoHeightOfParagraph(cursor);
3382 /* break the cursor row again */
3383 z = NextBreakPoint(row, paperwidth);
3385 if ( z != RowLast(row) ||
3386 (row->next && row->next->par == row->par &&
3387 RowLast(row) == row->par->Last() - 1)){
3389 /* it can happen that a paragraph loses one row
3390 * without a real breakup. This is when a word
3391 * is to long to be broken. Well, I don t care this
3393 if (row->next && row->next->par == row->par &&
3394 RowLast(row) == row->par->Last() - 1)
3395 RemoveRow(row->next);
3399 status = LyXText::NEED_MORE_REFRESH;
3401 BreakAgainOneRow(row);
3403 SetCursor(cursor.par, cursor.pos);
3404 /* cursor MUST be in row now */
3406 if (row->next && row->next->par == row->par)
3407 need_break_row = row->next;
3411 /* set the dimensions of the row */
3412 row->fill = Fill(row, paperwidth);
3413 int tmpheight = row->height;
3414 SetHeightOfRow(row);
3415 if (tmpheight == row->height)
3416 status = LyXText::NEED_VERY_LITTLE_REFRESH;
3418 status = LyXText::NEED_MORE_REFRESH;
3421 SetCursor(cursor.par, cursor.pos);
3425 /* restore the current font
3426 * That is what a user expects! */
3427 current_font = rawtmpfont;
3428 real_current_font = realtmpfont;
3430 /* check, wether the last characters font has changed. */
3431 rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
3432 if (rawparfont != rawtmpfont) {
3433 RedoHeightOfParagraph(cursor);
3435 /* now the special right address boxes */
3436 if (textclasslist.Style(parameters->textclass,
3437 cursor.par->GetLayout()).margintype == MARGIN_RIGHT_ADDRESS_BOX) {
3438 RedoDrawingOfParagraph(cursor);
3444 void LyXText::GetVisibleRow(LyXScreen & scr, int offset,
3445 Row * row_ptr, long y)
3447 /* returns a printed row */
3449 LyXParagraph::size_type pos, pos_end;
3454 int y_top, y_bottom;
3455 float fill_separator, fill_hfill, fill_label_hfill;
3456 LyXParagraph * par, * firstpar;
3460 if (row_ptr->height <= 0) {
3461 lyxerr << "LYX_ERROR: row.height: " << row_ptr->height << endl;
3464 left_margin = LabelEnd(row_ptr);
3465 PrepareToPrint(row_ptr, x, fill_separator,
3466 fill_hfill, fill_label_hfill);
3469 LyXParagraph::size_type main_body =
3470 BeginningOfMainBody(row_ptr->par);
3472 int main_body = BeginningOfMainBody(row_ptr->par);
3474 /* initialize the pixmap */
3476 scr.fillRectangle(gc_clear,
3477 0, offset, paperwidth, row_ptr->height);
3478 // check for NOT FAST SELECTION
3479 if (!fast_selection && !mono_video && selection) {
3480 /* selection code */
3481 if (sel_start_cursor.row == row_ptr &&
3482 sel_end_cursor.row == row_ptr) {
3483 scr.fillRectangle(gc_selection, sel_start_cursor.x,
3489 else if (sel_start_cursor.row == row_ptr) {
3490 scr.fillRectangle(gc_selection, sel_start_cursor.x,
3492 paperwidth - sel_start_cursor.x,
3494 } else if (sel_end_cursor.row == row_ptr) {
3495 scr.fillRectangle(gc_selection,0, offset,
3496 sel_end_cursor.x, row_ptr->height);
3497 } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
3498 scr.fillRectangle(gc_selection, 0, offset,
3499 paperwidth, row_ptr->height);
3502 } // end of NOT FAST SELECTION code
3504 if (row_ptr->par->appendix){
3505 scr.drawVerticalLine(gc_math, 1, offset, offset+row_ptr->height);
3506 scr.drawVerticalLine(gc_math, paperwidth-2 , offset, offset+row_ptr->height);
3509 if (row_ptr->par->pextra_type == PEXTRA_MINIPAGE) {
3510 /* draw a marker at the left margin! */
3511 LyXFont font = GetFont(row_ptr->par, 0);
3512 int asc = font.maxAscent();
3513 int x = (LYX_PAPER_MARGIN - font.width('|')) / 2;
3514 int y1 = (offset + row_ptr->baseline);
3515 int y2 = (offset + row_ptr->baseline) - asc;
3517 scr.drawVerticalLine(gc_minipage, x, y1, y2);
3519 if (row_ptr->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3520 LyXFont font(LyXFont::ALL_SANE);
3521 font.setSize(LyXFont::SIZE_FOOTNOTE);
3522 font.setColor(LyXFont::RED);
3524 int box_x = LYX_PAPER_MARGIN;
3525 box_x += font.textWidth(" wide-tab ", 10);
3526 if (row_ptr->previous &&
3527 row_ptr->previous->par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
3529 switch (row_ptr->par->footnotekind) {
3530 case LyXParagraph::MARGIN:
3533 case LyXParagraph::FIG:
3536 case LyXParagraph::TAB:
3539 case LyXParagraph::WIDE_FIG:
3542 case LyXParagraph::WIDE_TAB:
3545 case LyXParagraph::ALGORITHM:
3548 case LyXParagraph::FOOTNOTE:
3553 // Determine background color.
3554 gc_type back = gc_lighted;
3558 scr.fillRectangle(back,LYX_PAPER_MARGIN, offset+1,
3559 box_x - LYX_PAPER_MARGIN,
3560 int(font.maxAscent())+
3561 int(font.maxDescent()));
3563 scr.drawLine(gc_foot,
3566 paperwidth - 2*LYX_PAPER_MARGIN);
3568 scr.drawString(font, fs,
3569 offset + int(font.maxAscent())+1,
3571 scr.drawVerticalLine(gc_foot,
3575 + int(font.maxAscent())+
3576 int(font.maxDescent()));
3578 scr.drawLine(gc_foot,
3580 + int(font.maxAscent())
3581 + int(font.maxDescent()) + 1,
3582 LYX_PAPER_MARGIN, box_x - LYX_PAPER_MARGIN);
3585 /* draw the open floats in a red box */
3586 scr.drawVerticalLine(gc_foot,
3588 offset, offset + row_ptr->height);
3590 scr.drawVerticalLine(gc_foot,
3591 paperwidth - LYX_PAPER_MARGIN,
3593 offset + row_ptr->height);
3597 if (row_ptr->previous &&
3598 row_ptr->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3599 LyXFont font(LyXFont::ALL_SANE);
3600 font.setSize(LyXFont::SIZE_FOOTNOTE);
3602 int box_x = LYX_PAPER_MARGIN;
3603 box_x += font.textWidth(" wide-tab ", 10);
3605 scr.drawLine(gc_foot,
3608 paperwidth - LYX_PAPER_MARGIN - box_x);
3612 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
3613 row_ptr->par->GetLayout());
3614 firstpar = row_ptr->par->FirstPhysicalPar();
3617 y_bottom = row_ptr->height;
3619 /* is it a first row? */
3620 if (row_ptr->pos == 0
3621 && row_ptr->par == firstpar) {
3623 /* start of appendix? */
3624 if (row_ptr->par->start_of_appendix){
3625 scr.drawLine(gc_math,
3630 /* think about the margins */
3631 if (!row_ptr->previous)
3632 y_top += LYX_PAPER_MARGIN;
3634 if (row_ptr->par->pagebreak_top){ /* draw a top pagebreak */
3635 scr.drawOnOffLine(offset + y_top + 2 * DefaultHeight(),
3637 y_top += 3 * DefaultHeight();
3640 if (row_ptr->par->added_space_top.kind() == VSpace::VFILL) {
3641 /* draw a vfill top */
3642 scr.drawLine(gc_fill,
3644 0, LYX_PAPER_MARGIN);
3645 scr.drawLine(gc_fill,
3646 offset + y_top + 3 * DefaultHeight(),
3647 0, LYX_PAPER_MARGIN);
3648 scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2,
3650 offset + y_top + 3 *
3653 y_top += 3 * DefaultHeight();
3656 /* think about user added space */
3657 y_top += int(row_ptr->par->added_space_top.inPixels());
3659 /* think about the parskip */
3660 /* some parskips VERY EASY IMPLEMENTATION */
3661 if (parameters->paragraph_separation == LYX_PARSEP_SKIP) {
3662 if (layout.latextype == LATEX_PARAGRAPH
3663 && firstpar->GetDepth() == 0
3664 && firstpar->Previous())
3665 y_top += parameters->getDefSkip().inPixels();
3666 else if (firstpar->Previous()
3667 && textclasslist.Style(parameters->textclass,
3668 firstpar->Previous()->GetLayout()).latextype == LATEX_PARAGRAPH
3669 && firstpar->Previous()->GetDepth() == 0)
3670 // is it right to use defskip here, too? (AS)
3671 y_top += parameters->getDefSkip().inPixels();
3674 if (row_ptr->par->line_top) { /* draw a top line */
3675 y_top += GetFont(row_ptr->par, 0).ascent('x');
3677 scr.drawThickLine(offset + y_top,
3679 y_top += GetFont(row_ptr->par, 0).ascent('x');
3682 /* should we print a label? */
3683 if (layout.labeltype >= LABEL_STATIC
3684 && (layout.labeltype != LABEL_STATIC
3685 || layout.latextype != LATEX_ENVIRONMENT
3686 || row_ptr->par->IsFirstInSequence())) {
3687 font = GetFont(row_ptr->par, -2);
3688 if (!row_ptr->par->GetLabestring().empty()) {
3690 string tmpstring = row_ptr->par->GetLabestring();
3692 if (layout.labeltype == LABEL_COUNTER_CHAPTER) {
3693 if (parameters->secnumdepth >=0){
3694 /* this is special code for the chapter layout. This is printed in
3695 * an extra row and has a pagebreak at the top. */
3696 maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue())
3697 + int(layout.parsep) * DefaultHeight();
3698 scr.drawString(font, tmpstring,
3699 offset + row_ptr->baseline
3700 - row_ptr->ascent_of_text - maxdesc,
3704 x -= font.stringWidth( layout.labelsep);
3705 x -= font.stringWidth( tmpstring);
3707 scr.drawString(font, tmpstring,
3708 offset + row_ptr->baseline, int(x));
3712 /* the labels at the top of an environment. More or less for bibliography */
3713 } else if (layout.labeltype == LABEL_TOP_ENVIRONMENT ||
3714 layout.labeltype == LABEL_BIBLIO ||
3715 layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) {
3716 if (row_ptr->par->IsFirstInSequence()) {
3717 font = GetFont(row_ptr->par, -2);
3718 if (!row_ptr->par->GetLabestring().empty()) {
3719 string tmpstring = row_ptr->par->GetLabestring();
3721 maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue()
3722 + (layout.labelbottomsep * DefaultHeight()));
3724 int top_label_x = int(x);
3725 if (layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT){
3726 top_label_x = int(x + (paperwidth - RightMargin(row_ptr) - x) / 2);
3727 top_label_x -= (font.stringWidth( tmpstring)/2);
3730 scr.drawString(font, tmpstring,
3731 offset + row_ptr->baseline
3732 - row_ptr->ascent_of_text - maxdesc,
3737 if (layout.labeltype==LABEL_BIBLIO) { // ale970302
3738 if (row_ptr->par->bibkey) {
3740 x -= font.stringWidth(layout.labelsep);
3741 font = GetFont(row_ptr->par, -1);
3742 x -= row_ptr->par->bibkey->Width(font);
3743 row_ptr->par->bibkey->Draw(font, scr,
3744 offset + row_ptr->baseline,
3751 /* is it a last row? */
3752 par = row_ptr->par->LastPhysicalPar();
3753 if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
3754 && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {
3756 /* think about the margins */
3758 y_bottom -= LYX_PAPER_MARGIN;
3760 /* draw a bottom pagebreak */
3761 if (firstpar->pagebreak_bottom) {
3762 scr.drawOnOffLine(offset + y_bottom - 2 *
3765 y_bottom -= 3 * DefaultHeight();
3768 if (firstpar->added_space_bottom.kind() == VSpace::VFILL) {
3769 /* draw a vfill bottom */
3770 scr.drawLine(gc_fill,
3771 offset + y_bottom - 3 * DefaultHeight(),
3772 0, LYX_PAPER_MARGIN);
3773 scr.drawLine(gc_fill, offset + y_bottom - 2,
3774 0, LYX_PAPER_MARGIN);
3775 scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2,
3776 offset + y_bottom - 3 * DefaultHeight(),
3777 offset + y_bottom - 2
3779 y_bottom -= 3* DefaultHeight();
3782 /* think about user added space */
3783 y_bottom -= int(firstpar->added_space_bottom.inPixels());
3785 if (firstpar->line_bottom) {
3786 /* draw a bottom line */
3787 y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
3789 scr.drawThickLine(offset + y_bottom,
3791 y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
3795 /* draw the text in the pixmap */
3796 pos_end = RowLast(row_ptr);
3799 /* table stuff -- begin*/
3800 if (row_ptr->par->table) {
3802 int cell = NumberOfCell(row_ptr->par, row_ptr->pos);
3804 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
3806 while (pos <= pos_end) {
3807 if (row_ptr->par->IsNewline(pos)) {
3809 x = x_old + row_ptr->par->table->WidthOfColumn(cell);
3810 /* draw the table lines, still very simple */
3811 on_off = !row_ptr->par->table->TopLine(cell);
3813 !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
3814 !row_ptr->par->table->IsContRow(cell))
3815 scr.drawTableLine(offset + row_ptr->baseline -
3816 row_ptr->ascent_of_text,
3817 int(x_old), int(x - x_old), on_off);
3818 on_off = !row_ptr->par->table->BottomLine(cell);
3819 if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
3820 row_ptr->par->table->VeryLastRow(cell))
3821 scr.drawTableLine(offset + y_bottom - 1,
3822 int(x_old), int(x - x_old), on_off);
3823 on_off = !row_ptr->par->table->LeftLine(cell);
3825 scr.drawVerticalTableLine(int(x_old),
3826 offset + row_ptr->baseline -
3827 row_ptr->ascent_of_text,
3828 offset + y_bottom - 1,
3830 on_off = !row_ptr->par->table->RightLine(cell);
3832 scr.drawVerticalTableLine(int(x) -
3833 row_ptr->par->table->AdditionalWidth(cell),
3834 offset + row_ptr->baseline -
3835 row_ptr->ascent_of_text,
3836 offset + y_bottom - 1,
3839 /* take care about the alignment and other spaces */
3841 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
3842 if (row_ptr->par->table->IsFirstCell(cell))
3843 cell--; // little hack, sorry
3845 } else if (row_ptr->par->IsHfill(pos)) {
3848 scr.drawVerticalLine(gc_fill, int(x),
3849 offset + row_ptr->baseline - DefaultHeight()/2,
3850 offset + row_ptr->baseline);
3854 if (row_ptr->par->IsSeparator(pos)) {
3856 x+=SingleWidth(row_ptr->par, pos);
3857 /* -------> Only draw protected spaces when not in
3858 * free-spacing mode. */
3859 if (row_ptr->par->GetChar(pos)==LYX_META_PROTECTED_SEPARATOR && !layout.free_spacing) {
3860 scr.drawVerticalLine(gc_fill, int(tmpx),
3861 offset + row_ptr->baseline - 3,
3862 offset + row_ptr->baseline - 1);
3863 scr.drawLine(gc_fill,
3864 offset + row_ptr->baseline - 1,
3867 scr.drawVerticalLine(gc_fill, int(x-2),
3868 offset + row_ptr->baseline - 3,
3869 offset + row_ptr->baseline - 1);
3870 /* what about underbars? */
3871 font = GetFont(row_ptr->par, pos);
3872 if (font.underbar() == LyXFont::ON
3873 && font.latex() != LyXFont::ON) {
3874 scr.drawLine(gc_copy,
3876 row_ptr->baseline + 2,
3883 Draw(row_ptr, pos, scr, offset, x);
3887 /* do not forget the very last cell. This has no NEWLINE so
3888 * ignored by the code above*/
3889 if (cell == row_ptr->par->table->GetNumberOfCells()-1){
3890 x = x_old + row_ptr->par->table->WidthOfColumn(cell);
3891 on_off = !row_ptr->par->table->TopLine(cell);
3893 !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
3894 !row_ptr->par->table->IsContRow(cell))
3896 scr.drawTableLine(offset + row_ptr->baseline -
3897 row_ptr->ascent_of_text,
3898 int(x_old), int(x - x_old), on_off);
3899 on_off = !row_ptr->par->table->BottomLine(cell);
3900 if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
3901 row_ptr->par->table->VeryLastRow(cell))
3903 scr.drawTableLine(offset + y_bottom - 1,
3904 int(x_old), int(x - x_old), on_off);
3905 on_off = !row_ptr->par->table->LeftLine(cell);
3907 scr.drawVerticalTableLine(int(x_old),
3908 offset + row_ptr->baseline -
3909 row_ptr->ascent_of_text,
3910 offset + y_bottom - 1,
3912 on_off = !row_ptr->par->table->RightLine(cell);
3914 scr.drawVerticalTableLine(int(x) -
3915 row_ptr->par->table->AdditionalWidth(cell),
3916 offset + row_ptr->baseline -
3917 row_ptr->ascent_of_text,
3918 offset + y_bottom - 1,
3922 /* table stuff -- end*/
3924 while (pos <= pos_end) {
3926 if (row_ptr->par->IsHfill(pos)) {
3928 scr.drawVerticalLine(gc_fill, int(x),
3929 offset + row_ptr->baseline - DefaultHeight()/2,
3930 offset + row_ptr->baseline);
3931 if (HfillExpansion(row_ptr,pos)) {
3932 if (pos >= main_body) {
3933 scr.drawOnOffLine(offset + row_ptr->baseline -
3939 scr.drawOnOffLine(offset + row_ptr->baseline -
3942 int(fill_label_hfill));
3943 x += fill_label_hfill;
3945 scr.drawVerticalLine(gc_fill, int(x),
3946 offset + row_ptr->baseline -
3948 offset + row_ptr->baseline);
3953 if (row_ptr->par->IsSeparator(pos)) {
3955 x+=SingleWidth(row_ptr->par, pos);
3956 if (pos >= main_body)
3958 /* -------> Only draw protected spaces when not in
3959 * free-spacing mode. */
3960 if (row_ptr->par->GetChar(pos)==LYX_META_PROTECTED_SEPARATOR && !layout.free_spacing) {
3962 scr.drawVerticalLine(gc_fill, int(tmpx),
3963 offset + row_ptr->baseline - 3,
3964 offset + row_ptr->baseline - 1);
3965 scr.drawLine(gc_fill,
3966 offset + row_ptr->baseline - 1,
3969 scr.drawVerticalLine(gc_fill, int(x-2),
3970 offset + row_ptr->baseline - 3,
3971 offset + row_ptr->baseline - 1);
3972 /* what about underbars? */
3973 font = GetFont(row_ptr->par, pos);
3974 if (font.underbar() == LyXFont::ON
3975 && font.latex() != LyXFont::ON) {
3976 scr.drawLine(gc_copy,
3977 offset + row_ptr->baseline + 2,
3984 Draw(row_ptr, pos, scr, offset, x);
3986 if (pos == main_body) {
3987 x += GetFont(row_ptr->par, -2).stringWidth(
3989 if (row_ptr->par->IsLineSeparator(pos - 1))
3990 x-= SingleWidth(row_ptr->par, pos - 1);
3991 if (x < left_margin)
3996 // check for FAST SELECTION
3997 if (fast_selection || mono_video){
4000 /* selection code */
4001 if (sel_start_cursor.row == row_ptr && sel_end_cursor.row == row_ptr) {
4002 scr.fillRectangle(gc_select,sel_start_cursor.x, offset,
4003 sel_end_cursor.x - sel_start_cursor.x,
4005 } else if (sel_start_cursor.row == row_ptr) {
4006 scr.fillRectangle(gc_select, sel_start_cursor.x, offset,
4007 paperwidth - sel_start_cursor.x,
4009 } else if (sel_end_cursor.row == row_ptr) {
4010 scr.fillRectangle(gc_select, 0, offset,
4013 } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
4014 scr.fillRectangle(gc_select, 0, offset,
4015 paperwidth, row_ptr->height);
4020 // end of FAST SELECTION code
4025 int LyXText::DefaultHeight()
4027 LyXFont font(LyXFont::ALL_SANE);
4028 return int(font.maxAscent() + font.maxDescent() * 1.5);
4032 /* returns the column near the specified x-coordinate of the row
4033 * x is set to the real beginning of this column */
4034 int LyXText::GetColumnNearX(Row * row, int& x)
4037 float fill_separator, fill_hfill, fill_label_hfill;
4039 int left_margin = LabelEnd(row);
4040 PrepareToPrint(row, tmpx, fill_separator,
4041 fill_hfill, fill_label_hfill);
4042 int main_body = BeginningOfMainBody(row->par);
4046 int last = RowLast(row);
4047 if (row->par->IsNewline(last))
4050 LyXLayout const & layout = textclasslist.Style(parameters->textclass,
4051 row->par->GetLayout());
4052 /* table stuff -- begin */
4053 if (row->par->table) {
4054 if (!row->next || row->next->par != row->par)
4055 last = RowLast(row); /* the last row doesn't need a newline at the end*/
4056 int cell = NumberOfCell(row->par, row->pos);
4059 tmpx += row->par->table->GetBeginningOfTextInCell(cell);
4061 && tmpx + (SingleWidth(row->par, c)/2) <= x
4063 if (row->par->IsNewline(c)) {
4064 if (x_old + row->par->table->WidthOfColumn(cell) <= x){
4065 tmpx = x_old + row->par->table->WidthOfColumn(cell);
4068 tmpx += row->par->table->GetBeginningOfTextInCell(cell);
4073 tmpx += SingleWidth(row->par, c);
4078 /* table stuff -- end*/
4081 && tmpx + (SingleWidth(row->par, c)/2) <= x) {
4083 if (c && c == main_body
4084 && !row->par->IsLineSeparator(c - 1)) {
4085 tmpx += GetFont(row->par, -2)
4086 .stringWidth(layout.labelsep);
4087 if (tmpx < left_margin)
4091 tmpx += SingleWidth(row->par, c);
4092 if (HfillExpansion(row, c)) {
4096 tmpx += fill_label_hfill;
4098 else if (c >= main_body
4099 && row->par->IsSeparator(c)) {
4100 tmpx+= fill_separator;
4104 && row->par->IsLineSeparator(c - 1)) {
4105 tmpx += GetFont(row->par, -2)
4106 .stringWidth(layout.labelsep);
4107 tmpx-= SingleWidth(row->par, c - 1);
4108 if (tmpx < left_margin)
4112 /* make sure that a last space in a row doesnt count */
4113 if (c > 0 && c >= last
4114 && row->par->IsLineSeparator(c - 1)
4115 && !(!row->next || row->next->par != row->par)) {
4116 tmpx -= SingleWidth(row->par, c - 1);
4117 tmpx -= fill_separator;
4126 /* turn the selection into a new environment. If there is no selection,
4127 * create an empty environment */
4128 void LyXText::InsertFootnoteEnvironment(LyXParagraph::footnote_kind kind)
4130 /* no footnoteenvironment in a footnoteenvironment */
4131 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
4132 WriteAlert(_("Impossible operation"),
4133 _("You can't insert a float in a float!"),
4137 /* no marginpars in minipages */
4138 if (kind == LyXParagraph::MARGIN
4139 && cursor.par->pextra_type == PEXTRA_MINIPAGE) {
4140 WriteAlert(_("Impossible operation"),
4141 _("You can't insert a marginpar in a minipage!"),
4146 /* this doesnt make sense, if there is no selection */
4147 bool dummy_selection = false;
4149 sel_start_cursor = cursor; /* dummy selection */
4150 sel_end_cursor = cursor;
4151 dummy_selection = true;
4154 LyXParagraph *tmppar;
4156 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
4157 WriteAlert(_("Impossible operation"), _("Cannot cut table."), _("Sorry."));
4161 /* a test to make sure there is not already a footnote
4162 * in the selection. */
4164 tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
4166 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos) &&
4167 tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
4168 tmppar = tmppar->next;
4170 if (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
4171 || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
4172 WriteAlert(_("Impossible operation"),
4173 _("Float would include float!"),
4178 /* ok we have a selection. This is always between sel_start_cursor
4179 * and sel_end cursor */
4181 SetUndo(Undo::FINISH,
4182 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
4183 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
4185 if (sel_end_cursor.pos > 0
4186 && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1))
4187 sel_end_cursor.pos--; /* please break before a space at
4189 if (sel_start_cursor.par == sel_end_cursor.par
4190 && sel_start_cursor.pos > sel_end_cursor.pos)
4191 sel_start_cursor.pos--;
4193 sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
4195 sel_end_cursor.par = sel_end_cursor.par->Next();
4196 sel_end_cursor.pos = 0;
4198 // don't forget to insert a dummy layout paragraph if necessary
4199 if (sel_start_cursor.par->GetLayout() != sel_end_cursor.par->layout){
4200 sel_end_cursor.par->BreakParagraphConservative(0);
4201 sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
4202 sel_end_cursor.par = sel_end_cursor.par->next;
4205 sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
4207 cursor = sel_end_cursor;
4209 /* please break behind a space, if there is one. The space should
4211 if (sel_start_cursor.pos > 0
4212 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1))
4213 sel_start_cursor.pos--;
4214 if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)) {
4215 sel_start_cursor.par->Erase(sel_start_cursor.pos);
4218 sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
4219 tmppar = sel_start_cursor.par->Next();
4221 if (dummy_selection) {
4223 if (kind == LyXParagraph::TAB
4224 || kind == LyXParagraph::FIG
4225 || kind == LyXParagraph::WIDE_TAB
4226 || kind == LyXParagraph::WIDE_FIG
4227 || kind == LyXParagraph::ALGORITHM) {
4228 int lay = textclasslist.NumberOfLayout(parameters->textclass,
4230 if (lay == -1) // layout not found
4231 // use default layout "Standard" (0)
4233 tmppar->SetLayout(lay);
4237 if (sel_start_cursor.pos > 0) {
4238 /* the footnote-environment should begin with a standard layout.
4239 * Imagine you insert a footnote within an enumeration, you
4240 * certainly do not want an enumerated footnote! */
4244 /* this is a exception the user would sometimes expect, I hope */
4245 sel_start_cursor.par->Clear();
4249 while (tmppar != sel_end_cursor.par) {
4250 tmppar->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
4251 tmppar->footnotekind = kind;
4252 tmppar = tmppar->Next();
4255 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
4257 SetCursor(sel_start_cursor.par->Next(), 0);
4263 /* returns pointer to a specified row */
4265 Row * LyXText::GetRow(LyXParagraph * par, LyXParagraph::size_type pos, long &y)
4267 Row * LyXText::GetRow(LyXParagraph * par, int pos, long &y)
4273 if (par == currentrow->par || par == currentrow->par->Previous()){
4274 // do not dereference par, it may have been deleted
4275 // already! (Matthias)
4276 while (currentrow->previous && currentrow->previous->par != par){
4277 currentrow = currentrow->previous;
4278 currentrow_y -= currentrow->height;
4280 while (currentrow->previous && currentrow->previous->par == par){
4281 currentrow = currentrow->previous;
4282 currentrow_y -= currentrow->height;
4285 tmprow = currentrow;
4287 /* find the first row of the specified paragraph */
4288 while (tmprow->next && (tmprow->par != par)) {
4289 y += tmprow->height;
4290 tmprow = tmprow->next;
4293 if (tmprow->par == par){
4294 /* now find the wanted row */
4295 while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par &&
4296 tmprow->next->pos <= pos) {
4297 y += tmprow->height;
4298 tmprow = tmprow->next;
4300 currentrow = tmprow;
4307 /* find the first row of the specified paragraph */
4308 while (tmprow->next && (tmprow->par != par)) {
4309 y += tmprow->height;
4310 tmprow = tmprow->next;
4313 /* now find the wanted row */
4314 while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par &&
4315 tmprow->next->pos <= pos) {
4316 y += tmprow->height;
4317 tmprow = tmprow->next;
4320 currentrow = tmprow;