mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-22 10:00:33 +00:00
Cleanup the caret geometry code
Intended changes: * code is shorter and cleaner * caret scales better with zoom when cursor_width=0: completion indicator, l-shaped cursor... Details: * Rename BufferView::getPosAndHeight to getPosAndDim because ascent is needed too and width could in the future be set depending on font. * Get rid of rect_ in CaretWidget and record a Dimension (and y value) instead. Remove also caret_width_ and slant_, replace rtl_ with dir. * Make CaretWidget members public and lose the trailing _. * change CaretWidget::update to read its parameters from current bufferview.
This commit is contained in:
parent
7d96531909
commit
7f1b1729b4
@ -3062,23 +3062,26 @@ bool BufferView::paragraphVisible(DocIterator const & dit) const
|
||||
}
|
||||
|
||||
|
||||
void BufferView::caretPosAndHeight(Point & p, int & h) const
|
||||
void BufferView::caretPosAndDim(Point & p, Dimension & dim) const
|
||||
{
|
||||
int asc, des;
|
||||
Cursor const & cur = cursor();
|
||||
if (cur.inMathed()) {
|
||||
MathRow const & mrow = mathRow(&cur.cell());
|
||||
asc = mrow.caret_ascent;
|
||||
des = mrow.caret_descent;
|
||||
dim.asc = mrow.caret_ascent;
|
||||
dim.des = mrow.caret_descent;
|
||||
} else {
|
||||
Font const font = cur.real_current_font;
|
||||
frontend::FontMetrics const & fm = theFontMetrics(font);
|
||||
asc = fm.maxAscent();
|
||||
des = fm.maxDescent();
|
||||
dim.asc = fm.maxAscent();
|
||||
dim.des = fm.maxDescent();
|
||||
}
|
||||
h = asc + des;
|
||||
if (lyxrc.cursor_width > 0)
|
||||
dim.wid = lyxrc.cursor_width;
|
||||
else
|
||||
dim.wid = 1 + int((lyxrc.currentZoom + 50) / 200.0);
|
||||
|
||||
p = getPos(cur);
|
||||
p.y_ -= asc;
|
||||
p.y_ -= dim.asc;
|
||||
}
|
||||
|
||||
|
||||
@ -3087,11 +3090,11 @@ bool BufferView::caretInView() const
|
||||
if (!paragraphVisible(cursor()))
|
||||
return false;
|
||||
Point p;
|
||||
int h;
|
||||
caretPosAndHeight(p, h);
|
||||
Dimension dim;
|
||||
caretPosAndDim(p, dim);
|
||||
|
||||
// does the cursor touch the screen ?
|
||||
if (p.y_ + h < 0 || p.y_ >= workHeight())
|
||||
if (p.y_ + dim.height() < 0 || p.y_ >= workHeight())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ class Change;
|
||||
class CoordCache;
|
||||
class Cursor;
|
||||
class CursorSlice;
|
||||
class Dimension;
|
||||
class DispatchResult;
|
||||
class DocIterator;
|
||||
class DocumentClass;
|
||||
@ -313,7 +314,7 @@ public:
|
||||
/// is the caret currently visible in the view
|
||||
bool caretInView() const;
|
||||
/// get the position and height of the caret
|
||||
void caretPosAndHeight(Point & p, int & h) const;
|
||||
void caretPosAndDim(Point & p, Dimension & dim) const;
|
||||
|
||||
///
|
||||
void draw(frontend::Painter & pain, bool paint_caret);
|
||||
|
@ -558,6 +558,7 @@ public:
|
||||
};
|
||||
///
|
||||
ScrollWheelZoom scroll_wheel_zoom = SCROLL_WHEEL_ZOOM_CTRL;
|
||||
// FIXME: should be caret_width
|
||||
///
|
||||
int cursor_width = 1;
|
||||
/// One of: yes, no, ask
|
||||
|
@ -129,8 +129,8 @@ namespace frontend {
|
||||
|
||||
class CaretWidget {
|
||||
public:
|
||||
CaretWidget() : rtl_(false), l_shape_(false), completable_(false),
|
||||
x_(0), caret_width_(0), slant_(false), ascent_(0), slope_(0)
|
||||
CaretWidget() : dir(1), l_shape(false), completable(false),
|
||||
x(0), y(0), slope(0)
|
||||
{}
|
||||
|
||||
/* Draw the caret. Parameter \c horiz_offset is not 0 when there
|
||||
@ -138,116 +138,86 @@ public:
|
||||
*/
|
||||
void draw(QPainter & painter, int horiz_offset)
|
||||
{
|
||||
if (!rect_.isValid())
|
||||
if (dim.empty())
|
||||
return;
|
||||
|
||||
int const x = x_ - horiz_offset;
|
||||
int const y = rect_.top();
|
||||
int const lx = rtl_ ? x_ - rect_.left() : rect_.right() - x_;
|
||||
int const bot = rect_.bottom();
|
||||
int const dir = rtl_ ? -1 : 1;
|
||||
// correction is (1) for horizontal scrolling and (2) for
|
||||
// better positionning of large cursors.
|
||||
int const xx = x - horiz_offset - dim.wid / 2;
|
||||
int const lx = dim.height() / 3;
|
||||
|
||||
// draw caret box
|
||||
if (slant_ && !rtl_) {
|
||||
// slanted
|
||||
|
||||
QPainterPath path;
|
||||
path.moveTo(x + ascent_ * slope_, y);
|
||||
path.lineTo(x - (rect_.height() - ascent_) * slope_,
|
||||
y + rect_.height());
|
||||
path.lineTo(x + dir * caret_width_ - (rect_.height() - ascent_) * slope_,
|
||||
y + rect_.height());
|
||||
path.lineTo(x + dir * caret_width_ + ascent_ * slope_, y);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
painter.fillPath(path, color_);
|
||||
painter.setRenderHint(QPainter::Antialiasing, false);
|
||||
} else
|
||||
// regular
|
||||
painter.fillRect(x, y, dir * caret_width_, rect_.height(), color_);
|
||||
painter.setPen(color);
|
||||
QPainterPath path;
|
||||
path.moveTo(xx + dim.asc * slope, y);
|
||||
path.lineTo(xx - dim.des * slope, y + dim.height());
|
||||
path.lineTo(xx + dir * dim.wid - dim.des * slope, y + dim.height());
|
||||
path.lineTo(xx + dir * dim.wid + dim.asc * slope, y);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
painter.fillPath(path, color);
|
||||
painter.setRenderHint(QPainter::Antialiasing, false);
|
||||
|
||||
// draw RTL/LTR indication
|
||||
painter.setPen(color_);
|
||||
if (l_shape_) {
|
||||
painter.drawLine(x, bot, x + dir * (caret_width_ + lx - 1), bot);
|
||||
}
|
||||
if (l_shape)
|
||||
painter.fillRect(xx - dim.des * slope,
|
||||
y + dim.height() - dim.wid + 1,
|
||||
dir * (dim.wid + lx - 1), dim.wid, color);
|
||||
|
||||
// draw completion triangle
|
||||
if (completable_) {
|
||||
int const m = y + rect_.height() / 2;
|
||||
int const d = TabIndicatorWidth - 1;
|
||||
if (completable) {
|
||||
int const m = y + dim.height() / 2;
|
||||
int const d = TabIndicatorWidth * dim.wid - 1;
|
||||
// offset for slanted carret
|
||||
int const sx = (slant_ && !rtl_) ? (ascent_ - (rect_.height() / 2 - d)) * slope_ : 0;
|
||||
painter.drawLine(x + dir * (caret_width_ + 1) + sx, m - d,
|
||||
x + dir * (caret_width_ + d + 1) + sx, m);
|
||||
painter.drawLine(x + dir * (caret_width_ + 1) + sx, m + d,
|
||||
x + dir * (caret_width_ + d + 1) + sx, m);
|
||||
int const sx = (dim.asc - (dim.height() / 2 - d)) * slope;
|
||||
painter.drawLine(xx + dir * (dim.wid + 1) + sx, m - d,
|
||||
xx + dir * (dim.wid + d + 1) + sx, m);
|
||||
painter.drawLine(xx + dir * (dim.wid + 1) + sx, m + d,
|
||||
xx + dir * (dim.wid + d + 1) + sx, m);
|
||||
}
|
||||
}
|
||||
|
||||
void update(int x, int y, int h, bool l_shape,
|
||||
bool rtl, bool completable, bool slant, int ascent, double slope)
|
||||
{
|
||||
color_ = guiApp->colorCache().get(Color_cursor);
|
||||
l_shape_ = l_shape;
|
||||
rtl_ = rtl;
|
||||
completable_ = completable;
|
||||
x_ = x;
|
||||
slant_ = slant;
|
||||
ascent_ = ascent;
|
||||
slope_ = slope;
|
||||
void update(BufferView const * bv, bool complet) {
|
||||
// Cursor size and position
|
||||
Point point;
|
||||
bv->caretPosAndDim(point, dim);
|
||||
x = point.x_;
|
||||
y = point.y_;
|
||||
completable = complet;
|
||||
|
||||
// extension to left and right
|
||||
int l = 0;
|
||||
int r = 0;
|
||||
Cursor const & cur = bv->cursor();
|
||||
Font const & realfont = cur.real_current_font;
|
||||
FontMetrics const & fm = theFontMetrics(realfont.fontInfo());
|
||||
BufferParams const & bp = bv->buffer().params();
|
||||
bool const samelang = realfont.language() == bp.language;
|
||||
bool const isrtl = realfont.isVisibleRightToLeft();
|
||||
dir = isrtl ? -1 : 1;
|
||||
// special shape
|
||||
l_shape = (!samelang || isrtl != bp.language->rightToLeft())
|
||||
&& realfont.language() != latex_language;
|
||||
|
||||
// RTL/LTR indication
|
||||
if (l_shape_) {
|
||||
if (rtl)
|
||||
l += h / 3;
|
||||
else
|
||||
r += h / 3;
|
||||
}
|
||||
// use slanted caret for italics in text edit mode
|
||||
// except for selections because the selection rect does not slant
|
||||
bool const slant = fm.italic() && cur.inTexted() && !cur.selection();
|
||||
slope = slant ? fm.italicSlope() : 0;
|
||||
|
||||
// completion triangle
|
||||
if (completable_) {
|
||||
if (rtl)
|
||||
l = max(l, TabIndicatorWidth);
|
||||
else
|
||||
r = max(r, TabIndicatorWidth);
|
||||
}
|
||||
|
||||
//FIXME: LyXRC::cursor_width should be caret_width
|
||||
caret_width_ = lyxrc.cursor_width
|
||||
? lyxrc.cursor_width
|
||||
: 1 + int((lyxrc.currentZoom + 50) / 200.0);
|
||||
|
||||
// compute overall rectangle
|
||||
rect_ = QRect(x - l, y, caret_width_ + r + l, h);
|
||||
color = guiApp->colorCache().get(Color_cursor);
|
||||
}
|
||||
|
||||
QRect const & rect() { return rect_; }
|
||||
|
||||
private:
|
||||
/// caret is in RTL or LTR text
|
||||
bool rtl_;
|
||||
/// indication for RTL or LTR
|
||||
bool l_shape_;
|
||||
/// text direction (1 for LtR, -1 for RtL)
|
||||
int dir;
|
||||
/// indication for language change
|
||||
bool l_shape;
|
||||
/// triangle to show that a completion is available
|
||||
bool completable_;
|
||||
bool completable;
|
||||
///
|
||||
QColor color_;
|
||||
/// rectangle, possibly with l_shape and completion triangle
|
||||
QRect rect_;
|
||||
QColor color;
|
||||
/// dimension uf base caret
|
||||
Dimension dim;
|
||||
/// x position (were the vertical line is drawn)
|
||||
int x_;
|
||||
/// the width of the vertical blinking bar
|
||||
int caret_width_;
|
||||
/// caret is in slanted text
|
||||
bool slant_;
|
||||
/// the fontmetrics ascent for drawing slanted caret
|
||||
int ascent_;
|
||||
int x;
|
||||
/// y position (the top of the caret)
|
||||
int y;
|
||||
/// the slope for drawing slanted caret
|
||||
double slope_;
|
||||
double slope;
|
||||
};
|
||||
|
||||
|
||||
@ -631,6 +601,15 @@ void GuiWorkArea::Private::resetCaret()
|
||||
if (!buffer_view_->caretInView())
|
||||
return;
|
||||
|
||||
// completion indicator
|
||||
Cursor const & cur = buffer_view_->cursor();
|
||||
bool const completable = cur.inset().showCompletionCursor()
|
||||
&& completer_->completionAvailable()
|
||||
&& !completer_->popupVisible()
|
||||
&& !completer_->inlineVisible();
|
||||
|
||||
caret_->update(buffer_view_, completable);
|
||||
|
||||
needs_caret_geometry_update_ = true;
|
||||
caret_visible_ = true;
|
||||
}
|
||||
@ -644,40 +623,7 @@ void GuiWorkArea::Private::updateCaretGeometry()
|
||||
|| !buffer_view_->caretInView())
|
||||
return;
|
||||
|
||||
Point point;
|
||||
int h = 0;
|
||||
buffer_view_->caretPosAndHeight(point, h);
|
||||
Cursor & cur = buffer_view_->cursor();
|
||||
|
||||
// RTL or not RTL
|
||||
bool l_shape = false;
|
||||
Font const & realfont = cur.real_current_font;
|
||||
FontMetrics const & fm = theFontMetrics(realfont.fontInfo());
|
||||
BufferParams const & bp = buffer_view_->buffer().params();
|
||||
bool const samelang = realfont.language() == bp.language;
|
||||
bool const isrtl = realfont.isVisibleRightToLeft();
|
||||
|
||||
if (!samelang || isrtl != bp.language->rightToLeft())
|
||||
l_shape = true;
|
||||
|
||||
// The ERT language hack needs fixing up
|
||||
if (realfont.language() == latex_language)
|
||||
l_shape = false;
|
||||
|
||||
// show caret on screen
|
||||
bool completable = cur.inset().showCompletionCursor()
|
||||
&& completer_->completionAvailable()
|
||||
&& !completer_->popupVisible()
|
||||
&& !completer_->inlineVisible();
|
||||
|
||||
// use slanted caret for italics in text edit mode
|
||||
// except for selections because the selection rect does not slant
|
||||
int slant = fm.italic() && buffer_view_->cursor().inTexted()
|
||||
&& !buffer_view_->cursor().selection();
|
||||
double slope = fm.italicSlope();
|
||||
|
||||
caret_->update(point.x_, point.y_, h, l_shape, isrtl, completable, slant,
|
||||
fm.maxAscent(), slope);
|
||||
needs_caret_geometry_update_ = false;
|
||||
}
|
||||
|
||||
@ -1252,8 +1198,8 @@ void GuiWorkArea::Private::paintPreeditText(GuiPainter & pain)
|
||||
FontInfo const font = buffer_view_->cursor().getFont().fontInfo();
|
||||
FontMetrics const & fm = theFontMetrics(font);
|
||||
int const height = fm.maxHeight();
|
||||
int cur_x = caret_->rect().left();
|
||||
int cur_y = caret_->rect().bottom();
|
||||
int cur_x = caret_->x;
|
||||
int cur_y = caret_->y + height;
|
||||
|
||||
// get attributes of input method cursor.
|
||||
// cursor_pos : cursor position in preedit string.
|
||||
@ -1447,9 +1393,9 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e)
|
||||
|
||||
|
||||
// redraw area of preedit string.
|
||||
int height = d->caret_->rect().height();
|
||||
int cur_y = d->caret_->rect().bottom();
|
||||
viewport()->update(0, cur_y - height, viewport()->width(),
|
||||
int height = d->caret_->dim.height();
|
||||
int cur_y = d->caret_->y;
|
||||
viewport()->update(0, cur_y, viewport()->width(),
|
||||
(height + 1) * d->preedit_lines_);
|
||||
|
||||
if (d->preedit_string_.empty()) {
|
||||
@ -1470,13 +1416,9 @@ QVariant GuiWorkArea::inputMethodQuery(Qt::InputMethodQuery query) const
|
||||
// this is the CJK-specific composition window position and
|
||||
// the context menu position when the menu key is pressed.
|
||||
case Qt::ImMicroFocus:
|
||||
cur_r = d->caret_->rect();
|
||||
if (d->preedit_lines_ != 1)
|
||||
cur_r.moveLeft(10);
|
||||
cur_r.moveBottom(cur_r.bottom()
|
||||
+ cur_r.height() * (d->preedit_lines_ - 1));
|
||||
// return lower right of caret in LyX.
|
||||
return cur_r;
|
||||
return QRect(d->caret_->x - 10 * (d->preedit_lines_ != 1),
|
||||
d->caret_->y + d->caret_->dim.height() * d->preedit_lines_,
|
||||
d->caret_->dim.width(), d->caret_->dim.height());
|
||||
default:
|
||||
return QWidget::inputMethodQuery(query);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user