X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt%2FGuiWorkArea.cpp;h=02e03aaaeb780565d741ffd284345b3c09a852e9;hb=070270fdc719edcd0ae49a182acf58583038a765;hp=7c21088643dfd16fcc1e08f7b42c4d66f073ca8c;hpb=7f1b1729b4ccdb16e35e6d5052890103f13bd747;p=features.git diff --git a/src/frontends/qt/GuiWorkArea.cpp b/src/frontends/qt/GuiWorkArea.cpp index 7c21088643..02e03aaaeb 100644 --- a/src/frontends/qt/GuiWorkArea.cpp +++ b/src/frontends/qt/GuiWorkArea.cpp @@ -15,7 +15,6 @@ #include "GuiWorkArea_Private.h" #include "ColorCache.h" -#include "FontLoader.h" #include "GuiApplication.h" #include "GuiCompleter.h" #include "GuiKeySymbol.h" @@ -33,7 +32,6 @@ #include "Font.h" #include "FuncRequest.h" #include "KeySymbol.h" -#include "Language.h" #include "LyX.h" #include "LyXRC.h" #include "LyXVC.h" @@ -42,15 +40,14 @@ #include "Undo.h" #include "version.h" -#include "graphics/GraphicsImage.h" -#include "graphics/GraphicsLoader.h" - #include "support/convert.h" #include "support/debug.h" #include "support/lassert.h" #include "support/TempFile.h" #include "frontends/Application.h" +#include "frontends/CaretGeometry.h" + #include "frontends/FontMetrics.h" #include "frontends/WorkAreaManager.h" @@ -79,8 +76,6 @@ #include #include -int const TabIndicatorWidth = 3; - #undef KeyPress #undef NoModifier @@ -98,7 +93,7 @@ static mouse_button::state q_button_state(Qt::MouseButton button) case Qt::LeftButton: b = mouse_button::button1; break; - case Qt::MidButton: + case Qt::MiddleButton: b = mouse_button::button2; break; case Qt::RightButton: @@ -117,7 +112,7 @@ mouse_button::state q_motion_state(Qt::MouseButtons state) mouse_button::state b = mouse_button::none; if (state & Qt::LeftButton) b |= mouse_button::button1; - if (state & Qt::MidButton) + if (state & Qt::MiddleButton) b |= mouse_button::button2; if (state & Qt::RightButton) b |= mouse_button::button3; @@ -127,100 +122,6 @@ mouse_button::state q_motion_state(Qt::MouseButtons state) namespace frontend { -class CaretWidget { -public: - 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 - * has been horizontal scrolling in current row - */ - void draw(QPainter & painter, int horiz_offset) - { - if (dim.empty()) - return; - // 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 - 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 - 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 + dim.height() / 2; - int const d = TabIndicatorWidth * dim.wid - 1; - // offset for slanted carret - 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(BufferView const * bv, bool complet) { - // Cursor size and position - Point point; - bv->caretPosAndDim(point, dim); - x = point.x_; - y = point.y_; - completable = complet; - - 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; - - // 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; - - color = guiApp->colorCache().get(Color_cursor); - } - - /// 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; - /// - QColor color; - /// dimension uf base caret - Dimension dim; - /// x position (were the vertical line is drawn) - int x; - /// y position (the top of the caret) - int y; - /// the slope for drawing slanted caret - double slope; -}; - - // This is a 'heartbeat' generating synthetic mouse move events when the // cursor is at the top or bottom edge of the viewport. One scroll per 0.2 s SyntheticMouseEvent::SyntheticMouseEvent() @@ -229,26 +130,15 @@ SyntheticMouseEvent::SyntheticMouseEvent() GuiWorkArea::Private::Private(GuiWorkArea * parent) -: p(parent), buffer_view_(nullptr), lyx_view_(nullptr), caret_(nullptr), - caret_visible_(false), need_resize_(false), preedit_lines_(1), - last_pixel_ratio_(1.0), completer_(new GuiCompleter(p, p)), - dialog_mode_(false), shell_escape_(false), read_only_(false), - clean_(true), externally_modified_(false), needs_caret_geometry_update_(true) -{ -/* Qt on macOS and Wayland does not respect the - * Qt::WA_OpaquePaintEvent attribute and resets the widget backing - * store at each update. Therefore, we use our own backing store in - * these two cases. */ -#if QT_VERSION >= 0x050000 + : p(parent), completer_(new GuiCompleter(p, p)) +{ + /* Qt on macOS and Wayland does not respect the + * Qt::WA_OpaquePaintEvent attribute and resets the widget backing + * store at each update. Therefore, we use our own backing store + * in these two cases. + */ use_backingstore_ = guiApp->platformName() == "cocoa" || guiApp->platformName().contains("wayland"); -#else -# ifdef Q_OS_MAC - use_backingstore_ = true; -# else - use_backingstore_ = false; -# endif -#endif int const time = QApplication::cursorFlashTime() / 2; if (time > 0) { @@ -268,7 +158,6 @@ GuiWorkArea::Private::~Private() buffer_view_->buffer().workAreaManager().remove(p); } catch(...) {} delete buffer_view_; - delete caret_; // Completer has a QObject parent and is thus automatically destroyed. // See #4758. // delete completer_; @@ -318,7 +207,6 @@ void GuiWorkArea::init() // With Qt4.5 a mouse event will happen before the first paint event // so make sure that the buffer view has an up to date metrics. d->buffer_view_->resize(viewport()->width(), viewport()->height()); - d->caret_ = new frontend::CaretWidget(); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setAcceptDrops(true); @@ -608,7 +496,7 @@ void GuiWorkArea::Private::resetCaret() && !completer_->popupVisible() && !completer_->inlineVisible(); - caret_->update(buffer_view_, completable); + buffer_view_->buildCaretGeometry(completable); needs_caret_geometry_update_ = true; caret_visible_ = true; @@ -649,6 +537,33 @@ void GuiWorkArea::Private::hideCaret() } +/* Draw the caret. Parameter \c horiz_offset is not 0 when there + * has been horizontal scrolling in current row + */ +void GuiWorkArea::Private::drawCaret(QPainter & painter, int horiz_offset) const +{ + if (buffer_view_->caretGeometry().shapes.empty()) + return; + + QColor const color = guiApp->colorCache().get(Color_cursor); + painter.setPen(color); + painter.setRenderHint(QPainter::Antialiasing, true); + for (auto const & shape : buffer_view_->caretGeometry().shapes) { + bool first = true; + QPainterPath path; + for (Point const & p : shape) { + if (first) { + path.moveTo(p.x_ - horiz_offset, p.y_); + first = false; + } else + path.lineTo(p.x_ - horiz_offset, p.y_); + } + painter.fillPath(path, color); + } + painter.setRenderHint(QPainter::Antialiasing, false); +} + + void GuiWorkArea::Private::updateScrollbar() { // Prevent setRange() and setSliderPosition from causing recursive calls via @@ -1061,7 +976,6 @@ void GuiWorkArea::generateSyntheticMouseEvent() cur.boundary(bound); d->buffer_view_->buffer().changed(false); - return; } @@ -1197,9 +1111,11 @@ void GuiWorkArea::Private::paintPreeditText(GuiPainter & pain) // FIXME: shall we use real_current_font here? (see #10478) FontInfo const font = buffer_view_->cursor().getFont().fontInfo(); FontMetrics const & fm = theFontMetrics(font); - int const height = fm.maxHeight(); - int cur_x = caret_->x; - int cur_y = caret_->y + height; + Point point; + Dimension dim; + buffer_view_->caretPosAndDim(point, dim); + int cur_x = point.x_; + int cur_y = point.y_ + dim.height(); // get attributes of input method cursor. // cursor_pos : cursor position in preedit string. @@ -1252,7 +1168,7 @@ void GuiWorkArea::Private::paintPreeditText(GuiPainter & pain) // if we reached the right extremity of the screen, go to next line. if (cur_x + fm.width(typed_char) > p->viewport()->width() - right_margin) { cur_x = right_margin; - cur_y += height + 1; + cur_y += dim.height() + 1; ++preedit_lines_; } // preedit strings are displayed with dashed underline @@ -1350,7 +1266,7 @@ void GuiWorkArea::paintEvent(QPaintEvent * ev) if (d->caret_visible_) { if (d->needs_caret_geometry_update_) d->updateCaretGeometry(); - d->caret_->draw(pain, d->buffer_view_->horizScrollOffset()); + d->drawCaret(pain, d->buffer_view_->horizScrollOffset()); } d->updateScreen(ev->rect()); @@ -1393,10 +1309,11 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) // redraw area of preedit string. - int height = d->caret_->dim.height(); - int cur_y = d->caret_->y; - viewport()->update(0, cur_y, viewport()->width(), - (height + 1) * d->preedit_lines_); + // int height = d->caret_->dim.height(); + // int cur_y = d->caret_->y; + // viewport()->update(0, cur_y, viewport()->width(), + // (height + 1) * d->preedit_lines_); + viewport()->update(); if (d->preedit_string_.empty()) { d->preedit_lines_ = 1; @@ -1411,16 +1328,21 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) QVariant GuiWorkArea::inputMethodQuery(Qt::InputMethodQuery query) const { - QRect cur_r(0, 0, 0, 0); switch (query) { // this is the CJK-specific composition window position and // the context menu position when the menu key is pressed. - case Qt::ImMicroFocus: - 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); +#if (QT_VERSION < 0x050000) + case Qt::ImMicroFocus: { +#else + case Qt::ImCursorRectangle: { +#endif + CaretGeometry const & cg = bufferView().caretGeometry(); + return QRect(cg.left - 10 * (d->preedit_lines_ != 1), + cg.top + cg.height() * d->preedit_lines_, + cg.width(), cg.height()); + } + default: + return QWidget::inputMethodQuery(query); } } @@ -1627,7 +1549,7 @@ TabWorkArea::TabWorkArea(QWidget * parent) void TabWorkArea::mousePressEvent(QMouseEvent *me) { - if (me->button() == Qt::MidButton) + if (me->button() == Qt::MiddleButton) midpressed_tab_ = tabBar()->tabAt(me->pos()); else QTabWidget::mousePressEvent(me); @@ -1636,7 +1558,7 @@ void TabWorkArea::mousePressEvent(QMouseEvent *me) void TabWorkArea::mouseReleaseEvent(QMouseEvent *me) { - if (me->button() == Qt::MidButton) { + if (me->button() == Qt::MiddleButton) { int const midreleased_tab = tabBar()->tabAt(me->pos()); if (midpressed_tab_ == midreleased_tab && posIsTab(me->pos())) closeTab(midreleased_tab); @@ -2196,7 +2118,7 @@ void GuiWorkAreaContainer::updateDisplay() } -void GuiWorkAreaContainer::dispatch(FuncRequest f) const +void GuiWorkAreaContainer::dispatch(FuncRequest const & f) const { lyx::dispatch(FuncRequest(LFUN_BUFFER_SWITCH, wa_->bufferView().buffer().absFileName()));