deep iterators for math insets;

use brute force for to determine "best" position when doing cursor up/down
(will be sped up a bit again soonish...)


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@3153 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
André Pönitz 2001-12-05 17:50:18 +00:00
parent 6f5f012d3d
commit ebe6d25126
10 changed files with 493 additions and 166 deletions

View File

@ -68,6 +68,8 @@ libmathed_la_SOURCES = \
math_hullinset.h \
math_inset.C \
math_inset.h \
math_iterator.C \
math_iterator.h \
math_kerninset.C \
math_kerninset.h \
math_lefteqninset.C \

View File

@ -26,12 +26,12 @@ Inset hierarchy:
/ \
Array "Matrix"
Array Hull
(base for eqnarray/align/...)
There are only two "real LyXInsets" in here:
Formula - containing a pointer to a MathMatrixInset (a misnomer...)
Formula - containing a pointer to a MathHullInset
FormulaMacro - containing a pointer to a MathMacroTemplate

View File

@ -28,22 +28,23 @@
#include "debug.h"
#include "LColor.h"
#include "Painter.h"
#include "math_support.h"
#include "formulabase.h"
#include "math_cursor.h"
#include "math_casesinset.h"
#include "math_factory.h"
#include "math_arrayinset.h"
#include "math_braceinset.h"
#include "math_casesinset.h"
#include "math_charinset.h"
#include "math_cursor.h"
#include "math_deliminset.h"
#include "math_factory.h"
#include "math_hullinset.h"
#include "math_iterator.h"
#include "math_mathmlstream.h"
#include "math_parser.h"
#include "math_replace.h"
#include "math_scriptinset.h"
#include "math_spaceinset.h"
#include "math_specialcharinset.h"
#include "math_mathmlstream.h"
#include "math_replace.h"
#include "math_parser.h"
#include "math_support.h"
#define FILEDEBUG 0
@ -67,7 +68,7 @@ struct Selection
data_.push_back(MathArray(i1.cell(), i1.pos_, i2.pos_));
else {
std::vector<MathInset::idx_type> indices =
(*i1.par_)->idxBetween(i1.idx_, i2.idx_);
i1.par_->idxBetween(i1.idx_, i2.idx_);
for (MathInset::idx_type i = 0; i < indices.size(); ++i)
data_.push_back(i1.cell(indices[i]));
}
@ -82,7 +83,7 @@ struct Selection
i1.cell().erase(i1.pos_, i2.pos_);
else {
std::vector<MathInset::idx_type> indices =
(*i1.par_)->idxBetween(i1.idx_, i2.idx_);
i1.par_->idxBetween(i1.idx_, i2.idx_);
for (unsigned i = 0; i < indices.size(); ++i)
i1.cell(indices[i]).erase();
}
@ -116,13 +117,6 @@ struct Selection
Selection theSelection;
#if FILEDEBUG
std::ostream & operator<<(std::ostream & os, MathCursorPos const & p)
{
os << "(par: " << p.par_ << " idx: " << p.idx_ << " pos: " << p.pos_ << ")";
return os;
}
#endif
}
@ -136,11 +130,7 @@ MathCursor::MathCursor(InsetFormulaBase * formula, bool left)
void MathCursor::push(MathAtom & t)
{
MathCursorPos p;
p.par_ = &t;
p.idx_ = 0;
p.pos_ = 0;
Cursor_.push_back(p);
Cursor_.push_back(MathCursorPos(t.nucleus()));
}
@ -192,48 +182,19 @@ bool MathCursor::popRight()
#if FILEDEBUG
void MathCursor::dump(char const * what) const
{
lyxerr << "MC: " << what << "\n";
for (unsigned i = 0; i < Cursor_.size(); ++i)
lyxerr << " i: " << i
<< " Cursor: pos: " << Cursor_[i].pos_
<< " idx: " << Cursor_[i].idx_
<< " par: " << Cursor_[i].par_ << "\n";
for (unsigned i = 0; i < Anchor_.size(); ++i)
lyxerr << " i: " << i
<< " Anchor: pos: " << Anchor_[i].pos_
<< " idx: " << Anchor_[i].idx_
<< " par: " << Anchor_[i].par_ << "\n";
lyxerr << " sel: " << selection_ << "\n";
}
void MathCursor::seldump(char const * str) const
{
//lyxerr << "SEL: " << str << ": '" << theSelection << "'\n";
//dump(" Pos");
lyxerr << "\n\n\n=================vvvvvvvvvvvvv======================= "
<< str << "\ntheSelection: " << selection_
<< " '" /*<< theSelection.glue()*/ << "'\nCursor:";
for (unsigned int i = 0; i < Cursor_.size(); ++i)
lyxerr << Cursor_[i].par_ << "\n'" /*<< Cursor_[i].cell()*/ << "'\n";
lyxerr << "\nAnchor: ";
for (unsigned int i = 0; i < Anchor_.size(); ++i)
lyxerr << Anchor_[i].par_ << "\n'" /*<< Anchor_[i].cell()*/ << "'\n";
//lyxerr << "\ncursor.pos_: " << pos();
//lyxerr << "\nanchor.pos_: " << anchor().pos_;
lyxerr << "\n===================^^^^^^^^^^^^=====================\n\n\n";
}
void MathCursor::dump(char const * what) const
{
lyxerr << "MC: " << what << "\n";
lyxerr << " Cursor: " << Cursor_.size() << "\n";
for (unsigned i = 0; i < Cursor_.size(); ++i)
lyxerr << " i: " << i << " " << Cursor_[i] << "\n";
lyxerr << " Anchor: " << Anchor_.size() << "\n";
for (unsigned i = 0; i < Anchor_.size(); ++i)
lyxerr << " i: " << i << " " << Anchor_[i] << "\n";
lyxerr << " sel: " << selection_ << "\n";
}
#else
void MathCursor::seldump(char const *) const {}
void MathCursor::dump(char const *) const {}
void MathCursor::dump(char const *) const {}
#endif
@ -246,7 +207,7 @@ UpdatableInset * MathCursor::asHyperActiveInset() const
bool MathCursor::isInside(MathInset const * p) const
{
for (unsigned i = 0; i < Cursor_.size(); ++i)
if (Cursor_[i].par_->nucleus() == p)
if (Cursor_[i].par_ == p)
return true;
return false;
}
@ -267,7 +228,7 @@ bool MathCursor::openable(MathAtom const & t, bool sel) const
// we can't move into anything new during selection
if (Cursor_.size() == Anchor_.size())
return false;
if (&t != Anchor_[Cursor_.size()].par_)
if (t.nucleus() != Anchor_[Cursor_.size()].par_)
return false;
}
return true;
@ -280,7 +241,7 @@ bool MathCursor::positionable(MathAtom const & t, int x, int y) const
// we can't move into anything new during selection
if (Cursor_.size() >= Anchor_.size())
return false;
if (&t != Anchor_[Cursor_.size()].par_)
if (t.nucleus() != Anchor_[Cursor_.size()].par_)
return false;
}
@ -371,6 +332,7 @@ void MathCursor::last()
}
#if 0
void MathCursor::setPos(int x, int y)
{
//dump("setPos 1");
@ -407,6 +369,47 @@ void MathCursor::setPos(int x, int y)
//dump("setPos 2");
}
#else
void MathCursor::setPos(int x, int y)
{
dump("setPos 1");
cursor_type best_cursor;
double best_dist = 1e10;
MathIterator it(formula()->par().nucleus());
MathIterator et;
for ( ; it != et; ++it) {
if (selection_) {
// avoid deeper nested insets when selecting
if (it.cursor().size() > Anchor_.size())
continue;
// anchor might be deeper!
if (it.cursor().size() == Anchor_.size())
if (it.par() != Anchor_.back().par_)
continue;
//if (it.par() != Anchor_[it.cursor().size()].par_)
// continue;
}
//lyxerr << it.position() << endl;
int xo = it.position().xpos();
int yo = it.position().ypos();
double d = (x - xo) * (x - xo) + (y - yo) * (y - yo);
if (d < best_dist) {
best_dist = d;
best_cursor = it.cursor();
}
}
if (best_dist < 1e10)
Cursor_ = best_cursor;
//lyxerr << "x: " << x << " y: " << y << " dist: " << best_dist << "\n";
dump("setPos 2");
}
#endif
void MathCursor::home(bool sel)
{
@ -687,7 +690,7 @@ string MathCursor::macroName() const
void MathCursor::selCopy()
{
seldump("selCopy");
dump("selCopy");
if (selection_) {
theSelection.grab(*this);
selClear();
@ -697,7 +700,7 @@ void MathCursor::selCopy()
void MathCursor::selCut()
{
seldump("selCut");
dump("selCut");
if (selection_) {
theSelection.grab(*this);
theSelection.erase(*this);
@ -710,7 +713,7 @@ void MathCursor::selCut()
void MathCursor::selDel()
{
seldump("selDel");
dump("selDel");
if (selection_) {
theSelection.erase(*this);
if (pos() > size())
@ -722,7 +725,7 @@ void MathCursor::selDel()
void MathCursor::selPaste()
{
seldump("selPaste");
dump("selPaste");
theSelection.paste(*this);
//theSelection.grab(*this);
//selClear();
@ -741,23 +744,25 @@ void MathCursor::selHandle(bool sel)
void MathCursor::selStart()
{
seldump("selStart");
dump("selStart 1");
//theSelection.clear();
Anchor_ = Cursor_;
selection_ = true;
dump("selStart 2");
}
void MathCursor::selClear()
{
seldump("selClear");
dump("selClear 1");
selection_ = false;
dump("selClear 2");
}
void MathCursor::selGet(MathArray & ar)
{
seldump("selGet");
dump("selGet");
if (!selection_)
return;
@ -786,7 +791,7 @@ void MathCursor::drawSelection(Painter & pain) const
pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
} else {
std::vector<MathInset::idx_type> indices
= (*i1.par_)->idxBetween(i1.idx_, i2.idx_);
= i1.par_->idxBetween(i1.idx_, i2.idx_);
for (unsigned i = 0; i < indices.size(); ++i) {
MathXArray & c = i1.xcell(indices[i]);
int x1 = c.xo();
@ -850,14 +855,16 @@ void MathCursor::getPos(int & x, int & y)
#ifdef WITH_WARNINGS
#warning This should probably take cellXOffset and cellYOffset into account
#endif
dump("getPos 1");
x = xarray().xo() + xarray().pos2x(pos());
y = xarray().yo();
dump("getPos 2");
}
MathAtom & MathCursor::par() const
MathInset * MathCursor::par() const
{
return *cursor().par_;
return cursor().par_;
}
@ -906,7 +913,7 @@ bool MathCursor::selection() const
MathGridInset * MathCursor::enclosingGrid(MathCursor::idx_type & idx) const
{
for (int i = Cursor_.size() - 1; i >= 0; --i) {
MathGridInset * p = (*Cursor_[i].par_)->asGridInset();
MathGridInset * p = Cursor_[i].par_->asGridInset();
if (p) {
idx = Cursor_[i].idx_;
return p;
@ -1153,8 +1160,12 @@ MathCursorPos const & MathCursor::cursor() const
bool MathCursor::goUp()
{
// first ask the inset if it knows better then we
if (par()->idxUp(idx(), pos()))
if (par()->idxUp(idx(), pos())) {
int xlow, xhigh, ylow, yhigh;
xarray().boundingBox(xlow, xhigh, ylow, yhigh);
bruteFind(xlow, xhigh, ylow, yhigh);
return true;
}
// leave subscript to the nearest side
MathScriptInset * p = par()->asScriptInset();
@ -1175,8 +1186,12 @@ bool MathCursor::goUp()
bool MathCursor::goDown()
{
// first ask the inset if it knows better then we
if (par()->idxDown(idx(), pos()))
if (par()->idxDown(idx(), pos())) {
int xlow, xhigh, ylow, yhigh;
xarray().boundingBox(xlow, xhigh, ylow, yhigh);
bruteFind(xlow, xhigh, ylow, yhigh);
return true;
}
// leave superscript to the nearest side
MathScriptInset * p = par()->asScriptInset();
@ -1200,8 +1215,8 @@ bool MathCursor::bruteUpDown(int ylow, int yhigh)
int x0;
int y0;
getPos(x0, y0);
std::vector<MathCursorPos> save = Cursor_;
std::vector<MathCursorPos> best;
cursor_type save = Cursor_;
cursor_type best;
double best_dist = 1e10; // large enough
bool found = false;
for (int y = ylow; y < yhigh; y += 4) {
@ -1229,6 +1244,35 @@ bool MathCursor::bruteUpDown(int ylow, int yhigh)
}
bool MathCursor::bruteFind(int xlow, int xhigh, int ylow, int yhigh)
{
//lyxerr << "looking at range: " << ylow << " " << yhigh << "\n";
int x;
int y;
getPos(x, y);
cursor_type best_cursor;
double best_dist = 1e10;
MathIterator it(formula()->par().nucleus());
MathIterator et;
for ( ; it != et; ++it) {
int xo = it.position().xpos();
int yo = it.position().ypos();
if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) {
double d = (x - xo) * (x - xo) + (y - yo) * (y - yo);
if (d < best_dist) {
best_dist = d;
best_cursor = it.cursor();
}
}
}
if (best_dist < 1e10)
Cursor_ = best_cursor;
return true;
}
bool MathCursor::idxLeft()
{
return par()->idxLeft(idx(), pos());
@ -1443,51 +1487,6 @@ bool MathCursor::interpret(char c)
////////////////////////////////////////////////////////////////////////
bool operator==(MathCursorPos const & ti, MathCursorPos const & it)
{
return ti.par_ == it.par_ && ti.idx_ == it.idx_ && ti.pos_ == it.pos_;
}
bool operator<(MathCursorPos const & ti, MathCursorPos const & it)
{
if (ti.par_ != it.par_) {
lyxerr << "can't compare cursor and anchor in different insets\n";
return true;
}
if (ti.idx_ != it.idx_)
return ti.idx_ < it.idx_;
return ti.pos_ < it.pos_;
}
MathArray & MathCursorPos::cell(MathCursor::idx_type idx) const
{
return (*par_)->cell(idx);
}
MathArray & MathCursorPos::cell() const
{
return (*par_)->cell(idx_);
}
MathXArray & MathCursorPos::xcell(MathCursor::idx_type idx) const
{
return (*par_)->xcell(idx);
}
MathXArray & MathCursorPos::xcell() const
{
return (*par_)->xcell(idx_);
}
MathCursorPos MathCursor::normalAnchor() const
{
// use Anchor on the same level as Cursor
@ -1515,3 +1514,82 @@ void MathCursor::stripFromLastEqualSign()
}
////////////////////////////////////////////////////////////////////////
MathCursorPos::MathCursorPos()
: par_(0), idx_(0), pos_(0)
{}
MathCursorPos::MathCursorPos(MathInset * p)
: par_(p), idx_(0), pos_(0)
{}
MathArray & MathCursorPos::cell(MathCursor::idx_type idx) const
{
return par_->cell(idx);
}
MathArray & MathCursorPos::cell() const
{
return par_->cell(idx_);
}
MathXArray & MathCursorPos::xcell(MathCursor::idx_type idx) const
{
return par_->xcell(idx);
}
MathXArray & MathCursorPos::xcell() const
{
return par_->xcell(idx_);
}
int MathCursorPos::xpos() const
{
return xcell().xo() + xcell().pos2x(pos_);
}
int MathCursorPos::ypos() const
{
return xcell().yo();
}
std::ostream & operator<<(std::ostream & os, MathCursorPos const & p)
{
os << "(par: " << p.par_ << " idx: " << p.idx_ << " pos: " << p.pos_ << ")";
return os;
}
bool operator==(MathCursorPos const & ti, MathCursorPos const & it)
{
return ti.par_ == it.par_ && ti.idx_ == it.idx_ && ti.pos_ == it.pos_;
}
bool operator!=(MathCursorPos const & ti, MathCursorPos const & it)
{
return ti.par_ != it.par_ || ti.idx_ != it.idx_ || ti.pos_ != it.pos_;
}
bool operator<(MathCursorPos const & ti, MathCursorPos const & it)
{
if (ti.par_ != it.par_) {
lyxerr << "can't compare cursor and anchor in different insets\n";
return true;
}
if (ti.idx_ != it.idx_)
return ti.idx_ < it.idx_;
return ti.pos_ < it.pos_;
}

View File

@ -42,13 +42,12 @@ this formula's mathHullInset to the current position.
/// Description of a position
struct MathCursorPos {
/// pointer to an inset
MathAtom * par_;
/// cell index of a position in this inset
MathInset::idx_type idx_;
/// position in this cell
MathInset::pos_type pos_;
class MathCursorPos {
public:
///
MathCursorPos();
///
explicit MathCursorPos(MathInset * p);
/// returns cell corresponding to this position
MathArray & cell() const;
@ -58,12 +57,28 @@ struct MathCursorPos {
MathXArray & xcell() const;
/// returns xcell corresponding to this position
MathXArray & xcell(MathInset::idx_type idx) const;
///
int xpos() const;
///
int ypos() const;
public:
/// pointer to an inset
MathInset * par_;
/// cell index of a position in this inset
MathInset::idx_type idx_;
/// position in this cell
MathInset::pos_type pos_;
};
/// test for equality
bool operator==(MathCursorPos const &, MathCursorPos const &);
/// test for unequality
/// test for inequality
bool operator!=(MathCursorPos const &, MathCursorPos const &);
/// test for order
bool operator<(MathCursorPos const &, MathCursorPos const &);
/// output
std::ostream & operator<<(std::ostream &, MathCursorPos const &);
/// see above
@ -128,7 +143,7 @@ public:
/// in pixels from top of screen
void getPos(int & x, int & y);
///
MathAtom & par() const;
MathInset * par() const;
/// return the next enclosing grid inset and the cursor's index in it
MathGridInset * enclosingGrid(idx_type &) const;
///
@ -275,6 +290,8 @@ private:
bool goDown();
/// moves position somehow down
bool bruteUpDown(int ylow, int yhigh);
/// moves position into box
bool bruteFind(int xlow, int xhigh, int ylow, int yhigh);
///
string macroName() const;

View File

@ -487,31 +487,27 @@ int MathGridInset::cellYOffset(idx_type idx) const
}
bool MathGridInset::idxUp(idx_type & /*idx*/, pos_type & /*pos*/) const
bool MathGridInset::idxUp(idx_type & idx, pos_type & pos) const
{
return false;
/*
//return false;
if (idx < ncols())
return false;
int x = cellXOffset(idx) + xcell(idx).pos2x(pos);
idx -= ncols();
pos = xcell(idx).x2pos(x - cellXOffset(idx));
return true;
*/
}
bool MathGridInset::idxDown(idx_type & /*idx*/, pos_type & /*pos*/) const
bool MathGridInset::idxDown(idx_type & idx, pos_type & pos) const
{
return false;
/*
//return false;
if (idx >= ncols() * (nrows() - 1))
return false;
int x = cellXOffset(idx) + xcell(idx).pos2x(pos);
idx += ncols();
pos = xcell(idx).x2pos(x - cellXOffset(idx));
return true;
*/
}

View File

@ -72,6 +72,7 @@ class LaTeXFeatures;
class BufferView;
class UpdatableInset;
class MathMacroTemplate;
class MathPosFinder;
class MathInset {

137
src/mathed/math_iterator.C Normal file
View File

@ -0,0 +1,137 @@
#include <config.h>
#include "debug.h"
#include "math_iterator.h"
MathIterator::MathIterator()
{}
MathIterator::MathIterator(MathInset * p)
{
push(p);
}
MathIterator::MathIterator(MathCursor::cursor_type const & c)
: cursor_(c)
{}
MathCursorPos const & MathIterator::position() const
{
return cursor_.back();
}
MathCursorPos & MathIterator::position()
{
return cursor_.back();
}
MathCursor::cursor_type const & MathIterator::cursor() const
{
return cursor_;
}
MathInset * MathIterator::par() const
{
return cursor_.size() ? cursor_.back().par_ : 0;
}
MathXArray const & MathIterator::xcell() const
{
if (!par())
lyxerr << "MathIterator::xcell: no cell\n";
return par()->xcell(position().idx_);
}
MathInset * MathIterator::nextInset() const
{
if (position().pos_ == xcell().data_.size())
return 0;
return (xcell().begin() + position().pos_)->nucleus();
}
void MathIterator::push(MathInset * p)
{
//lyxerr << "push: " << p << endl;
cursor_.push_back(MathCursorPos(p));
}
void MathIterator::pop()
{
//lyxerr << "pop: " << endl;
cursor_.pop_back();
}
MathCursorPos const & MathIterator::operator*() const
{
return position();
}
MathCursorPos const & MathIterator::operator->() const
{
return position();
}
void MathIterator::operator++()
{
// move into the current inset if possible
// it is impossible for pos() == size()!
if (nextInset() && nextInset()->isActive()) {
push(nextInset());
return;
}
// otherwise move on one cell position if possible
if (position().pos_ < xcell().data_.size()) {
// pos() == size() is valid!
++position().pos_;
return;
}
// otherwise move on one cell if possible
if (position().idx_ + 1 < par()->nargs()) {
// idx() == nargs() is _not_ valid!
++position().idx_;
position().pos_ = 0;
return;
}
// otherwise leave array, move on one cell
// this might yield pos() == size(), but that's a ok.
pop();
++position().pos_;
}
bool operator==(MathIterator const & it, MathIterator const & jt)
{
//lyxerr << "==: " << it.cursor().size() << " " << jt.cursor().size() << endl;
if (it.cursor().size() != jt.cursor().size())
return false;
return it.cursor() == jt.cursor();
}
bool operator!=(MathIterator const & it, MathIterator const & jt)
{
//lyxerr << "!=: " << it.cursor().size() << " " << jt.cursor().size() << endl;
if (it.cursor().size() != jt.cursor().size())
return true;
return it.cursor() != jt.cursor();
}

View File

@ -0,0 +1,51 @@
#ifndef MATH_ITERATOR_H
#define MATH_ITERATOR_H
#include "math_cursor.h"
// this helper struct is used for traversing math insets
class MathIterator {
public:
/// default constructor, used for end of range
MathIterator();
/// start with given formula
explicit MathIterator(MathInset * p);
/// start with given position
explicit MathIterator(MathCursor::cursor_type const & cursor);
///
MathCursorPos const & operator*() const;
///
MathCursorPos const & operator->() const;
///
void operator++();
/// read access to top most item
MathCursorPos const & position() const;
/// write access to top most item
MathCursorPos & position();
/// read access to full path
MathCursor::cursor_type const & cursor() const;
/// read access to top most inset
MathInset * par() const;
private:
/// write access to top most item
MathXArray const & xcell() const;
/// write access to top most item
MathInset * nextInset() const;
/// own level down
void push(MathInset *);
/// own level up
void pop();
/// current position
MathCursor::cursor_type cursor_;
};
///
bool operator==(MathIterator const &, MathIterator const &);
///
bool operator!=(MathIterator const &, MathIterator const &);
#endif

View File

@ -151,3 +151,39 @@ bool MathXArray::covers(int x, int y) const
int const y1 = yo_ + descent_;
return x >= x0 && x <= x1 && y >= y0 && y <= y1;
}
void MathXArray::boundingBox(int & x1, int & x2, int & y1, int & y2)
{
x1 = xo_;
x2 = xo_ + width_;
y1 = yo_ - ascent_;
y2 = yo_ + descent_;
}
/*
void MathXArray::findPos(MathPosFinder & f) const
{
double x = xo_;
double y = yo_;
for (const_iterator it = begin(); it < end(); ++it) {
// check this position in the cell first
f.visit(x, y);
f.nextPos();
// check inset
MathInset const * p = it->nucleus();
p->findPos(f);
// move on
MathScriptInset const * q = (it + 1 == end()) ? 0 : asScript(it);
if (q) {
x += q->width(p);
f.nextPos();
++it;
} else {
x += p->width();
}
}
}
*/

View File

@ -14,66 +14,75 @@
class Painter;
/** This class extends a MathArray by drawing routines and caches for
* metric information.
*/
class MathXArray
{
public:
///
/// type for positions and sizes
typedef MathArray::size_type size_type;
///
/// const iterator into the underlying MathArray
typedef MathArray::const_iterator const_iterator;
///
/// constructor
MathXArray();
///
/// rebuild cached metrics information
void metrics(MathMetricsInfo const & st) const;
///
/// redraw cell using cache metrics information
void draw(Painter & pain, int x, int y) const;
///
/// access to cached x coordinate of last drawing
int xo() const { return xo_; }
///
/// access to cached y coordinate of last drawing
int yo() const { return yo_; }
///
/// returns x coordinate of given position in the array
int pos2x(size_type pos) const;
///
/// returns position of given x coordinate
size_type x2pos(int pos) const;
/// returns distance of this cell to the point given by x and y
// assumes valid position and size cache
int dist(int x, int y) const;
///
/// ascent of this cell above the baseline
int ascent() const { return ascent_; }
///
/// descent of this cell below the baseline
int descent() const { return descent_; }
///
/// height of the cell
int height() const { return ascent_ + descent_; }
///
/// width of this cell
int width() const { return width_; }
/// do we cover point(x, y)?
bool covers(int x, int y) const;
/// bounding box of this cell
void boundingBox(int & xlow, int & xhigh, int & ylow, int & yhigh);
/// find best position to do things
//void findPos(PosFinder &) const;
///
/// begin iterator of the underlying MathArray
const_iterator begin() const { return data_.begin(); }
///
/// end iterator of the underlying MathArray
const_iterator end() const { return data_.end(); }
public:
///
/// the underlying MathArray
MathArray data_;
///
/// cached width of cell
mutable int width_;
///
/// cached ascent of cell
mutable int ascent_;
///
/// cached descent of cell
mutable int descent_;
///
/// cached x coordinate of last drawing
mutable int xo_;
///
/// cached y coordinate of last drawing
mutable int yo_;
///
/// cache size information of last drawing
mutable MathMetricsInfo size_;
};
/// output cell on a stream
std::ostream & operator<<(std::ostream & os, MathXArray const & ar);
#endif