X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBufferView.cpp;h=c93966b2572a838ba79ea99d6626935ccb4e0614;hb=1acedf11da79f509da706bc8d6d2f491c9676087;hp=1ccc1c3c9dff698de5fe01edbf0761a867131f39;hpb=d3980b14a81f4e09bd27b15b5978b070bd840a99;p=lyx.git diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 1ccc1c3c9d..c93966b257 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -58,6 +58,7 @@ #include "insets/InsetText.h" #include "frontends/alert.h" +#include "frontends/Application.h" #include "frontends/Delegates.h" #include "frontends/FontMetrics.h" #include "frontends/Painter.h" @@ -67,6 +68,7 @@ #include "support/convert.h" #include "support/debug.h" +#include "support/ExceptionMessage.h" #include "support/FileFilterList.h" #include "support/filetools.h" #include "support/gettext.h" @@ -176,6 +178,7 @@ void gotoInset(BufferView * bv, vector const & codes, tmpcur.clearSelection(); bv->setCursor(tmpcur); + bv->showCursor(); } @@ -349,9 +352,7 @@ void BufferView::processUpdateFlags(Update::flags flags) << ", singlepar = " << (flags & Update::SinglePar) << "] buffer: " << &buffer_); - // Update macro store - if (!(cursor().inMathed() && cursor().inMacroMode())) - buffer_.updateMacros(); + buffer_.updateMacros(); // Now do the first drawing step if needed. This consists on updating // the CoordCache in updateMetrics(). @@ -424,12 +425,12 @@ void BufferView::updateScrollbar() << " curr par: " << d->cursor_.bottom().pit() << " default height " << defaultRowHeight()); - int const parsize = int(t.paragraphs().size() - 1); + int const parsize = int(t.paragraphs().size()); if (d->par_height_.size() != parsize) { d->par_height_.clear(); - // FIXME: We assume a default paragraph height of 4 rows. This + // FIXME: We assume a default paragraph height of 2 rows. This // should probably be pondered with the screen width. - d->par_height_.resize(parsize, defaultRowHeight() * 4); + d->par_height_.resize(parsize, defaultRowHeight() * 2); } // It would be better to fix the scrollbar to understand @@ -442,24 +443,35 @@ void BufferView::updateScrollbar() for (pit_type pit = first.first; pit <= last.first; ++pit) { ParagraphMetrics const & pm = tm.parMetrics(pit); d->par_height_[pit] = pm.height(); - if (first_visible_pit < 0 && pm.position() + pm.descent() > 0) - first_visible_pit = pit; + if (first_visible_pit >= 0 || pm.position() + pm.descent() <= 0) + continue; + first_visible_pit = pit; + LYXERR(Debug::SCROLLING, "first visible pit " << first_visible_pit); + // FIXME: we should look for the first visible row within + // the deepest inset! + int row_pos = pm.position(); + size_t const nrows = pm.rows().size(); + for (size_t i = 0; i != nrows; ++i) { + Row const & row = pm.rows()[i]; + if (row_pos >= 0) { + LYXERR(Debug::SCROLLING, "first visible row " << i + << "(row pos = " << row_pos << ");"); + break; + } + row_pos += row.height(); + } + d->scrollbarParameters_.position = row_pos; } - LYXERR(Debug::SCROLLING, "first_visible_pit " << first_visible_pit); - d->scrollbarParameters_.height = 0; for (size_t i = 0; i != d->par_height_.size(); ++i) { + if (i == first_visible_pit) + d->scrollbarParameters_.position += d->scrollbarParameters_.height; d->scrollbarParameters_.height += d->par_height_[i]; - if (i != first_visible_pit) - continue; - // FIXME: we should look for the first visible row within - // the deepest inset! - d->scrollbarParameters_.position = d->scrollbarParameters_.height; } - d->scrollbarParameters_.lineScrollHeight = - tm.parMetrics(first_visible_pit).rows()[0].height(); + // We prefer fixed size line scrolling. + d->scrollbarParameters_.lineScrollHeight = defaultRowHeight(); } @@ -469,11 +481,34 @@ ScrollbarParameters const & BufferView::scrollbarParameters() const } +docstring BufferView::toolTip(int x, int y) const +{ + // Get inset under mouse, if there is one. + Inset const * covering_inset = getCoveringInset(buffer_.text(), x, y); + if (!covering_inset) + // No inset, no tooltip... + return docstring(); + return covering_inset->toolTip(*this, x, y); +} + + +docstring BufferView::contextMenu(int x, int y) const +{ + // Get inset under mouse, if there is one. + Inset const * covering_inset = getCoveringInset(buffer_.text(), x, y); + if (covering_inset) + return covering_inset->contextMenu(*this, x, y); + + // FIXME: Do something more elaborate here. + return from_ascii("edit"); +} + + void BufferView::scrollDocView(int value) { int const offset = value - d->scrollbarParameters_.position; - //TextMetrics & tm = d->text_metrics_[&buffer_.text()]; - if (abs(offset) <= 3*height_) { + // If the offset is less than 2 screen height, prefer to scroll instead. + if (abs(offset) <= 2 * height_) { scroll(offset); return; } @@ -671,7 +706,15 @@ void BufferView::showCursor() CursorSlice & bot = d->cursor_.bottom(); TextMetrics & tm = d->text_metrics_[bot.text()]; - int const bot_pit = d->cursor_.bottom().pit(); + pos_type const max_pit = pos_type(bot.text()->paragraphs().size() - 1); + int bot_pit = d->cursor_.bottom().pit(); + if (bot_pit > max_pit) { + // FIXME: Why does this happen? + LYXERR0("bottom pit is greater that max pit: " + << bot_pit << " > " << max_pit); + bot_pit = max_pit; + } + if (bot_pit == tm.first().first - 1) tm.newParMetricsUp(); else if (bot_pit == tm.last().first + 1) @@ -695,15 +738,14 @@ void BufferView::showCursor() int offset = coordOffset(d->cursor_, d->cursor_.boundary()).y_; d->anchor_pit_ = bot_pit; + Dimension const & row_dim = d->cursor_.textRow().dimension(); if (d->anchor_pit_ == 0) d->anchor_ypos_ = offset + pm.ascent(); - else if (d->anchor_pit_ >= pos_type(bot.text()->paragraphs().size() - 1)) { - d->anchor_pit_ = bot.text()->paragraphs().size() - 1; - d->anchor_ypos_ = offset + pm.height() - height_; - } else { - d->anchor_ypos_ = offset + pm.ascent() - height_ / 2; - } + else if (d->anchor_pit_ == max_pit) + d->anchor_ypos_ = height_ - offset - row_dim.descent(); + else + d->anchor_ypos_ = defaultRowHeight() * 2 - offset - row_dim.descent(); updateMetrics(); buffer_.changed(); @@ -745,7 +787,7 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) case LFUN_SCREEN_RECENTER: case LFUN_BIBTEX_DATABASE_ADD: case LFUN_BIBTEX_DATABASE_DEL: - case LFUN_WORDS_COUNT: + case LFUN_STATISTICS: case LFUN_NEXT_INSET_TOGGLE: flag.enabled(true); break; @@ -789,6 +831,7 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) case LFUN_SCREEN_UP: case LFUN_SCREEN_DOWN: + case LFUN_SCROLL: flag.enabled(true); break; @@ -861,7 +904,7 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) } -Update::flags BufferView::dispatch(FuncRequest const & cmd) +bool BufferView::dispatch(FuncRequest const & cmd) { //lyxerr << [ cmd = " << cmd << "]" << endl; @@ -873,27 +916,25 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) << " button[" << cmd.button() << ']'); Cursor & cur = d->cursor_; - // Default Update flags. - Update::flags updateFlags = Update::Force | Update::FitCursor; switch (cmd.action) { case LFUN_UNDO: cur.message(_("Undo")); cur.clearSelection(); - if (!cur.textUndo()) { + if (!cur.textUndo()) cur.message(_("No further undo information")); - updateFlags = Update::None; - } + else + processUpdateFlags(Update::Force | Update::FitCursor); break; case LFUN_REDO: cur.message(_("Redo")); cur.clearSelection(); - if (!cur.textRedo()) { + if (!cur.textRedo()) cur.message(_("No further redo information")); - updateFlags = Update::None; - } + else + processUpdateFlags(Update::Force | Update::FitCursor); break; case LFUN_FONT_STATE: @@ -939,12 +980,12 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) if (b == &buffer_) { // Set the cursor setCursor(makeDocIterator(par, 0)); + showCursor(); } else { // Switch to other buffer view and resend cmd theLyXFunc().dispatch(FuncRequest( LFUN_BUFFER_SWITCH, b->absFileName())); theLyXFunc().dispatch(cmd); - updateFlags = Update::None; } break; } @@ -1093,7 +1134,7 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) break; } - case LFUN_WORDS_COUNT: { + case LFUN_STATISTICS: { DocIterator from, to; if (cur.selection()) { from = cur.selectionBegin(); @@ -1102,24 +1143,30 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) from = doc_iterator_begin(buffer_.inset()); to = doc_iterator_end(buffer_.inset()); } - int const count = countWords(from, to); + int const words = countWords(from, to); + int const chars = countChars(from, to, false); + int const chars_blanks = countChars(from, to, true); docstring message; - if (count != 1) { - if (cur.selection()) - message = bformat(_("%1$d words in selection."), - count); - else - message = bformat(_("%1$d words in document."), - count); - } - else { - if (cur.selection()) - message = _("One word in selection."); - else - message = _("One word in document."); - } - - Alert::information(_("Count words"), message); + if (cur.selection()) + message = _("Statistics for the selection:\n"); + else + message = _("Statistics for the document:\n"); + if (words != 1) + message += bformat(_("\n%1$d words"), words); + else + message += _("\nOne word"); + if (chars_blanks != 1) + message += bformat(_("\n%1$d characters (including blanks)"), + chars_blanks); + else + message += _("\nOne character (including blanks)"); + if (chars != 1) + message += bformat(_("\n%1$d characters (excluding blanks)"), + chars); + else + message += _("\nOne character (excluding blanks)"); + + Alert::information(_("Statistics"), message); } break; @@ -1128,10 +1175,15 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) buffer_.params().compressed = !buffer_.params().compressed; break; - case LFUN_BUFFER_TOGGLE_EMBEDDING: + case LFUN_BUFFER_TOGGLE_EMBEDDING: { // turn embedding on/off - buffer_.embeddedFiles().enable(!buffer_.params().embedded); + try { + buffer_.embeddedFiles().enable(!buffer_.params().embedded, buffer_); + } catch (ExceptionMessage const & message) { + Alert::error(message.title_, message.details_); + } break; + } case LFUN_NEXT_INSET_TOGGLE: { // this is the real function we want to invoke @@ -1155,9 +1207,11 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) if (!cur.result().dispatched()) cur.dispatch(tmpcmd); - if (cur.result().dispatched()) - cur.clearSelection(); - + if (!cur.result().dispatched()) + // It did not work too; no action needed. + break; + cur.clearSelection(); + processUpdateFlags(Update::SinglePar | Update::FitCursor); break; } @@ -1174,13 +1228,18 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) d->text_metrics_[&buffer_.text()].editXY(cur, p.x_, p.y_); //FIXME: what to do with cur.x_target()? cur.finishUndo(); - // The metrics are already up to date. see scroll() - updateFlags = Update::None; break; } + case LFUN_SCROLL: + lfunScroll(cmd); + break; + case LFUN_SCREEN_UP_SELECT: case LFUN_SCREEN_DOWN_SELECT: { + // Those two are not ready yet for consumption. + return false; + cur.selHandle(true); size_t initial_depth = cur.depth(); Point const p = getPos(cur, cur.boundary()); @@ -1196,15 +1255,14 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) // But no screen update is needed. d->update_strategy_ = NoScreenUpdate; buffer_.changed(); - updateFlags = Update::Force | Update::FitCursor; break; } default: - updateFlags = Update::None; + return false; } - return updateFlags; + return true; } @@ -1257,7 +1315,8 @@ void BufferView::resize(int width, int height) } -Inset const * BufferView::getCoveringInset(Text const & text, int x, int y) +Inset const * BufferView::getCoveringInset(Text const & text, + int x, int y) const { TextMetrics & tm = d->text_metrics_[&text]; Inset * inset = tm.checkInsetHit(x, y); @@ -1366,6 +1425,27 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0) } +void BufferView::lfunScroll(FuncRequest const & cmd) +{ + string const scroll_type = cmd.getArg(0); + int const scroll_step = + (scroll_type == "line")? d->scrollbarParameters_.lineScrollHeight + : (scroll_type == "page")? height_ : 0; + if (scroll_step == 0) + return; + string const scroll_quantity = cmd.getArg(1); + if (scroll_quantity == "up") + scrollUp(scroll_step); + else if (scroll_quantity == "down") + scrollDown(scroll_step); + else { + int const scroll_value = convert(scroll_quantity); + if (scroll_value) + scroll(scroll_step * scroll_value); + } +} + + void BufferView::scroll(int y) { if (y > 0) @@ -1445,7 +1525,7 @@ void BufferView::gotoLabel(docstring const & label) it->getLabelList(buffer_, labels); if (find(labels.begin(), labels.end(), label) != labels.end()) { setCursor(it); - processUpdateFlags(Update::FitCursor); + showCursor(); return; } } @@ -1509,6 +1589,8 @@ bool BufferView::checkDepm(Cursor & cur, Cursor & old) if (!changed) return false; + d->cursor_ = cur; + updateLabels(buffer_); updateMetrics(); @@ -1664,7 +1746,7 @@ void BufferView::updateMetrics() int y1 = d->anchor_ypos_ - anchor_pm.ascent(); // We are now just above the anchor paragraph. pit_type pit1 = d->anchor_pit_ - 1; - for (; pit1 >= 0 && y1 > 0; --pit1) { + for (; pit1 >= 0 && y1 >= 0; --pit1) { tm.redoParagraph(pit1); ParagraphMetrics & pm = tm.par_metrics_[pit1]; y1 -= pm.descent(); @@ -1677,7 +1759,7 @@ void BufferView::updateMetrics() int y2 = d->anchor_ypos_ + anchor_pm.descent(); // We are now just below the anchor paragraph. pit_type pit2 = d->anchor_pit_ + 1; - for (; pit2 < npit && y2 < height_; ++pit2) { + for (; pit2 < npit && y2 <= height_; ++pit2) { tm.redoParagraph(pit2); ParagraphMetrics & pm = tm.par_metrics_[pit2]; y2 += pm.ascent();