diff --git a/src/Gui/Dialogs/DlgExpressionInput.cpp b/src/Gui/Dialogs/DlgExpressionInput.cpp index 4bb9d22371..7e4ec4a6dd 100644 --- a/src/Gui/Dialogs/DlgExpressionInput.cpp +++ b/src/Gui/Dialogs/DlgExpressionInput.cpp @@ -115,7 +115,7 @@ DlgExpressionInput::DlgExpressionInput(const App::ObjectIdentifier & _path, } else { ui->expression->setMinimumWidth(300); - ui->expression->setMinimumHeight(50); + ui->expression->setMinimumHeight(80); ui->msg->setWordWrap(true); ui->msg->setMaximumHeight(200); ui->msg->setMinimumWidth(280); diff --git a/src/Gui/ExpressionCompleter.cpp b/src/Gui/ExpressionCompleter.cpp index ee206c8ff9..15dff8d3bf 100644 --- a/src/Gui/ExpressionCompleter.cpp +++ b/src/Gui/ExpressionCompleter.cpp @@ -888,6 +888,8 @@ void ExpressionCompleter::slotUpdate(const QString& prefix, int pos) else if (auto itemView = popup()) { itemView->setVisible(false); } + + Q_EMIT completerSlotUpdated(); } ExpressionValidator::ExpressionValidator(QObject* parent) @@ -1116,6 +1118,10 @@ void ExpressionTextEdit::setDocumentObject(const App::DocumentObject* currentDoc &ExpressionTextEdit::textChanged2, completer, &ExpressionCompleter::slotUpdate); + connect(completer, + &ExpressionCompleter::completerSlotUpdated, + this, + &ExpressionTextEdit::adjustCompleterToCursor); } } @@ -1135,6 +1141,7 @@ void ExpressionTextEdit::slotTextChanged() { if (!block) { QTextCursor cursor = textCursor(); + completer->popup()->setVisible(false); // hide the completer to avoid flickering Q_EMIT textChanged2(cursor.block().text(), cursor.positionInBlock()); } } @@ -1185,6 +1192,49 @@ void ExpressionTextEdit::contextMenuEvent(QContextMenuEvent* event) delete menu; } +void ExpressionTextEdit::adjustCompleterToCursor() +{ + if (!completer || !completer->popup()) { + return; + } + + // get longest string width + int maxCompletionWidth = 0; + for (int i = 0; i < completer->completionModel()->rowCount(); ++i) { + const QModelIndex index = completer->completionModel()->index(i, 0); + const QString element = completer->completionModel()->data(index).toString(); + maxCompletionWidth = std::max(maxCompletionWidth, static_cast(element.size()) * completer->popup()->fontMetrics().averageCharWidth()); + } + if (maxCompletionWidth == 0) { + return; // no completions available + } + + const QPoint cursorPos = cursorRect(textCursor()).topLeft(); + int posX = cursorPos.x(); + int posY = cursorPos.y(); + + completer->popup()->setMaximumWidth(this->viewport()->width() * 0.6); + completer->popup()->setMaximumHeight(this->viewport()->height() * 0.6); + + const QSize completerSize { maxCompletionWidth + 40, completer->popup()->size().height() }; // 40 is margin for scrollbar + completer->popup()->resize(completerSize); + + // vertical correction + if (posY + completerSize.height() > viewport()->height()) { + posY -= completerSize.height(); + } else { + posY += fontMetrics().height(); + } + + // horizontal correction + if (posX + completerSize.width() > viewport()->width()) { + posX = viewport()->width() - completerSize.width(); + } + + completer->popup()->move(mapToGlobal(QPoint{ posX, posY })); + completer->popup()->setVisible(true); +} + /////////////////////////////////////////////////////////////////////// ExpressionParameter* ExpressionParameter::instance() diff --git a/src/Gui/ExpressionCompleter.h b/src/Gui/ExpressionCompleter.h index af29fe4396..fce6efa163 100644 --- a/src/Gui/ExpressionCompleter.h +++ b/src/Gui/ExpressionCompleter.h @@ -78,6 +78,9 @@ public: public Q_SLOTS: void slotUpdate(const QString &prefix, int pos); +Q_SIGNALS: + void completerSlotUpdated(); + private: void init(); QString pathFromIndex ( const QModelIndex & index ) const override; @@ -139,6 +142,7 @@ Q_SIGNALS: public Q_SLOTS: void slotTextChanged(); void slotCompleteText(const QString & completionPrefix); + void adjustCompleterToCursor(); private: ExpressionCompleter * completer; bool block;