-
-// x is an absolute screen coord
-// returns the column near the specified x-coordinate of the row
-// x is set to the real beginning of this column
-pos_type LyXText::getColumnNearX(pit_type const pit,
- Row const & row, int & x, bool & boundary) const
-{
- int const xo = theCoords.get(this, pit).x_;
- x -= xo;
- RowMetrics const r = computeRowMetrics(pit, row);
- Paragraph const & par = pars_[pit];
-
- pos_type vc = row.pos();
- pos_type end = row.endpos();
- pos_type c = 0;
- LyXLayout_ptr const & layout = par.layout();
-
- bool left_side = false;
-
- pos_type body_pos = par.beginOfBody();
-
- double tmpx = r.x;
- double last_tmpx = tmpx;
-
- if (body_pos > 0 &&
- (body_pos > end || !par.isLineSeparator(body_pos - 1)))
- body_pos = 0;
-
- // check for empty row
- if (vc == end) {
- x = int(tmpx) + xo;
- return 0;
- }
-
- while (vc < end && tmpx <= x) {
- c = bidi.vis2log(vc);
- last_tmpx = tmpx;
- if (body_pos > 0 && c == body_pos - 1) {
- tmpx += r.label_hfill +
- font_metrics::width(layout->labelsep, getLabelFont(par));
- if (par.isLineSeparator(body_pos - 1))
- tmpx -= singleWidth(par, body_pos - 1);
- }
-
- if (hfillExpansion(par, row, c)) {
- tmpx += singleWidth(par, c);
- if (c >= body_pos)
- tmpx += r.hfill;
- else
- tmpx += r.label_hfill;
- } else if (par.isSeparator(c)) {
- tmpx += singleWidth(par, c);
- if (c >= body_pos)
- tmpx += r.separator;
- } else {
- tmpx += singleWidth(par, c);
- }
- ++vc;
- }
-
- if ((tmpx + last_tmpx) / 2 > x) {
- tmpx = last_tmpx;
- left_side = true;
- }
-
- BOOST_ASSERT(vc <= end); // This shouldn't happen.
-
- boundary = false;
- // This (rtl_support test) is not needed, but gives
- // some speedup if rtl_support == false
- bool const lastrow = lyxrc.rtl_support && row.endpos() == par.size();
-
- // If lastrow is false, we don't need to compute
- // the value of rtl.
- bool const rtl = lastrow ? isRTL(par) : false;
- if (lastrow &&
- ((rtl && left_side && vc == row.pos() && x < tmpx - 5) ||
- (!rtl && !left_side && vc == end && x > tmpx + 5)))
- c = end;
- else if (vc == row.pos()) {
- c = bidi.vis2log(vc);
- if (bidi.level(c) % 2 == 1)
- ++c;
- } else {
- c = bidi.vis2log(vc - 1);
- bool const rtl = (bidi.level(c) % 2 == 1);
- if (left_side == rtl) {
- ++c;
- boundary = bidi.isBoundary(*bv()->buffer(), par, c);
- }
- }
-
- // The following code is necessary because the cursor position past
- // the last char in a row is logically equivalent to that before
- // the first char in the next row. That's why insets causing row
- // divisions -- Newline and display-style insets -- must be treated
- // specially, so cursor up/down doesn't get stuck in an air gap -- MV
- // Newline inset, air gap below:
- if (row.pos() < end && c >= end && par.isNewline(end - 1)) {
- if (bidi.level(end -1) % 2 == 0)
- tmpx -= singleWidth(par, end - 1);
- else
- tmpx += singleWidth(par, end - 1);
- c = end - 1;
- }
-
- // Air gap above display inset:
- if (row.pos() < end && c >= end && end < par.size()
- && par.isInset(end) && par.getInset(end)->display()) {
- c = end - 1;
- }
- // Air gap below display inset:
- if (row.pos() < end && c >= end && par.isInset(end - 1)
- && par.getInset(end - 1)->display()) {
- c = end - 1;
- }
-
- x = int(tmpx) + xo;
-
- if (end == par.size())
- return c - row.pos();
-
- if (c && !par.isSeparator(c-1)) {
- boundary = true;
- return c - row.pos();
- }
-
- return min(c - row.pos(), end - 1 - row.pos());
-}
-
-