From 4d440a14734cd372156ffae1082f5fdac1da94d7 Mon Sep 17 00:00:00 2001 From: John Levon Date: Wed, 26 Feb 2003 17:04:10 +0000 Subject: [PATCH] The row-painter patch git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@6287 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/ChangeLog | 27 + src/Makefile.am | 2 + src/frontends/ChangeLog | 4 + src/frontends/screen.C | 21 +- src/insets/ChangeLog | 6 + src/insets/inset.h | 4 +- src/insets/insetert.C | 2 +- src/insets/insettext.C | 7 +- src/insets/updatableinset.C | 2 +- src/lyxrow.C | 18 +- src/lyxrow.h | 6 + src/lyxtext.h | 187 ++--- src/paragraph.h | 8 +- src/rowpainter.C | 1087 ++++++++++++++++++++++++++++ src/rowpainter.h | 107 +++ src/text.C | 1323 ++++------------------------------- src/text2.C | 34 +- src/text3.C | 6 +- src/vspace.C | 6 +- src/vspace.h | 3 +- 20 files changed, 1502 insertions(+), 1358 deletions(-) create mode 100644 src/rowpainter.C create mode 100644 src/rowpainter.h diff --git a/src/ChangeLog b/src/ChangeLog index 5738419f1d..5594dfa5d6 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,30 @@ +2003-02-26 John Levon + + * lyxrow.h: + * lyxrow.C: add isParStart,isParEnd helpers + + * paragraph.h: make isInserted/DeletedText take refs + + * paragraph_funcs.h: + * paragraph_funcs.C: remove #if 0'd code + + * lyxtext.h: + * text3.C: + * text2.C: + * text.C: use lyxrow helpers above. + Move draw and paint routines to RowPainter. + Make several methods use refs not pointers. + Make backgroundColor() const. + Add markChangeInDraw(), isInInset(). + Merge changeRegionCase into changeCase. + Make workWidth() shouldn't-happen code into an Assert. + + * rowpainter.h: + * rowpainter.C: new class for painting a row. + + * vspace.h: + * vspace.C: make inPixels take a ref + 2003-02-26 Angus Leeming * BufferView_pimpl.C (dispatch): use InsetCommand::localDispatch for diff --git a/src/Makefile.am b/src/Makefile.am index fc82d14626..b6ae4bbe25 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -189,6 +189,8 @@ lyx_SOURCES = \ ispell.h \ pspell.C \ pspell.h \ + rowpainter.C \ + rowpainter.h \ sgml.C \ sgml.h \ tabular.C \ diff --git a/src/frontends/ChangeLog b/src/frontends/ChangeLog index 0d0419d0b8..cf5b5dfd95 100644 --- a/src/frontends/ChangeLog +++ b/src/frontends/ChangeLog @@ -1,3 +1,7 @@ +2003-02-26 John Levon + + * screen.C: use RowPainter + 2003-02-26 Angus Leeming * screen.[Ch]: ensure that the LyX splash screen is drawn if desired. diff --git a/src/frontends/screen.C b/src/frontends/screen.C index b0b3efed91..63075d9194 100644 --- a/src/frontends/screen.C +++ b/src/frontends/screen.C @@ -24,6 +24,7 @@ #include "font_metrics.h" #include "language.h" #include "debug.h" +#include "rowpainter.h" // Splash screen-specific stuff #include "lyxfont.h" @@ -431,16 +432,23 @@ void LyXScreen::drawFromTo(LyXText * text, BufferView * bv, 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(); @@ -463,7 +471,10 @@ void LyXScreen::drawOneRow(LyXText * text, BufferView * bv, Row * row, if (((y + row->height()) > 0) && ((y - row->height()) <= static_cast(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; } diff --git a/src/insets/ChangeLog b/src/insets/ChangeLog index d5a9beaeb4..c2b86fe0a2 100644 --- a/src/insets/ChangeLog +++ b/src/insets/ChangeLog @@ -1,3 +1,9 @@ +2003-02-26 John Levon + + * insettext.C: use RowPainter + + * inset.h: make helpers take const * + 2003-02-26 Angus Leeming * insetcommand.[Ch] (localDispatch): new method. diff --git a/src/insets/inset.h b/src/insets/inset.h index 9f865c0c3f..77bb0bae81 100644 --- a/src/insets/inset.h +++ b/src/insets/inset.h @@ -385,7 +385,7 @@ bool Inset::checkInsertChar(LyXFont &) * 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 @@ inline bool isEditableInset(Inset * i) * 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; } diff --git a/src/insets/insetert.C b/src/insets/insetert.C index 7f0c4a2bf6..7187863e6e 100644 --- a/src/insets/insetert.C +++ b/src/insets/insetert.C @@ -351,7 +351,7 @@ int InsetERT::latex(Buffer const *, ostream & os, bool /*fragile*/, 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); diff --git a/src/insets/insettext.C b/src/insets/insettext.C index b251d181eb..b9a15b1bdf 100644 --- a/src/insets/insettext.C +++ b/src/insets/insettext.C @@ -36,6 +36,7 @@ #include "WordLangTuple.h" #include "paragraph_funcs.h" #include "sgml.h" +#include "rowpainter.h" #include "frontends/Alert.h" #include "frontends/Dialogs.h" @@ -468,8 +469,10 @@ void InsetText::draw(BufferView * bv, LyXFont const & f, 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); diff --git a/src/insets/updatableinset.C b/src/insets/updatableinset.C index fa31bad229..9ed4b5cb7f 100644 --- a/src/insets/updatableinset.C +++ b/src/insets/updatableinset.C @@ -168,7 +168,7 @@ int UpdatableInset::getMaxWidth(BufferView * bv, UpdatableInset const *) const w = static_cast (owner())->getMaxWidth(bv, this); } else { - w = bv->text->workWidth(bv, const_cast(this)); + w = bv->text->workWidth(*bv, const_cast(this)); } if (w < 0) { return -1; diff --git a/src/lyxrow.C b/src/lyxrow.C index f879c65176..e5cb15826f 100644 --- a/src/lyxrow.C +++ b/src/lyxrow.C @@ -130,12 +130,24 @@ Row * Row::previous() const } +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 Row::lastPrintablePos() const 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 @@ bool Row::hfillExpansion(pos_type pos) const // 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 diff --git a/src/lyxrow.h b/src/lyxrow.h index c82190dec6..ab94db1a4c 100644 --- a/src/lyxrow.h +++ b/src/lyxrow.h @@ -67,6 +67,12 @@ public: /// 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 diff --git a/src/lyxtext.h b/src/lyxtext.h index ff3a73257b..7fc88c31ea 100644 --- a/src/lyxtext.h +++ b/src/lyxtext.h @@ -101,6 +101,10 @@ public: 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 at cursor position void breakParagraph(BufferView *, char keep_layout = 0); @@ -365,17 +369,10 @@ public: text_uppercase = 2 }; /// Change the case of the word at cursor position. - void changeCase(BufferView *, TextCase action); + void changeCase(BufferView &, TextCase action); /// 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 *); /// @@ -440,9 +437,9 @@ public: /// void checkParagraph(BufferView *, Paragraph * par, lyx::pos_type pos); /// - int workWidth(BufferView *) const; + int workWidth(BufferView &) const; /// - int workWidth(BufferView *, Inset * inset) const; + int workWidth(BufferView &, Inset * inset) const; /// void computeBidiTables(Buffer const *, Row * row) const; @@ -489,13 +486,8 @@ private: /// float getCursorX(BufferView *, Row *, lyx::pos_type pos, lyx::pos_type last, bool boundary) const; - /// - void changeRegionCase(BufferView * bv, - LyXCursor const & from, - LyXCursor const & to, - LyXText::TextCase action); /// used in setlayout - void makeFontEntriesLayoutSpecific(Buffer const *, Paragraph * par); + void makeFontEntriesLayoutSpecific(Buffer const &, Paragraph & par); /** forces the redrawing of a paragraph. Needed when manipulating a right address box @@ -527,81 +519,9 @@ private: /// 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 +544,40 @@ public: */ 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,54 +592,20 @@ private: * 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; /// returns the minimum space a row needs on the screen in pixel - int fill(BufferView *, Row * row, int workwidth) const; - - /** returns the minimum space a manual label needs on the - screen in pixel */ - int labelFill(BufferView *, Row const * row) const; + int fill(BufferView &, Row & row, int workwidth) 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. + * returns the minimum space a manual label needs on the + * screen in pixels */ - 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(); + int labelFill(BufferView &, Row const & row) const; + /// FIXME + int labelEnd(BufferView &, Row const & row) const; /// mutable std::vector log2vis_list; @@ -702,13 +622,6 @@ private: /// 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 +636,10 @@ public: /// 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 diff --git a/src/paragraph.h b/src/paragraph.h index 17a14511ce..8ed4536de3 100644 --- a/src/paragraph.h +++ b/src/paragraph.h @@ -344,15 +344,15 @@ private: }; -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 diff --git a/src/rowpainter.C b/src/rowpainter.C new file mode 100644 index 0000000000..31c3df5130 --- /dev/null +++ b/src/rowpainter.C @@ -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 + +#include + +#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 PAPER_MARGIN; +extern int CHANGEBAR_MARGIN; +extern int 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(&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(&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(&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(&par_)); + return text_.singleWidth(bv, par, pos, c); +} + + +LyXFont const RowPainter::getLabelFont() const +{ + Paragraph * par(const_cast(&par_)); + return text_.getLabelFont(bv_.buffer(), par); +} + + +char const RowPainter::transformChar(char c, lyx::pos_type pos) const +{ + Paragraph * par(const_cast(&par_)); + return text_.transformChar(c, par, pos); +} + + +int RowPainter::leftMargin() const +{ + BufferView * bv(perv(bv_)); + Row * row(const_cast(&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(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(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(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_.isInInset() + ? 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(&bv_)); + Row * row(const_cast(&row_)); + text_.prepareToPrint(bv, row, x_, separator_, hfill_, label_hfill_); + + // FIXME: what is this fixing ? + if (text_.isInInset() && (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(); +} diff --git a/src/rowpainter.h b/src/rowpainter.h new file mode 100644 index 0000000000..4e799cec19 --- /dev/null +++ b/src/rowpainter.h @@ -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 + +#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 diff --git a/src/text.C b/src/text.C index dbc2432193..ef52b90a72 100644 --- a/src/text.C +++ b/src/text.C @@ -32,6 +32,7 @@ #include "undo_funcs.h" #include "WordLangTuple.h" #include "paragraph_funcs.h" +#include "rowpainter.h" #include "insets/insettext.h" @@ -47,55 +48,33 @@ using std::endl; using std::pair; using lyx::pos_type; -namespace { - /// top, right, bottom pixel margin -int const PAPER_MARGIN = 20; +extern int const PAPER_MARGIN = 20; /// margin for changebar -int const CHANGEBAR_MARGIN = 10; +extern int const CHANGEBAR_MARGIN = 10; /// left margin -int const LEFT_MARGIN = PAPER_MARGIN + CHANGEBAR_MARGIN; - -} // namespace anon +extern int const LEFT_MARGIN = PAPER_MARGIN + CHANGEBAR_MARGIN; extern int bibitemMaxWidth(BufferView *, LyXFont const &); -int LyXText::workWidth(BufferView * bview) const +int LyXText::workWidth(BufferView & bview) const { if (inset_owner) { - return inset_owner->textWidth(bview); + // FIXME: pass (const ?) ref + return inset_owner->textWidth(&bview); } - return bview->workWidth(); + return bview.workWidth(); } -int LyXText::workWidth(BufferView * bview, Inset * inset) const +int LyXText::workWidth(BufferView & bview, Inset * inset) const { - Paragraph * par = 0; - pos_type pos = -1; - - par = inset->parOwner(); - if (par) - pos = par->getPositionOfInset(inset); - - if (!par || pos == -1) { - lyxerr << "LyXText::workWidth: something is wrong," - " fall back to the brute force method" << endl; - Buffer::inset_iterator it = bview->buffer()->inset_iterator_begin(); - Buffer::inset_iterator end = bview->buffer()->inset_iterator_end(); - for (; it != end; ++it) { - if (&(*it) == inset) { - par = it.getPar(); - pos = it.getPos(); - break; - } - } - } + Paragraph * par = inset->parOwner(); + lyx::Assert(par); - if (!par) { - return workWidth(bview); - } + pos_type pos = par->getPositionOfInset(inset); + lyx::Assert(pos != -1); LyXLayout_ptr const & layout = par->layout(); @@ -106,21 +85,25 @@ int LyXText::workWidth(BufferView * bview, Inset * inset) const Row dummyrow; dummyrow.par(par); dummyrow.pos(pos); - return workWidth(bview) - leftMargin(bview, &dummyrow); + return workWidth(bview) - leftMargin(&bview, &dummyrow); } else { int dummy_y; Row * row = getRow(par, pos, dummy_y); Row * frow = row; while (frow->previous() && frow->par() == frow->previous()->par()) frow = frow->previous(); + + // FIXME: I don't understand this code - jbl + 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(); } if (maxw) return maxw; + } return workWidth(bview); } @@ -407,280 +390,6 @@ bool LyXText::isBoundary(Buffer const * buf, Paragraph * par, } -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; @@ -828,12 +537,12 @@ int LyXText::leftMargin(BufferView * bview, Row const * row) const break; } - if ((workWidth(bview) > 0) && + if ((workWidth(*bview) > 0) && !row->par()->params().leftIndent().zero()) { LyXLength const len = row->par()->params().leftIndent(); int const tw = inset_owner ? - inset_owner->latexTextWidth(bview) : workWidth(bview); + inset_owner->latexTextWidth(bview) : workWidth(*bview); x += len.inPixels(tw); } @@ -873,16 +582,16 @@ int LyXText::leftMargin(BufferView * bview, Row const * row) const } -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,54 +600,53 @@ int LyXText::rightMargin(Buffer const * buf, Row const * row) const // 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(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; } -int LyXText::labelEnd(BufferView * bview, Row const * row) const +int LyXText::labelEnd(BufferView & bview, Row const & row) const { - if (row->par()->layout()->margintype == MARGIN_MANUAL) { - Row tmprow; - tmprow = *row; - tmprow.pos(row->par()->size()); + if (row.par()->layout()->margintype == MARGIN_MANUAL) { + Row tmprow = row; + tmprow.pos(row.par()->size()); // just the beginning of the main body - return leftMargin(bview, &tmprow); - } else { - // LabelEnd is only needed, - // if the layout fills a flushleft label. - return 0; + return leftMargin(&bview, &tmprow); } + + // LabelEnd is only needed if the layout + // fills a flushleft label. + return 0; } @@ -956,7 +664,7 @@ LyXText::nextBreakPoint(BufferView * bview, Row const * row, int width) const // 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(); @@ -1039,7 +747,7 @@ LyXText::nextBreakPoint(BufferView * bview, Row const * row, int width) const getLabelFont(bview->buffer(), par)); if (par->isLineSeparator(i - 1)) x-= singleWidth(bview, par, i - 1); - int left_margin = labelEnd(bview, row); + int left_margin = labelEnd(*bview, *row); if (x < left_margin) x = left_margin; } @@ -1068,92 +776,91 @@ LyXText::nextBreakPoint(BufferView * bview, Row const * row, int width) const // returns the minimum space a row needs on the screen in pixel -int LyXText::fill(BufferView * bview, Row * row, int paper_width) const +int LyXText::fill(BufferView & bview, Row & row, int paper_width) const { if (paper_width < 0) return 0; int w; // get the pure distance - pos_type const last = row->lastPrintablePos(); + pos_type const last = row.lastPrintablePos(); // special handling of the right address boxes - if (row->par()->layout()->margintype == MARGIN_RIGHT_ADDRESS_BOX) { - int const tmpfill = row->fill(); - row->fill(0); // the minfill in MarginLeft() - w = leftMargin(bview, row); - row->fill(tmpfill); + if (row.par()->layout()->margintype == MARGIN_RIGHT_ADDRESS_BOX) { + int const tmpfill = row.fill(); + row.fill(0); // the minfill in MarginLeft() + w = leftMargin(&bview, &row); + row.fill(tmpfill); } else - w = leftMargin(bview, row); + w = leftMargin(&bview, &row); - LyXLayout_ptr const & layout = row->par()->layout(); + Paragraph * par = row.par(); + LyXLayout_ptr const & layout = par->layout(); - pos_type const main_body = row->par()->beginningOfMainBody(); - pos_type i = row->pos(); + pos_type const main_body = par->beginningOfMainBody(); + pos_type i = row.pos(); while (i <= last) { if (main_body > 0 && i == main_body) { - w += font_metrics::width(layout->labelsep, getLabelFont(bview->buffer(), row->par())); - if (row->par()->isLineSeparator(i - 1)) - w -= singleWidth(bview, row->par(), i - 1); + w += font_metrics::width(layout->labelsep, getLabelFont(bview.buffer(), par)); + if (par->isLineSeparator(i - 1)) + w -= singleWidth(&bview, par, i - 1); int left_margin = labelEnd(bview, row); if (w < left_margin) w = left_margin; } - w += singleWidth(bview, row->par(), i); + w += singleWidth(&bview, par, i); ++i; } if (main_body > 0 && main_body > last) { - w += font_metrics::width(layout->labelsep, getLabelFont(bview->buffer(), row->par())); - if (last >= 0 && row->par()->isLineSeparator(last)) - w -= singleWidth(bview, row->par(), last); + w += font_metrics::width(layout->labelsep, getLabelFont(bview.buffer(), par)); + if (last >= 0 && par->isLineSeparator(last)) + w -= singleWidth(&bview, par, last); int const left_margin = labelEnd(bview, row); if (w < left_margin) 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; } // returns the minimum space a manual label needs on the screen in pixel -int LyXText::labelFill(BufferView * bview, Row const * row) const +int LyXText::labelFill(BufferView & bview, Row const & row) const { - pos_type last = row->par()->beginningOfMainBody() - 1; + pos_type last = row.par()->beginningOfMainBody(); + + lyx::Assert(last > 0); + // -1 because a label ends either with a space that is in the label, // or with the beginning of a footnote that is outside the label. - - // I don't understand this code in depth, but sometimes "last" is - // less than 0 and this causes a crash. This fix seems to work - // correctly, but I bet the real error is elsewhere. The bug is - // triggered when you have an open footnote in a paragraph - // environment with a manual label. (Asger) - if (last < 0) last = 0; + --last; // a separator at this end does not count - if (row->par()->isLineSeparator(last)) + if (row.par()->isLineSeparator(last)) --last; int w = 0; - pos_type i = row->pos(); + pos_type i = row.pos(); while (i <= last) { - w += singleWidth(bview, row->par(), i); + w += singleWidth(&bview, row.par(), i); ++i; } int fill = 0; - if (!row->par()->params().labelWidthString().empty()) { - fill = max(font_metrics::width(row->par()->params().labelWidthString(), - getLabelFont(bview->buffer(), row->par())) - w, - 0); + string const & labwidstr = row.par()->params().labelWidthString(); + if (!labwidstr.empty()) { + LyXFont const labfont = getLabelFont(bview.buffer(), row.par()); + int const labwidth = font_metrics::width(labwidstr, labfont); + fill = max(labwidth - w, 0); } return fill; } -LColor::color LyXText::backgroundColor() +LColor::color LyXText::backgroundColor() const { if (inset_owner) return inset_owner->backgroundColor(); @@ -1267,13 +974,13 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row) const && 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 +989,7 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row) const 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 @@ -1385,14 +1092,13 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row) const // is it a bottom line? if (row->par() == par - && (!row->next() || row->next()->par() != row->par())) - { + && (!row->next() || row->next()->par() != row->par())) { // 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 @@ -1463,7 +1169,7 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row) const row->width(int(maxwidth + x)); if (inset_owner) { Row * r = firstrow; - width = max(0,workWidth(bview)); + width = max(0, workWidth(*bview)); while (r) { if (r->width() > width) width = r->width(); @@ -1484,7 +1190,7 @@ void LyXText::appendParagraph(BufferView * bview, Row * row) const pos_type const lastposition = row->par()->size(); do { // Get the next breakpoint - pos_type z = nextBreakPoint(bview, row, workWidth(bview)); + pos_type z = nextBreakPoint(bview, row, workWidth(*bview)); Row * tmprow = row; @@ -1501,20 +1207,43 @@ void LyXText::appendParagraph(BufferView * bview, Row * row) const // Set the dimensions of the row // fixed fill setting now by calling inset->update() in // SingleWidth when needed! - tmprow->fill(fill(bview, tmprow, workWidth(bview))); + tmprow->fill(fill(*bview, *tmprow, workWidth(*bview))); setHeightOfRow(bview, tmprow); } while (not_ready); } +// Do we even need this at all ? Code that uses RowPainter *already* +// sets need_break_row when it sees a CHANGED_IN_DRAW, though not +// quite like this +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()); + /* FIXME */ +} + + void LyXText::breakAgain(BufferView * bview, Row * row) const { bool not_ready = true; do { // get the next breakpoint - pos_type z = nextBreakPoint(bview, row, workWidth(bview)); + pos_type z = nextBreakPoint(bview, row, workWidth(*bview)); Row * tmprow = row; if (z < row->par()->size()) { @@ -1548,7 +1277,7 @@ void LyXText::breakAgain(BufferView * bview, Row * row) const } // set the dimensions of the row - tmprow->fill(fill(bview, tmprow, workWidth(bview))); + tmprow->fill(fill(*bview, *tmprow, workWidth(*bview))); setHeightOfRow(bview, tmprow); } while (not_ready); } @@ -1558,7 +1287,7 @@ void LyXText::breakAgain(BufferView * bview, Row * row) const void LyXText::breakAgainOneRow(BufferView * bview, Row * row) { // get the next breakpoint - pos_type z = nextBreakPoint(bview, row, workWidth(bview)); + pos_type z = nextBreakPoint(bview, row, workWidth(*bview)); Row * tmprow = row; if (z < row->par()->size()) { @@ -1590,7 +1319,7 @@ void LyXText::breakAgainOneRow(BufferView * bview, Row * row) } // set the dimensions of the row - tmprow->fill(fill(bview, tmprow, workWidth(bview))); + tmprow->fill(fill(*bview, *tmprow, workWidth(*bview))); setHeightOfRow(bview, tmprow); } @@ -1673,7 +1402,7 @@ void LyXText::breakParagraph(BufferView * bview, char keep_layout) removeParagraph(cursor.row()); // set the dimensions of the cursor row - cursor.row()->fill(fill(bview, cursor.row(), workWidth(bview))); + cursor.row()->fill(fill(*bview, *cursor.row(), workWidth(*bview))); setHeightOfRow(bview, cursor.row()); @@ -1861,14 +1590,14 @@ void LyXText::insertChar(BufferView * bview, char c) { pos_type z = nextBreakPoint(bview, row->previous(), - workWidth(bview)); + workWidth(*bview)); if (z >= row->pos()) { row->pos(z + 1); // set the dimensions of the row above - row->previous()->fill(fill(bview, - row->previous(), - workWidth(bview))); + row->previous()->fill(fill(*bview, + *row->previous(), + workWidth(*bview))); setHeightOfRow(bview, row->previous()); @@ -1904,7 +1633,7 @@ void LyXText::insertChar(BufferView * bview, char c) if (row->fill() >= 0) { // needed because a newline will set fill to -1. Otherwise // we would not get a rebreak! - row->fill(fill(bview, row, workWidth(bview))); + row->fill(fill(*bview, *row, workWidth(*bview))); } if (c == Paragraph::META_INSET || row->fill() < 0) { @@ -1998,10 +1727,10 @@ void LyXText::prepareToPrint(BufferView * bview, bool const is_rtl = row->par()->isRightToLeftPar(bview->buffer()->params); if (is_rtl) { - x = (workWidth(bview) > 0) - ? rightMargin(bview->buffer(), row) : 0; + x = (workWidth(*bview) > 0) + ? rightMargin(*bview->buffer(), *row) : 0; } else - x = (workWidth(bview) > 0) + x = (workWidth(*bview) > 0) ? leftMargin(bview, row) : 0; // is there a manual margin with a manual label @@ -2012,7 +1741,7 @@ void LyXText::prepareToPrint(BufferView * bview, // one more since labels are left aligned nlh = row->numberOfLabelHfills() + 1; if (nlh && !row->par()->getLabelWidthString().empty()) { - fill_label_hfill = labelFill(bview, row) / nlh; + fill_label_hfill = labelFill(*bview, *row) / nlh; } } @@ -2025,7 +1754,7 @@ void LyXText::prepareToPrint(BufferView * bview, // we don't have to look at the alignment if it is ALIGN_LEFT and // if the row is already larger then the permitted width as then // we force the LEFT_ALIGN'edness! - } else if (static_cast(row->width()) < workWidth(bview)) { + } else if (static_cast(row->width()) < workWidth(*bview)) { // is it block, flushleft or flushright? // set x how you need it int align; @@ -2354,7 +2083,7 @@ LyXText::selectNextWordToSpellcheck(BufferView * bview, float & value) const 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 +2116,7 @@ LyXText::selectNextWordToSpellcheck(BufferView * bview, float & value) const // 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 @@ -2495,14 +2224,7 @@ void LyXText::deleteLineForward(BufferView * bview) } -// Change the case of a word at cursor position. -// This function directly manipulates Paragraph::text because there -// is no Paragraph::SetChar currently. I did what I could to ensure -// that it is correct. I guess part of it should be moved to -// Paragraph, but it will have to change for 1.1 anyway. At least -// it does not access outside of the allocated array as the older -// version did. (JMarc) -void LyXText::changeCase(BufferView * bview, LyXText::TextCase action) +void LyXText::changeCase(BufferView & bview, LyXText::TextCase action) { LyXCursor from; LyXCursor to; @@ -2512,21 +2234,12 @@ void LyXText::changeCase(BufferView * bview, LyXText::TextCase action) to = selection.end; } else { getWord(from, to, PARTIAL_WORD); - setCursor(bview, to.par(), to.pos() + 1); + setCursor(&bview, to.par(), to.pos() + 1); } - changeRegionCase(bview, from, to, action); -} - - -void LyXText::changeRegionCase(BufferView * bview, - LyXCursor const & from, - LyXCursor const & to, - LyXText::TextCase action) -{ lyx::Assert(from <= to); - setUndo(bview, Undo::FINISH, from.par(), to.par()->next()); + setUndo(&bview, Undo::FINISH, from.par(), to.par()->next()); pos_type pos = from.pos(); Paragraph * par = from.par(); @@ -2554,14 +2267,14 @@ void LyXText::changeRegionCase(BufferView * bview, } #warning changes par->setChar(pos, c); - checkParagraph(bview, par, pos); + checkParagraph(&bview, par, pos); ++pos; } if (to.row() != from.row()) { refresh_y = from.y() - from.row()->baseline(); refresh_row = from.row(); - status(bview, LyXText::NEED_MORE_REFRESH); + status(&bview, LyXText::NEED_MORE_REFRESH); } } @@ -2579,8 +2292,8 @@ void LyXText::transposeChars(BufferView & bview) 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); @@ -2597,10 +2310,7 @@ void LyXText::transposeChars(BufferView & bview) tmppar->insertChar(ipos, c1); tmppar->insertChar(ipos + 1, c2); - /* fugly */ - BufferView * bv(const_cast(&bview)); - - checkParagraph(bv, tmppar, tmppos); + checkParagraph(&bview, tmppar, tmppos); } @@ -2849,7 +2559,7 @@ void LyXText::backspace(BufferView * bview) // is there a break one row above if (row->previous() && row->previous()->par() == row->par()) { z = nextBreakPoint(bview, row->previous(), - workWidth(bview)); + workWidth(*bview)); if (z >= row->pos()) { row->pos(z + 1); @@ -2870,8 +2580,7 @@ void LyXText::backspace(BufferView * bview) // set the dimensions of the row above y -= tmprow->height(); - tmprow->fill(fill(bview, tmprow, - workWidth(bview))); + tmprow->fill(fill(*bview, *tmprow, workWidth(*bview))); setHeightOfRow(bview, tmprow); refresh_y = y; @@ -2893,7 +2602,7 @@ void LyXText::backspace(BufferView * bview) // break the cursor row again if (row->next() && row->next()->par() == row->par() && (row->lastPos() == row->par()->size() - 1 || - nextBreakPoint(bview, row, workWidth(bview)) != row->lastPos())) { + nextBreakPoint(bview, row, workWidth(*bview)) != row->lastPos())) { // it can happen that a paragraph loses one row // without a real breakup. This is when a word @@ -2922,7 +2631,7 @@ void LyXText::backspace(BufferView * bview) need_break_row = 0; } else { // set the dimensions of the row - row->fill(fill(bview, row, workWidth(bview))); + row->fill(fill(*bview, *row, workWidth(*bview))); int const tmpheight = row->height(); setHeightOfRow(bview, row); if (tmpheight == row->height()) @@ -2961,760 +2670,6 @@ void LyXText::backspace(BufferView * bview) } -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(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(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 diff --git a/src/text2.C b/src/text2.C index d54274f447..c4d67743d6 100644 --- a/src/text2.C +++ b/src/text2.C @@ -53,17 +53,17 @@ using lyx::pos_type; 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) {} @@ -409,21 +409,21 @@ void LyXText::toggleInset(BufferView * bview) /* used in setlayout */ // Asger is not sure we want to do this... -void LyXText::makeFontEntriesLayoutSpecific(Buffer const * buf, - Paragraph * par) +void LyXText::makeFontEntriesLayoutSpecific(Buffer const & buf, + Paragraph & par) { - LyXLayout_ptr const & layout = par->layout(); + LyXLayout_ptr const & layout = par.layout(); LyXFont layoutfont; - for (pos_type pos = 0; pos < par->size(); ++pos) { - if (pos < par->beginningOfMainBody()) + for (pos_type pos = 0; pos < par.size(); ++pos) { + if (pos < par.beginningOfMainBody()) layoutfont = layout->labelfont; else layoutfont = layout->font; - LyXFont tmpfont = par->getFontSettings(buf->params, pos); + LyXFont tmpfont = par.getFontSettings(buf.params, pos); tmpfont.reduce(layoutfont); - par->setFont(pos, tmpfont); + par.setFont(pos, tmpfont); } } @@ -458,7 +458,7 @@ Paragraph * LyXText::setLayout(BufferView * bview, do { par->applyLayout(lyxlayout); - makeFontEntriesLayoutSpecific(bview->buffer(), par); + makeFontEntriesLayoutSpecific(*bview->buffer(), *par); Paragraph * fppar = par; fppar->params().spaceTop(lyxlayout->fill_top ? VSpace(VSpace::VFILL) @@ -1634,7 +1634,7 @@ void LyXText::checkParagraph(BufferView * bview, Paragraph * par, // is there a break one row above if (row->previous() && row->previous()->par() == row->par()) { - z = nextBreakPoint(bview, row->previous(), workWidth(bview)); + z = nextBreakPoint(bview, row->previous(), workWidth(*bview)); if (z >= row->pos()) { // set the dimensions of the row above y -= row->previous()->height(); @@ -2373,6 +2373,12 @@ bool LyXText::isTopLevel() const } +bool LyXText::isInInset() const +{ + return inset_owner; +} + + int defaultRowHeight() { LyXFont const font(LyXFont::ALL_SANE); diff --git a/src/text3.C b/src/text3.C index e37f2bf1dc..679996ea18 100644 --- a/src/text3.C +++ b/src/text3.C @@ -995,7 +995,7 @@ Inset::RESULT LyXText::dispatch(FuncRequest const & cmd) case LFUN_UPCASE_WORD: update(bv, false); - changeCase(bv, LyXText::text_uppercase); + changeCase(*bv, LyXText::text_uppercase); if (inset_owner) bv->updateInset(inset_owner, true); update(bv); @@ -1003,7 +1003,7 @@ Inset::RESULT LyXText::dispatch(FuncRequest const & cmd) case LFUN_LOWCASE_WORD: update(bv, false); - changeCase(bv, LyXText::text_lowercase); + changeCase(*bv, LyXText::text_lowercase); if (inset_owner) bv->updateInset(inset_owner, true); update(bv); @@ -1011,7 +1011,7 @@ Inset::RESULT LyXText::dispatch(FuncRequest const & cmd) case LFUN_CAPITALIZE_WORD: update(bv, false); - changeCase(bv, LyXText::text_capitalization); + changeCase(*bv, LyXText::text_capitalization); if (inset_owner) bv->updateInset(inset_owner, true); update(bv); diff --git a/src/vspace.C b/src/vspace.C index f62d348c10..a87181a6d3 100644 --- a/src/vspace.C +++ b/src/vspace.C @@ -465,7 +465,7 @@ string const VSpace::asLatexCommand(BufferParams const & params) const -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 @@ int VSpace::inPixels(BufferView const * bv) const 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 @@ int VSpace::inPixels(BufferView const * bv) const break; case LENGTH: - retval = len_.len().inPixels(bv->workWidth()); + retval = len_.len().inPixels(bv.workWidth()); break; } diff --git a/src/vspace.h b/src/vspace.h index 95b68bfe7e..9109e95a64 100644 --- a/src/vspace.h +++ b/src/vspace.h @@ -62,7 +62,8 @@ public: /// 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_; -- 2.39.5