Transfer metrics and screen related methods from Text to TextMetrics.

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@19991 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Abdelrazak Younes 2007-09-02 09:44:08 +00:00
parent aa670e90c8
commit 4048448236
13 changed files with 679 additions and 679 deletions

View File

@ -344,7 +344,7 @@ void BufferView::scrollDocView(int value)
void BufferView::setCursorFromScrollbar()
{
Text & t = buffer_.text();
TextMetrics & tm = text_metrics_[&buffer_.text()];
int const height = 2 * defaultRowHeight();
int const first = height;
@ -358,14 +358,14 @@ void BufferView::setCursorFromScrollbar()
// We reset the cursor because bv_funcs::status() does not
// work when the cursor is within mathed.
cur.reset(buffer_.inset());
t.setCursorFromCoordinates(cur, 0, first);
tm.setCursorFromCoordinates(cur, 0, first);
cur.clearSelection();
break;
case bv_funcs::CUR_BELOW:
// We reset the cursor because bv_funcs::status() does not
// work when the cursor is within mathed.
cur.reset(buffer_.inset());
t.setCursorFromCoordinates(cur, 0, last);
tm.setCursorFromCoordinates(cur, 0, last);
cur.clearSelection();
break;
case bv_funcs::CUR_INSIDE:
@ -373,7 +373,7 @@ void BufferView::setCursorFromScrollbar()
int const newy = min(last, max(y, first));
if (y != newy) {
cur.reset(buffer_.inset());
t.setCursorFromCoordinates(cur, 0, newy);
tm.setCursorFromCoordinates(cur, 0, newy);
}
}
}
@ -987,7 +987,7 @@ void BufferView::resize(int width, int height)
Inset const * BufferView::getCoveringInset(Text const & text, int x, int y)
{
pit_type pit = text.getPitNearY(*this, y);
pit_type pit = text_metrics_[&text].getPitNearY(y);
BOOST_ASSERT(pit != -1);
Paragraph const & par = text.getPar(pit);
@ -1105,7 +1105,7 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0)
}
// Build temporary cursor.
Inset * inset = buffer_.text().editXY(cur, cmd.x, cmd.y);
Inset * inset = text_metrics_[&buffer_.text()].editXY(cur, cmd.x, cmd.y);
// Put anchor at the same position.
cur.resetAnchor();

View File

@ -1213,7 +1213,7 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded)
xo = targetX();
// first get the current line
TextMetrics const & tm = bv_->textMetrics(text());
TextMetrics & tm = bv_->textMetrics(text());
ParagraphMetrics const & pm = tm.parMetrics(pit());
int row;
if (pos() && boundary())
@ -1237,9 +1237,9 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded)
Cursor old = *this;
// To next/previous row
if (up)
text()->editXY(*this, xo, yo - textRow().ascent() - 1);
tm.editXY(*this, xo, yo - textRow().ascent() - 1);
else
text()->editXY(*this, xo, yo + textRow().descent() + 1);
tm.editXY(*this, xo, yo + textRow().descent() + 1);
clearSelection();
// This happens when you move out of an inset.

View File

@ -360,176 +360,6 @@ double Text::spacing(Buffer const & buffer,
}
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();
LayoutPtr const & layout = par.layout();
docstring parindent = layout->parindent;
int l_margin = 0;
if (isMainText(buffer))
l_margin += changebarMargin();
l_margin += theFontMetrics(buffer.params().getFont()).signedWidth(
tclass.leftmargin());
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()) {
l_margin += theFontMetrics(buffer.params().getFont()).signedWidth(
layout->leftmargin);
}
if (!par.getLabelstring().empty()) {
l_margin += labelfont_metrics.signedWidth(layout->labelindent);
l_margin += labelfont_metrics.width(par.getLabelstring());
l_margin += labelfont_metrics.width(layout->labelsep);
}
break;
case MARGIN_MANUAL: {
l_margin += labelfont_metrics.signedWidth(layout->labelindent);
// 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);
l_margin += labelfont_metrics.width(layout->labelsep);
}
}
break;
}
case MARGIN_STATIC: {
l_margin += theFontMetrics(buffer.params().getFont()).
signedWidth(layout->leftmargin) * 4 / (par.getDepth() + 4);
break;
}
case MARGIN_FIRST_DYNAMIC:
if (layout->labeltype == LABEL_MANUAL) {
if (pos >= par.beginOfBody()) {
l_margin += labelfont_metrics.signedWidth(layout->leftmargin);
} else {
l_margin += labelfont_metrics.signedWidth(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_))) {
l_margin += labelfont_metrics.signedWidth(layout->leftmargin);
} else if (layout->labeltype != LABEL_TOP_ENVIRONMENT
&& layout->labeltype != LABEL_BIBLIO
&& layout->labeltype !=
LABEL_CENTERED_TOP_ENVIRONMENT) {
l_margin += labelfont_metrics.signedWidth(layout->labelindent);
l_margin += labelfont_metrics.width(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();
// FIXME: This is wrong.
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))
{
l_margin += theFontMetrics(buffer.params().getFont()).signedWidth(
parindent);
}
return l_margin;
}
Color_color Text::backgroundColor() const
{
return Color_color(Color::color(background_color_));
@ -1471,129 +1301,6 @@ bool Text::read(Buffer const & buf, Lexer & lex, ErrorList & errorList)
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();
double x = row.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;
// 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) {
FontMetrics const & labelfm = theFontMetrics(
getLabelFont(buffer, par));
x += row.label_hfill + labelfm.width(par.layout()->labelsep);
if (par.isLineSeparator(body_pos - 1))
x -= tm.singleWidth(pit, 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 += pm.singleWidth(pos, font);
if (pm.hfillExpansion(row, pos))
x += (pos >= body_pos) ? row.hfill : row.label_hfill;
else if (par.isSeparator(pos) && pos >= body_pos)
x += row.separator;
}
// see correction above
if (boundary_correction) {
if (isRTL(buffer, sl, boundary))
x -= tm.singleWidth(pit, ppos);
else
x += tm.singleWidth(pit, 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)
{
@ -1748,56 +1455,6 @@ docstring Text::getPossibleLabel(Cursor & cur) const
}
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());

View File

@ -140,21 +140,6 @@ public:
/// FIXME: replace Cursor with DocIterator.
docstring currentState(Cursor & cur);
/** returns row near the specified
* y-coordinate in given paragraph (relative to the screen).
*/
/// FIXME: move to TextMetrics.
Row const & getRowNearY(BufferView const & bv, int y,
pit_type pit) const;
/// returns the paragraph number closest to screen y-coordinate.
/// This method uses the BufferView CoordCache to locate the
/// paragraph. The y-coodinate is allowed to be off-screen and
/// the CoordCache will be automatically updated if needed. This is
/// the reason why we need a non const BufferView.
/// FIXME: move to TextMetrics.
pit_type getPitNearY(BufferView & bv, int y) const;
/** Find the word under \c from in the relative location
* defined by \c word_location.
* @param from return here the start of the word
@ -192,21 +177,6 @@ public:
///
void recUndo(Cursor & cur, pit_type first) const;
/// sets cursor only within this Text.
/// x,y are screen coordinates
void setCursorFromCoordinates(Cursor & cur, int x, int y);
/// sets cursor recursively descending into nested editable insets
/**
\return the inset pointer if x,y is covering that inset
\param x,y are absolute screen coordinates.
\retval inset is non-null if the cursor is positionned inside
*/
/// FIXME: move to TextMetrics.
/// FIXME: cleanup to use BufferView::getCoveringInset() and
/// setCursorFromCoordinates() instead of checkInsetHit().
Inset * editXY(Cursor & cur, int x, int y);
/// Move cursor one position left
/**
* Returns true if an update is needed after the move.
@ -232,10 +202,6 @@ public:
/// FIXME: move to TextMetrics.
bool cursorEnd(Cursor & cur);
///
void cursorPrevious(Cursor & cur);
///
void cursorNext(Cursor & cur);
///
bool cursorTop(Cursor & cur);
///
bool cursorBottom(Cursor & cur);
@ -283,25 +249,9 @@ public:
/// FIXME: replace Cursor with DocIterator.
void insertStringAsParagraphs(Cursor & cur, docstring const & str);
/// Returns an inset if inset was hit, or 0 if not.
/// \warning This method is not recursive! It will return the
/// outermost inset within this Text.
/// \sa BufferView::getCoveringInset() to get the innermost inset.
Inset * checkInsetHit(BufferView &, int x, int y);
/// return the color of the canvas
Color_color backgroundColor() 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.
*/
/// FIXME: move to TextMetrics.
int leftMargin(Buffer const &, int max_width, pit_type pit, pos_type pos) const;
int leftMargin(Buffer const &, int max_width, pit_type pit) const;
/// access to our paragraphs
ParagraphList const & paragraphs() const { return pars_; }
ParagraphList & paragraphs() { return pars_; }
@ -339,15 +289,6 @@ public:
/// returns whether we've seen our usual 'end' marker
bool read(Buffer const & buf, Lexer & lex, ErrorList & errorList);
///
/// FIXME: move to TextMetrics.
int cursorX(BufferView const &, CursorSlice const & cursor,
bool boundary) const;
///
/// FIXME: move to TextMetrics.
int cursorY(BufferView const & bv, CursorSlice const & cursor,
bool boundary) const;
/// delete double spaces, leading spaces, and empty paragraphs around old cursor.
/// \retval true if a change has happened and we need a redraw.
/// FIXME: replace Cursor with DocIterator. This is not possible right

View File

@ -88,58 +88,6 @@ bool Text::isMainText(Buffer const & buffer) const
}
//takes screen x,y coordinates
Inset * Text::checkInsetHit(BufferView & bv, int x, int y)
{
pit_type pit = getPitNearY(bv, y);
BOOST_ASSERT(pit != -1);
Paragraph const & par = pars_[pit];
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": x: " << x
<< " y: " << y
<< " pit: " << pit
<< endl;
InsetList::const_iterator iit = par.insetlist.begin();
InsetList::const_iterator iend = par.insetlist.end();
for (; iit != iend; ++iit) {
Inset * inset = iit->inset;
#if 1
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": examining inset " << inset << endl;
if (bv.coordCache().getInsets().has(inset))
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": xo: " << inset->xo(bv) << "..."
<< inset->xo(bv) + inset->width()
<< " yo: " << inset->yo(bv) - inset->ascent()
<< "..."
<< inset->yo(bv) + inset->descent()
<< endl;
else
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": inset has no cached position" << endl;
#endif
if (inset->covers(bv, x, y)) {
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": Hit inset: " << inset << endl;
return inset;
}
}
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": No inset hit. " << endl;
return 0;
}
// Gets the fully instantiated font at a given position in a paragraph
// Basically the same routine as Paragraph::getFont() in Paragraph.cpp.
// The difference is that this one is used for displaying, and thus we
@ -792,156 +740,6 @@ void Text::setCurrentFont(Cursor & cur)
}
}
// y is screen coordinate
pit_type Text::getPitNearY(BufferView & bv, int y) const
{
BOOST_ASSERT(!paragraphs().empty());
BOOST_ASSERT(bv.coordCache().getParPos().find(this) != bv.coordCache().getParPos().end());
CoordCache::InnerParPosCache const & cc = bv.coordCache().getParPos().find(this)->second;
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": y: " << y << " cache size: " << cc.size()
<< endl;
// look for highest numbered paragraph with y coordinate less than given y
pit_type pit = 0;
int yy = -1;
CoordCache::InnerParPosCache::const_iterator it = cc.begin();
CoordCache::InnerParPosCache::const_iterator et = cc.end();
CoordCache::InnerParPosCache::const_iterator last = et; last--;
TextMetrics & tm = bv.textMetrics(this);
ParagraphMetrics const & pm = tm.parMetrics(it->first);
// If we are off-screen (before the visible part)
if (y < 0
// and even before the first paragraph in the cache.
&& y < it->second.y_ - int(pm.ascent())) {
// and we are not at the first paragraph in the inset.
if (it->first == 0)
return 0;
// then this is the paragraph we are looking for.
pit = it->first - 1;
// rebreak it and update the CoordCache.
tm.redoParagraph(pit);
bv.coordCache().parPos()[this][pit] =
Point(0, it->second.y_ - pm.descent());
return pit;
}
ParagraphMetrics const & pm_last = bv.parMetrics(this, last->first);
// If we are off-screen (after the visible part)
if (y > bv.workHeight()
// and even after the first paragraph in the cache.
&& y >= last->second.y_ + int(pm_last.descent())) {
pit = last->first + 1;
// and we are not at the last paragraph in the inset.
if (pit == int(pars_.size()))
return last->first;
// then this is the paragraph we are looking for.
// rebreak it and update the CoordCache.
tm.redoParagraph(pit);
bv.coordCache().parPos()[this][pit] =
Point(0, last->second.y_ + pm_last.ascent());
return pit;
}
for (; it != et; ++it) {
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< " examining: pit: " << it->first
<< " y: " << it->second.y_
<< endl;
ParagraphMetrics const & pm = bv.parMetrics(this, it->first);
if (it->first >= pit && int(it->second.y_) - int(pm.ascent()) <= y) {
pit = it->first;
yy = it->second.y_;
}
}
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": found best y: " << yy << " for pit: " << pit
<< endl;
return pit;
}
Row const & Text::getRowNearY(BufferView const & bv, int y, pit_type pit) const
{
ParagraphMetrics const & pm = bv.parMetrics(this, pit);
int yy = bv.coordCache().get(this, pit).y_ - pm.ascent();
BOOST_ASSERT(!pm.rows().empty());
RowList::const_iterator rit = pm.rows().begin();
RowList::const_iterator const rlast = boost::prior(pm.rows().end());
for (; rit != rlast; yy += rit->height(), ++rit)
if (yy + rit->height() > y)
break;
return *rit;
}
// x,y are absolute screen coordinates
// sets cursor recursively descending into nested editable insets
Inset * Text::editXY(Cursor & cur, int x, int y)
{
if (lyxerr.debugging(Debug::WORKAREA)) {
lyxerr << "Text::editXY(cur, " << x << ", " << y << ")" << std::endl;
cur.bv().coordCache().dump();
}
pit_type pit = getPitNearY(cur.bv(), y);
BOOST_ASSERT(pit != -1);
Row const & row = getRowNearY(cur.bv(), y, pit);
bool bound = false;
TextMetrics const & tm = cur.bv().textMetrics(this);
int xx = x; // is modified by getColumnNearX
pos_type const pos = row.pos()
+ tm.getColumnNearX(pit, row, xx, bound);
cur.pit() = pit;
cur.pos() = pos;
cur.boundary(bound);
cur.setTargetX(x);
// try to descend into nested insets
Inset * inset = checkInsetHit(cur.bv(), x, y);
//lyxerr << "inset " << inset << " hit at x: " << x << " y: " << y << endl;
if (!inset) {
// Either we deconst editXY or better we move current_font
// and real_current_font to Cursor
setCurrentFont(cur);
return 0;
}
Inset * insetBefore = pos? pars_[pit].getInset(pos - 1): 0;
//Inset * insetBehind = pars_[pit].getInset(pos);
// This should be just before or just behind the
// cursor position set above.
BOOST_ASSERT((pos != 0 && inset == insetBefore)
|| inset == pars_[pit].getInset(pos));
// Make sure the cursor points to the position before
// this inset.
if (inset == insetBefore) {
--cur.pos();
cur.boundary(false);
}
// Try to descend recursively inside the inset.
inset = inset->editXY(cur, x, y);
if (cur.top().text() == this)
setCurrentFont(cur);
return inset;
}
bool Text::checkAndActivateInset(Cursor & cur, bool front)
{

View File

@ -193,44 +193,6 @@ string const freefont2string()
}
void Text::cursorPrevious(Cursor & cur)
{
pos_type cpos = cur.pos();
pit_type cpar = cur.pit();
int x = cur.x_target();
setCursorFromCoordinates(cur, x, 0);
cur.dispatch(FuncRequest(cur.selection()? LFUN_UP_SELECT: LFUN_UP));
if (cpar == cur.pit() && cpos == cur.pos())
// we have a row which is taller than the workarea. The
// simplest solution is to move to the previous row instead.
cur.dispatch(FuncRequest(cur.selection()? LFUN_UP_SELECT: LFUN_UP));
finishUndo();
cur.updateFlags(Update::Force | Update::FitCursor);
}
void Text::cursorNext(Cursor & cur)
{
pos_type cpos = cur.pos();
pit_type cpar = cur.pit();
int x = cur.x_target();
setCursorFromCoordinates(cur, x, cur.bv().workHeight() - 1);
cur.dispatch(FuncRequest(cur.selection()? LFUN_DOWN_SELECT: LFUN_DOWN));
if (cpar == cur.pit() && cpos == cur.pos())
// we have a row which is taller than the workarea. The
// simplest solution is to move to the next row instead.
cur.dispatch(
FuncRequest(cur.selection()? LFUN_DOWN_SELECT: LFUN_DOWN));
finishUndo();
cur.updateFlags(Update::Force | Update::FitCursor);
}
namespace {
@ -352,6 +314,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
BOOST_ASSERT(cur.text() == this);
BufferView * bv = &cur.bv();
TextMetrics & tm = cur.bv().textMetrics(this);
CursorSlice oldTopSlice = cur.top();
bool oldBoundary = cur.boundary();
bool sel = cur.selection();
@ -535,7 +498,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
if (cur.pit() == 0 && cur.textRow().pos() == 0)
cur.undispatched();
else {
cursorPrevious(cur);
tm.cursorPrevious(cur);
}
break;
@ -546,7 +509,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
&& cur.textRow().endpos() == cur.lastpos())
cur.undispatched();
else {
cursorNext(cur);
tm.cursorNext(cur);
}
break;
@ -845,8 +808,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
case LFUN_SERVER_GET_XY:
cur.message(from_utf8(
convert<string>(cursorX(cur.bv(), cur.top(), cur.boundary()))
+ ' ' + convert<string>(cursorY(cur.bv(), cur.top(), cur.boundary()))));
convert<string>(tm.cursorX(cur.top(), cur.boundary()))
+ ' ' + convert<string>(tm.cursorY(cur.top(), cur.boundary()))));
break;
case LFUN_SERVER_SET_XY: {
@ -858,7 +821,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
lyxerr << "SETXY: Could not parse coordinates in '"
<< to_utf8(cmd.argument()) << std::endl;
else
setCursorFromCoordinates(cur, x, y);
tm.setCursorFromCoordinates(cur, x, y);
break;
}
@ -1062,7 +1025,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
int const wh = bv->workHeight();
int const y = std::max(0, std::min(wh - 1, cmd.y));
setCursorFromCoordinates(cur, cmd.x, y);
tm.setCursorFromCoordinates(cur, cmd.x, y);
cur.setTargetX(cmd.x);
if (cmd.y >= wh)
lyx::dispatch(FuncRequest(LFUN_DOWN_SELECT));

View File

@ -36,6 +36,7 @@
#include "ParIterator.h"
#include "rowpainter.h"
#include "Text.h"
#include "Undo.h"
#include "VSpace.h"
#include "frontends/FontMetrics.h"
@ -158,7 +159,7 @@ bool TextMetrics::metrics(MetricsInfo & mi, Dimension & dim)
// the full allowable width.
dim_.wid = max_width_;
//lyxerr << "Text::metrics: width: " << mi.base.textwidth
//lyxerr << "TextMetrics::metrics: width: " << mi.base.textwidth
// << " maxWidth: " << max_width_ << "\nfont: " << mi.base.font << endl;
bool changed = false;
@ -237,7 +238,7 @@ bool TextMetrics::redoParagraph(pit_type const pit)
for (; ii != iend; ++ii) {
Dimension old_dim = ii->inset->dimension();
Dimension dim;
int const w = max_width_ - text_->leftMargin(buffer, max_width_, pit, ii->pos)
int const w = max_width_ - leftMargin(max_width_, pit, ii->pos)
- right_margin;
Font const & font = ii->inset->noFontChange() ?
bufferfont : text_->getFont(buffer, par, ii->pos);
@ -250,7 +251,7 @@ bool TextMetrics::redoParagraph(pit_type const pit)
pos_type first = 0;
size_t row_index = 0;
// maximum pixel width of a row
int width = max_width_ - right_margin; // - leftMargin(buffer, max_width_, pit, row);
int width = max_width_ - right_margin; // - leftMargin(max_width_, pit, row);
do {
Dimension dim;
pos_type end = rowBreakPoint(width, pit, first);
@ -331,7 +332,7 @@ void TextMetrics::computeRowMetrics(pit_type const pit,
if (is_rtl)
row.x = rightMargin(pit);
else
row.x = text_->leftMargin(buffer, max_width_, pit, row.pos());
row.x = leftMargin(max_width_, pit, row.pos());
// is there a manual margin with a manual label
LayoutPtr const & layout = par.layout();
@ -495,7 +496,7 @@ int TextMetrics::labelEnd(pit_type const pit) const
if (text_->getPar(pit).layout()->margintype != MARGIN_MANUAL)
return 0;
// return the beginning of the body
return text_->leftMargin(bv_->buffer(), max_width_, pit);
return leftMargin(max_width_, pit);
}
@ -522,7 +523,7 @@ pit_type TextMetrics::rowBreakPoint(int width, pit_type const pit,
// nearest that.
int label_end = labelEnd(pit);
int const left = text_->leftMargin(buffer, max_width_, pit, pos);
int const left = leftMargin(max_width_, pit, pos);
int x = left;
// pixel width since last breakpoint
@ -612,7 +613,7 @@ int TextMetrics::rowWidth(int right_margin, pit_type const pit,
// get the pure distance
ParagraphMetrics const & pm = par_metrics_[pit];
Paragraph const & par = text_->getPar(pit);
int w = text_->leftMargin(buffer, max_width_, pit, first);
int w = leftMargin(max_width_, pit, first);
int label_end = labelEnd(pit);
pos_type const body_pos = par.beginOfBody();
@ -988,6 +989,590 @@ pos_type TextMetrics::x2pos(pit_type pit, int row, int x) const
}
// y is screen coordinate
pit_type TextMetrics::getPitNearY(int y)
{
BOOST_ASSERT(!text_->paragraphs().empty());
BOOST_ASSERT(bv_->coordCache().getParPos().find(text_) != bv_->coordCache().getParPos().end());
CoordCache::InnerParPosCache const & cc = bv_->coordCache().getParPos().find(text_)->second;
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": y: " << y << " cache size: " << cc.size()
<< endl;
// look for highest numbered paragraph with y coordinate less than given y
pit_type pit = 0;
int yy = -1;
CoordCache::InnerParPosCache::const_iterator it = cc.begin();
CoordCache::InnerParPosCache::const_iterator et = cc.end();
CoordCache::InnerParPosCache::const_iterator last = et; last--;
ParagraphMetrics const & pm = par_metrics_[it->first];
// If we are off-screen (before the visible part)
if (y < 0
// and even before the first paragraph in the cache.
&& y < it->second.y_ - int(pm.ascent())) {
// and we are not at the first paragraph in the inset.
if (it->first == 0)
return 0;
// then this is the paragraph we are looking for.
pit = it->first - 1;
// rebreak it and update the CoordCache.
redoParagraph(pit);
bv_->coordCache().parPos()[text_][pit] =
Point(0, it->second.y_ - pm.descent());
return pit;
}
ParagraphMetrics const & pm_last = par_metrics_[last->first];
// If we are off-screen (after the visible part)
if (y > bv_->workHeight()
// and even after the first paragraph in the cache.
&& y >= last->second.y_ + int(pm_last.descent())) {
pit = last->first + 1;
// and we are not at the last paragraph in the inset.
if (pit == int(text_->paragraphs().size()))
return last->first;
// then this is the paragraph we are looking for.
// rebreak it and update the CoordCache.
redoParagraph(pit);
bv_->coordCache().parPos()[text_][pit] =
Point(0, last->second.y_ + pm_last.ascent());
return pit;
}
for (; it != et; ++it) {
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< " examining: pit: " << it->first
<< " y: " << it->second.y_
<< endl;
ParagraphMetrics const & pm = par_metrics_[it->first];
if (it->first >= pit && int(it->second.y_) - int(pm.ascent()) <= y) {
pit = it->first;
yy = it->second.y_;
}
}
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": found best y: " << yy << " for pit: " << pit
<< endl;
return pit;
}
Row const & TextMetrics::getRowNearY(int y, pit_type pit) const
{
ParagraphMetrics const & pm = par_metrics_[pit];
int yy = bv_->coordCache().get(text_, pit).y_ - pm.ascent();
BOOST_ASSERT(!pm.rows().empty());
RowList::const_iterator rit = pm.rows().begin();
RowList::const_iterator const rlast = boost::prior(pm.rows().end());
for (; rit != rlast; yy += rit->height(), ++rit)
if (yy + rit->height() > y)
break;
return *rit;
}
// x,y are absolute screen coordinates
// sets cursor recursively descending into nested editable insets
Inset * TextMetrics::editXY(Cursor & cur, int x, int y)
{
if (lyxerr.debugging(Debug::WORKAREA)) {
lyxerr << "TextMetrics::editXY(cur, " << x << ", " << y << ")" << std::endl;
cur.bv().coordCache().dump();
}
pit_type pit = getPitNearY(y);
BOOST_ASSERT(pit != -1);
Row const & row = getRowNearY(y, pit);
bool bound = false;
int xx = x; // is modified by getColumnNearX
pos_type const pos = row.pos()
+ getColumnNearX(pit, row, xx, bound);
cur.pit() = pit;
cur.pos() = pos;
cur.boundary(bound);
cur.setTargetX(x);
// try to descend into nested insets
Inset * inset = checkInsetHit(x, y);
//lyxerr << "inset " << inset << " hit at x: " << x << " y: " << y << endl;
if (!inset) {
// Either we deconst editXY or better we move current_font
// and real_current_font to Cursor
text_->setCurrentFont(cur);
return 0;
}
ParagraphList const & pars = text_->paragraphs();
Inset const * insetBefore = pos? pars[pit].getInset(pos - 1): 0;
//Inset * insetBehind = pars[pit].getInset(pos);
// This should be just before or just behind the
// cursor position set above.
BOOST_ASSERT((pos != 0 && inset == insetBefore)
|| inset == pars[pit].getInset(pos));
// Make sure the cursor points to the position before
// this inset.
if (inset == insetBefore) {
--cur.pos();
cur.boundary(false);
}
// Try to descend recursively inside the inset.
inset = inset->editXY(cur, x, y);
if (cur.top().text() == text_)
text_->setCurrentFont(cur);
return inset;
}
void TextMetrics::setCursorFromCoordinates(Cursor & cur, int const x, int const y)
{
BOOST_ASSERT(text_ == cur.text());
pit_type pit = getPitNearY(y);
ParagraphMetrics const & pm = par_metrics_[pit];
int yy = bv_->coordCache().get(text_, 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() + getColumnNearX(pit, row, xx, bound);
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": setting cursor pit: " << pit
<< " pos: " << pos
<< endl;
text_->setCursor(cur, pit, pos, true, bound);
// remember new position.
cur.setTargetX();
}
//takes screen x,y coordinates
Inset * TextMetrics::checkInsetHit(int x, int y)
{
pit_type pit = getPitNearY(y);
BOOST_ASSERT(pit != -1);
Paragraph const & par = text_->paragraphs()[pit];
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": x: " << x
<< " y: " << y
<< " pit: " << pit
<< endl;
InsetList::const_iterator iit = par.insetlist.begin();
InsetList::const_iterator iend = par.insetlist.end();
for (; iit != iend; ++iit) {
Inset * inset = iit->inset;
#if 1
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": examining inset " << inset << endl;
if (bv_->coordCache().getInsets().has(inset))
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": xo: " << inset->xo(*bv_) << "..."
<< inset->xo(*bv_) + inset->width()
<< " yo: " << inset->yo(*bv_) - inset->ascent()
<< "..."
<< inset->yo(*bv_) + inset->descent()
<< endl;
else
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": inset has no cached position" << endl;
#endif
if (inset->covers(*bv_, x, y)) {
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": Hit inset: " << inset << endl;
return inset;
}
}
LYXERR(Debug::DEBUG)
<< BOOST_CURRENT_FUNCTION
<< ": No inset hit. " << endl;
return 0;
}
int TextMetrics::cursorX(CursorSlice const & sl,
bool boundary) const
{
BOOST_ASSERT(sl.text() == text_);
pit_type const pit = sl.pit();
Paragraph const & par = text_->paragraphs()[pit];
ParagraphMetrics const & pm = par_metrics_[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();
double x = row.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 = text_->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;
// 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) {
FontMetrics const & labelfm = theFontMetrics(
text_->getLabelFont(buffer, par));
x += row.label_hfill + labelfm.width(par.layout()->labelsep);
if (par.isLineSeparator(body_pos - 1))
x -= singleWidth(pit, 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 = text_->getFont(buffer, par, pos);
}
x += pm.singleWidth(pos, font);
if (pm.hfillExpansion(row, pos))
x += (pos >= body_pos) ? row.hfill : row.label_hfill;
else if (par.isSeparator(pos) && pos >= body_pos)
x += row.separator;
}
// see correction above
if (boundary_correction) {
if (text_->isRTL(buffer, sl, boundary))
x -= singleWidth(pit, ppos);
else
x += singleWidth(pit, ppos);
}
return int(x);
}
int TextMetrics::cursorY(CursorSlice const & sl, bool boundary) const
{
//lyxerr << "TextMetrics::cursorY: boundary: " << boundary << std::endl;
ParagraphMetrics const & pm = par_metrics_[sl.pit()];
if (pm.rows().empty())
return 0;
int h = 0;
h -= par_metrics_[0].rows()[0].ascent();
for (pit_type pit = 0; pit < sl.pit(); ++pit) {
h += par_metrics_[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;
}
void TextMetrics::cursorPrevious(Cursor & cur)
{
pos_type cpos = cur.pos();
pit_type cpar = cur.pit();
int x = cur.x_target();
setCursorFromCoordinates(cur, x, 0);
cur.dispatch(FuncRequest(cur.selection()? LFUN_UP_SELECT: LFUN_UP));
if (cpar == cur.pit() && cpos == cur.pos())
// we have a row which is taller than the workarea. The
// simplest solution is to move to the previous row instead.
cur.dispatch(FuncRequest(cur.selection()? LFUN_UP_SELECT: LFUN_UP));
finishUndo();
cur.updateFlags(Update::Force | Update::FitCursor);
}
void TextMetrics::cursorNext(Cursor & cur)
{
pos_type cpos = cur.pos();
pit_type cpar = cur.pit();
int x = cur.x_target();
setCursorFromCoordinates(cur, x, cur.bv().workHeight() - 1);
cur.dispatch(FuncRequest(cur.selection()? LFUN_DOWN_SELECT: LFUN_DOWN));
if (cpar == cur.pit() && cpos == cur.pos())
// we have a row which is taller than the workarea. The
// simplest solution is to move to the next row instead.
cur.dispatch(
FuncRequest(cur.selection()? LFUN_DOWN_SELECT: LFUN_DOWN));
finishUndo();
cur.updateFlags(Update::Force | Update::FitCursor);
}
int TextMetrics::leftMargin(int max_width, pit_type pit) const
{
BOOST_ASSERT(pit >= 0);
BOOST_ASSERT(pit < int(text_->paragraphs().size()));
return leftMargin(max_width, pit, text_->paragraphs()[pit].size());
}
int TextMetrics::leftMargin(int max_width,
pit_type const pit, pos_type const pos) const
{
ParagraphList const & pars = text_->paragraphs();
BOOST_ASSERT(pit >= 0);
BOOST_ASSERT(pit < int(pars.size()));
Paragraph const & par = pars[pit];
BOOST_ASSERT(pos >= 0);
BOOST_ASSERT(pos <= par.size());
Buffer const & buffer = bv_->buffer();
//lyxerr << "TextMetrics::leftMargin: pit: " << pit << " pos: " << pos << endl;
TextClass const & tclass = buffer.params().getTextClass();
LayoutPtr const & layout = par.layout();
docstring parindent = layout->parindent;
int l_margin = 0;
if (text_->isMainText(buffer))
l_margin += changebarMargin();
l_margin += theFontMetrics(buffer.params().getFont()).signedWidth(
tclass.leftmargin());
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(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 = text_->getLabelFont(buffer, par);
FontMetrics const & labelfont_metrics = theFontMetrics(labelfont);
switch (layout->margintype) {
case MARGIN_DYNAMIC:
if (!layout->leftmargin.empty()) {
l_margin += theFontMetrics(buffer.params().getFont()).signedWidth(
layout->leftmargin);
}
if (!par.getLabelstring().empty()) {
l_margin += labelfont_metrics.signedWidth(layout->labelindent);
l_margin += labelfont_metrics.width(par.getLabelstring());
l_margin += labelfont_metrics.width(layout->labelsep);
}
break;
case MARGIN_MANUAL: {
l_margin += labelfont_metrics.signedWidth(layout->labelindent);
// 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);
l_margin += labelfont_metrics.width(layout->labelsep);
}
}
break;
}
case MARGIN_STATIC: {
l_margin += theFontMetrics(buffer.params().getFont()).
signedWidth(layout->leftmargin) * 4 / (par.getDepth() + 4);
break;
}
case MARGIN_FIRST_DYNAMIC:
if (layout->labeltype == LABEL_MANUAL) {
if (pos >= par.beginOfBody()) {
l_margin += labelfont_metrics.signedWidth(layout->leftmargin);
} else {
l_margin += labelfont_metrics.signedWidth(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))) {
l_margin += labelfont_metrics.signedWidth(layout->leftmargin);
} else if (layout->labeltype != LABEL_TOP_ENVIRONMENT
&& layout->labeltype != LABEL_BIBLIO
&& layout->labeltype !=
LABEL_CENTERED_TOP_ENVIRONMENT) {
l_margin += labelfont_metrics.signedWidth(layout->labelindent);
l_margin += labelfont_metrics.width(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();
// FIXME: This is wrong.
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))
{
l_margin += theFontMetrics(buffer.params().getFont()).signedWidth(
parindent);
}
return l_margin;
}
int TextMetrics::singleWidth(pit_type pit, pos_type pos) const
{
Buffer const & buffer = bv_->buffer();
@ -1181,8 +1766,8 @@ void TextMetrics::drawRowSelection(PainterInfo & pi, int x, Row const & row,
{
Buffer & buffer = bv_->buffer();
DocIterator cur = beg;
int x1 = text_->cursorX(*bv_, beg.top(), beg.boundary());
int x2 = text_->cursorX(*bv_, end.top(), end.boundary());
int x1 = cursorX(beg.top(), beg.boundary());
int x2 = cursorX(end.top(), end.boundary());
int y1 = bv_funcs::getPos(*bv_, cur, cur.boundary()).y_ - row.ascent();
int y2 = y1 + row.height();
@ -1236,11 +1821,11 @@ void TextMetrics::drawRowSelection(PainterInfo & pi, int x, Row const & row,
if (x1 == -1) {
// the previous segment was just drawn, now the next starts
x1 = text_->cursorX(*bv_, cur.top(), cur.boundary());
x1 = cursorX(cur.top(), cur.boundary());
}
if (!(cur < end) || drawNow) {
x2 = text_->cursorX(*bv_, cur.top(), cur.boundary());
x2 = cursorX(cur.top(), cur.boundary());
pi.pain.fillRectangle(x + min(x1,x2), y1, abs(x2 - x1), y2 - y1,
Color::selection);
@ -1251,7 +1836,7 @@ void TextMetrics::drawRowSelection(PainterInfo & pi, int x, Row const & row,
}
}
//int Text::pos2x(pit_type pit, pos_type pos) const
//int TextMetrics::pos2x(pit_type pit, pos_type pos) const
//{
// ParagraphMetrics const & pm = par_metrics_[pit];
// Row const & r = pm.rows()[row];

View File

@ -136,6 +136,60 @@ public:
// FIXME: is there a need for this?
//int pos2x(pit_type pit, pos_type pos) const;
/** returns row near the specified
* y-coordinate in given paragraph (relative to the screen).
*/
Row const & getRowNearY(int y,
pit_type pit) const;
/// returns the paragraph number closest to screen y-coordinate.
/// This method uses the BufferView CoordCache to locate the
/// paragraph. The y-coodinate is allowed to be off-screen and
/// the CoordCache will be automatically updated if needed. This is
/// the reason why we need a non const BufferView.
pit_type getPitNearY(int y);
/// sets cursor recursively descending into nested editable insets
/**
\return the inset pointer if x,y is covering that inset
\param x,y are absolute screen coordinates.
\retval inset is non-null if the cursor is positionned inside
*/
/// FIXME: cleanup to use BufferView::getCoveringInset() and
/// setCursorFromCoordinates() instead of checkInsetHit().
Inset * editXY(Cursor & cur, int x, int y);
/// sets cursor only within this Text.
/// x,y are screen coordinates
void setCursorFromCoordinates(Cursor & cur, int x, int y);
///
int cursorX(CursorSlice const & cursor,
bool boundary) const;
///
int cursorY(CursorSlice const & cursor,
bool boundary) const;
///
void cursorPrevious(Cursor & cur);
///
void cursorNext(Cursor & cur);
/// Returns an inset if inset was hit, or 0 if not.
/// \warning This method is not recursive! It will return the
/// outermost inset within this Text.
/// \sa BufferView::getCoveringInset() to get the innermost inset.
Inset * checkInsetHit(int x, int y);
/**
* 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(int max_width, pit_type pit, pos_type pos) const;
int leftMargin(int max_width, pit_type pit) const;
private:
/// The BufferView owner.

View File

@ -189,7 +189,8 @@ Point coordOffset(BufferView const & bv, DocIterator const & dit,
// Add contribution of initial rows of outermost paragraph
CursorSlice const & sl = dit[0];
ParagraphMetrics const & pm = bv.parMetrics(sl.text(), sl.pit());
TextMetrics const & tm = bv.textMetrics(sl.text());
ParagraphMetrics const & pm = tm.parMetrics(sl.pit());
BOOST_ASSERT(!pm.rows().empty());
y -= pm.rows()[0].ascent();
#if 1
@ -211,7 +212,8 @@ Point coordOffset(BufferView const & bv, DocIterator const & dit,
y += pm.rows()[rend].ascent();
// Make relative position from the nested inset now bufferview absolute.
int xx = dit.bottom().text()->cursorX(bv, dit.bottom(), boundary && dit.depth() == 1);
int xx = bv.textMetrics(dit.bottom().text()).cursorX(
dit.bottom(), boundary && dit.depth() == 1);
x += xx;
// In the RTL case place the nested inset at the left of the cursor in

View File

@ -3912,14 +3912,14 @@ Inset * InsetTabular::editXY(Cursor & cur, int x, int y)
cur.push(*this);
cur.idx() = getNearestCell(cur.bv(), x, y);
resetPos(cur);
return cell(cur.idx())->text_.editXY(cur, x, y);
return cur.bv().textMetrics(&cell(cur.idx())->text_).editXY(cur, x, y);
}
void InsetTabular::setCursorFromCoordinates(Cursor & cur, int x, int y) const
{
cur.idx() = getNearestCell(cur.bv(), x, y);
cell(cur.idx())->text_.setCursorFromCoordinates(cur, x, y);
cur.bv().textMetrics(&cell(cur.idx())->text_).setCursorFromCoordinates(cur, x, y);
}

View File

@ -226,7 +226,7 @@ void InsetText::edit(Cursor & cur, bool left)
Inset * InsetText::editXY(Cursor & cur, int x, int y)
{
return text_.editXY(cur, x, y);
return cur.bv().textMetrics(&text_).editXY(cur, x, y);
}
@ -322,8 +322,8 @@ void InsetText::validate(LaTeXFeatures & features) const
void InsetText::cursorPos(BufferView const & bv,
CursorSlice const & sl, bool boundary, int & x, int & y) const
{
x = text_.cursorX(bv, sl, boundary) + border_;
y = text_.cursorY(bv, sl, boundary);
x = bv.textMetrics(&text_).cursorX(sl, boundary) + border_;
y = bv.textMetrics(&text_).cursorY(sl, boundary);
}

View File

@ -117,8 +117,8 @@ Text * InsetMathMBox::getText(int) const
void InsetMathMBox::cursorPos(BufferView const & bv,
CursorSlice const & sl, bool boundary, int & x, int & y) const
{
x = text_.cursorX(bv, sl, boundary);
y = text_.cursorY(bv, sl, boundary);
x = bv.textMetrics(&text_).cursorX(sl, boundary);
y = bv.textMetrics(&text_).cursorY(sl, boundary);
}

View File

@ -82,7 +82,7 @@ Font const RowPainter::getLabelFont() const
int RowPainter::leftMargin() const
{
return text_.leftMargin(pi_.base.bv->buffer(), text_metrics_.width(), pit_,
return text_metrics_.leftMargin(text_metrics_.width(), pit_,
row_.pos());
}