Hopefully a mostly mechanical patch. I couldn't reproduce any new problems with it.
This has some real ugliness in it because I am trying to make some steps towards constifying and refifying the core code. As I work further on propogating this outwards, stuff should become cleaner. Comments ?? Note this is a slightly older version, since cvs.lyx.org died YET again regards john Index: Makefile.am =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/Makefile.am,v retrieving revision 1.153 diff -u -r1.153 Makefile.am --- Makefile.am 10 Feb 2003 16:31:37 -0000 1.153 +++ Makefile.am 26 Feb 2003 01:36:53 -0000 @@ -189,6 +189,8 @@ ispell.h \ pspell.C \ pspell.h \ + rowpainter.C \ + rowpainter.h \ sgml.C \ sgml.h \ tabular.C \ Index: lyxrow.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/lyxrow.C,v retrieving revision 1.14 diff -u -r1.14 lyxrow.C --- lyxrow.C 17 Feb 2003 01:53:13 -0000 1.14 +++ lyxrow.C 26 Feb 2003 01:36:54 -0000 @@ -130,12 +130,24 @@ } +bool Row::isParStart() const +{ + return !pos(); +} + + +bool Row::isParEnd() const +{ + return !next() || next()->par() != par(); +} + + pos_type Row::lastPos() const { if (!par()->size()) return 0; - if (!next() || next()->par() != par()) { + if (isParEnd()) { return par()->size() - 1; } else { return next()->pos() - 1; @@ -162,7 +174,7 @@ pos_type const last = lastPos(); // if this row is an end of par, just act like lastPos() - if (!next() || par() != next()->par()) + if (isParEnd()) return last; bool const nextrownotinset = !nextRowIsAllInset(*this, last); @@ -256,7 +268,7 @@ // at the beginning of a row it does not count, if it is not // the first row of a paragaph - if (!this->pos()) + if (isParStart()) return true; // in some labels it does not count Index: lyxrow.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/lyxrow.h,v retrieving revision 1.21 diff -u -r1.21 lyxrow.h --- lyxrow.h 14 Feb 2003 00:41:38 -0000 1.21 +++ lyxrow.h 26 Feb 2003 01:36:54 -0000 @@ -67,6 +67,12 @@ /// Row * previous() const; + /// return true if this row is the start of a paragraph + bool isParStart() const; + + /// return true if this row is the end of a paragraph + bool isParEnd() const; + /// return the position of the last character in this row lyx::pos_type lastPos() const; /// return the position of the last normal, printable character in this row Index: lyxtext.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/lyxtext.h,v retrieving revision 1.133 diff -u -r1.133 lyxtext.h --- lyxtext.h 14 Feb 2003 00:41:38 -0000 1.133 +++ lyxtext.h 26 Feb 2003 01:36:55 -0000 @@ -101,6 +101,10 @@ void setCharFont(BufferView *, Paragraph * par, lyx::pos_type pos, LyXFont const & font, bool toggleall); + /// return true if the row changed + void markChangeInDraw(BufferView * bv, Row * row, Row * next); + /// + void breakAgainOneRow(BufferView *, Row * row); /// what you expect when pressing <enter> at cursor position void breakParagraph(BufferView *, char keep_layout = 0); @@ -369,13 +373,6 @@ /// void transposeChars(BufferView &); - /** returns a printed row in a pixmap. The y value is needed to - decide, wether it is selected text or not. This is a strange - solution but faster. - */ - void getVisibleRow(BufferView *, int y_offset, int x_offset, - Row * row_ptr, int y, bool cleared=false); - /// void toggleInset(BufferView *); /// @@ -527,81 +524,9 @@ /// void breakAgain(BufferView *, Row * row) const; - /// - void breakAgainOneRow(BufferView *, Row * row); /// Calculate and set the height of the row void setHeightOfRow(BufferView *, Row * row_ptr) const; - /** this calculates the specified parameters. needed when setting - * the cursor and when creating a visible row */ - void prepareToPrint(BufferView *, Row * row, float & x, - float & fill_separator, - float & fill_hfill, - float & fill_label_hfill, - bool bidi = true) const; - - /// A struct used for drawing routines - struct DrawRowParams { - // the bufferview - BufferView * bv; - // the row - Row * row; - // the painter to use - Painter * pain; - // has the background been cleared - bool cleared; - /// x offset (e.g. for insets) - int xo; - /// y offset (e.g. for insets) - int yo; - /// FIXME - float x; - /// FIXME - int y; - /// the inset/view full width - int width; - /// hfill size - float hfill; - /// label hfill size - float label_hfill; - /// fill separator size - float separator; - }; - - /// paint the background - bool paintRowBackground(DrawRowParams & p); - - /// paint the selection background - void paintRowSelection(DrawRowParams & p); - - /// paint change bar - void paintChangeBar(DrawRowParams & p); - - /// paint appendix marker - void paintRowAppendix(DrawRowParams & p); - - /// paint page break marker. Returns its height. - int paintPageBreak(string const & label, int y, DrawRowParams & p); - - /// paint env depth bar - void paintRowDepthBar(DrawRowParams & p); - - /// get the on-screen size of the length marker - int getLengthMarkerHeight(BufferView * bv, VSpace const & vsp) const; - - /// paint an added space marker - int drawLengthMarker(DrawRowParams & p, string const & str, - VSpace const & vsp, int start); - - /// paint a first row in a paragraph - void paintFirstRow(DrawRowParams & p); - - /// paint a last row in a paragraph - void paintLastRow(DrawRowParams & p); - - /// paint text - void paintRowText(DrawRowParams & p); - // fix the cursor `cur' after a characters has been deleted at `where' // position. Called by deleteEmptyParagraphMechanism void fixCursorAfterDelete(BufferView * bv, @@ -624,6 +549,40 @@ */ Inset * checkInsetHit(BufferView * bv, int & x, int & y) const; + /// + int singleWidth(BufferView *, Paragraph * par, + lyx::pos_type pos) const; + /// + int singleWidth(BufferView *, Paragraph * par, + lyx::pos_type pos, char c) const; + + /// return the color of the canvas + LColor::color backgroundColor() const; + + /// + mutable bool bidi_same_direction; + + unsigned char transformChar(unsigned char c, Paragraph * par, + lyx::pos_type pos) const; + + /** + * Returns the left beginning of the text. + * This information cannot be taken from the layout object, because + * in LaTeX the beginning of the text fits in some cases + * (for example sections) exactly the label-width. + */ + int leftMargin(BufferView *, Row const * row) const; + /// + int rightMargin(Buffer const &, Row const & row) const; + + /** this calculates the specified parameters. needed when setting + * the cursor and when creating a visible row */ + void prepareToPrint(BufferView *, Row * row, float & x, + float & fill_separator, + float & fill_hfill, + float & fill_label_hfill, + bool bidi = true) const; + private: /// void setCounter(Buffer const *, Paragraph * par) const; @@ -638,29 +597,6 @@ * some low level functions */ - /// - int singleWidth(BufferView *, Paragraph * par, - lyx::pos_type pos) const; - /// - int singleWidth(BufferView *, Paragraph * par, - lyx::pos_type pos, char c) const; - - - /// draw normal chars - void drawChars(DrawRowParams & p, lyx::pos_type & vpos, - bool hebrew, bool arabic); - /// draw from arabic composed char - void drawArabicComposeChar(DrawRowParams & p, lyx::pos_type & vpos); - /// draw from hebrew composed char - void drawHebrewComposeChar(DrawRowParams & p, lyx::pos_type & vpos); - /// draw a mark for foreign language, starting from orig_x - void drawForeignMark(DrawRowParams & p, float const orig_x, LyXFont const & orig_font); - /// draw an inset - bool drawInset(DrawRowParams & p, lyx::pos_type const pos); - /// draw new line marker - void drawNewline(DrawRowParams & p, lyx::pos_type const pos); - /// draw text - bool draw(DrawRowParams & p, lyx::pos_type & vpos); /// get the next breakpoint in a given paragraph lyx::pos_type nextBreakPoint(BufferView *, Row const * row, int width) const; @@ -671,23 +607,10 @@ screen in pixel */ int labelFill(BufferView *, Row const * row) const; - /** - * Returns the left beginning of the text. - * This information cannot be taken from the layout object, because - * in LaTeX the beginning of the text fits in some cases - * (for example sections) exactly the label-width. - */ - int leftMargin(BufferView *, Row const * row) const; - /// - int rightMargin(Buffer const *, Row const * row) const; /// int labelEnd (BufferView *, Row const * row) const; /// - LColor::color backgroundColor(); - - - /// mutable std::vector<lyx::pos_type> log2vis_list; /// @@ -703,13 +626,6 @@ mutable lyx::pos_type bidi_end; /// - mutable bool bidi_same_direction; - - /// - unsigned char transformChar(unsigned char c, Paragraph * par, - lyx::pos_type pos) const; - - /// void charInserted(); public: // @@ -723,6 +639,10 @@ /// return true if this is the outer-most lyxtext bool isTopLevel() const; + + /// return true if this is owned by an inset. FIXME: why the difference + /// with isTopLevel() ?? + bool isInInset() const; }; /// return the default height of a row in pixels, considering font zoom Index: paragraph.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/paragraph.h,v retrieving revision 1.56 diff -u -r1.56 paragraph.h --- paragraph.h 21 Feb 2003 09:20:14 -0000 1.56 +++ paragraph.h 26 Feb 2003 01:36:56 -0000 @@ -344,15 +344,15 @@ }; -inline bool isInsertedText(Paragraph const * par, lyx::pos_type pos) +inline bool isInsertedText(Paragraph const & par, lyx::pos_type pos) { - return par->lookupChange(pos) == Change::INSERTED; + return par.lookupChange(pos) == Change::INSERTED; } -inline bool isDeletedText(Paragraph const * par, lyx::pos_type pos) +inline bool isDeletedText(Paragraph const & par, lyx::pos_type pos) { - return par->lookupChange(pos) == Change::DELETED; + return par.lookupChange(pos) == Change::DELETED; } #endif // PARAGRAPH_H Index: rowpainter.C =================================================================== RCS file: rowpainter.C diff -N rowpainter.C --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ rowpainter.C 26 Feb 2003 01:36:56 -0000 @@ -0,0 +1,1087 @@ +/** + * \file rowpainter.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author various + * \author John Levon + * + * Full author contact details are available in file CREDITS + */ + +#include <config.h> + +#include <algorithm> + +#include "frontends/Painter.h" +#include "frontends/screen.h" +#include "frontends/font_metrics.h" +#include "support/LAssert.h" +#include "paragraph.h" +#include "support/textutils.h" + +#include "insets/insettext.h" +#include "ParagraphParameters.h" +#include "BufferView.h" +#include "buffer.h" +#include "gettext.h" +#include "language.h" +#include "encoding.h" +#include "lyxtext.h" +#include "lyxrow.h" +#include "rowpainter.h" +#include "lyxrc.h" + + +using std::max; +using lyx::pos_type; + +extern int const PAPER_MARGIN; +extern int const CHANGEBAR_MARGIN; +extern int const LEFT_MARGIN; + +namespace { + +// "temporary". We'll never get to use more +// references until we start adding hacks like +// these until other places catch up. +BufferView * perv(BufferView const & bv) +{ + return const_cast<BufferView *>(&bv); +} + +} // namespace anon + + +RowPainter::RowPainter(BufferView const & bv, LyXText const & text, Row const & row) + : bv_(bv), pain_(bv_.painter()), text_(text), row_(row), par_(*row.par()) +{ +} + + +/// "temporary" +LyXFont const RowPainter::getFont(pos_type pos) const +{ + Paragraph * perverted_par = const_cast<Paragraph *>(&par_); + return text_.getFont(bv_.buffer(), perverted_par, pos); +} + + +int RowPainter::singleWidth(lyx::pos_type pos) const +{ + BufferView * bv(perv(bv_)); + Paragraph * par(const_cast<Paragraph*>(&par_)); + return text_.singleWidth(bv, par, pos); +} + + +int RowPainter::singleWidth(lyx::pos_type pos, char c) const +{ + BufferView * bv(perv(bv_)); + Paragraph * par(const_cast<Paragraph*>(&par_)); + return text_.singleWidth(bv, par, pos, c); +} + + +LyXFont const RowPainter::getLabelFont() const +{ + Paragraph * par(const_cast<Paragraph*>(&par_)); + return text_.getLabelFont(bv_.buffer(), par); +} + + +char const RowPainter::transformChar(char c, lyx::pos_type pos) const +{ + Paragraph * par(const_cast<Paragraph*>(&par_)); + return text_.transformChar(c, par, pos); +} + + +int RowPainter::leftMargin() const +{ + BufferView * bv(perv(bv_)); + Row * row(const_cast<Row *>(&row_)); + return text_.leftMargin(bv, row); +} + + +void RowPainter::paintNewline(pos_type const pos) +{ + LyXFont const font = getFont(pos); + int const wid = font_metrics::width('n', font); + int const asc = font_metrics::maxAscent(font); + int const y = yo_ + row_.baseline(); + // FIXME: rtl_pos, or ltr_pos ? + bool const rtl_pos = (text_.bidi_level(pos) % 2 == 0); + int xp[3]; + int yp[3]; + + yp[0] = int(y - 0.875 * asc * 0.75); + yp[1] = int(y - 0.500 * asc * 0.75); + yp[2] = int(y - 0.125 * asc * 0.75); + + if (rtl_pos) { + xp[0] = int(x_ + wid * 0.375); + xp[1] = int(x_); + xp[2] = int(x_ + wid * 0.375); + } else { + xp[0] = int(x_ + wid * 0.625); + xp[1] = int(x_ + wid); + xp[2] = int(x_ + wid * 0.625); + } + + pain_.lines(xp, yp, 3, LColor::eolmarker); + + yp[0] = int(y - 0.500 * asc * 0.75); + yp[1] = int(y - 0.500 * asc * 0.75); + yp[2] = int(y - asc * 0.75); + + if (rtl_pos) { + xp[0] = int(x_); + xp[1] = int(x_ + wid); + xp[2] = int(x_ + wid); + } else { + xp[0] = int(x_ + wid); + xp[1] = int(x_); + xp[2] = int(x_); + } + + pain_.lines(xp, yp, 3, LColor::eolmarker); + + x_ += wid; +} + + +bool RowPainter::paintInset(pos_type const pos) +{ + Inset * inset = const_cast<Inset*>(par_.getInset(pos)); + + lyx::Assert(inset); + + LyXFont const & font = getFont(pos); + + inset->update(perv(bv_), font, false); + inset->draw(perv(bv_), font, yo_ + row_.baseline(), x_, cleared_); + + // return true if something changed when we drew an inset + + return (!text_.need_break_row && !text_.isInInset() + && bv_.text->status() == LyXText::CHANGED_IN_DRAW); +} + + +void RowPainter::paintHebrewComposeChar(pos_type & vpos) +{ + pos_type pos = text_.vis2log(vpos); + + string str; + + // first char + char c = par_.getChar(pos); + str += c; + ++vpos; + + LyXFont const & font = getFont(pos); + int const width = font_metrics::width(c, font); + int dx = 0; + + for (pos_type i = pos - 1; i >= 0; --i) { + c = par_.getChar(i); + if (!Encodings::IsComposeChar_hebrew(c)) { + if (IsPrintableNonspace(c)) { + int const width2 = + singleWidth(i, c); + // dalet / resh + dx = (c == 'ø' || c == 'ã') + ? width2 - width + : (width2 - width) / 2; + } + break; + } + } + + // Draw nikud + pain_.text(int(x_) + dx, yo_ + row_.baseline(), str, font); +} + + +void RowPainter::paintArabicComposeChar(pos_type & vpos) +{ + pos_type pos = text_.vis2log(vpos); + string str; + + // first char + char c = par_.getChar(pos); + c = transformChar(c, pos); + str +=c; + ++vpos; + + LyXFont const & font = getFont(pos); + int const width = font_metrics::width(c, font); + int dx = 0; + + for (pos_type i = pos-1; i >= 0; --i) { + c = par_.getChar(i); + if (!Encodings::IsComposeChar_arabic(c)) { + if (IsPrintableNonspace(c)) { + int const width2 = + singleWidth(i, c); + dx = (width2 - width) / 2; + } + break; + } + } + // Draw nikud + pain_.text(int(x_) + dx, yo_ + row_.baseline(), str, font); +} + + +void RowPainter::paintChars(pos_type & vpos, bool hebrew, bool arabic) +{ + pos_type pos = text_.vis2log(vpos); + pos_type const last = row_.lastPrintablePos(); + LyXFont orig_font(getFont(pos)); + + // first character + string str; + str += par_.getChar(pos); + if (arabic) { + unsigned char c = str[0]; + str[0] = transformChar(c, pos); + } + + bool prev_struckout(isDeletedText(par_, pos)); + bool prev_newtext(isInsertedText(par_, pos)); + + ++vpos; + + // collect as much similar chars as we can + while (vpos <= last && (pos = text_.vis2log(vpos)) >= 0) { + char c = par_.getChar(pos); + + if (!IsPrintableNonspace(c)) + break; + + if (prev_struckout != isDeletedText(par_, pos)) + break; + + if (prev_newtext != isInsertedText(par_, pos)) + break; + + if (arabic && Encodings::IsComposeChar_arabic(c)) + break; + if (hebrew && Encodings::IsComposeChar_hebrew(c)) + break; + + if (orig_font != getFont(pos)) + break; + + if (arabic) + c = transformChar(c, pos); + str += c; + ++vpos; + } + + if (prev_struckout) { + orig_font.setColor(LColor::strikeout); + } else if (prev_newtext) { + orig_font.setColor(LColor::newtext); + } + + // Draw text and set the new x position + pain_.text(int(x_), yo_ + row_.baseline(), str, orig_font); + x_ += font_metrics::width(str, orig_font); +} + + +void RowPainter::paintForeignMark(float const orig_x, LyXFont const & orig_font) +{ + if (!lyxrc.mark_foreign_language) + return; + if (orig_font.language() == latex_language) + return; + if (orig_font.language() == bv_.buffer()->params.language) + return; + + int const y = yo_ + row_.baseline() + 1; + pain_.line(int(orig_x), y, int(x_), y, LColor::language); +} + + +bool RowPainter::paintFromPos(pos_type & vpos) +{ + pos_type const pos = text_.vis2log(vpos); + + LyXFont const & orig_font = getFont(pos); + + float const orig_x = x_; + + char const c = par_.getChar(pos); + + if (IsNewlineChar(c)) { + ++vpos; + paintNewline(pos); + return true; + } else if (IsInsetChar(c)) { + if (paintInset(pos)) + return true; + ++vpos; + paintForeignMark(orig_x, orig_font); + return false; + } + + // usual characters, no insets + + // special case languages + bool const hebrew = (orig_font.language()->lang() == "hebrew"); + bool const arabic = + orig_font.language()->lang() == "arabic" && + (lyxrc.font_norm_type == LyXRC::ISO_8859_6_8 || + lyxrc.font_norm_type == LyXRC::ISO_10646_1); + + // draw as many chars as we can + if ((!hebrew && !arabic) + || (hebrew && !Encodings::IsComposeChar_hebrew(c)) + || (arabic && !Encodings::IsComposeChar_arabic(c))) { + paintChars(vpos, hebrew, arabic); + } else if (hebrew) { + paintHebrewComposeChar(vpos); + } else if (arabic) { + paintArabicComposeChar(vpos); + } + + paintForeignMark(orig_x, orig_font); + + return false; +} + + +bool RowPainter::paintBackground() +{ + pos_type const last = row_.lastPrintablePos(); + bool clear_area = true; + Inset const * inset = 0; + + if (!bv_.screen().forceClear() && last == row_.pos() + && par_.isInset(row_.pos())) { + inset = par_.getInset(row_.pos()); + clear_area = inset->doClearArea(); + } + + if (cleared_) { + return true; + } + + if (clear_area) { + int const x = xo_; + int const y = yo_ < 0 ? 0 : yo_; + int const h = yo_ < 0 ? row_.height() + yo_ : row_.height(); + pain_.fillRectangle(x, y, width_, h, text_.backgroundColor()); + return true; + } + + if (!inset) + return false; + + LyXFont font(LyXFont::ALL_SANE); + + // FIXME + BufferView * bv = perv(bv_); + + int h = row_.baseline() - inset->ascent(bv, font); + + // first clear the whole row above the inset! + if (h > 0) { + pain_.fillRectangle(xo_, yo_, width_, h, text_.backgroundColor()); + } + + // clear the space below the inset! + h += inset->ascent(bv, font) + inset->descent(bv, font); + if ((row_.height() - h) > 0) { + pain_.fillRectangle(xo_, yo_ + h, + width_, row_.height() - h, text_.backgroundColor()); + } + + // clear the space behind the inset, if needed + if (!inset->display() && !inset->needFullRow()) { + int const xp = int(x_) + inset->width(bv, font); + if (width_ - xp > 0) { + pain_.fillRectangle(xp, yo_, width_ - xp, + row_.height(), text_.backgroundColor()); + } + } + + return false; +} + + +void RowPainter::paintSelection() +{ + bool const is_rtl = par_.isRightToLeftPar(bv_.buffer()->params); + + // the current selection + int const startx = text_.selection.start.x(); + int const endx = text_.selection.end.x(); + int const starty = text_.selection.start.y(); + int const endy = text_.selection.end.y(); + Row const * startrow = text_.selection.start.row(); + Row const * endrow = text_.selection.end.row(); + + // Bleh. + Row const * row = &row_; + + if (text_.bidi_same_direction) { + int x; + int y = yo_; + int w; + int h = row_.height(); + + if (startrow == row && endrow == row) { + if (startx < endx) { + x = xo_ + startx; + w = endx - startx; + pain_.fillRectangle(x, y, w, h, LColor::selection); + } else { + x = xo_ + endx; + w = startx - endx; + pain_.fillRectangle(x, y, w, h, LColor::selection); + } + } else if (startrow == row) { + int const x = (is_rtl) ? xo_ : (xo_ + startx); + int const w = (is_rtl) ? startx : (width_ - startx); + pain_.fillRectangle(x, y, w, h, LColor::selection); + } else if (endrow == row) { + int const x = (is_rtl) ? (xo_ + endx) : xo_; + int const w = (is_rtl) ? (width_ - endx) : endx; + pain_.fillRectangle(x, y, w, h, LColor::selection); + } else if (y_ > starty && y_ < endy) { + pain_.fillRectangle(xo_, y, width_, h, LColor::selection); + } + return; + } else if (startrow != row && endrow != row) { + if (y_ > starty && y_ < endy) { + int w = width_; + int h = row_.height(); + pain_.fillRectangle(xo_, yo_, w, h, LColor::selection); + } + return; + } + + if ((startrow != row && !is_rtl) || (endrow != row && is_rtl)) + pain_.fillRectangle(xo_, yo_, int(x_), row_.height(), LColor::selection); + + pos_type const main_body = par_.beginningOfMainBody(); + pos_type const last = row_.lastPrintablePos(); + float tmpx = x_; + + for (pos_type vpos = row_.pos(); vpos <= last; ++vpos) { + pos_type pos = text_.vis2log(vpos); + float const old_tmpx = tmpx; + if (main_body > 0 && pos == main_body - 1) { + LyXLayout_ptr const & layout = par_.layout(); + LyXFont const lfont = getLabelFont(); + + tmpx += label_hfill_ + font_metrics::width(layout->labelsep, lfont); + + if (par_.isLineSeparator(main_body - 1)) + tmpx -= singleWidth(main_body - 1); + } + + if (row_.hfillExpansion(pos)) { + tmpx += singleWidth(pos); + if (pos >= main_body) + tmpx += hfill_; + else + tmpx += label_hfill_; + } + + else if (par_.isSeparator(pos)) { + tmpx += singleWidth(pos); + if (pos >= main_body) + tmpx += separator_; + } else { + tmpx += singleWidth(pos); + } + + if ((startrow != row || text_.selection.start.pos() <= pos) && + (endrow != row || pos < text_.selection.end.pos())) { + // Here we do not use x_ as xo_ was added to x_. + pain_.fillRectangle(int(old_tmpx), yo_, + int(tmpx - old_tmpx + 1), + row_.height(), LColor::selection); + } + } + + if ((startrow != row && is_rtl) || (endrow != row && !is_rtl)) { + pain_.fillRectangle(xo_ + int(tmpx), + yo_, int(bv_.workWidth() - tmpx), + row_.height(), LColor::selection); + } +} + + +void RowPainter::paintChangeBar() +{ + pos_type const start = row_.pos(); + pos_type const end = row_.lastPrintablePos(); + + if (!par_.isChanged(start, end)) + return; + + int const height = (row_.next() + ? row_.height() + row_.next()->top_of_text() + : row_.baseline()); + + pain_.fillRectangle(4, yo_, 5, height, LColor::changebar); +} + + +void RowPainter::paintAppendix() +{ + // FIXME: can be just width_ ? + int const ww = bv_.workWidth(); + + if (par_.params().appendix()) { + pain_.line(1, yo_, 1, yo_ + row_.height(), LColor::appendixline); + pain_.line(ww - 2, yo_, ww - 2, yo_ + row_.height(), LColor::appendixline); + } +} + + +void RowPainter::paintDepthBar() +{ + Paragraph::depth_type const depth = par_.getDepth(); + + if (depth <= 0) + return; + + Paragraph::depth_type prev_depth = 0; + if (row_.previous()) + prev_depth = row_.previous()->par()->getDepth(); + Paragraph::depth_type next_depth = 0; + if (row_.next()) + next_depth = row_.next()->par()->getDepth(); + + for (Paragraph::depth_type i = 1; i <= depth; ++i) { + int x = (PAPER_MARGIN / 5) * i + xo_; + // only consider the changebar space if we're drawing outer left + if (!xo_) + x += CHANGEBAR_MARGIN; + int const h = yo_ + row_.height() - 1 - (i - next_depth - 1) * 3; + + pain_.line(x, yo_, x, h, LColor::depthbar); + + int const w = PAPER_MARGIN / 5; + + if (i > prev_depth) { + pain_.fillRectangle(x, yo_, w, 2, LColor::depthbar); + } + if (i > next_depth) { + pain_.fillRectangle(x, h, w, 2, LColor::depthbar); + } + } +} + + +int getLengthMarkerHeight(BufferView const & bv, VSpace const & vsp) +{ + if (vsp.kind() == VSpace::NONE) + return 0; + + int const arrow_size = 4; + int const space_size = int(vsp.inPixels(bv)); + + LyXFont font; + font.decSize(); + int const min_size = max(3 * arrow_size, + font_metrics::maxAscent(font) + + font_metrics::maxDescent(font)); + + if (vsp.length().len().value() < 0.0) + return min_size; + else + return max(min_size, space_size); +} + + +int RowPainter::paintLengthMarker(string const & prefix, VSpace const & vsp, int start) +{ + if (vsp.kind() == VSpace::NONE) + return 0; + + int const arrow_size = 4; + int const size = getLengthMarkerHeight(bv_, vsp); + int const end = start + size; + + // the label to display (if any) + string str; + // y-values for top arrow + int ty1, ty2; + // y-values for bottom arrow + int by1, by2; + + str = prefix + " (" + vsp.asLyXCommand() + ")"; + + if (vsp.kind() == VSpace::VFILL) { + ty1 = ty2 = start; + by1 = by2 = end; + } else { + // adding or removing space + bool const added = vsp.kind() != VSpace::LENGTH || + vsp.length().len().value() > 0.0; + ty1 = added ? (start + arrow_size) : start; + ty2 = added ? start : (start + arrow_size); + by1 = added ? (end - arrow_size) : end; + by2 = added ? end : (end - arrow_size); + } + + int const leftx = xo_ + leftMargin(); + int const midx = leftx + arrow_size; + int const rightx = midx + arrow_size; + + // first the string + int w = 0; + int a = 0; + int d = 0; + + LyXFont font; + font.setColor(LColor::added_space).decSize().decSize(); + font_metrics::rectText(str, font, w, a, d); + + pain_.rectText(leftx + 2 * arrow_size + 5, + start + ((end - start) / 2) + d, + str, font); + + // top arrow + pain_.line(leftx, ty1, midx, ty2, LColor::added_space); + pain_.line(midx, ty2, rightx, ty1, LColor::added_space); + + // bottom arrow + pain_.line(leftx, by1, midx, by2, LColor::added_space); + pain_.line(midx, by2, rightx, by1, LColor::added_space); + + // joining line + pain_.line(midx, ty2, midx, by2, LColor::added_space); + + return size; +} + + +int RowPainter::paintPageBreak(string const & label, int y) +{ + LyXFont pb_font; + pb_font.setColor(LColor::pagebreak).decSize(); + + int w = 0; + int a = 0; + int d = 0; + font_metrics::rectText(label, pb_font, w, a, d); + + int const text_start = xo_ + ((width_ - w) / 2); + int const text_end = text_start + w; + + pain_.rectText(text_start, y + d, label, pb_font); + + pain_.line(xo_, y, text_start, y, + LColor::pagebreak, Painter::line_onoffdash); + pain_.line(text_end, y, xo_ + width_, y, + LColor::pagebreak, Painter::line_onoffdash); + + return 3 * defaultRowHeight(); +} + + +void RowPainter::paintFirst() +{ + ParagraphParameters const & parparams = par_.params(); + + // start of appendix? + if (parparams.startOfAppendix()) { + pain_.line(1, yo_, width_ - 2, yo_, LColor::appendixline); + } + + int y_top = 0; + + // the top margin + if (!row_.previous() && text_.isTopLevel()) + y_top += PAPER_MARGIN; + + // draw a top pagebreak + if (parparams.pagebreakTop()) { + y_top += paintPageBreak(_("Page Break (top)"), + yo_ + y_top + 2 * defaultRowHeight()); + } + + // draw the additional space if needed: + y_top += paintLengthMarker(_("Space above"), parparams.spaceTop(), + yo_ + y_top); + + Buffer const * buffer = bv_.buffer(); + + LyXLayout_ptr const & layout = par_.layout(); + + if (buffer->params.paragraph_separation == BufferParams::PARSEP_SKIP) { + if (par_.previous()) { + if (layout->latextype == LATEX_PARAGRAPH + && !par_.getDepth()) { + y_top += buffer->params.getDefSkip().inPixels(bv_); + } else { + LyXLayout_ptr const & playout = + par_.previous()->layout(); + if (playout->latextype == LATEX_PARAGRAPH + && !par_.previous()->getDepth()) { + // is it right to use defskip here, too? (AS) + y_top += buffer->params.getDefSkip().inPixels(bv_); + } + } + } + } + + int const ww = bv_.workWidth(); + + // draw a top line + if (parparams.lineTop()) { + LyXFont font(LyXFont::ALL_SANE); + int const asc = font_metrics::ascent('x', getFont(0)); + + y_top += asc; + + int const w = (text_.isInInset() ? text_.inset_owner->width(perv(bv_), font) : ww); + int const xp = static_cast<int>(text_.isInInset() ? xo_ : 0); + pain_.line(xp, yo_ + y_top, xp + w, yo_ + y_top, + LColor::topline, Painter::line_solid, + Painter::line_thick); + + y_top += asc; + } + + bool const is_rtl = par_.isRightToLeftPar(bv_.buffer()->params); + + // should we print a label? + if (layout->labeltype >= LABEL_STATIC + && (layout->labeltype != LABEL_STATIC + || layout->latextype != LATEX_ENVIRONMENT + || par_.isFirstInSequence())) { + + LyXFont font = getLabelFont(); + if (!par_.getLabelstring().empty()) { + float x = x_; + string const str = par_.getLabelstring(); + + // this is special code for the chapter layout. This is + // printed in an extra row and has a pagebreak at + // the top. + if (layout->labeltype == LABEL_COUNTER_CHAPTER) { + if (buffer->params.secnumdepth >= 0) { + float spacing_val = 1.0; + if (!parparams.spacing().isDefault()) { + spacing_val = parparams.spacing().getValue(); + } else { + spacing_val = buffer->params.spacing.getValue(); + } + + int const maxdesc = + int(font_metrics::maxDescent(font) * layout->spacing.getValue() * spacing_val) + + int(layout->parsep) * defaultRowHeight(); + + if (is_rtl) { + x = ww - leftMargin() - + font_metrics::width(str, font); + } + + pain_.text(int(x), + yo_ + row_.baseline() - + row_.ascent_of_text() - maxdesc, + str, font); + } + } else { + if (is_rtl) { + x = ww - leftMargin() + + font_metrics::width(layout->labelsep, font); + } else { + x = x_ - font_metrics::width(layout->labelsep, font) + - font_metrics::width(str, font); + } + + pain_.text(int(x), yo_ + row_.baseline(), str, font); + } + } + + // the labels at the top of an environment. + // More or less for bibliography + } else if (par_.isFirstInSequence() && + (layout->labeltype == LABEL_TOP_ENVIRONMENT || + layout->labeltype == LABEL_BIBLIO || + layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)) { + LyXFont font = getLabelFont(); + if (!par_.getLabelstring().empty()) { + string const str = par_.getLabelstring(); + float spacing_val = 1.0; + if (!parparams.spacing().isDefault()) { + spacing_val = parparams.spacing().getValue(); + } else { + spacing_val = buffer->params.spacing.getValue(); + } + + int maxdesc = + int(font_metrics::maxDescent(font) * layout->spacing.getValue() * spacing_val + + (layout->labelbottomsep * defaultRowHeight())); + + float x = x_; + if (layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) { + x = ((is_rtl ? leftMargin() : x_) + + ww - text_.rightMargin(*bv_.buffer(), row_)) / 2; + x -= font_metrics::width(str, font) / 2; + } else if (is_rtl) { + x = ww - leftMargin() - + font_metrics::width(str, font); + } + pain_.text(int(x), yo_ + row_.baseline() + - row_.ascent_of_text() - maxdesc, + str, font); + } + } +} + + +void RowPainter::paintLast() +{ + ParagraphParameters const & parparams = par_.params(); + int y_bottom = row_.height() - 1; + + // the bottom margin + if (!row_.next() && text_.isTopLevel()) + y_bottom -= PAPER_MARGIN; + + int const ww = bv_.workWidth(); + + // draw a bottom pagebreak + if (parparams.pagebreakBottom()) { + y_bottom -= paintPageBreak(_("Page Break (bottom)"), + yo_ + y_bottom - 2 * defaultRowHeight()); + } + + // draw the additional space if needed: + int const height = getLengthMarkerHeight(bv_, parparams.spaceBottom()); + y_bottom -= paintLengthMarker(_("Space below"), parparams.spaceBottom(), + yo_ + y_bottom - height); + + // draw a bottom line + if (parparams.lineBottom()) { + LyXFont font(LyXFont::ALL_SANE); + int const asc = font_metrics::ascent('x', + getFont(max(pos_type(0), par_.size() - 1))); + + y_bottom -= asc; + + int const w = (text_.isInInset() ? text_.inset_owner->width(perv(bv_), font) : ww); + int const xp = static_cast<int>(text_.isInInset() ? xo_ : 0); + int const y = yo_ + y_bottom; + pain_.line(xp, y, xp + w, y, LColor::topline, Painter::line_solid, + Painter::line_thick); + + y_bottom -= asc; + } + + bool const is_rtl = par_.isRightToLeftPar(bv_.buffer()->params); + int const endlabel = par_.getEndLabel(); + + // draw an endlabel + switch (endlabel) { + case END_LABEL_BOX: + case END_LABEL_FILLED_BOX: + { + LyXFont const font = getLabelFont(); + int const size = int(0.75 * font_metrics::maxAscent(font)); + int const y = (yo_ + row_.baseline()) - size; + int x = is_rtl ? LEFT_MARGIN : ww - PAPER_MARGIN - size; + + if (row_.fill() <= size) + x += (size - row_.fill() + 1) * (is_rtl ? -1 : 1); + + if (endlabel == END_LABEL_BOX) { + pain_.rectangle(x, y, size, size, LColor::eolmarker); + } else { + pain_.fillRectangle(x, y, size, size, LColor::eolmarker); + } + break; + } + case END_LABEL_STATIC: + { +#if 0 + LyXFont font(LyXFont::ALL_SANE); + font = getLabelFont(); +#else + LyXFont font = getLabelFont(); +#endif + string const & str = par_.layout()->endlabelstring(); + int const x = is_rtl ? + int(x_) - font_metrics::width(str, font) + : ww - text_.rightMargin(*bv_.buffer(), row_) - row_.fill(); + pain_.text(x, yo_ + row_.baseline(), str, font); + break; + } + case END_LABEL_NO_LABEL: + break; + } +} + + +bool RowPainter::paintText() +{ + pos_type const last = row_.lastPrintablePos(); + pos_type main_body = par_.beginningOfMainBody(); + if (main_body > 0 && + (main_body - 1 > last || + !par_.isLineSeparator(main_body - 1))) { + main_body = 0; + } + + LyXLayout_ptr const & layout = par_.layout(); + + bool running_strikeout = false; + bool is_struckout = false; + float last_strikeout_x = 0.0; + + pos_type vpos = row_.pos(); + while (vpos <= last) { + if (x_ > bv_.workWidth()) + break; + pos_type pos = text_.vis2log(vpos); + + if (x_ + singleWidth(pos) < 0) { + x_ += singleWidth(pos); + ++vpos; + continue; + } + + is_struckout = isDeletedText(par_, pos); + + if (is_struckout && !running_strikeout) { + running_strikeout = true; + last_strikeout_x = x_; + } + + bool const highly_editable_inset = par_.isInset(pos) + && isHighlyEditableInset(par_.getInset(pos)); + + // if we reach the end of a struck out range, paint it + // we also don't paint across things like tables + if (running_strikeout && (highly_editable_inset || !is_struckout)) { + int const middle = yo_ + row_.top_of_text() + + ((row_.baseline() - row_.top_of_text()) / 2); + pain_.line(int(last_strikeout_x), middle, int(x_), middle, + LColor::strikeout, Painter::line_solid, Painter::line_thin); + running_strikeout = false; + } + + if (main_body > 0 && pos == main_body - 1) { + int const lwidth = font_metrics::width(layout->labelsep, + getLabelFont()); + + x_ += label_hfill_ + lwidth + - singleWidth(main_body - 1); + } + + if (par_.isHfill(pos)) { + x_ += 1; + + int const y0 = yo_ + row_.baseline(); + int const y1 = y0 - defaultRowHeight() / 2; + + pain_.line(int(x_), y1, int(x_), y0, + LColor::added_space); + + if (row_.hfillExpansion(pos)) { + int const y2 = (y0 + y1) / 2; + + if (pos >= main_body) { + pain_.line(int(x_), y2, + int(x_ + hfill_), y2, + LColor::added_space, + Painter::line_onoffdash); + x_ += hfill_; + } else { + pain_.line(int(x_), y2, + int(x_ + label_hfill_), y2, + LColor::added_space, + Painter::line_onoffdash); + x_ += label_hfill_; + } + pain_.line(int(x_), y1, + int(x_), y0, + LColor::added_space); + } + x_ += 2; + ++vpos; + } else if (par_.isSeparator(pos)) { + x_ += singleWidth(pos); + if (pos >= main_body) + x_ += separator_; + ++vpos; + } else { + if (!paintFromPos(vpos)) + return true; + } + } + + // if we reach the end of a struck out range, paint it + if (running_strikeout) { + int const middle = yo_ + row_.top_of_text() + + ((row_.baseline() - row_.top_of_text()) / 2); + pain_.line(int(last_strikeout_x), middle, int(x_), middle, + LColor::strikeout, Painter::line_solid, Painter::line_thin); + running_strikeout = false; + } + return false; +} + + +bool RowPainter::paint(int y_offset, int x_offset, int y, bool cleared) +{ + xo_ = x_offset; + yo_ = y_offset; + y_ = y; + cleared_ = cleared; + width_ = text_.inset_owner + ? text_.inset_owner->textWidth(perv(bv_), true) : bv_.workWidth(); + + // FIXME: must be a cleaner way here. Aren't these calculations + // belonging to row metrics ? + BufferView * bv(const_cast<BufferView *>(&bv_)); + Row * row(const_cast<Row *>(&row_)); + text_.prepareToPrint(bv, row, x_, separator_, hfill_, label_hfill_); + + // FIXME: what is this fixing ? + if (text_.inset_owner && (x_ < 0)) + x_ = 0; + x_ += xo_; + + // clear to background if necessary + cleared_ = paintBackground(); + + // paint the selection background + if (text_.selection.set()) { + paintSelection(); + } + + // vertical lines for appendix + paintAppendix(); + + // environment depth brackets + paintDepthBar(); + + // changebar + paintChangeBar(); + + if (row_.isParStart()) { + paintFirst(); + } + + if (row_.isParEnd()) { + paintLast(); + } + + // paint text + return paintText(); +} Index: rowpainter.h =================================================================== RCS file: rowpainter.h diff -N rowpainter.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ rowpainter.h 26 Feb 2003 01:36:56 -0000 @@ -0,0 +1,107 @@ +/** + * \file rowpainter.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author various + * \author John Levon + * + * Full author contact details are available in file CREDITS + */ + +#ifndef ROWPAINTER_H +#define ROWPAINTER_H + +#include <config.h> + +#include "LString.h" +#include "support/types.h" + +class LyXText; +class BufferView; +class Row; +class Paragraph; +class Painter; +class LyXFont; +class VSpace; + +/** + * A class used for painting an individual row of text. + */ +class RowPainter { +public: + /// initialise painter + RowPainter(BufferView const & bv, LyXText const & text, Row const & row); + + /// paint the row. Returns true if CHANGED_IN_DRAW (e.g. image was loaded) + bool paint(int y_offset, int x_offset, int y, bool cleared = false); + +private: + // paint various parts + bool paintBackground(); + void paintSelection(); + void paintAppendix(); + void paintDepthBar(); + void paintChangeBar(); + void paintFirst(); + void paintLast(); + void paintNewline(lyx::pos_type const pos); + void paintForeignMark(float const orig_x, LyXFont const & orig_font); + void paintHebrewComposeChar(lyx::pos_type & vpos); + void paintArabicComposeChar(lyx::pos_type & vpos); + void paintChars(lyx::pos_type & vpos, bool hebrew, bool arabic); + int paintPageBreak(string const & label, int y); + int paintLengthMarker(string const & prefix, VSpace const & vsp, int start); + /// returns true when CHANGED_IN_DRAW + bool paintText(); + /// returns true when CHANGED_IN_DRAW + bool paintFromPos(lyx::pos_type & vpos); + /// returns true when CHANGED_IN_DRAW + bool paintInset(lyx::pos_type const pos); + + /// return left margin + int leftMargin() const; + + /// return the font at the given pos + LyXFont const getFont(lyx::pos_type pos) const; + + /// return the label font for this row + LyXFont const getLabelFont() const; + + char const transformChar(char c, lyx::pos_type pos) const; + + /// return pixel width for the given pos + int singleWidth(lyx::pos_type pos) const; + int singleWidth(lyx::pos_type pos, char c) const; + + /// bufferview to paint on + BufferView const & bv_; + + /// Painter to use + Painter & pain_; + + /// LyXText for the row + LyXText const & text_; + + /// The row to paint + Row const & row_; + + /// Row's paragraph + Paragraph const & par_; + + // Looks ugly - is + int xo_; + int yo_; + float x_; + int y_; + bool cleared_; + int width_; + float separator_; + float hfill_; + float label_hfill_; +}; + +/// return the pixel height of a space marker before/after a par +int getLengthMarkerHeight(BufferView const & bv, VSpace const & vsp); + +#endif // ROWPAINTER_H Index: text.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/text.C,v retrieving revision 1.292 diff -u -r1.292 text.C --- text.C 21 Feb 2003 09:20:14 -0000 1.292 +++ text.C 26 Feb 2003 01:37:01 -0000 @@ -32,6 +32,7 @@ #include "undo_funcs.h" #include "WordLangTuple.h" #include "paragraph_funcs.h" +#include "rowpainter.h" #include "insets/insettext.h" @@ -47,8 +48,6 @@ using std::pair; using lyx::pos_type; -namespace { - /// top, right, bottom pixel margin int const PAPER_MARGIN = 20; /// margin for changebar @@ -56,8 +55,6 @@ /// left margin int const LEFT_MARGIN = PAPER_MARGIN + CHANGEBAR_MARGIN; -} // namespace anon - extern int bibitemMaxWidth(BufferView *, LyXFont const &); @@ -114,7 +111,7 @@ while (frow->previous() && frow->par() == frow->previous()->par()) frow = frow->previous(); unsigned int maxw = 0; - while (frow->next() && frow->par() == frow->next()->par()) { + while (!frow->isParEnd()) { if ((frow != row) && (maxw < frow->width())) maxw = frow->width(); frow = frow->next(); @@ -407,280 +404,6 @@ } -void LyXText::drawNewline(DrawRowParams & p, pos_type const pos) -{ - // Draw end-of-line marker - LyXFont const font = getFont(p.bv->buffer(), p.row->par(), pos); - int const wid = font_metrics::width('n', font); - int const asc = font_metrics::maxAscent(font); - int const y = p.yo + p.row->baseline(); - int xp[3]; - int yp[3]; - - yp[0] = int(y - 0.875 * asc * 0.75); - yp[1] = int(y - 0.500 * asc * 0.75); - yp[2] = int(y - 0.125 * asc * 0.75); - - if (bidi_level(pos) % 2 == 0) { - xp[0] = int(p.x + wid * 0.375); - xp[1] = int(p.x); - xp[2] = int(p.x + wid * 0.375); - } else { - xp[0] = int(p.x + wid * 0.625); - xp[1] = int(p.x + wid); - xp[2] = int(p.x + wid * 0.625); - } - - p.pain->lines(xp, yp, 3, LColor::eolmarker); - - yp[0] = int(y - 0.500 * asc * 0.75); - yp[1] = int(y - 0.500 * asc * 0.75); - yp[2] = int(y - asc * 0.75); - - if (bidi_level(pos) % 2 == 0) { - xp[0] = int(p.x); - xp[1] = int(p.x + wid); - xp[2] = int(p.x + wid); - } else { - xp[0] = int(p.x + wid); - xp[1] = int(p.x); - xp[2] = int(p.x); - } - - p.pain->lines(xp, yp, 3, LColor::eolmarker); - - p.x += wid; -} - - -bool LyXText::drawInset(DrawRowParams & p, pos_type const pos) -{ - Inset * inset = p.row->par()->getInset(pos); - - // FIXME: shouldn't happen - if (!inset) { - return true; - } - - LyXFont const & font = getFont(p.bv->buffer(), p.row->par(), pos); - // we need this here as the row pointer may be illegal - // at a later time (Jug20020502) - Row * prev = p.row->previous(); - - inset->update(p.bv, font, false); - inset->draw(p.bv, font, p.yo + p.row->baseline(), p.x, p.cleared); - - if (!need_break_row && !inset_owner - && p.bv->text->status() == CHANGED_IN_DRAW) { - if (prev && prev->par() == p.row->par()) { - breakAgainOneRow(p.bv, prev); - if (prev->next() != p.row) { - // breakAgainOneRow() has removed p.row - p.row = 0; // see what this breaks - need_break_row = prev; - } else { - need_break_row = p.row; - } - } else if (!prev) { - need_break_row = firstrow; - } else { - need_break_row = prev->next(); - } - setCursor(p.bv, cursor.par(), cursor.pos()); - return false; - } - return true; -} - - -void LyXText::drawForeignMark(DrawRowParams & p, float const orig_x, LyXFont const & orig_font) -{ - if (!lyxrc.mark_foreign_language) - return; - if (orig_font.language() == latex_language) - return; - if (orig_font.language() == p.bv->buffer()->params.language) - return; - - int const y = p.yo + p.row->baseline() + 1; - p.pain->line(int(orig_x), y, int(p.x), y, LColor::language); -} - - -void LyXText::drawHebrewComposeChar(DrawRowParams & p, pos_type & vpos) -{ - pos_type pos = vis2log(vpos); - - string str; - - // first char - char c = p.row->par()->getChar(pos); - str += c; - ++vpos; - - LyXFont const & font = getFont(p.bv->buffer(), p.row->par(), pos); - int const width = font_metrics::width(c, font); - int dx = 0; - - for (pos_type i = pos-1; i >= 0; --i) { - c = p.row->par()->getChar(i); - if (!Encodings::IsComposeChar_hebrew(c)) { - if (IsPrintableNonspace(c)) { - int const width2 = - singleWidth(p.bv, p.row->par(), i, c); - // dalet / resh - dx = (c == 'ø' || c == 'ã') - ? width2 - width - : (width2 - width) / 2; - } - break; - } - } - - // Draw nikud - p.pain->text(int(p.x) + dx, p.yo + p.row->baseline(), str, font); -} - - -void LyXText::drawArabicComposeChar(DrawRowParams & p, pos_type & vpos) -{ - pos_type pos = vis2log(vpos); - string str; - - // first char - char c = p.row->par()->getChar(pos); - c = transformChar(c, p.row->par(), pos); - str +=c; - ++vpos; - - LyXFont const & font = getFont(p.bv->buffer(), p.row->par(), pos); - int const width = font_metrics::width(c, font); - int dx = 0; - - for (pos_type i = pos-1; i >= 0; --i) { - c = p.row->par()->getChar(i); - if (!Encodings::IsComposeChar_arabic(c)) { - if (IsPrintableNonspace(c)) { - int const width2 = - singleWidth(p.bv, p.row->par(), i, c); - dx = (width2 - width) / 2; - } - break; - } - } - // Draw nikud - p.pain->text(int(p.x) + dx, p.yo + p.row->baseline(), str, font); -} - - -void LyXText::drawChars(DrawRowParams & p, pos_type & vpos, - bool hebrew, bool arabic) -{ - pos_type pos = vis2log(vpos); - pos_type const last = p.row->lastPrintablePos(); - LyXFont orig_font(getFont(p.bv->buffer(), p.row->par(), pos)); - - // first character - string str; - str += p.row->par()->getChar(pos); - if (arabic) { - unsigned char c = str[0]; - str[0] = transformChar(c, p.row->par(), pos); - } - - bool prev_struckout(isDeletedText(p.row->par(), pos)); - bool prev_newtext(isInsertedText(p.row->par(), pos)); - - ++vpos; - - // collect as much similar chars as we can - while (vpos <= last && (pos = vis2log(vpos)) >= 0) { - char c = p.row->par()->getChar(pos); - - if (!IsPrintableNonspace(c)) - break; - - if (prev_struckout != isDeletedText(p.row->par(), pos)) - break; - - if (prev_newtext != isInsertedText(p.row->par(), pos)) - break; - - if (arabic && Encodings::IsComposeChar_arabic(c)) - break; - if (hebrew && Encodings::IsComposeChar_hebrew(c)) - break; - - if (orig_font != getFont(p.bv->buffer(), p.row->par(), pos)) - break; - - if (arabic) - c = transformChar(c, p.row->par(), pos); - str += c; - ++vpos; - } - - if (prev_struckout) { - orig_font.setColor(LColor::strikeout); - } else if (prev_newtext) { - orig_font.setColor(LColor::newtext); - } - - // Draw text and set the new x position - p.pain->text(int(p.x), p.yo + p.row->baseline(), str, orig_font); - p.x += font_metrics::width(str, orig_font); -} - - -bool LyXText::draw(DrawRowParams & p, pos_type & vpos) -{ - pos_type const pos = vis2log(vpos); - Paragraph * par = p.row->par(); - - LyXFont const & orig_font = getFont(p.bv->buffer(), par, pos); - - float const orig_x = p.x; - - char const c = par->getChar(pos); - - if (IsNewlineChar(c)) { - ++vpos; - drawNewline(p, pos); - return true; - } else if (IsInsetChar(c)) { - if (!drawInset(p, pos)) - return false; - ++vpos; - drawForeignMark(p, orig_x, orig_font); - return true; - } - - // usual characters, no insets - - // special case languages - bool const hebrew = (orig_font.language()->lang() == "hebrew"); - bool const arabic = - orig_font.language()->lang() == "arabic" && - (lyxrc.font_norm_type == LyXRC::ISO_8859_6_8 || - lyxrc.font_norm_type == LyXRC::ISO_10646_1); - - // draw as many chars as we can - if ((!hebrew && !arabic) - || (hebrew && !Encodings::IsComposeChar_hebrew(c)) - || (arabic && !Encodings::IsComposeChar_arabic(c))) { - drawChars(p, vpos, hebrew, arabic); - } else if (hebrew) { - drawHebrewComposeChar(p, vpos); - } else if (arabic) { - drawArabicComposeChar(p, vpos); - } - - drawForeignMark(p, orig_x, orig_font); - - return true; -} - - int LyXText::leftMargin(BufferView * bview, Row const * row) const { Inset * ins; @@ -873,16 +596,16 @@ } -int LyXText::rightMargin(Buffer const * buf, Row const * row) const +int LyXText::rightMargin(Buffer const & buf, Row const & row) const { Inset * ins; - if ((row->par()->getChar(row->pos()) == Paragraph::META_INSET) && - (ins=row->par()->getInset(row->pos())) && + if ((row.par()->getChar(row.pos()) == Paragraph::META_INSET) && + (ins=row.par()->getInset(row.pos())) && (ins->needFullRow() || ins->display())) return PAPER_MARGIN; - LyXTextClass const & tclass = buf->params.getLyXTextClass(); - LyXLayout_ptr const & layout = row->par()->layout(); + LyXTextClass const & tclass = buf.params.getLyXTextClass(); + LyXLayout_ptr const & layout = row.par()->layout(); int x = PAPER_MARGIN + font_metrics::signedWidth(tclass.rightmargin(), @@ -891,37 +614,37 @@ // this is the way, LyX handles the LaTeX-Environments. // I have had this idea very late, so it seems to be a // later added hack and this is true - if (row->par()->getDepth()) { + if (row.par()->getDepth()) { // find the next level paragraph - Paragraph * newpar = row->par(); + Paragraph const * newpar = row.par(); do { newpar = newpar->previous(); } while (newpar - && newpar->getDepth() >= row->par()->getDepth()); + && newpar->getDepth() >= row.par()->getDepth()); // make a corresponding row. Needed to call LeftMargin() // check wether it is a sufficent paragraph if (newpar && newpar->layout()->isEnvironment()) { Row dummyrow; - dummyrow.par(newpar); + dummyrow.par(const_cast<Paragraph *>(newpar)); dummyrow.pos(0); - x = rightMargin(buf, &dummyrow); + x = rightMargin(buf, dummyrow); } else { // this is no longer an error, because this function // is used to clear impossible depths after changing // a layout. Since there is always a redo, // LeftMargin() is always called - row->par()->params().depth(0); + row.par()->params().depth(0); } } //lyxerr << "rightmargin: " << layout->rightmargin << endl; x += font_metrics::signedWidth(layout->rightmargin, tclass.defaultfont()) - * 4 / (row->par()->getDepth() + 4); + * 4 / (row.par()->getDepth() + 4); return x; } @@ -956,7 +679,7 @@ // position of the last possible breakpoint // -1 isn't a suitable value, but a flag pos_type last_separator = -1; - width -= rightMargin(bview->buffer(), row); + width -= rightMargin(*bview->buffer(), *row); pos_type const main_body = par->beginningOfMainBody(); LyXLayout_ptr const & layout = par->layout(); @@ -1112,7 +835,7 @@ w = left_margin; } - int const fill = paper_width - w - rightMargin(bview->buffer(), row); + int const fill = paper_width - w - rightMargin(*bview->buffer(), *row); return fill; } @@ -1153,7 +876,7 @@ } -LColor::color LyXText::backgroundColor() +LColor::color LyXText::backgroundColor() const { if (inset_owner) return inset_owner->backgroundColor(); @@ -1257,7 +980,7 @@ row->ascent_of_text(maxasc); // is it a top line? - if (!row->pos() && (row->par() == firstpar)) { + if (!row->isParStart() && (row->par() == firstpar)) { // some parksips VERY EASY IMPLEMENTATION if (bview->buffer()->params.paragraph_separation == @@ -1267,13 +990,13 @@ && firstpar->getDepth() == 0 && firstpar->previous()) { - maxasc += bview->buffer()->params.getDefSkip().inPixels(bview); + maxasc += bview->buffer()->params.getDefSkip().inPixels(*bview); } else if (firstpar->previous() && firstpar->previous()->layout()->isParagraph() && firstpar->previous()->getDepth() == 0) { // is it right to use defskip here too? (AS) - maxasc += bview->buffer()->params.getDefSkip().inPixels(bview); + maxasc += bview->buffer()->params.getDefSkip().inPixels(*bview); } } @@ -1282,7 +1005,7 @@ maxasc += PAPER_MARGIN; // add the vertical spaces, that the user added - maxasc += getLengthMarkerHeight(bview, firstpar->params().spaceTop()); + maxasc += getLengthMarkerHeight(*bview, firstpar->params().spaceTop()); // do not forget the DTP-lines! // there height depends on the font of the nearest character @@ -1384,15 +1107,13 @@ } // is it a bottom line? - if (row->par() == par - && (!row->next() || row->next()->par() != row->par())) - { + if (row->par() == par && row->isParEnd()) { // the bottom margin if (!par->next() && isTopLevel()) maxdesc += PAPER_MARGIN; // add the vertical spaces, that the user added - maxdesc += getLengthMarkerHeight(bview, firstpar->params().spaceBottom()); + maxdesc += getLengthMarkerHeight(*bview, firstpar->params().spaceBottom()); // do not forget the DTP-lines! // there height depends on the font of the nearest character @@ -1508,6 +1229,25 @@ } +void LyXText::markChangeInDraw(BufferView * bv, Row * row, Row * prev) +{ + if (prev && prev->par() == row->par()) { + breakAgainOneRow(bv, prev); + if (prev->next() != row) { + // breakAgainOneRow() has removed row_ + need_break_row = prev; + } else { + need_break_row = row; + } + } else if (!prev) { + need_break_row = firstrow; + } else { + need_break_row = prev->next(); + } + setCursor(bv, cursor.par(), cursor.pos()); +} + + void LyXText::breakAgain(BufferView * bview, Row * row) const { bool not_ready = true; @@ -1518,7 +1258,7 @@ Row * tmprow = row; if (z < row->par()->size()) { - if (!row->next() || (row->next() && row->next()->par() != row->par())) { + if (row->isParEnd()) { // insert a new row ++z; insertRow(row, row->par(), z); @@ -1562,8 +1302,7 @@ Row * tmprow = row; if (z < row->par()->size()) { - if (!row->next() - || (row->next() && row->next()->par() != row->par())) { + if (row->isParEnd()) { // insert a new row ++z; insertRow(row, row->par(), z); @@ -1845,7 +1584,7 @@ if (!jumped_over_space) { // refresh the positions Row * tmprow = row; - while (tmprow->next() && tmprow->next()->par() == row->par()) { + while (!tmprow->isParEnd()) { tmprow = tmprow->next(); tmprow->pos(tmprow->pos() + 1); } @@ -1885,7 +1624,7 @@ false, cursor.boundary()); // cursor MUST be in row now. - if (row->next() && row->next()->par() == row->par()) + if (!row->isParEnd()) need_break_row = row->next(); else need_break_row = 0; @@ -1914,7 +1653,7 @@ breakAgainOneRow(bview, row); // will the cursor be in another row now? if (row->lastPos() <= cursor.pos() + 1 && row->next()) { - if (row->next() && row->next()->par() == row->par()) + if (!row->isParEnd()) // this should always be true row = row->next(); breakAgainOneRow(bview, row); @@ -1928,7 +1667,7 @@ != cursor.boundary()) setCursor(bview, cursor.par(), cursor.pos(), false, !cursor.boundary()); - if (row->next() && row->next()->par() == row->par()) + if (!row->isParEnd()) need_break_row = row->next(); else need_break_row = 0; @@ -1999,7 +1738,7 @@ row->par()->isRightToLeftPar(bview->buffer()->params); if (is_rtl) { x = (workWidth(bview) > 0) - ? rightMargin(bview->buffer(), row) : 0; + ? rightMargin(*bview->buffer(), *row) : 0; } else x = (workWidth(bview) > 0) ? leftMargin(bview, row) : 0; @@ -2053,7 +1792,7 @@ switch (align) { case LYX_ALIGN_BLOCK: ns = row->numberOfSeparators(); - if (ns && row->next() && row->next()->par() == row->par() && + if (ns && !row->isParEnd() && !(row->next()->par()->isNewline(row->next()->pos() - 1)) && !(row->next()->par()->isInset(row->next()->pos()) && row->next()->par()->getInset(row->next()->pos()) @@ -2354,7 +2093,7 @@ bool const is_bad_inset(cpar->isInset(cpos) && !cpar->getInset(cpos)->allowSpellcheck()); - if (cpar->isLetter(cpos) && !isDeletedText(cpar, cpos) + if (cpar->isLetter(cpos) && !isDeletedText(*cpar, cpos) && !is_bad_inset) break; @@ -2387,7 +2126,7 @@ // and ligature break are part of a word) while (cursor.pos() < cursor.par()->size() && cursor.par()->isLetter(cursor.pos()) - && !isDeletedText(cursor.par(), cursor.pos())) + && !isDeletedText(*cursor.par(), cursor.pos())) cursor.pos(cursor.pos() + 1); // Finally, we copy the word to a string and return it @@ -2579,8 +2318,8 @@ if (tmppos == 0 || tmppos == tmppar->size()) return; - if (isDeletedText(tmppar, tmppos - 1) - || isDeletedText(tmppar, tmppos)) + if (isDeletedText(*tmppar, tmppos - 1) + || isDeletedText(*tmppar, tmppos)) return; unsigned char c1 = tmppar->getChar(tmppos); @@ -2801,7 +2540,7 @@ cursor.par()->erase(cursor.pos()); // refresh the positions Row * tmprow = row; - while (tmprow->next() && tmprow->next()->par() == row->par()) { + while (!tmprow->isParEnd()) { tmprow = tmprow->next(); tmprow->pos(tmprow->pos() - 1); } @@ -2815,7 +2554,7 @@ cursor.pos(), current_font); // refresh the positions tmprow = row; - while (tmprow->next() && tmprow->next()->par() == row->par()) { + while (!tmprow->isParEnd()) { tmprow = tmprow->next(); tmprow->pos(tmprow->pos() + 1); } @@ -2825,8 +2564,7 @@ // refresh the positions Row * tmprow = row; - while (tmprow->next() - && tmprow->next()->par() == row->par()) { + while (!tmprow->isParEnd()) { tmprow = tmprow->next(); tmprow->pos(tmprow->pos() - 1); } @@ -2838,8 +2576,7 @@ cursor.par()->erase(cursor.pos()); // refresh the positions tmprow = row; - while (tmprow->next() && - tmprow->next()->par() == row->par()) { + while (!tmprow->isParEnd()) { tmprow = tmprow->next(); tmprow->pos(tmprow->pos() - 1); } @@ -2862,7 +2599,7 @@ need_break_row = 0; } else { breakAgainOneRow(bview, row); - if (row->next() && row->next()->par() == row->par()) + if (!row->isParEnd()) need_break_row = row->next(); else need_break_row = 0; @@ -2891,7 +2628,7 @@ } // break the cursor row again - if (row->next() && row->next()->par() == row->par() && + if (!row->isParEnd() && (row->lastPos() == row->par()->size() - 1 || nextBreakPoint(bview, row, workWidth(bview)) != row->lastPos())) { @@ -2908,7 +2645,7 @@ breakAgainOneRow(bview, row); // will the cursor be in another row now? - if (row->next() && row->next()->par() == row->par() && + if (!row->isParEnd() && row->lastPos() <= cursor.pos()) { row = row->next(); breakAgainOneRow(bview, row); @@ -2916,7 +2653,7 @@ setCursor(bview, cursor.par(), cursor.pos(), false, cursor.boundary()); - if (row->next() && row->next()->par() == row->par()) + if (!row->isParEnd()) need_break_row = row->next(); else need_break_row = 0; @@ -2961,760 +2698,6 @@ } -bool LyXText::paintRowBackground(DrawRowParams & p) -{ - bool clear_area = true; - Inset * inset = 0; - LyXFont font(LyXFont::ALL_SANE); - - pos_type const last = p.row->lastPrintablePos(); - - if (!p.bv->screen().forceClear() && last == p.row->pos() - && p.row->par()->isInset(p.row->pos())) { - inset = p.row->par()->getInset(p.row->pos()); - if (inset) { - clear_area = inset->doClearArea(); - } - } - - if (p.cleared) { - return true; - } - - if (clear_area) { - int const x = p.xo; - int const y = p.yo < 0 ? 0 : p.yo; - int const h = p.yo < 0 ? p.row->height() + p.yo : p.row->height(); - p.pain->fillRectangle(x, y, p.width, h, backgroundColor()); - return true; - } - - if (inset == 0) - return false; - - int h = p.row->baseline() - inset->ascent(p.bv, font); - - // first clear the whole row above the inset! - if (h > 0) { - p.pain->fillRectangle(p.xo, p.yo, p.width, h, backgroundColor()); - } - - // clear the space below the inset! - h += inset->ascent(p.bv, font) + inset->descent(p.bv, font); - if ((p.row->height() - h) > 0) { - p.pain->fillRectangle(p.xo, p.yo + h, - p.width, p.row->height() - h, backgroundColor()); - } - - // clear the space behind the inset, if needed - if (!inset->display() && !inset->needFullRow()) { - int const xp = int(p.x) + inset->width(p.bv, font); - if (p.width - xp > 0) { - p.pain->fillRectangle(xp, p.yo, p.width - xp, - p.row->height(), backgroundColor()); - } - } - - return false; -} - - -void LyXText::paintRowSelection(DrawRowParams & p) -{ - bool const is_rtl = p.row->par()->isRightToLeftPar(p.bv->buffer()->params); - - // the current selection - int const startx = selection.start.x(); - int const endx = selection.end.x(); - int const starty = selection.start.y(); - int const endy = selection.end.y(); - Row const * startrow = selection.start.row(); - Row const * endrow = selection.end.row(); - - Row * row = p.row; - - if (bidi_same_direction) { - int x; - int y = p.yo; - int w; - int h = row->height(); - - if (startrow == row && endrow == row) { - if (startx < endx) { - x = p.xo + startx; - w = endx - startx; - p.pain->fillRectangle(x, y, w, h, LColor::selection); - } else { - x = p.xo + endx; - w = startx - endx; - p.pain->fillRectangle(x, y, w, h, LColor::selection); - } - } else if (startrow == row) { - int const x = (is_rtl) ? p.xo : (p.xo + startx); - int const w = (is_rtl) ? startx : (p.width - startx); - p.pain->fillRectangle(x, y, w, h, LColor::selection); - } else if (endrow == row) { - int const x = (is_rtl) ? (p.xo + endx) : p.xo; - int const w = (is_rtl) ? (p.width - endx) : endx; - p.pain->fillRectangle(x, y, w, h, LColor::selection); - } else if (p.y > starty && p.y < endy) { - p.pain->fillRectangle(p.xo, y, p.width, h, LColor::selection); - } - return; - } else if (startrow != row && endrow != row) { - if (p.y > starty && p.y < endy) { - int w = p.width; - int h = row->height(); - p.pain->fillRectangle(p.xo, p.yo, w, h, LColor::selection); - } - return; - } - - if ((startrow != row && !is_rtl) || (endrow != row && is_rtl)) - p.pain->fillRectangle(p.xo, p.yo, int(p.x), row->height(), LColor::selection); - - Buffer const * buffer = p.bv->buffer(); - Paragraph * par = row->par(); - pos_type const main_body = par->beginningOfMainBody(); - pos_type const last = row->lastPrintablePos(); - float tmpx = p.x; - - for (pos_type vpos = row->pos(); vpos <= last; ++vpos) { - pos_type pos = vis2log(vpos); - float const old_tmpx = tmpx; - if (main_body > 0 && pos == main_body - 1) { - LyXLayout_ptr const & layout = par->layout(); - LyXFont const lfont = getLabelFont(buffer, par); - - tmpx += p.label_hfill + font_metrics::width(layout->labelsep, lfont); - - if (par->isLineSeparator(main_body - 1)) - tmpx -= singleWidth(p.bv, par, main_body - 1); - } - - if (row->hfillExpansion(pos)) { - tmpx += singleWidth(p.bv, par, pos); - if (pos >= main_body) - tmpx += p.hfill; - else - tmpx += p.label_hfill; - } - - else if (par->isSeparator(pos)) { - tmpx += singleWidth(p.bv, par, pos); - if (pos >= main_body) - tmpx += p.separator; - } else { - tmpx += singleWidth(p.bv, par, pos); - } - - if ((startrow != row || selection.start.pos() <= pos) && - (endrow != row || pos < selection.end.pos())) { - // Here we do not use p.x as p.xo was added to p.x. - p.pain->fillRectangle(int(old_tmpx), p.yo, - int(tmpx - old_tmpx + 1), - row->height(), LColor::selection); - } - } - - if ((startrow != row && is_rtl) || (endrow != row && !is_rtl)) { - p.pain->fillRectangle(p.xo + int(tmpx), - p.yo, int(p.bv->workWidth() - tmpx), - row->height(), LColor::selection); - } -} - - -void LyXText::paintChangeBar(DrawRowParams & p) -{ - pos_type const start = p.row->pos(); - pos_type const end = p.row->lastPrintablePos(); - - if (!p.row->par()->isChanged(start, end)) - return; - - int const height = (p.row->next() - ? p.row->height() + p.row->next()->top_of_text() - : p.row->baseline()); - - p.pain->fillRectangle(4, p.yo, 5, - height, LColor::changebar); -} - - -void LyXText::paintRowAppendix(DrawRowParams & p) -{ - // FIXME: can be just p.width ? - int const ww = p.bv->workWidth(); - Paragraph * firstpar = p.row->par(); - - if (firstpar->params().appendix()) { - p.pain->line(1, p.yo, 1, p.yo + p.row->height(), LColor::appendixline); - p.pain->line(ww - 2, p.yo, ww - 2, p.yo + p.row->height(), LColor::appendixline); - } -} - - -void LyXText::paintRowDepthBar(DrawRowParams & p) -{ - Paragraph::depth_type const depth = p.row->par()->getDepth(); - - if (depth <= 0) - return; - - Paragraph::depth_type prev_depth = 0; - if (p.row->previous()) - prev_depth = p.row->previous()->par()->getDepth(); - Paragraph::depth_type next_depth = 0; - if (p.row->next()) - next_depth = p.row->next()->par()->getDepth(); - - for (Paragraph::depth_type i = 1; i <= depth; ++i) { - int x = (PAPER_MARGIN / 5) * i + p.xo; - // only consider the changebar space if we're drawing outer left - if (!p.xo) - x += CHANGEBAR_MARGIN; - int const h = p.yo + p.row->height() - 1 - (i - next_depth - 1) * 3; - - p.pain->line(x, p.yo, x, h, LColor::depthbar); - - int const w = PAPER_MARGIN / 5; - - if (i > prev_depth) { - p.pain->fillRectangle(x, p.yo, w, 2, LColor::depthbar); - } - if (i > next_depth) { - p.pain->fillRectangle(x, h, w, 2, LColor::depthbar); - } - } -} - - -int LyXText::getLengthMarkerHeight(BufferView * bv, VSpace const & vsp) const -{ - if (vsp.kind() == VSpace::NONE) - return 0; - - int const arrow_size = 4; - int const space_size = int(vsp.inPixels(bv)); - - LyXFont font; - font.decSize(); - int const min_size = max(3 * arrow_size, - font_metrics::maxAscent(font) - + font_metrics::maxDescent(font)); - - if (vsp.length().len().value() < 0.0) - return min_size; - else - return max(min_size, space_size); -} - - -int LyXText::drawLengthMarker(DrawRowParams & p, string const & prefix, - VSpace const & vsp, int start) -{ - if (vsp.kind() == VSpace::NONE) - return 0; - - int const arrow_size = 4; - int const size = getLengthMarkerHeight(p.bv, vsp); - int const end = start + size; - - // the label to display (if any) - string str; - // y-values for top arrow - int ty1, ty2; - // y-values for bottom arrow - int by1, by2; - - str = prefix + " (" + vsp.asLyXCommand() + ")"; - - if (vsp.kind() == VSpace::VFILL ) { - ty1 = ty2 = start; - by1 = by2 = end; - } else { - // adding or removing space - bool const added = vsp.kind() != VSpace::LENGTH || - vsp.length().len().value() > 0.0; - ty1 = added ? (start + arrow_size) : start; - ty2 = added ? start : (start + arrow_size); - by1 = added ? (end - arrow_size) : end; - by2 = added ? end : (end - arrow_size); - } - - int const leftx = p.xo + leftMargin(p.bv, p.row); - int const midx = leftx + arrow_size; - int const rightx = midx + arrow_size; - - // first the string - int w = 0; - int a = 0; - int d = 0; - - LyXFont font; - font.setColor(LColor::added_space).decSize().decSize(); - font_metrics::rectText(str, font, w, a, d); - - p.pain->rectText(leftx + 2 * arrow_size + 5, - start + ((end - start) / 2) + d, - str, font); - - // top arrow - p.pain->line(leftx, ty1, midx, ty2, LColor::added_space); - p.pain->line(midx, ty2, rightx, ty1, LColor::added_space); - - // bottom arrow - p.pain->line(leftx, by1, midx, by2, LColor::added_space); - p.pain->line(midx, by2, rightx, by1, LColor::added_space); - - // joining line - p.pain->line(midx, ty2, midx, by2, LColor::added_space); - - return size; -} - - -int LyXText::paintPageBreak(string const & label, int y, DrawRowParams & p) -{ - LyXFont pb_font; - pb_font.setColor(LColor::pagebreak).decSize(); - - int w = 0; - int a = 0; - int d = 0; - font_metrics::rectText(label, pb_font, w, a, d); - - int const text_start = p.xo + ((p.width - w) / 2); - int const text_end = text_start + w; - - p.pain->rectText(text_start, y + d, label, pb_font); - - p.pain->line(p.xo, y, text_start, y, - LColor::pagebreak, Painter::line_onoffdash); - p.pain->line(text_end, y, p.xo + p.width, y, - LColor::pagebreak, Painter::line_onoffdash); - - return 3 * defaultRowHeight(); -} - - -void LyXText::paintFirstRow(DrawRowParams & p) -{ - Paragraph * par = p.row->par(); - ParagraphParameters const & parparams = par->params(); - - // start of appendix? - if (parparams.startOfAppendix()) { - p.pain->line(1, p.yo, p.width - 2, p.yo, LColor::appendixline); - } - - int y_top = 0; - - // the top margin - if (!p.row->previous() && isTopLevel()) - y_top += PAPER_MARGIN; - - // draw a top pagebreak - if (parparams.pagebreakTop()) { - y_top += paintPageBreak(_("Page Break (top)"), - p.yo + y_top + 2 * defaultRowHeight(), p); - } - - // draw the additional space if needed: - y_top += drawLengthMarker(p, _("Space above"), - parparams.spaceTop(), p.yo + y_top); - - Buffer const * buffer = p.bv->buffer(); - - LyXLayout_ptr const & layout = par->layout(); - - // think about the parskip - // some parskips VERY EASY IMPLEMENTATION - if (buffer->params.paragraph_separation == BufferParams::PARSEP_SKIP) { - if (par->previous()) { - if (layout->latextype == LATEX_PARAGRAPH - && !par->getDepth()) { - y_top += buffer->params.getDefSkip().inPixels(p.bv); - } else { - LyXLayout_ptr const & playout = - par->previous()->layout(); - if (playout->latextype == LATEX_PARAGRAPH - && !par->previous()->getDepth()) { - // is it right to use defskip here, too? (AS) - y_top += buffer->params.getDefSkip().inPixels(p.bv); - } - } - } - } - - int const ww = p.bv->workWidth(); - - // draw a top line - if (parparams.lineTop()) { - LyXFont font(LyXFont::ALL_SANE); - int const asc = font_metrics::ascent('x', getFont(buffer, par, 0)); - - y_top += asc; - - int const w = (inset_owner ? inset_owner->width(p.bv, font) : ww); - int const xp = static_cast<int>(inset_owner ? p.xo : 0); - p.pain->line(xp, p.yo + y_top, xp + w, p.yo + y_top, - LColor::topline, Painter::line_solid, - Painter::line_thick); - - y_top += asc; - } - - bool const is_rtl = p.row->par()->isRightToLeftPar(p.bv->buffer()->params); - - // should we print a label? - if (layout->labeltype >= LABEL_STATIC - && (layout->labeltype != LABEL_STATIC - || layout->latextype != LATEX_ENVIRONMENT - || par->isFirstInSequence())) { - - LyXFont font = getLabelFont(buffer, par); - if (!par->getLabelstring().empty()) { - float x = p.x; - string const str = par->getLabelstring(); - - // this is special code for the chapter layout. This is - // printed in an extra row and has a pagebreak at - // the top. - if (layout->labeltype == LABEL_COUNTER_CHAPTER) { - if (buffer->params.secnumdepth >= 0) { - float spacing_val = 1.0; - if (!parparams.spacing().isDefault()) { - spacing_val = parparams.spacing().getValue(); - } else { - spacing_val = buffer->params.spacing.getValue(); - } - - int const maxdesc = - int(font_metrics::maxDescent(font) * layout->spacing.getValue() * spacing_val) - + int(layout->parsep) * defaultRowHeight(); - - if (is_rtl) { - x = ww - leftMargin(p.bv, p.row) - - font_metrics::width(str, font); - } - - p.pain->text(int(x), - p.yo + p.row->baseline() - - p.row->ascent_of_text() - maxdesc, - str, font); - } - } else { - if (is_rtl) { - x = ww - leftMargin(p.bv, p.row) - + font_metrics::width(layout->labelsep, font); - } else { - x = p.x - font_metrics::width(layout->labelsep, font) - - font_metrics::width(str, font); - } - - p.pain->text(int(x), p.yo + p.row->baseline(), str, font); - } - } - // the labels at the top of an environment. - // More or less for bibliography - } else if (par->isFirstInSequence() && - (layout->labeltype == LABEL_TOP_ENVIRONMENT || - layout->labeltype == LABEL_BIBLIO || - layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)) { - LyXFont font = getLabelFont(buffer, par); - if (!par->getLabelstring().empty()) { - string const str = par->getLabelstring(); - float spacing_val = 1.0; - if (!parparams.spacing().isDefault()) { - spacing_val = parparams.spacing().getValue(); - } else { - spacing_val = buffer->params.spacing.getValue(); - } - - int maxdesc = - int(font_metrics::maxDescent(font) * layout->spacing.getValue() * spacing_val - + (layout->labelbottomsep * defaultRowHeight())); - - float x = p.x; - if (layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) { - x = ((is_rtl ? leftMargin(p.bv, p.row) : p.x) - + ww - rightMargin(buffer, p.row)) / 2; - x -= font_metrics::width(str, font) / 2; - } else if (is_rtl) { - x = ww - leftMargin(p.bv, p.row) - - font_metrics::width(str, font); - } - p.pain->text(int(x), p.yo + p.row->baseline() - - p.row->ascent_of_text() - maxdesc, - str, font); - } - } -} - - -void LyXText::paintLastRow(DrawRowParams & p) -{ - Paragraph * par = p.row->par(); - ParagraphParameters const & parparams = par->params(); - int y_bottom = p.row->height() - 1; - - // the bottom margin - if (!p.row->next() && isTopLevel()) - y_bottom -= PAPER_MARGIN; - - int const ww = p.bv->workWidth(); - - // draw a bottom pagebreak - if (parparams.pagebreakBottom()) { - y_bottom -= paintPageBreak(_("Page Break (bottom)"), - p.yo + y_bottom - 2 * defaultRowHeight(), p); - } - - // draw the additional space if needed: - int const height = getLengthMarkerHeight(p.bv, - parparams.spaceBottom()); - y_bottom -= drawLengthMarker(p, _("Space below"), - parparams.spaceBottom(), - p.yo + y_bottom - height); - - Buffer const * buffer = p.bv->buffer(); - - // draw a bottom line - if (parparams.lineBottom()) { - LyXFont font(LyXFont::ALL_SANE); - int const asc = font_metrics::ascent('x', - getFont(buffer, par, - max(pos_type(0), par->size() - 1))); - - y_bottom -= asc; - - int const w = (inset_owner ? inset_owner->width(p.bv, font) : ww); - int const xp = static_cast<int>(inset_owner ? p.xo : 0); - int const y = p.yo + y_bottom; - p.pain->line(xp, y, xp + w, y, LColor::topline, Painter::line_solid, - Painter::line_thick); - - y_bottom -= asc; - } - - bool const is_rtl = p.row->par()->isRightToLeftPar(p.bv->buffer()->params); - int const endlabel = par->getEndLabel(); - - // draw an endlabel - switch (endlabel) { - case END_LABEL_BOX: - case END_LABEL_FILLED_BOX: - { - LyXFont const font = getLabelFont(buffer, par); - int const size = int(0.75 * font_metrics::maxAscent(font)); - int const y = (p.yo + p.row->baseline()) - size; - int x = is_rtl ? LEFT_MARGIN : ww - PAPER_MARGIN - size; - - if (p.row->fill() <= size) - x += (size - p.row->fill() + 1) * (is_rtl ? -1 : 1); - - if (endlabel == END_LABEL_BOX) { - p.pain->rectangle(x, y, size, size, LColor::eolmarker); - } else { - p.pain->fillRectangle(x, y, size, size, - LColor::eolmarker); - } - break; - } - case END_LABEL_STATIC: - { -#if 0 - LyXFont font(LyXFont::ALL_SANE); - font = getLabelFont(buffer, par); -#else - LyXFont font = getLabelFont(buffer, par); -#endif - string const & str = par->layout()->endlabelstring(); - int const x = is_rtl ? - int(p.x) - font_metrics::width(str, font) - : ww - rightMargin(buffer, p.row) - p.row->fill(); - p.pain->text(x, p.yo + p.row->baseline(), str, font); - break; - } - case END_LABEL_NO_LABEL: - break; - } -} - - -void LyXText::paintRowText(DrawRowParams & p) -{ - Paragraph * par = p.row->par(); - Buffer const * buffer = p.bv->buffer(); - - pos_type const last = p.row->lastPrintablePos(); - pos_type main_body = par->beginningOfMainBody(); - if (main_body > 0 && - (main_body - 1 > last || - !par->isLineSeparator(main_body - 1))) { - main_body = 0; - } - - LyXLayout_ptr const & layout = par->layout(); - - bool running_strikeout = false; - bool is_struckout = false; - float last_strikeout_x = 0.0; - - pos_type vpos = p.row->pos(); - while (vpos <= last) { - if (p.x > p.bv->workWidth()) - break; - pos_type pos = vis2log(vpos); - - if (p.x + singleWidth(p.bv, par, pos) < 0) { - p.x += singleWidth(p.bv, par, pos); - ++vpos; - continue; - } - - is_struckout = isDeletedText(par, pos); - - if (is_struckout && !running_strikeout) { - running_strikeout = true; - last_strikeout_x = p.x; - } - - bool const highly_editable_inset = par->isInset(pos) - && isHighlyEditableInset(par->getInset(pos)); - - // if we reach the end of a struck out range, paint it - // we also don't paint across things like tables - if (running_strikeout && (highly_editable_inset || !is_struckout)) { - int const middle = p.yo + p.row->top_of_text() - + ((p.row->baseline() - p.row->top_of_text()) / 2); - p.pain->line(int(last_strikeout_x), middle, int(p.x), middle, - LColor::strikeout, Painter::line_solid, Painter::line_thin); - running_strikeout = false; - } - - if (main_body > 0 && pos == main_body - 1) { - int const lwidth = font_metrics::width(layout->labelsep, - getLabelFont(buffer, par)); - - p.x += p.label_hfill + lwidth - - singleWidth(p.bv, par, main_body - 1); - } - - if (par->isHfill(pos)) { - p.x += 1; - - int const y0 = p.yo + p.row->baseline(); - int const y1 = y0 - defaultRowHeight() / 2; - - p.pain->line(int(p.x), y1, int(p.x), y0, - LColor::added_space); - - if (p.row->hfillExpansion(pos)) { - int const y2 = (y0 + y1) / 2; - - if (pos >= main_body) { - p.pain->line(int(p.x), y2, - int(p.x + p.hfill), y2, - LColor::added_space, - Painter::line_onoffdash); - p.x += p.hfill; - } else { - p.pain->line(int(p.x), y2, - int(p.x + p.label_hfill), y2, - LColor::added_space, - Painter::line_onoffdash); - p.x += p.label_hfill; - } - p.pain->line(int(p.x), y1, - int(p.x), y0, - LColor::added_space); - } - p.x += 2; - ++vpos; - } else if (par->isSeparator(pos)) { - p.x += singleWidth(p.bv, par, pos); - if (pos >= main_body) - p.x += p.separator; - ++vpos; - } else { - if (!draw(p, vpos)) - break; - } - } - - // if we reach the end of a struck out range, paint it - if (running_strikeout) { - int const middle = p.yo + p.row->top_of_text() - + ((p.row->baseline() - p.row->top_of_text()) / 2); - p.pain->line(int(last_strikeout_x), middle, int(p.x), middle, - LColor::strikeout, Painter::line_solid, Painter::line_thin); - running_strikeout = false; - } -} - - -void LyXText::getVisibleRow(BufferView * bv, int y_offset, int x_offset, - Row * row, int y, bool cleared) -{ - if (row->height() <= 0) { - lyxerr << "LYX_ERROR: row.height: " - << row->height() << endl; - return; - } - - DrawRowParams p; - - // set up drawing parameters - p.bv = bv; - p.pain = &bv->painter(); - p.row = row; - p.xo = x_offset; - p.yo = y_offset; - prepareToPrint(bv, row, p.x, p.separator, p.hfill, p.label_hfill); - if (inset_owner && (p.x < 0)) - p.x = 0; - p.x += p.xo; - p.y = y; - p.width = inset_owner ? inset_owner->textWidth(bv, true) : bv->workWidth(); - p.cleared = cleared; - - // start painting - - // clear to background if necessary - p.cleared = paintRowBackground(p); - - // paint the selection background - if (selection.set()) { - paintRowSelection(p); - } - - // vertical lines for appendix - paintRowAppendix(p); - - // environment depth brackets - paintRowDepthBar(p); - - // changebar - paintChangeBar(p); - - // draw any stuff wanted for a first row of a paragraph - if (!row->pos()) { - paintFirstRow(p); - } - - // draw any stuff wanted for the last row of a paragraph - if (!row->next() || (row->next()->par() != row->par())) { - paintLastRow(p); - } - - // paint text - paintRowText(p); -} - - // returns the column near the specified x-coordinate of the row // x is set to the real beginning of this column pos_type @@ -3789,7 +2772,7 @@ boundary = false; bool const lastrow = lyxrc.rtl_support // This is not needed, but gives // some speedup if rtl_support=false - && (!row->next() || row->next()->par() != row->par()); + && (row->isParEnd()); bool const rtl = (lastrow) ? row->par()->isRightToLeftPar(bview->buffer()->params) : false; // If lastrow is false, we don't need to compute Index: text2.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/text2.C,v retrieving revision 1.277 diff -u -r1.277 text2.C --- text2.C 21 Feb 2003 09:20:17 -0000 1.277 +++ text2.C 26 Feb 2003 01:37:03 -0000 @@ -53,17 +53,17 @@ LyXText::LyXText(BufferView * bv) : height(0), width(0), first_y(0), - inset_owner(0), the_locking_inset(0), need_break_row(0), + inset_owner(0), the_locking_inset(0), need_break_row(0), refresh_y(0), refresh_row(0), bv_owner(bv), status_(LyXText::UNCHANGED), firstrow(0), lastrow(0) {} LyXText::LyXText(InsetText * inset) - : height(0), width(0), first_y(0), - inset_owner(inset), the_locking_inset(0), need_break_row(0), - refresh_y(0), refresh_row(0), bv_owner(0), - status_(LyXText::UNCHANGED), firstrow(0), lastrow(0) + : height(0), width(0), first_y(0), + inset_owner(inset), the_locking_inset(0), need_break_row(0), + refresh_y(0), refresh_row(0), bv_owner(0), + status_(LyXText::UNCHANGED), firstrow(0), lastrow(0) {} @@ -2370,6 +2370,12 @@ { /// only the top-level lyxtext has a non-null bv owner return bv_owner; +} + + +bool LyXText::isInInset() const +{ + return inset_owner; } Index: vspace.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/vspace.C,v retrieving revision 1.67 diff -u -r1.67 vspace.C --- vspace.C 14 Feb 2003 00:41:43 -0000 1.67 +++ vspace.C 26 Feb 2003 01:37:04 -0000 @@ -465,7 +465,7 @@ -int VSpace::inPixels(BufferView const * bv) const +int VSpace::inPixels(BufferView const & bv) const { // Height of a normal line in pixels (zoom factor considered) int const default_height = defaultRowHeight(); // [pixels] @@ -479,7 +479,7 @@ break; case DEFSKIP: - retval = bv->buffer()->params.getDefSkip().inPixels(bv); + retval = bv.buffer()->params.getDefSkip().inPixels(bv); break; // This is how the skips are normally defined by LateX. @@ -502,7 +502,7 @@ break; case LENGTH: - retval = len_.len().inPixels(bv->workWidth()); + retval = len_.len().inPixels(bv.workWidth()); break; } Index: vspace.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/vspace.h,v retrieving revision 1.25 diff -u -r1.25 vspace.h --- vspace.h 13 Feb 2003 16:52:45 -0000 1.25 +++ vspace.h 26 Feb 2003 01:37:04 -0000 @@ -62,7 +62,8 @@ /// the latex representation string const asLatexCommand(BufferParams const & params) const; /// the size of the space on-screen - int inPixels(BufferView const * bv) const; + int inPixels(BufferView const & bv) const; + private: /// This VSpace kind vspace_kind kind_; Index: frontends/screen.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/screen.C,v retrieving revision 1.27 diff -u -r1.27 screen.C --- frontends/screen.C 14 Feb 2003 00:41:43 -0000 1.27 +++ frontends/screen.C 26 Feb 2003 01:37:05 -0000 @@ -24,6 +24,7 @@ #include "font_metrics.h" #include "language.h" #include "debug.h" +#include "rowpainter.h" // Splash screen-specific stuff #include "lyxfont.h" @@ -419,16 +420,23 @@ while (row != 0 && y < y2) { LyXText::text_status st = text->status(); - text->getVisibleRow(bv, y + yo, - xo, row, y + text->first_y); + // we need this here as the row pointer may be illegal + // at a later time (Jug20020502) + Row * prev = row->previous(); + RowPainter rp(*bv, *text, *row); + if (rp.paint(y + yo, xo, y + text->first_y)) + text->markChangeInDraw(bv, row, prev); + internal = internal && (st != LyXText::CHANGED_IN_DRAW); while (internal && text->status() == LyXText::CHANGED_IN_DRAW) { text->fullRebreak(bv); st = LyXText::NEED_MORE_REFRESH; text->setCursor(bv, text->cursor.par(), text->cursor.pos()); text->status(bv, st); - text->getVisibleRow(bv, y + yo, - xo, row, y + text->first_y); + Row * prev = row->previous(); + RowPainter rp(*bv, *text, *row); + if (rp.paint(y + yo, xo, y + text->first_y)) + text->markChangeInDraw(bv, row, prev); } y += row->height(); row = row->next(); @@ -451,7 +459,10 @@ if (((y + row->height()) > 0) && ((y - row->height()) <= static_cast<int>(workarea().workHeight()))) { - text->getVisibleRow(bv, y, xo, row, y + text->first_y); + Row * prev = row->previous(); + RowPainter rp(*bv, *text, *row); + if (rp.paint(y, xo, y + text->first_y)) + text->markChangeInDraw(bv, row, prev); } force_clear_ = false; } Index: insets/inset.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/insets/inset.h,v retrieving revision 1.72 diff -u -r1.72 inset.h --- insets/inset.h 21 Feb 2003 12:11:53 -0000 1.72 +++ insets/inset.h 26 Feb 2003 01:37:07 -0000 @@ -385,7 +385,7 @@ * returns true if pointer argument is valid * and points to an editable inset */ -inline bool isEditableInset(Inset * i) +inline bool isEditableInset(Inset const * i) { return i && i->editable(); } @@ -394,7 +394,7 @@ * returns true if pointer argument is valid * and points to a highly editable inset */ -inline bool isHighlyEditableInset(Inset * i) +inline bool isHighlyEditableInset(Inset const * i) { return i && i->editable() == Inset::HIGHLY_EDITABLE; } Index: insets/insetert.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/insets/insetert.C,v retrieving revision 1.99 diff -u -r1.99 insetert.C --- insets/insetert.C 25 Feb 2003 14:51:37 -0000 1.99 +++ insets/insetert.C 26 Feb 2003 01:37:08 -0000 @@ -351,7 +351,7 @@ pos_type siz = par->size(); for (pos_type i = 0; i < siz; ++i) { // ignore all struck out text - if (isDeletedText(par, i)) + if (isDeletedText(*par, i)) continue; Paragraph::value_type c = par->getChar(i); Index: insets/insettext.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/insets/insettext.C,v retrieving revision 1.345 diff -u -r1.345 insettext.C --- insets/insettext.C 18 Feb 2003 16:58:15 -0000 1.345 +++ insets/insettext.C 26 Feb 2003 01:37:12 -0000 @@ -468,8 +468,10 @@ int yf = y_offset + first; y = 0; while ((row != 0) && (yf < ph)) { - lt->getVisibleRow(bv, y + y_offset + first, int(x), - row, y + lt->first_y, cleared); + Row * prev = row->previous(); + RowPainter rp(*bv, *lt, *row); + if (rp.paint(y + y_offset + first, int(x), y + lt->first_y, cleared)) + lt->markChangeInDraw(bv, row, prev); if (bv->text->status() == LyXText::CHANGED_IN_DRAW) { lt->need_break_row = row; lt->fullRebreak(bv);