+#include <config.h>
#include "dimension.h"
+#include "math_support.h"
+
+#include <iostream>
+
void Dimension::operator+=(Dimension const & dim)
{
d = dim.d;
w += dim.w;
}
+
+
+std::ostream & operator<<(std::ostream & os, Dimension const & dim)
+{
+ os << " (" << dim.w << 'x' << dim.a << '-' << dim.d << ") ";
+ return os;
+}
+
+
+void Dimension::clear(LyXFont const & font)
+{
+ math_font_max_dim(font, a, d);
+ w = 0;
+}
#ifndef DIMENSION_H
#define DIMENSION_H
+#include <iosfwd>
+
+class LyXFont;
+
class Dimension {
public:
/// constructor
void operator+=(Dimension const & dim);
/// set to empty box
void clear() { w = a = d = 0; }
+ /// set to empty box suitble for given font
+ void clear(LyXFont const & font);
/// get height
int height() const { return a + d; }
/// get ascent
int d;
};
+std::ostream & operator<<(std::ostream & os, Dimension const & dim);
+
#endif
void MathCursor::getPos(int & x, int & y)
{
-#ifdef WITH_WARNINGS
-#warning This should probably take cellXOffset and cellYOffset into account
-#endif
- x = xarray().xo() + xarray().pos2x(pos());
- // move cursor visually into empty cells ("blue rectangles");
- if (array().empty())
- x += 2;
- y = xarray().yo();
- //lyxerr << "getPos: " << x << " " << y << "\n";
+ par()->getPos(idx(), pos(), x, y);
}
}
+void MathInset::getPos(idx_type, pos_type, int & x, int & y) const
+{
+ lyxerr << "MathInset::getPos() called directly!\n";
+ x = y = 0;
+}
+
+
void MathInset::normalize(NormalStream & os) const
{
os << "[unknown ";
virtual void dimensions(Dimension & dim) const;
/// total height (== ascent + descent)
virtual int height() const;
+ /// get cursor position
+ virtual void getPos(idx_type idx, pos_type pos, int & x, int & y) const;
/// Where should we go when we press the up or down cursor key?
virtual bool idxUpDown(idx_type & idx, bool up) const;
}
+void MathNestInset::getPos(idx_type idx, pos_type pos, int & x, int & y) const
+{
+ x = cells_[idx].xo() + cells_[idx].pos2x(pos);
+ y = cells_[idx].yo();
+ // move cursor visually into empty cells ("blue rectangles");
+ if (!cells_[idx].data().size())
+ x += 2;
+}
+
void MathNestInset::substitute(MathMacro const & m)
{
for (idx_type i = 0; i < nargs(); ++i)
void substitute(MathMacro const & macro);
/// identifies NestInsets
MathNestInset * asNestInset() { return this; }
+ /// get cursor position
+ void getPos(idx_type idx, pos_type pos, int & x, int & y) const;
/// order of movement through the cells when pressing the left key
bool idxLeft(idx_type & idx, pos_type & pos) const;
}
+void MathParboxInset::getPos(idx_type idx, pos_type pos, int & x, int & y) const
+{
+ for (int r = 0, n = rows_.size(); r < n; ++r) {
+ if (pos >= rows_[r].begin && pos < rows_[r].end) {
+ //lyxerr << "found cursor at pos " << pos << " in row " << r << "\n";
+ x = cells_[0].xo() + cells_[0].pos2x(rows_[r].begin, pos, rows_[r].glue);
+ y = cells_[0].yo() + rows_[r].yo;
+ break;
+ }
+ }
+ // move cursor visually into empty cells ("blue rectangles");
+ if (cell(0).empty())
+ x += 2;
+}
+
+
void MathParboxInset::metrics(MathMetricsInfo & mi) const
{
MathFontSetChanger dummy(mi.base, "textnormal");
// delete old cache
rows_.clear();
-#if 1
+#if 0
dim_ = xcell(0).metrics(mi);
#else
- xcell(0).metricsExternal(mi, rows_);
+ vector<Dimension> dims;
+ xcell(0).metricsExternal(mi, dims);
int spaces = 0;
- Dimension safe(0, 0, 0);
- Dimension curr(0, 0, 0);
+ Dimension safe;
+ Dimension curr;
+ safe.clear(mi.base.font);
+ curr.clear(mi.base.font);
+ int begin = 0;
int safepos = 0;
int yo = 0;
- for (size_type i = 0, n = cell(0).size(); i != n; ++i) {
+ for (size_type i = 0, n = cell(0).size(); i < n; ++i) {
+ //lyxerr << "at pos: " << i << " of " << n << " safepos: " << safepos
+ // << " curr: " << curr << " safe: " << safe
+ // << " spaces: " << spaces << endl;
+
+
+ // 0 1 2 3 4 5 6
+ // <char> <char> <char> <space> <char> <char> <char>
+ // ................... <safe>
+ // ..........................<curr>
+ // ....................<safepos>
+
// Special handling of spaces. We reached a safe position for breaking.
if (cell(0)[i]->getChar() == ' ') {
+ //lyxerr << "reached safe pos\n";
+ // we don't count the space into the safe pos
safe += curr;
- safepos = i + 1;
+ // we reset to this safepos if the next chunk does not fit
+ safepos = i;
++spaces;
- // restart chunk
- curr = Dimension(0, 0, 0);
+ // restart chunk with size of the space
+ curr.clear(mi.base.font);
+ curr += dims[i];
continue;
}
- // This is a regular item. Go on if we either don't care for
+ // This is a regular char. Go on if we either don't care for
// the width limit or have not reached that limit.
- curr += rows_[i].dim;
+ curr += dims[i];
if (curr.w + safe.w <= lyx_width_)
continue;
// We passed the limit. Create a row entry.
+ //lyxerr << "passed limit\n";
MathXArray::Row row;
if (spaces) {
// but we had a space break before this position.
- row.dim = safe;
- row.glue = (lyx_width_ - safe.w) / spaces;
- row.end = safepos;
- i = safepos;
+ // so retreat to this position
+ row.dim = safe;
+ row.glue = (lyx_width_ - safe.w) / spaces;
+ row.begin = begin;
+ row.end = safepos; // this is position of the safe space
+ i = safepos; // i gets incremented at end of loop
+ begin = i + 1; // next chunk starts after the space
+ //lyxerr << "... but had safe pos. glue: " << row.glue << "\n";
spaces = 0;
} else {
+ lyxerr << "... without safe pos\n";
// This item is too large and it is the only one.
// We have no choice but to produce an overfull box.
- row.dim = curr; // safe should be 0.
- row.glue = 0; // does not matter
- row.end = i + 1;
+ row.dim = curr; // safe should be 0.
+ row.glue = 0; // does not matter
+ row.begin = begin;
+ row.end = i + 1;
+ begin = i + 1;
}
- yo += rows_[i].dim.height();
row.yo = yo;
+ yo += row.dim.height();
rows_.push_back(row);
+ // in any case, start the new row with empty boxes
+ curr.clear(mi.base.font);
+ safe.clear(mi.base.font);
}
- // last row:
+ // last row: put in everything else
MathXArray::Row row;
- row.dim = safe;
- row.dim += curr;
- row.end = cell(0).size();
- row.glue = spaces ? (lyx_width_ - row.dim.w) / spaces : 0;
- yo += row.dim.height();
- row.yo = yo;
+ row.dim = safe;
+ row.dim += curr;
+ row.begin = begin;
+ row.end = cell(0).size();
+ row.glue = 0; // last line is left aligned
+ row.yo = yo;
rows_.push_back(row);
// what to report?
- dim_ = xcell(0).dim();
+ dim_.w = lyx_width_;
+ dim_.a = rows_.front().dim.a;
+ dim_.d = rows_.back().dim.d + yo;
metricsMarkers();
#endif
}
void MathParboxInset::draw(MathPainterInfo & pi, int x, int y) const
{
MathFontSetChanger dummy(pi.base, "textnormal");
-#if 1
+#if 0
xcell(0).draw(pi, x + 1, y);
#else
xcell(0).drawExternal(pi, x + 1, y, rows_);
MathParboxInset * asParboxInset() { return this; }
///
MathInset * clone() const;
+ /// get cursor position
+ void getPos(idx_type idx, pos_type pos, int & x, int & y) const;
///
void metrics(MathMetricsInfo & mi) const;
///
void MathXArray::metricsExternal(MathMetricsInfo & mi,
- std::vector<Row> & v) const
+ std::vector<Dimension> & v) const
{
//if (clean_)
// return;
if (q) {
q->metrics(p, mi);
q->dimensions2(p, d);
+ v.push_back(d);
+ v.push_back(Dimension());
++it;
- v.push_back(Row());
- v.back().dim = d;
- v.push_back(Row());
} else {
p->metrics(mi);
p->dimensions(d);
- v.push_back(Row());
- v.back().dim = d;
+ v.push_back(d);
}
}
+ //for (int i = 0; i < data_.size(); ++i)
+ // lyxerr << "i: " << i << " dim: " << v[i] << endl;
//lyxerr << "MathXArray::metrics(): '" << dim_ << "\n";
}
void MathXArray::drawExternal(MathPainterInfo & pi, int x, int y,
std::vector<Row> const & v) const
{
- for (size_type r = 0, pos = 0; r != v.size(); ++r) {
+ //for (size_type r = 0; r < v.size(); ++r)
+ // lyxerr << "row " << r << " to: " << v[r].end << endl;
+ //lyxerr << " data: " << data_ << endl;
+
+ xo_ = x;
+ yo_ = y;
+
+ for (size_type r = 0; r < v.size(); ++r) {
int xx = x;
int yy = y + v[r].yo;
- for ( ; pos != v[r].end; ++pos) {
+ for (size_type pos = v[r].begin; pos < v[r].end && pos < data_.size(); ++pos) {
+ //lyxerr << "drawing pos " << pos << " of " << data_.size()
+ // << " " << int(data_[pos]->getChar()) << endl;
MathInset const * p = data_[pos].nucleus();
+
+ // insert extra glue
+ if (p->getChar() == ' ')
+ xx += v[r].glue;
+
MathScriptInset const * q = 0;
- if (pos + 1 != data_.size())
- q = asScript(begin() + pos + 1);
+ if (pos + 1 < data_.size())
+ q = asScript(begin() + pos);
if (q) {
q->draw(p, pi, xx, yy);
xx += q->width2(p);
}
-int MathXArray::pos2x(size_type targetpos) const
+int MathXArray::pos2x(size_type pos) const
+{
+ return pos2x(0, pos, 0);
+}
+
+int MathXArray::pos2x(size_type pos1, size_type pos2, int glue) const
{
int x = 0;
- const_iterator target = min(begin() + targetpos, end());
- for (const_iterator it = begin(); it < target; ++it) {
+ size_type target = min(pos2, data_.size());
+ for (size_type i = pos1; i < target; ++i) {
+ const_iterator it = begin() + i;
MathInset const * p = it->nucleus();
- MathScriptInset const * q = (it + 1 == end()) ? 0 : asScript(it);
+ if (p->getChar() == ' ')
+ x += glue;
+ MathScriptInset const * q = (i + 1 == data_.size()) ? 0 : asScript(it);
if (q) {
- ++it;
- if (it < target)
+ ++i;
+ if (i < target)
x += q->width2(p);
else // "half" position
x += q->dxx(p) + q->nwid(p);
struct Row {
/// constructor
Row() {}
+ /// first position of this row
+ size_type begin;
/// last position of this row plus one
size_type end;
/// y offset relative to yo
/// rebuild cached metrics information
Dimension const & metrics(MathMetricsInfo & mi) const;
/// rebuild cached metrics information
- void metricsExternal(MathMetricsInfo & mi,
- std::vector<MathXArray::Row> &) const;
+ void metricsExternal(MathMetricsInfo & mi, std::vector<Dimension> &) const;
/// redraw cell using cache metrics information
void draw(MathPainterInfo & pi, int x, int y) const;
/// redraw cell using external metrics information
/// returns x coordinate of given position in the array
int pos2x(size_type pos) const;
/// returns position of given x coordinate
+ int pos2x(size_type pos1, size_type pos2, int glue) 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