Android: Fix select handles misplacement on QDialog

Get select handles {Left, Right}Point from a mapToGlobal with a cursorRectangleof anchorRectangle
of the selected word/text.

Task-number: QTBUG-90799
Change-Id: I4fed19a1d3bb2247656b052306307e6980074405
Reviewed-by: Rami Potinkara <rami.potinkara@qt.io>
Reviewed-by: Ville Voutilainen <ville.voutilainen@qt.io>
bb10
Pekka Gehör 2021-02-24 14:22:49 +02:00
parent 13c8db52a2
commit 32cdf0ce0f
6 changed files with 63 additions and 7 deletions

View File

@ -202,6 +202,11 @@ public class CursorHandle implements ViewTreeObserver.OnPreDrawListener
}
}
public int width()
{
return m_cursorView.getDrawable().getIntrinsicWidth();
}
// The handle was dragged by a given relative position
public void updatePosition(int x, int y) {
y -= m_yShift;

View File

@ -513,6 +513,17 @@ public class QtActivityDelegate
private static final int CursorHandleShowSelection = 2;
private static final int CursorHandleShowEdit = 0x100;
public int getSelectHandleWidth()
{
int width = 0;
if (m_leftSelectionHandle != null && m_rightSelectionHandle != null) {
width = Math.max(m_leftSelectionHandle.width(), m_rightSelectionHandle.width());
} else if (m_cursorHandle != null) {
width = m_cursorHandle.width();
}
return width;
}
/* called from the C++ code when the position of the cursor or selection handles needs to
be adjusted.
mode is one of QAndroidInputContext::CursorHandleShowMode

View File

@ -864,6 +864,11 @@ public class QtNative
});
}
private static int getSelectHandleWidth()
{
return m_activityDelegate.getSelectHandleWidth();
}
private static void updateHandles(final int mode,
final int editX,
final int editY,

View File

@ -121,6 +121,11 @@ namespace QtAndroidInput
return m_softwareKeyboardRect;
}
int getSelectHandleWidth()
{
return QJniObject::callStaticMethod<jint>(applicationClass(), "getSelectHandleWidth");
}
void updateHandles(int mode, QPoint editMenuPos, uint32_t editButtons, QPoint cursor, QPoint anchor, bool rtl)
{
QJniObject::callStaticMethod<void>(applicationClass(), "updateHandles", "(IIIIIIIIZ)V",

View File

@ -62,6 +62,7 @@ namespace QtAndroidInput
// cursor/selection handles
void updateHandles(int handleCount, QPoint editMenuPos = QPoint(), uint32_t editButtons = 0,
QPoint cursor = QPoint(), QPoint anchor = QPoint(), bool rtl = false);
int getSelectHandleWidth();
bool registerNatives(JNIEnv *env);
}

View File

@ -92,6 +92,7 @@ private:
static QAndroidInputContext *m_androidInputContext = nullptr;
static char const *const QtNativeInputConnectionClassName = "org/qtproject/qt/android/QtNativeInputConnection";
static char const *const QtExtractedTextClassName = "org/qtproject/qt/android/QtExtractedText";
static int m_selectHandleWidth = 0;
static jclass m_extractedTextClass = 0;
static jmethodID m_classConstructorMethodID = 0;
static jfieldID m_partialEndOffsetFieldID = 0;
@ -609,7 +610,6 @@ void QAndroidInputContext::updateSelectionHandles()
auto im = qGuiApp->inputMethod();
QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImEnabled
| Qt::ImCurrentSelection | Qt::ImHints | Qt::ImSurroundingText
| Qt::ImReadOnly);
@ -619,6 +619,7 @@ void QAndroidInputContext::updateSelectionHandles()
int anchor = query.value(Qt::ImAnchorPosition).toInt();
const QVariant readOnlyVariant = query.value(Qt::ImReadOnly);
bool readOnly = readOnlyVariant.toBool();
QPlatformWindow *qPlatformWindow = qGuiApp->focusWindow()->handle();
if ( cpos == anchor && (!readOnlyVariant.isValid() || readOnly)) {
QtAndroidInput::updateHandles(Hidden);
@ -627,7 +628,7 @@ void QAndroidInputContext::updateSelectionHandles()
if (cpos == anchor || im->anchorRectangle().isNull()) {
auto curRect = cursorRectangle();
QPoint cursorPoint = qGuiApp->focusWindow()->handle()->mapToGlobal(QPoint(curRect.x() + (curRect.width() / 2), curRect.y() + curRect.height()));
QPoint cursorPoint = qPlatformWindow->mapToGlobal(QPoint(curRect.x() + (curRect.width() / 2), curRect.y() + curRect.height()));
QPoint editMenuPoint(cursorPoint.x(), cursorPoint.y());
m_handleMode &= ShowEditPopup;
m_handleMode |= ShowCursor;
@ -646,14 +647,26 @@ void QAndroidInputContext::updateSelectionHandles()
auto rightRect = anchorRectangle();
if (cpos > anchor)
std::swap(leftRect, rightRect);
//Move the left or right select handle to the center from the screen edge
//the select handle is close to or over the screen edge. Otherwise, the
//select handle might go out of the screen and it would be impossible to drag.
QPoint leftPoint(qPlatformWindow->mapToGlobal(leftRect.bottomLeft().toPoint()));
QPoint rightPoint(qPlatformWindow->mapToGlobal(rightRect.bottomRight().toPoint()));
QPoint leftPoint(leftRect.bottomLeft().toPoint());
QPoint righPoint(rightRect.bottomRight().toPoint());
QPoint editPoint(leftRect.united(rightRect).topLeft().toPoint());
if (m_selectHandleWidth == 0)
m_selectHandleWidth = QtAndroidInput::getSelectHandleWidth() / 2;
int rightSideOfScreen = QtAndroid::androidPlatformIntegration()->screen()->availableGeometry().right();
if (leftPoint.x() < m_selectHandleWidth)
leftPoint.setX(m_selectHandleWidth);
if (rightPoint.x() > rightSideOfScreen - m_selectHandleWidth)
rightPoint.setX(rightSideOfScreen - m_selectHandleWidth);
QPoint editPoint(qPlatformWindow->mapToGlobal(leftRect.united(rightRect).topLeft().toPoint()));
uint32_t buttons = readOnly ? EditContext::CopyButton | EditContext::SelectAllButton
: EditContext::AllButtons;
QtAndroidInput::updateHandles(m_handleMode, editPoint, buttons, leftPoint, righPoint,
QtAndroidInput::updateHandles(m_handleMode, editPoint, buttons, leftPoint, rightPoint,
query.value(Qt::ImCurrentSelection).toString().isRightToLeft());
m_hideCursorHandleTimer.stop();
}
@ -690,7 +703,23 @@ void QAndroidInputContext::handleLocationChanged(int handleId, int x, int y)
}
bool ok;
const int handlePos = queryFocusObject(Qt::ImCursorPosition, point).toInt(&ok);
auto object = m_focusObject->parent();
int dialogMoveX = 0;
while (object) {
if (QString::compare(object->metaObject()->className(),
"QDialog", Qt::CaseInsensitive) == 0) {
dialogMoveX += object->property("x").toInt();
}
object = object->parent();
};
auto position =
QPointF(QHighDpi::fromNativePixels(point, QGuiApplication::focusWindow()));
const QPointF fixedPosition = QPointF(position.x() - dialogMoveX, position.y());
const QInputMethod *im = QGuiApplication::inputMethod();
const QTransform mapToLocal = im->inputItemTransform().inverted();
const int handlePos = im->queryFocusObject(Qt::ImCursorPosition, mapToLocal.map(fixedPosition)).toInt(&ok);
if (!ok)
return;