From 702f9f5b5dac850847fe805a64666ebb9232865e Mon Sep 17 00:00:00 2001 From: Artur Twardy Date: Mon, 7 Oct 2024 21:40:28 +0200 Subject: [PATCH] Lua: Fix for TextEditor widget positioning Position widget at cursor coordinates if widget fits in TextEditor viewport, otherwise move the widget to be fully visible on the view and tries not to cover the cursor. Enable option to fill the remanining viewport width. Adds utils function to convert sol::table to std::tuple Change-Id: I6d0f52e82b9380888259e36819e3cab127e8fddd Reviewed-by: Marcus Tillmanns Reviewed-by: hjk Reviewed-by: --- src/plugins/lua/bindings/texteditor.cpp | 85 +++++++++++++++++++------ src/plugins/lua/bindings/utils.h | 1 - src/plugins/lua/meta/texteditor.lua | 4 +- 3 files changed, 69 insertions(+), 21 deletions(-) diff --git a/src/plugins/lua/bindings/texteditor.cpp b/src/plugins/lua/bindings/texteditor.cpp index 6c3f9e95d9b..0066b96fc54 100644 --- a/src/plugins/lua/bindings/texteditor.cpp +++ b/src/plugins/lua/bindings/texteditor.cpp @@ -5,6 +5,7 @@ #include "../luatr.h" #include +#include #include #include #include @@ -45,22 +46,65 @@ TextEditor::TextEditorWidget *getSuggestionReadyEditorWidget(TextEditor::TextDoc return widget; } -void addFloatingWidget(BaseTextEditor *editor, QWidget *widget, int position) +void fillRemainingViewportWidth(QWidget *widget, const QSize &viewportSize, const QMargins &margins) { - widget->setParent(editor->editorWidget()->viewport()); - const auto editorWidget = editor->editorWidget(); - - QTextCursor cursor = QTextCursor(editor->textDocument()->document()); - cursor.setPosition(position); - const QRect cursorRect = editorWidget->cursorRect(cursor); - - QPoint widgetPos = cursorRect.bottomLeft(); - widgetPos.ry() += (cursorRect.top() - cursorRect.bottom()) / 2; - - widget->move(widgetPos); - widget->show(); + int maxWidth = viewportSize.width() - margins.right() - widget->x(); + widget->setFixedWidth(maxWidth); } +QPoint getPositionOnViewport(const BaseTextEditor * const editor, const QWidget * const widget, + int basePostion, const QSize &viewportSize, const QMargins &margins) +{ + QTextCursor cursor = QTextCursor(editor->textDocument()->document()); + cursor.setPosition(basePostion); + + const QRect cursorRect = editor->editorWidget()->cursorRect(cursor); + QPoint widgetPosDefault = cursorRect.bottomLeft(); + + widgetPosDefault.ry() += (cursorRect.top() - cursorRect.bottom()) / 2; + + int fontSize = editor->textDocument()->fontSettings().fontSize(); + int maxX = viewportSize.width() - margins.right() - widget->width(); + int maxY = viewportSize.height() - widget->height() - fontSize; + + if (maxX < 0) { + qWarning() << QStringLiteral("Floating Widget positioning: x (%1) < 0. Widget will not " + "fit in the viewport. Viewport.width (%2), widget.width (%3), " + "widget margin.right (%4). Setting x to 0.") + .arg(maxX).arg(viewportSize.width()).arg(widget->width()).arg(margins.right()); + maxX = 0; + } + + if (maxY < 0) { + qWarning() << QStringLiteral("Floating Widget positioning: y (%1) < 0. Widget is too big" + "for the viewport. Viewport.height (%2), widget.height (%3)." + "Setting y to 0.") + .arg(maxY).arg(viewportSize.height()).arg(widget->height()); + maxY = 0; + } + + int x = widgetPosDefault.x() > maxX ? maxX : widgetPosDefault.x(); + int y = widgetPosDefault.y() + fontSize; + y = y > maxY ? maxY : y; + + return {x, y}; +} + +void addFloatingWidget(BaseTextEditor *editor, QWidget *widget, int pos, const QRect &margins, + bool fillWidth = false) +{ + QMargins widgetMargins{margins.left(), margins.top(), margins.width(), margins.height()}; + + widget->setParent(editor->editorWidget()->viewport()); + TextEditorWidget *editorWidget = editor->editorWidget(); + const QSize viewportSize = editorWidget->viewport()->size(); + + widget->move(getPositionOnViewport(editor, widget, pos, viewportSize, widgetMargins)); + if (fillWidth) + fillRemainingViewportWidth(widget, viewportSize, widgetMargins); + + widget->show(); +} } // namespace namespace Lua::Internal { @@ -234,17 +278,20 @@ void setupTextEditorModule() }, "addFloatingWidget", sol::overload( - [](const TextEditorPtr &textEditor, QWidget *widget, int position) { + [](const TextEditorPtr &textEditor, QWidget *widget, int position, + const QRect &margins, bool fillWidth) { QTC_ASSERT(textEditor, throw sol::error("TextEditor is not valid")); - addFloatingWidget(textEditor, widget, position); + addFloatingWidget(textEditor, widget, position, margins, fillWidth); }, - [](const TextEditorPtr &textEditor, Layouting::Widget *widget, int position) { + [](const TextEditorPtr &textEditor, Layouting::Widget *widget, int position, + const QRect &margins, bool fillWidth) { QTC_ASSERT(textEditor, throw sol::error("TextEditor is not valid")); - addFloatingWidget(textEditor, widget->emerge(), position); + addFloatingWidget(textEditor, widget->emerge(), position, margins, fillWidth); }, - [](const TextEditorPtr &textEditor, Layouting::Layout *layout, int position) { + [](const TextEditorPtr &textEditor, Layouting::Layout *layout, int position, + const QRect &margins, bool fillWidth = false) { QTC_ASSERT(textEditor, throw sol::error("TextEditor is not valid")); - addFloatingWidget(textEditor, layout->emerge(), position); + addFloatingWidget(textEditor, layout->emerge(), position, margins, fillWidth); }), "cursor", [](const TextEditorPtr &textEditor) { diff --git a/src/plugins/lua/bindings/utils.h b/src/plugins/lua/bindings/utils.h index a6b65c762d0..b42c5f85e72 100644 --- a/src/plugins/lua/bindings/utils.h +++ b/src/plugins/lua/bindings/utils.h @@ -49,5 +49,4 @@ inline void mirrorEnum(sol::table &target, QMetaEnum metaEnum, const QString &na for (int i = 0; i < metaEnum.keyCount(); ++i) widgetAttributes.set(metaEnum.key(i), metaEnum.value(i)); }; - } // namespace Lua::Internal diff --git a/src/plugins/lua/meta/texteditor.lua b/src/plugins/lua/meta/texteditor.lua index d4575c14cae..a11138f7ad2 100644 --- a/src/plugins/lua/meta/texteditor.lua +++ b/src/plugins/lua/meta/texteditor.lua @@ -100,7 +100,9 @@ function TextEditor:cursor() end ---text document and will be automatically managed to stay pined to that position. ---@param widget Widget|Layout The widget to be added as a floating widget. ---@param position integer The position in the document where the widget should appear. -function TextEditor:addFloatingWidget(widget, position) end +---@param margins integer[] Four integers, representing left, top, right, bottom margins +---@param fillWidth boolean If true, the widget will fill remaining space from its x position to size of the TextEditor viewport +function TextEditor:addFloatingWidget(widget, position, margins, fillWidth) end ---Checks if the current suggestion is locked. The suggestion is locked when the user can use it. ---@return boolean True if the suggestion is locked, false otherwise.