/// Moves cursor to the next inset with one of the given codes.
-void gotoInset(BufferView * bv, vector<InsetCode> const & codes,
+bool gotoInset(BufferView * bv, vector<InsetCode> const & codes,
bool same_content)
{
Cursor tmpcur = bv->cursor();
if (!findInset(tmpcur, codes, same_content)) {
bv->cursor().message(_("No more insets"));
- return;
+ return false;
}
tmpcur.clearSelection();
bv->setCursor(tmpcur);
- bv->showCursor();
+ return bv->scrollToCursor(bv->cursor(), false, true);
}
///
CoordCache coord_cache_;
///
- typedef map<MathData const *, MathRow> MathRows;
+ typedef unordered_map<MathData const *, MathRow> MathRows;
MathRows math_rows_;
/// this is used to handle XSelection events in the right manner.
}
-int BufferView::rightMargin() const
+int BufferView::defaultMargin() const
{
// The value used to be hardcoded to 10
- int const default_margin = zoomedPixels(10);
+ return zoomedPixels(20);
+}
+
+
+int BufferView::rightMargin() const
+{
// The additional test for the case the outliner is opened.
- if (!full_screen_ || !lyxrc.full_screen_limit
- || width_ < lyxrc.full_screen_width + 2 * default_margin)
- return default_margin;
+ if (full_screen_ && lyxrc.full_screen_limit)
+ return max(defaultMargin(), (width_ - lyxrc.full_screen_width) / 2);
- return (width_ - lyxrc.full_screen_width) / 2;
+ return defaultMargin();
}
if (needsFitCursor()) {
// First try to make the selection start visible
// (which is just the cursor when there is no selection)
- scrollToCursor(d->cursor_.selectionBegin(), false);
+ scrollToCursor(d->cursor_.selectionBegin(), false, false);
// Metrics have to be recomputed (maybe again)
updateMetrics();
// Is the cursor visible? (only useful if cursor is at end of selection)
if (needsFitCursor()) {
// then try to make cursor visible instead
- scrollToCursor(d->cursor_, false);
+ scrollToCursor(d->cursor_, false, false);
// Metrics have to be recomputed (maybe again)
updateMetrics(flags);
}
// cut off at the top
if (pixels <= d->scrollbarParameters_.min) {
DocIterator dit = doc_iterator_begin(&buffer_);
- showCursor(dit, false, update);
+ showCursor(dit, false, false, update);
LYXERR(Debug::SCROLLING, "scroll to top");
return;
}
if (pixels >= d->scrollbarParameters_.max) {
DocIterator dit = doc_iterator_end(&buffer_);
dit.backwardPos();
- showCursor(dit, false, update);
+ showCursor(dit, false, false, update);
LYXERR(Debug::SCROLLING, "scroll to bottom");
return;
}
DocIterator dit = doc_iterator_begin(&buffer_);
dit.pit() = i;
LYXERR(Debug::SCROLLING, "pixels = " << pixels << " -> scroll to pit " << i);
- showCursor(dit, false, update);
+ showCursor(dit, false, false, update);
}
// restoration is inaccurate. If a bookmark was within an inset,
// it will be restored to the left of the outmost inset that contains
// the bookmark.
- if (bottom_pit < int(buffer_.paragraphs().size())) {
+ if (!success && bottom_pit < int(buffer_.paragraphs().size())) {
dit = doc_iterator_begin(&buffer_);
dit.pit() = bottom_pit;
void BufferView::recenter()
{
- showCursor(d->cursor_, true, true);
+ showCursor(d->cursor_, true, false, true);
}
void BufferView::showCursor()
{
- showCursor(d->cursor_, false, true);
+ showCursor(d->cursor_, false, false, true);
}
void BufferView::showCursor(DocIterator const & dit,
- bool recenter, bool update)
+ bool recenter, bool force, bool update)
{
- if (scrollToCursor(dit, recenter) && update)
+ if (scrollToCursor(dit, recenter, force) && update)
processUpdateFlags(Update::Force);
}
-void BufferView::scrollToCursor()
-{
- if (scrollToCursor(d->cursor_, false))
- processUpdateFlags(Update::Force);
-}
-
-
-bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter)
+bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter, bool force)
{
// We are not properly started yet, delay until resizing is done.
if (height_ == 0)
else if (bot_pit == tm.last().first + 1)
tm.newParMetricsDown();
- if (tm.contains(bot_pit)) {
+ if (tm.contains(bot_pit) && !force) {
ParagraphMetrics const & pm = tm.parMetrics(bot_pit);
LBUFERR(!pm.rows().empty());
// FIXME: smooth scrolling doesn't work in mathed.
CursorSlice const & cs = dit.innerTextSlice();
- int offset = coordOffset(dit).y_;
- int ypos = pm.position() + offset;
+ int const ypos = pm.position() + coordOffset(dit).y_;
+ ParagraphMetrics const & inner_pm =
+ textMetrics(cs.text()).parMetrics(cs.pit());
Dimension const & row_dim =
- pm.getRow(cs.pos(), dit.boundary()).dim();
+ inner_pm.getRow(cs.pos(), dit.boundary()).dim();
int scrolled = 0;
if (recenter)
scrolled = scroll(ypos - height_/2);
// If the top part of the row falls of the screen, we scroll
// up to align the top of the row with the top of the screen.
else if (ypos - row_dim.ascent() < 0 && ypos < height_) {
- int ynew = row_dim.ascent();
+ int const ynew = row_dim.ascent();
scrolled = scrollUp(ynew - ypos);
}
// If the bottom of the row falls of the screen, we scroll down.
else if (ypos + row_dim.descent() > height_ && ypos > 0) {
- int ynew = height_ - row_dim.descent();
+ int const ynew = height_ - row_dim.descent();
scrolled = scrollDown(ypos - ynew);
}
tm.redoParagraph(bot_pit);
ParagraphMetrics const & pm = tm.parMetrics(bot_pit);
- int offset = coordOffset(dit).y_;
+ int const offset = coordOffset(dit).y_;
d->anchor_pit_ = bot_pit;
CursorSlice const & cs = dit.innerTextSlice();
else if (d->anchor_pit_ == max_pit)
d->anchor_ypos_ = height_ - offset - row_dim.descent();
else if (offset > height_)
- d->anchor_ypos_ = height_ - offset - defaultRowHeight();
+ d->anchor_ypos_ = height_ - offset - row_dim.descent();
else
- d->anchor_ypos_ = defaultRowHeight() * 2;
+ d->anchor_ypos_ = row_dim.ascent();
return true;
}
success = setCursorFromEntries({id, pos},
{id_end, pos_end});
}
- if (success)
- dr.screenUpdate(Update::Force | Update::FitCursor);
+ if (success && scrollToCursor(d->cursor_, false, true))
+ dr.screenUpdate(Update::Force);
} else {
// Switch to other buffer view and resend cmd
lyx::dispatch(FuncRequest(
}
case LFUN_NOTE_NEXT:
- gotoInset(this, { NOTE_CODE }, false);
- // FIXME: if SinglePar is changed to act on the inner
- // paragraph, this will not be OK anymore. The update is
- // useful for auto-open collapsible insets.
- dr.screenUpdate(Update::SinglePar | Update::FitCursor);
+ if (gotoInset(this, { NOTE_CODE }, false))
+ dr.screenUpdate(Update::Force);
break;
case LFUN_REFERENCE_NEXT: {
- gotoInset(this, { LABEL_CODE, REF_CODE }, true);
- // FIXME: if SinglePar is changed to act on the inner
- // paragraph, this will not be OK anymore. The update is
- // useful for auto-open collapsible insets.
- dr.screenUpdate(Update::SinglePar | Update::FitCursor);
+ if (gotoInset(this, { LABEL_CODE, REF_CODE }, true))
+ dr.screenUpdate(Update::Force);
break;
}
}
case LFUN_COPY:
+ // With multi-cell table content, we pass down to the inset
+ if (cur.inTexted() && cur.selection()
+ && cur.selectionBegin().idx() != cur.selectionEnd().idx()) {
+ buffer_.dispatch(cmd, dr);
+ dispatched = dr.dispatched();
+ break;
+ }
cap::copySelection(cur);
cur.message(_("Copy"));
break;
}
+Inset const * BufferView::clickableMathInset(InsetMathNest const * inset,
+ CoordCache::Insets const & inset_cache, int x, int y) const
+{
+ for (size_t i = 0; i < inset->nargs(); ++i) {
+ MathData const & ar = inset->cell(i);
+ for (size_t j = 0; j < ar.size(); ++j) {
+ string const name = lyxerr.debugging(Debug::MATHED)
+ ? insetName(ar[j].nucleus()->lyxCode())
+ : string();
+ LYXERR(Debug::MATHED, "Checking inset: " << name);
+ if (ar[j].nucleus()->clickable(*this, x, y)) {
+ if (inset_cache.covers(ar[j].nucleus(), x, y)) {
+ LYXERR(Debug::MATHED, "Clickable inset: "
+ << name);
+ return ar[j].nucleus();
+ }
+ }
+ InsetMathNest const * imn =
+ ar[j].nucleus()->asNestInset();
+ if (imn) {
+ Inset const * inner =
+ clickableMathInset(imn, inset_cache, x, y);
+ if (inner)
+ return inner;
+ }
+ }
+ }
+ return nullptr;
+}
+
+
void BufferView::updateHoveredInset() const
{
// Get inset under mouse, if there is one.
int const x = d->mouse_position_cache_.x_;
int const y = d->mouse_position_cache_.y_;
Inset const * covering_inset = getCoveringInset(buffer_.text(), x, y);
+ if (covering_inset && covering_inset->asInsetMath()) {
+ Inset const * inner_inset = clickableMathInset(
+ covering_inset->asInsetMath()->asNestInset(),
+ coordCache().getInsets(), x, y);
+ if (inner_inset)
+ covering_inset = inner_inset;
+ }
d->clickable_inset_ = covering_inset && covering_inset->clickable(*this, x, y);
} else {
Font const font = cur.real_current_font;
frontend::FontMetrics const & fm = theFontMetrics(font);
- dim.wid = fm.lineWidth();
+ // lineWidth() can be 0 to mean 'thin line' on HiDpi, but the
+ // caret drawing code is not prepared for that.
+ dim.wid = max(fm.lineWidth(), 1);
dim.asc = fm.maxAscent();
dim.des = fm.maxDescent();
}