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 <marcus.tillmanns@qt.io>
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: <lie@spyro-soft.com>
This commit is contained in:
Artur Twardy
2024-10-07 21:40:28 +02:00
parent c6a8b5844f
commit 702f9f5b5d
3 changed files with 69 additions and 21 deletions

View File

@@ -5,6 +5,7 @@
#include "../luatr.h" #include "../luatr.h"
#include <texteditor/basehoverhandler.h> #include <texteditor/basehoverhandler.h>
#include <texteditor/fontsettings.h>
#include <texteditor/textdocument.h> #include <texteditor/textdocument.h>
#include <texteditor/textdocumentlayout.h> #include <texteditor/textdocumentlayout.h>
#include <texteditor/texteditor.h> #include <texteditor/texteditor.h>
@@ -45,22 +46,65 @@ TextEditor::TextEditorWidget *getSuggestionReadyEditorWidget(TextEditor::TextDoc
return widget; 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()); int maxWidth = viewportSize.width() - margins.right() - widget->x();
const auto editorWidget = editor->editorWidget(); widget->setFixedWidth(maxWidth);
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();
} }
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
namespace Lua::Internal { namespace Lua::Internal {
@@ -234,17 +278,20 @@ void setupTextEditorModule()
}, },
"addFloatingWidget", "addFloatingWidget",
sol::overload( 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")); 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")); 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")); QTC_ASSERT(textEditor, throw sol::error("TextEditor is not valid"));
addFloatingWidget(textEditor, layout->emerge(), position); addFloatingWidget(textEditor, layout->emerge(), position, margins, fillWidth);
}), }),
"cursor", "cursor",
[](const TextEditorPtr &textEditor) { [](const TextEditorPtr &textEditor) {

View File

@@ -49,5 +49,4 @@ inline void mirrorEnum(sol::table &target, QMetaEnum metaEnum, const QString &na
for (int i = 0; i < metaEnum.keyCount(); ++i) for (int i = 0; i < metaEnum.keyCount(); ++i)
widgetAttributes.set(metaEnum.key(i), metaEnum.value(i)); widgetAttributes.set(metaEnum.key(i), metaEnum.value(i));
}; };
} // namespace Lua::Internal } // namespace Lua::Internal

View File

@@ -100,7 +100,9 @@ function TextEditor:cursor() end
---text document and will be automatically managed to stay pined to that position. ---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 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. ---@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. ---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. ---@return boolean True if the suggestion is locked, false otherwise.