#include "buffer_funcs.h"
#include "BufferParams.h"
#include "BufferView.h"
-#include "bufferview_funcs.h"
+#include "Changes.h"
#include "Cursor.h"
#include "ParIterator.h"
-#include "CoordCache.h"
#include "CutAndPaste.h"
#include "debug.h"
#include "DispatchResult.h"
#include "Length.h"
#include "Lexer.h"
#include "LyXRC.h"
-#include "Row.h"
-#include "MetricsInfo.h"
#include "Paragraph.h"
#include "paragraph_funcs.h"
#include "ParagraphParameters.h"
-#include "rowpainter.h"
-#include "Undo.h"
+#include "TextMetrics.h"
#include "VSpace.h"
#include "WordLangTuple.h"
#include "support/convert.h"
#include <boost/current_function.hpp>
+#include <boost/next_prior.hpp>
#include <sstream>
BufferParams const & bp = buf.params();
if (token[0] != '\\') {
-#if 0
- string::const_iterator cit = token.begin();
- for (; cit != token.end(); ++cit)
- par.insertChar(par.size(), (*cit), font, change);
-#else
docstring dstr = lex.getDocString();
- docstring::const_iterator cit = dstr.begin();
- docstring::const_iterator cend = dstr.end();
- for (; cit != cend; ++cit)
- par.insertChar(par.size(), *cit, font, change);
-#endif
+ par.appendString(dstr, font, change);
+
} else if (token == "\\begin_layout") {
lex.eatLine();
- string layoutname = lex.getString();
+ docstring layoutname = lex.getDocString();
font = Font(Font::ALL_INHERIT, bp.language);
change = Change(Change::UNCHANGED);
if (!hasLayout) {
errorList.push_back(ErrorItem(_("Unknown layout"),
bformat(_("Layout '%1$s' does not exist in textclass '%2$s'\nTrying to use the default instead.\n"),
- from_utf8(layoutname), from_utf8(tclass.name())), par.id(), 0, par.size()));
+ layoutname, from_utf8(tclass.name())), par.id(), 0, par.size()));
layoutname = tclass.defaultLayoutName();
}
par.layout(bp.getTextClass()[layoutname]);
// Test whether the layout is obsolete.
- Layout_ptr const & layout = par.layout();
+ LayoutPtr const & layout = par.layout();
if (!layout->obsoleted_by().empty())
par.layout(bp.getTextClass()[layout->obsoleted_by()]);
// Insets don't make sense in a free-spacing context! ---Kayvan
if (par.isFreeSpacing()) {
if (token == "\\InsetSpace")
- par.insertChar(par.size(), ' ', font, change);
+ par.appendChar(' ', font, change);
else if (lex.isOK()) {
lex.next();
string const next_token = lex.getString();
if (next_token == "\\-")
- par.insertChar(par.size(), '-', font, change);
+ par.appendChar('-', font, change);
else {
lex.printError("Token `$$Token' "
"is in free space "
font, change);
}
} else if (token == "\\backslash") {
- par.insertChar(par.size(), '\\', font, change);
+ par.appendChar('\\', font, change);
} else if (token == "\\newline") {
auto_ptr<Inset> inset(new InsetNewline);
inset->read(buf, lex);
} // namespace anon
+bool Text::empty() const
+{
+ return pars_.empty() || (pars_.size() == 1 && pars_[0].empty()
+ // FIXME: Should we consider the labeled type as empty too?
+ && pars_[0].layout()->labeltype == LABEL_NO_LABEL);
+}
+
double Text::spacing(Buffer const & buffer,
Paragraph const & par) const
}
-int Text::singleWidth(Buffer const & buffer, Paragraph const & par,
- pos_type pos) const
-{
- return singleWidth(par, pos, par.getChar(pos),
- getFont(buffer, par, pos));
-}
-
-
-int Text::singleWidth(Paragraph const & par,
- pos_type pos, char_type c, Font const & font) const
-{
- // The most common case is handled first (Asger)
- if (isPrintable(c)) {
- Language const * language = font.language();
- if (language->rightToLeft()) {
- if (language->lang() == "arabic_arabtex" ||
- language->lang() == "arabic_arabi" ||
- language->lang() == "farsi") {
- if (Encodings::isComposeChar_arabic(c))
- return 0;
- c = par.transformChar(c, pos);
- } else if (language->lang() == "hebrew" &&
- Encodings::isComposeChar_hebrew(c))
- return 0;
- }
- return theFontMetrics(font).width(c);
- }
-
- if (c == Paragraph::META_INSET)
- return par.getInset(pos)->width();
-
- return theFontMetrics(font).width(c);
-}
-
-
-int Text::leftMargin(Buffer const & buffer, int max_width, pit_type pit) const
-{
- BOOST_ASSERT(pit >= 0);
- BOOST_ASSERT(pit < int(pars_.size()));
- return leftMargin(buffer, max_width, pit, pars_[pit].size());
-}
-
-
-int Text::leftMargin(Buffer const & buffer, int max_width,
- pit_type const pit, pos_type const pos) const
-{
- BOOST_ASSERT(pit >= 0);
- BOOST_ASSERT(pit < int(pars_.size()));
- Paragraph const & par = pars_[pit];
- BOOST_ASSERT(pos >= 0);
- BOOST_ASSERT(pos <= par.size());
- //lyxerr << "Text::leftMargin: pit: " << pit << " pos: " << pos << endl;
- TextClass const & tclass = buffer.params().getTextClass();
- Layout_ptr const & layout = par.layout();
-
- string parindent = layout->parindent;
-
- int l_margin = 0;
-
- if (isMainText(buffer))
- l_margin += changebarMargin();
-
- // FIXME UNICODE
- docstring leftm = from_utf8(tclass.leftmargin());
- l_margin += theFontMetrics(buffer.params().getFont()).signedWidth(leftm);
-
- if (par.getDepth() != 0) {
- // find the next level paragraph
- pit_type newpar = outerHook(pit, pars_);
- if (newpar != pit_type(pars_.size())) {
- if (pars_[newpar].layout()->isEnvironment()) {
- l_margin = leftMargin(buffer, max_width, newpar);
- }
- if (par.layout() == tclass.defaultLayout()) {
- if (pars_[newpar].params().noindent())
- parindent.erase();
- else
- parindent = pars_[newpar].layout()->parindent;
- }
- }
- }
-
- // This happens after sections in standard classes. The 1.3.x
- // code compared depths too, but it does not seem necessary
- // (JMarc)
- if (par.layout() == tclass.defaultLayout()
- && pit > 0 && pars_[pit - 1].layout()->nextnoindent)
- parindent.erase();
-
- Font const labelfont = getLabelFont(buffer, par);
- FontMetrics const & labelfont_metrics = theFontMetrics(labelfont);
-
- switch (layout->margintype) {
- case MARGIN_DYNAMIC:
- if (!layout->leftmargin.empty()) {
- // FIXME UNICODE
- docstring leftm = from_utf8(layout->leftmargin);
- l_margin += theFontMetrics(buffer.params().getFont()).signedWidth(leftm);
- }
- if (!par.getLabelstring().empty()) {
- // FIXME UNICODE
- docstring labin = from_utf8(layout->labelindent);
- l_margin += labelfont_metrics.signedWidth(labin);
- docstring labstr = par.getLabelstring();
- l_margin += labelfont_metrics.width(labstr);
- docstring labsep = from_utf8(layout->labelsep);
- l_margin += labelfont_metrics.width(labsep);
- }
- break;
-
- case MARGIN_MANUAL: {
- // FIXME UNICODE
- docstring labin = from_utf8(layout->labelindent);
- l_margin += labelfont_metrics.signedWidth(labin);
- // The width of an empty par, even with manual label, should be 0
- if (!par.empty() && pos >= par.beginOfBody()) {
- if (!par.getLabelWidthString().empty()) {
- docstring labstr = par.getLabelWidthString();
- l_margin += labelfont_metrics.width(labstr);
- docstring labsep = from_utf8(layout->labelsep);
- l_margin += labelfont_metrics.width(labsep);
- }
- }
- break;
- }
-
- case MARGIN_STATIC: {
- // FIXME UNICODE
- docstring leftm = from_utf8(layout->leftmargin);
- l_margin += theFontMetrics(buffer.params().getFont()).signedWidth(leftm)
- * 4 / (par.getDepth() + 4);
- break;
- }
-
- case MARGIN_FIRST_DYNAMIC:
- if (layout->labeltype == LABEL_MANUAL) {
- if (pos >= par.beginOfBody()) {
- // FIXME UNICODE
- l_margin += labelfont_metrics.signedWidth(
- from_utf8(layout->leftmargin));
- } else {
- // FIXME UNICODE
- l_margin += labelfont_metrics.signedWidth(
- from_utf8(layout->labelindent));
- }
- } else if (pos != 0
- // Special case to fix problems with
- // theorems (JMarc)
- || (layout->labeltype == LABEL_STATIC
- && layout->latextype == LATEX_ENVIRONMENT
- && !isFirstInSequence(pit, pars_))) {
- // FIXME UNICODE
- l_margin += labelfont_metrics.signedWidth(from_utf8(layout->leftmargin));
- } else if (layout->labeltype != LABEL_TOP_ENVIRONMENT
- && layout->labeltype != LABEL_BIBLIO
- && layout->labeltype !=
- LABEL_CENTERED_TOP_ENVIRONMENT) {
- l_margin += labelfont_metrics.signedWidth(from_utf8(layout->labelindent));
- l_margin += labelfont_metrics.width(from_utf8(layout->labelsep));
- l_margin += labelfont_metrics.width(par.getLabelstring());
- }
- break;
-
- case MARGIN_RIGHT_ADDRESS_BOX: {
-#if 0
- // ok, a terrible hack. The left margin depends on the widest
- // row in this paragraph.
- RowList::iterator rit = par.rows().begin();
- RowList::iterator end = par.rows().end();
-#ifdef WITH_WARNINGS
-#warning This is wrong.
-#endif
- int minfill = max_width;
- for ( ; rit != end; ++rit)
- if (rit->fill() < minfill)
- minfill = rit->fill();
- l_margin += theFontMetrics(params.getFont()).signedWidth(layout->leftmargin);
- l_margin += minfill;
-#endif
- // also wrong, but much shorter.
- l_margin += max_width / 2;
- break;
- }
- }
-
- if (!par.params().leftIndent().zero())
- l_margin += par.params().leftIndent().inPixels(max_width);
-
- LyXAlignment align;
-
- if (par.params().align() == LYX_ALIGN_LAYOUT)
- align = layout->align;
- else
- align = par.params().align();
-
- // set the correct parindent
- if (pos == 0
- && (layout->labeltype == LABEL_NO_LABEL
- || layout->labeltype == LABEL_TOP_ENVIRONMENT
- || layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT
- || (layout->labeltype == LABEL_STATIC
- && layout->latextype == LATEX_ENVIRONMENT
- && !isFirstInSequence(pit, pars_)))
- && align == LYX_ALIGN_BLOCK
- && !par.params().noindent()
- // in some insets, paragraphs are never indented
- && !(par.inInset() && par.inInset()->neverIndent(buffer))
- // display style insets are always centered, omit indentation
- && !(!par.empty()
- && par.isInset(pos)
- && par.getInset(pos)->display())
- && (par.layout() != tclass.defaultLayout()
- || buffer.params().paragraph_separation ==
- BufferParams::PARSEP_INDENT))
- {
- docstring din = from_utf8(parindent);
- l_margin += theFontMetrics(buffer.params().getFont()).signedWidth(din);
- }
-
- return l_margin;
-}
-
-
-Color_color Text::backgroundColor() const
-{
- return Color_color(Color::color(background_color_));
-}
-
-
-void Text::breakParagraph(Cursor & cur, bool keep_layout)
+void Text::breakParagraph(Cursor & cur, bool inverse_logic)
{
BOOST_ASSERT(this == cur.text());
pit_type cpit = cur.pit();
TextClass const & tclass = cur.buffer().params().getTextClass();
- Layout_ptr const & layout = cpar.layout();
+ LayoutPtr const & layout = cpar.layout();
// this is only allowed, if the current paragraph is not empty
// or caption and if it has not the keepempty flag active
cpar.eraseChar(cur.pos(), cur.buffer().params().trackChanges);
// What should the layout for the new paragraph be?
- int preserve_layout = 0;
- if (keep_layout)
- preserve_layout = 2;
- else
- preserve_layout = layout->isEnvironment();
+ bool keep_layout = inverse_logic ?
+ !layout->isEnvironment()
+ : layout->isEnvironment();
// We need to remember this before we break the paragraph, because
// that invalidates the layout variable
bool const isempty = cpar.allowEmpty() && cpar.empty();
lyx::breakParagraph(cur.buffer().params(), paragraphs(), cpit,
- cur.pos(), preserve_layout);
+ cur.pos(), keep_layout);
// After this, neither paragraph contains any rows!
BOOST_ASSERT(this == cur.text());
BOOST_ASSERT(c != Paragraph::META_INSET);
- recordUndo(cur, Undo::INSERT);
+ cur.recordUndo(INSERT_UNDO);
+ TextMetrics const & tm = cur.bv().textMetrics(this);
Buffer const & buffer = cur.buffer();
Paragraph & par = cur.paragraph();
// try to remove this
static docstring const number_unary_operators = from_ascii("+-");
static docstring const number_seperators = from_ascii(".,:");
- if (current_font.number() == Font::ON) {
+ if (cur.current_font.number() == Font::ON) {
if (!isDigit(c) && !contains(number_operators, c) &&
!(contains(number_seperators, c) &&
cur.pos() != 0 &&
cur.pos() != cur.lastpos() &&
- getFont(buffer, par, cur.pos()).number() == Font::ON &&
- getFont(buffer, par, cur.pos() - 1).number() == Font::ON)
+ tm.getDisplayFont(pit, cur.pos()).number() == Font::ON &&
+ tm.getDisplayFont(pit, cur.pos() - 1).number() == Font::ON)
)
number(cur); // Set current_font.number to OFF
} else if (isDigit(c) &&
- real_current_font.isVisibleRightToLeft()) {
+ cur.real_current_font.isVisibleRightToLeft()) {
number(cur); // Set current_font.number to ON
if (cur.pos() != 0) {
|| par.isSeparator(cur.pos() - 2)
|| par.isNewline(cur.pos() - 2))
) {
- setCharFont(buffer, pit, cur.pos() - 1, current_font);
+ setCharFont(buffer, pit, cur.pos() - 1, cur.current_font,
+ tm.font_);
} else if (contains(number_seperators, c)
&& cur.pos() >= 2
- && getFont(buffer, par, cur.pos() - 2).number() == Font::ON) {
- setCharFont(buffer, pit, cur.pos() - 1, current_font);
+ && tm.getDisplayFont(pit, cur.pos() - 2).number() == Font::ON) {
+ setCharFont(buffer, pit, cur.pos() - 1, cur.current_font,
+ tm.font_);
}
}
}
if ((cur.pos() >= 2) && (par.isLineSeparator(cur.pos() - 1))) {
// get font in front and behind the space in question. But do NOT
// use getFont(cur.pos()) because the character c is not inserted yet
- Font const & pre_space_font = getFont(buffer, par, cur.pos() - 2);
- Font const & post_space_font = real_current_font;
+ Font const & pre_space_font = tm.getDisplayFont(cur.pit(), cur.pos() - 2);
+ Font const & post_space_font = cur.real_current_font;
bool pre_space_rtl = pre_space_font.isVisibleRightToLeft();
bool post_space_rtl = post_space_font.isVisibleRightToLeft();
// adjacent character whose direction is the paragraph's
// direction; don't touch other properties of the font
Language const * lang =
- (pre_space_rtl == par.isRightToLeftPar(buffer.params())) ?
+ (pre_space_rtl == par.isRTL(buffer.params())) ?
pre_space_font.language() : post_space_font.language();
- Font space_font = getFont(buffer, par, cur.pos() - 1);
+ Font space_font = tm.getDisplayFont(cur.pit(), cur.pos() - 1);
space_font.setLanguage(lang);
par.setFont(cur.pos() - 1, space_font);
}
}
}
- par.insertChar(cur.pos(), c, current_font, cur.buffer().params().trackChanges);
+ par.insertChar(cur.pos(), c, cur.current_font, cur.buffer().params().trackChanges);
checkBufferStructure(cur.buffer(), cur);
// cur.updateFlags(Update::Force);
setCursor(cur.top(), cur.pit(), cur.pos() + 1);
- charInserted();
+ charInserted(cur);
}
-void Text::charInserted()
+void Text::charInserted(Cursor & cur)
{
// Here we call finishUndo for every 20 characters inserted.
// This is from my experience how emacs does it. (Lgb)
if (counter < 20) {
++counter;
} else {
- finishUndo();
+ cur.finishUndo();
counter = 0;
}
}
if (!cur.selection())
return;
- recordUndoSelection(cur, Undo::ATOMIC);
+ cur.recordUndoSelection();
pit_type begPit = cur.selectionBegin().pit();
pit_type endPit = cur.selectionEnd().pit();
//
- finishUndo();
+ cur.finishUndo();
cur.clearSelection();
setCursorIntern(cur, begPit, begPos);
cur.updateFlags(Update::Force);
}
-// Delete from cursor up to the end of the current or next word.
void Text::deleteWordForward(Cursor & cur)
{
BOOST_ASSERT(this == cur.text());
if (cur.lastpos() == 0)
- cursorRight(cur);
+ cursorForward(cur);
else {
cur.resetAnchor();
cur.selection() = true;
}
-// Delete from cursor to start of current or prior word.
void Text::deleteWordBackward(Cursor & cur)
{
BOOST_ASSERT(this == cur.text());
if (cur.lastpos() == 0)
- cursorLeft(cur);
+ cursorBackward(cur);
else {
cur.resetAnchor();
cur.selection() = true;
// Kill to end of line.
-void Text::deleteLineForward(Cursor & cur)
-{
- BOOST_ASSERT(this == cur.text());
- if (cur.lastpos() == 0) {
- // Paragraph is empty, so we just go to the right
- cursorRight(cur);
- } else {
- cur.resetAnchor();
- cur.selection() = true; // to avoid deletion
- cursorEnd(cur);
- cur.setSelection();
- // What is this test for ??? (JMarc)
- if (!cur.selection())
- deleteWordForward(cur);
- else
- cutSelection(cur, true, false);
- checkBufferStructure(cur.buffer(), cur);
- }
-}
-
-
void Text::changeCase(Cursor & cur, Text::TextCase action)
{
BOOST_ASSERT(this == cur.text());
cursorRightOneWord(cur);
}
- recordUndoSelection(cur, Undo::ATOMIC);
+ cur.recordUndoSelection();
pit_type begPit = from.pit();
pit_type endPit = to.pit();
}
Paragraph const & prevpar = prevcur.paragraph();
if (cur.pit() > 0 && par.layout() == prevpar.layout()) {
- recordUndo(cur, Undo::ATOMIC, prevcur.pit());
+ cur.recordUndo(ATOMIC_UNDO, prevcur.pit());
mergeParagraph(bufparams, cur.text()->paragraphs(),
prevcur.pit());
updateLabels(cur.buffer());
if (cur.pos() != cur.lastpos()) {
// this is the code for a normal delete, not pasting
// any paragraphs
- recordUndo(cur, Undo::DELETE);
+ cur.recordUndo(DELETE_UNDO);
if(!par.eraseChar(cur.pos(), cur.buffer().params().trackChanges)) {
// the character has been logically deleted only => skip it
- cur.forwardPosNoDescend();
+ cur.top().forwardPos();
}
checkBufferStructure(cur.buffer(), cur);
needsUpdate = true;
// is it an empty paragraph?
if (cur.lastpos() == 0
|| (cur.lastpos() == 1 && par.isSeparator(0))) {
- recordUndo(cur, Undo::ATOMIC, prevcur.pit(), cur.pit());
+ cur.recordUndo(ATOMIC_UNDO, prevcur.pit(), cur.pit());
plist.erase(boost::next(plist.begin(), cur.pit()));
needsUpdate = true;
}
// is previous par empty?
else if (prevcur.lastpos() == 0
|| (prevcur.lastpos() == 1 && prevpar.isSeparator(0))) {
- recordUndo(cur, Undo::ATOMIC, prevcur.pit(), cur.pit());
+ cur.recordUndo(ATOMIC_UNDO, prevcur.pit(), cur.pit());
plist.erase(boost::next(plist.begin(), prevcur.pit()));
needsUpdate = true;
}
// Correction: Pasting is always allowed with standard-layout
else if (par.layout() == prevpar.layout()
|| par.layout() == tclass.defaultLayout()) {
- recordUndo(cur, Undo::ATOMIC, prevcur.pit());
+ cur.recordUndo(ATOMIC_UNDO, prevcur.pit());
mergeParagraph(bufparams, plist, prevcur.pit());
needsUpdate = true;
}
} else {
// this is the code for a normal backspace, not pasting
// any paragraphs
- recordUndo(cur, Undo::DELETE);
- // We used to do cursorLeftIntern() here, but it is
+ cur.recordUndo(DELETE_UNDO);
+ // We used to do cursorBackwardIntern() here, but it is
// not a good idea since it triggers the auto-delete
- // mechanism. So we do a cursorLeftIntern()-lite,
+ // mechanism. So we do a cursorBackwardIntern()-lite,
// without the dreaded mechanism. (JMarc)
setCursorIntern(cur, cur.pit(), cur.pos() - 1,
false, cur.boundary());
}
if (cur.pos() == cur.lastpos())
- setCurrentFont(cur);
+ cur.setCurrentFont();
needsUpdate |= handleBibitems(cur);
bool Text::dissolveInset(Cursor & cur) {
BOOST_ASSERT(this == cur.text());
- if (isMainText(*cur.bv().buffer()) || cur.inset().nargs() != 1)
+ if (isMainText(cur.bv().buffer()) || cur.inset().nargs() != 1)
return false;
- recordUndoInset(cur);
+ cur.recordUndoInset();
cur.selHandle(false);
// save position
pos_type spos = cur.pos();
// change it to the buffer language.
ParagraphList::iterator it = plist.begin();
ParagraphList::iterator it_end = plist.end();
- for (; it != it_end; it++) {
- it->changeLanguage(b.params(), latex_language,
- b.getLanguage());
- }
+ for (; it != it_end; it++)
+ it->changeLanguage(b.params(), latex_language, b.language());
- pasteParagraphList(cur, plist, b.params().textclass,
+ pasteParagraphList(cur, plist, b.params().getTextClassPtr(),
b.errorList("Paste"));
// restore position
cur.pit() = std::min(cur.lastpit(), spit);
}
-// only used for inset right now. should also be used for main text
-void Text::draw(PainterInfo & pi, int x, int y) const
-{
- paintTextInset(*this, pi, x, y);
-}
-
-
-// only used for inset right now. should also be used for main text
-void Text::drawSelection(PainterInfo & pi, int x, int) const
-{
- Cursor & cur = pi.base.bv->cursor();
- if (!cur.selection())
- return;
- if (!ptr_cmp(cur.text(), this))
- return;
-
- LYXERR(Debug::DEBUG)
- << BOOST_CURRENT_FUNCTION
- << "draw selection at " << x
- << endl;
-
- DocIterator beg = cur.selectionBegin();
- DocIterator end = cur.selectionEnd();
-
- BufferView & bv = *pi.base.bv;
-
- // the selection doesn't touch the visible screen?
- if (bv_funcs::status(&bv, beg) == bv_funcs::CUR_BELOW
- || bv_funcs::status(&bv, end) == bv_funcs::CUR_ABOVE)
- return;
-
- TextMetrics const & tm = bv.textMetrics(this);
- ParagraphMetrics const & pm1 = tm.parMetrics(beg.pit());
- ParagraphMetrics const & pm2 = tm.parMetrics(end.pit());
- Row const & row1 = pm1.getRow(beg.pos(), beg.boundary());
- Row const & row2 = pm2.getRow(end.pos(), end.boundary());
-
- // clip above
- int middleTop;
- bool const clipAbove =
- (bv_funcs::status(&bv, beg) == bv_funcs::CUR_ABOVE);
- if (clipAbove)
- middleTop = 0;
- else
- middleTop = bv_funcs::getPos(bv, beg, beg.boundary()).y_ + row1.descent();
-
- // clip below
- int middleBottom;
- bool const clipBelow =
- (bv_funcs::status(&bv, end) == bv_funcs::CUR_BELOW);
- if (clipBelow)
- middleBottom = bv.workHeight();
- else
- middleBottom = bv_funcs::getPos(bv, end, end.boundary()).y_ - row2.ascent();
-
- // start and end in the same line?
- if (!(clipAbove || clipBelow) && &row1 == &row2)
- // then only draw this row's selection
- drawRowSelection(pi, x, row1, beg, end, false, false);
- else {
- if (!clipAbove) {
- // get row end
- DocIterator begRowEnd = beg;
- begRowEnd.pos() = row1.endpos();
- begRowEnd.boundary(true);
-
- // draw upper rectangle
- drawRowSelection(pi, x, row1, beg, begRowEnd, false, true);
- }
-
- if (middleTop < middleBottom) {
- // draw middle rectangle
- pi.pain.fillRectangle(x, middleTop,
- tm.width(), middleBottom - middleTop,
- Color::selection);
- }
-
- if (!clipBelow) {
- // get row begin
- DocIterator endRowBeg = end;
- endRowBeg.pos() = row2.pos();
- endRowBeg.boundary(false);
-
- // draw low rectangle
- drawRowSelection(pi, x, row2, endRowBeg, end, true, false);
- }
- }
-}
-
-
-void Text::drawRowSelection(PainterInfo & pi, int x, Row const & row,
- DocIterator const & beg, DocIterator const & end,
- bool drawOnBegMargin, bool drawOnEndMargin) const
-{
- BufferView & bv = *pi.base.bv;
- Buffer & buffer = *bv.buffer();
- TextMetrics const & tm = bv.textMetrics(this);
- DocIterator cur = beg;
- int x1 = cursorX(bv, beg.top(), beg.boundary());
- int x2 = cursorX(bv, end.top(), end.boundary());
- int y1 = bv_funcs::getPos(bv, cur, cur.boundary()).y_ - row.ascent();
- int y2 = y1 + row.height();
-
- // draw the margins
- if (drawOnBegMargin) {
- if (isRTL(buffer, beg.paragraph()))
- pi.pain.fillRectangle(x + x1, y1, tm.width() - x1, y2 - y1, Color::selection);
- else
- pi.pain.fillRectangle(x, y1, x1, y2 - y1, Color::selection);
- }
-
- if (drawOnEndMargin) {
- if (isRTL(buffer, beg.paragraph()))
- pi.pain.fillRectangle(x, y1, x2, y2 - y1, Color::selection);
- else
- pi.pain.fillRectangle(x + x2, y1, tm.width() - x2, y2 - y1, Color::selection);
- }
-
- // if we are on a boundary from the beginning, it's probably
- // a RTL boundary and we jump to the other side directly as this
- // segement is 0-size and confuses the logic below
- if (cur.boundary())
- cur.boundary(false);
-
- // go through row and draw from RTL boundary to RTL boundary
- while (cur < end) {
- bool drawNow = false;
-
- // simplified cursorRight code below which does not
- // descend into insets and which does not go into the
- // next line. Compare the logic with the original cursorRight
-
- // if left of boundary -> just jump to right side
- // but for RTL boundaries don't, because: abc|DDEEFFghi -> abcDDEEF|Fghi
- if (cur.boundary()) {
- cur.boundary(false);
- } else if (isRTLBoundary(buffer, cur.paragraph(), cur.pos() + 1)) {
- // in front of RTL boundary -> Stay on this side of the boundary because:
- // ab|cDDEEFFghi -> abc|DDEEFFghi
- ++cur.pos();
- cur.boundary(true);
- drawNow = true;
- } else {
- // move right
- ++cur.pos();
-
- // line end?
- if (cur.pos() == row.endpos())
- cur.boundary(true);
- }
-
- if (x1 == -1) {
- // the previous segment was just drawn, now the next starts
- x1 = cursorX(bv, cur.top(), cur.boundary());
- }
-
- if (!(cur < end) || drawNow) {
- x2 = cursorX(bv, cur.top(), cur.boundary());
- pi.pain.fillRectangle(x + min(x1,x2), y1, abs(x2 - x1), y2 - y1,
- Color::selection);
-
- // reset x1, so it is set again next round (which will be on the
- // right side of a boundary or at the selection end)
- x1 = -1;
- }
- }
-}
-
-
-
-bool Text::isLastRow(pit_type pit, Row const & row) const
-{
- return row.endpos() >= pars_[pit].size()
- && pit + 1 == pit_type(paragraphs().size());
-}
-
-
-bool Text::isFirstRow(pit_type pit, Row const & row) const
-{
- return row.pos() == 0 && pit == 0;
-}
-
-
void Text::getWord(CursorSlice & from, CursorSlice & to,
word_location const loc)
{
depth_type dth = 0;
for (; pit != end; ++pit)
pit->write(buf, os, buf.params(), dth);
+
+ // Close begin_deeper
+ for(; dth > 0; --dth)
+ os << "\n\\end_deeper";
}
return true;
}
-int Text::cursorX(BufferView const & bv, CursorSlice const & sl,
- bool boundary) const
-{
- TextMetrics const & tm = bv.textMetrics(sl.text());
- pit_type const pit = sl.pit();
- Paragraph const & par = pars_[pit];
- ParagraphMetrics const & pm = tm.parMetrics(pit);
- if (pm.rows().empty())
- return 0;
-
- pos_type ppos = sl.pos();
- // Correct position in front of big insets
- bool const boundary_correction = ppos != 0 && boundary;
- if (boundary_correction)
- --ppos;
-
- Row const & row = pm.getRow(sl.pos(), boundary);
-
- pos_type cursor_vpos = 0;
-
- Buffer const & buffer = *bv.buffer();
- RowMetrics const m = tm.computeRowMetrics(pit, row);
- double x = m.x;
- Bidi bidi;
- bidi.computeTables(par, buffer, row);
-
- pos_type const row_pos = row.pos();
- pos_type const end = row.endpos();
- // Spaces at logical line breaks in bidi text must be skipped during
- // cursor positioning. However, they may appear visually in the middle
- // of a row; they must be skipped, wherever they are...
- // * logically "abc_[HEBREW_\nHEBREW]"
- // * visually "abc_[_WERBEH\nWERBEH]"
- pos_type skipped_sep_vpos = -1;
-
- if (end <= row_pos)
- cursor_vpos = row_pos;
- else if (ppos >= end)
- cursor_vpos = isRTL(buffer, par) ? row_pos : end;
- else if (ppos > row_pos && ppos >= end)
- // Place cursor after char at (logical) position pos - 1
- cursor_vpos = (bidi.level(ppos - 1) % 2 == 0)
- ? bidi.log2vis(ppos - 1) + 1 : bidi.log2vis(ppos - 1);
- else
- // Place cursor before char at (logical) position ppos
- cursor_vpos = (bidi.level(ppos) % 2 == 0)
- ? bidi.log2vis(ppos) : bidi.log2vis(ppos) + 1;
-
- pos_type body_pos = par.beginOfBody();
- if (body_pos > 0 &&
- (body_pos > end || !par.isLineSeparator(body_pos - 1)))
- body_pos = 0;
-
- // Use font span to speed things up, see below
- FontSpan font_span;
- Font font;
- FontMetrics const & labelfm = theFontMetrics(
- getLabelFont(buffer, par));
-
- // If the last logical character is a separator, skip it, unless
- // it's in the last row of a paragraph; see skipped_sep_vpos declaration
- if (end > 0 && end < par.size() && par.isSeparator(end - 1))
- skipped_sep_vpos = bidi.log2vis(end - 1);
-
- for (pos_type vpos = row_pos; vpos < cursor_vpos; ++vpos) {
- // Skip the separator which is at the logical end of the row
- if (vpos == skipped_sep_vpos)
- continue;
- pos_type pos = bidi.vis2log(vpos);
- if (body_pos > 0 && pos == body_pos - 1) {
- // FIXME UNICODE
- docstring const lsep = from_utf8(par.layout()->labelsep);
- x += m.label_hfill + labelfm.width(lsep);
- if (par.isLineSeparator(body_pos - 1))
- x -= singleWidth(buffer, par, body_pos - 1);
- }
-
- // Use font span to speed things up, see above
- if (pos < font_span.first || pos > font_span.last) {
- font_span = par.fontSpan(pos);
- font = getFont(buffer, par, pos);
- }
-
- x += singleWidth(par, pos, par.getChar(pos), font);
-
- if (par.hfillExpansion(row, pos))
- x += (pos >= body_pos) ? m.hfill : m.label_hfill;
- else if (par.isSeparator(pos) && pos >= body_pos)
- x += m.separator;
- }
-
- // see correction above
- if (boundary_correction) {
- if (isRTL(buffer, sl, boundary))
- x -= singleWidth(buffer, par, ppos);
- else
- x += singleWidth(buffer, par, ppos);
- }
-
- return int(x);
-}
-
-
-int Text::cursorY(BufferView const & bv, CursorSlice const & sl, bool boundary) const
-{
- //lyxerr << "Text::cursorY: boundary: " << boundary << std::endl;
- ParagraphMetrics const & pm = bv.parMetrics(this, sl.pit());
- if (pm.rows().empty())
- return 0;
-
- int h = 0;
- h -= bv.parMetrics(this, 0).rows()[0].ascent();
- for (pit_type pit = 0; pit < sl.pit(); ++pit) {
- h += bv.parMetrics(this, pit).height();
- }
- int pos = sl.pos();
- if (pos && boundary)
- --pos;
- size_t const rend = pm.pos2row(pos);
- for (size_t rit = 0; rit != rend; ++rit)
- h += pm.rows()[rit].height();
- h += pm.rows()[rend].ascent();
- return h;
-}
-
-
// Returns the current font and depth as a message.
docstring Text::currentState(Cursor & cur)
{
// I think we should only show changes from the default
// font. (Asger)
// No, from the document font (MV)
- Font font = real_current_font;
+ Font font = cur.real_current_font;
font.reduce(buf.params().getFont());
os << bformat(_("Font: %1$s"), font.stateText(&buf.params()));
{
pit_type pit = cur.pit();
- Layout_ptr layout = pars_[pit].layout();
+ LayoutPtr layout = pars_[pit].layout();
docstring text;
docstring par_text = pars_[pit].asString(cur.buffer(), false);
// For section, subsection, etc...
if (layout->latextype == LATEX_PARAGRAPH && pit != 0) {
- Layout_ptr const & layout2 = pars_[pit - 1].layout();
+ LayoutPtr const & layout2 = pars_[pit - 1].layout();
if (layout2->latextype != LATEX_PARAGRAPH) {
--pit;
layout = layout2;
name = from_ascii(layout->latexname());
// for captions, we just take the caption type
- Inset * caption_inset = cur.innerInsetOfType(Inset::CAPTION_CODE);
+ Inset * caption_inset = cur.innerInsetOfType(CAPTION_CODE);
if (caption_inset)
name = from_ascii(static_cast<InsetCaption *>(caption_inset)->type());
// If none of the above worked, we'll see if we're inside various
// types of insets and take our abbreviation from them.
if (name.empty()) {
- Inset::Code const codes[] = {
- Inset::FLOAT_CODE,
- Inset::WRAP_CODE,
- Inset::FOOT_CODE
+ InsetCode const codes[] = {
+ FLOAT_CODE,
+ WRAP_CODE,
+ FOOT_CODE
};
for (unsigned int i = 0; i < (sizeof codes / sizeof codes[0]); ++i) {
Inset * float_inset = cur.innerInsetOfType(codes[i]);
}
-void Text::setCursorFromCoordinates(Cursor & cur, int const x, int const y)
-{
- BOOST_ASSERT(this == cur.text());
- pit_type pit = getPitNearY(cur.bv(), y);
-
- TextMetrics const & tm = cur.bv().textMetrics(this);
- ParagraphMetrics const & pm = tm.parMetrics(pit);
-
- int yy = cur.bv().coordCache().get(this, pit).y_ - pm.ascent();
- LYXERR(Debug::DEBUG)
- << BOOST_CURRENT_FUNCTION
- << ": x: " << x
- << " y: " << y
- << " pit: " << pit
- << " yy: " << yy << endl;
-
- int r = 0;
- BOOST_ASSERT(pm.rows().size());
- for (; r < int(pm.rows().size()) - 1; ++r) {
- Row const & row = pm.rows()[r];
- if (int(yy + row.height()) > y)
- break;
- yy += row.height();
- }
-
- Row const & row = pm.rows()[r];
-
- LYXERR(Debug::DEBUG)
- << BOOST_CURRENT_FUNCTION
- << ": row " << r
- << " from pos: " << row.pos()
- << endl;
-
- bool bound = false;
- int xx = x;
- pos_type const pos = row.pos()
- + tm.getColumnNearX(pit, row, xx, bound);
-
- LYXERR(Debug::DEBUG)
- << BOOST_CURRENT_FUNCTION
- << ": setting cursor pit: " << pit
- << " pos: " << pos
- << endl;
-
- setCursor(cur, pit, pos, true, bound);
- // remember new position.
- cur.setTargetX();
-}
-
-
void Text::charsTranspose(Cursor & cur)
{
BOOST_ASSERT(this == cur.text());
// Track the changes if Change Tracking is enabled.
bool const trackChanges = cur.buffer().params().trackChanges;
- recordUndo(cur);
+ cur.recordUndo();
par.eraseChar(pos2, trackChanges);
par.eraseChar(pos1, trackChanges);