Android: Move CursorHandles to QtEditText

The CursorHandles are the handles visible when trying
to select text from a text edit, or select a position
in the text. As it is not used anywhere outside
a text edit, move it inside QtEditText, making it
easier to handle cases where we have multiple windows,
and multiple QtTextEdits.

Task-number: QTBUG-126180
Change-Id: I765f229050ca33887570c1434bdc0a2aa3659649
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
(cherry picked from commit 996e1fba5e83e09a897272b16062a8e4fad291ef)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Tinja Paavoseppä 2024-07-25 14:41:18 +03:00 committed by Qt Cherry-pick Bot
parent e1b7a0d3ee
commit f149f0245f
6 changed files with 122 additions and 91 deletions

View File

@ -69,6 +69,12 @@ class CursorView extends ImageView
class CursorHandle implements ViewTreeObserver.OnPreDrawListener
{
private static final String QtTag = "QtCursorHandle";
// Handle IDs
static final int IdCursorHandle = 1;
static final int IdLeftHandle = 2;
static final int IdRightHandle = 3;
private final View m_layout;
private CursorView m_cursorView = null;
private PopupWindow m_popup = null;
@ -138,9 +144,9 @@ class CursorHandle implements ViewTreeObserver.OnPreDrawListener
int x2 = x + layoutLocation[0] - activityLocation[0];
int y2 = y + layoutLocation[1] + m_yShift + (activityLocationInWindow[1] - activityLocation[1]);
if (m_id == QtInputDelegate.IdCursorHandle) {
if (m_id == IdCursorHandle) {
x2 -= m_popup.getWidth() / 2 ;
} else if ((m_id == QtInputDelegate.IdLeftHandle && !m_rtl) || (m_id == QtInputDelegate.IdRightHandle && m_rtl)) {
} else if ((m_id == IdLeftHandle && !m_rtl) || (m_id == IdRightHandle && m_rtl)) {
x2 -= m_popup.getWidth() * 3 / 4;
} else {
x2 -= m_popup.getWidth() / 4;

View File

@ -23,9 +23,7 @@ class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayout
private int m_posX;
private int m_posY;
private int m_buttons;
private CursorHandle m_cursorHandle;
private CursorHandle m_leftSelectionHandle;
private CursorHandle m_rightSelectionHandle;
private QtEditText m_currentEditText = null; // TODO, get rid of this reference
EditPopupMenu(Activity activity, View layout)
{
@ -53,8 +51,7 @@ class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayout
}
// Show the handle at a given position (or move it if it is already shown)
void setPosition(final int x, final int y, final int buttons,
CursorHandle cursorHandle, CursorHandle leftSelectionHandle, CursorHandle rightSelectionHandle)
void setPosition(final int x, final int y, final int buttons, final QtEditText editText)
{
initOverlay();
@ -76,16 +73,13 @@ class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayout
x2 -= viewSize.x / 2 ;
y2 -= viewSize.y;
if (y2 < 0) {
if (cursorHandle != null) {
y2 = cursorHandle.bottom();
} else if (leftSelectionHandle != null && rightSelectionHandle != null) {
y2 = Math.max(leftSelectionHandle.bottom(), rightSelectionHandle.bottom());
if (y2 <= 0)
m_layout.requestLayout();
}
if (y2 < 0 && editText != null) {
y2 = editText.getSelectionHandleBottom();
}
if (y2 <= 0)
m_layout.requestLayout();
if (m_layout.getWidth() < x + viewSize.x / 2)
x2 = m_layout.getWidth() - viewSize.x;
@ -100,9 +94,7 @@ class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayout
m_posX = x;
m_posY = y;
m_buttons = buttons;
m_cursorHandle = cursorHandle;
m_leftSelectionHandle = leftSelectionHandle;
m_rightSelectionHandle = rightSelectionHandle;
m_currentEditText = editText;
}
void hide() {
@ -118,7 +110,7 @@ class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayout
// For example if the keyboard appears.
// Adjust the position of the handle accordingly
if (m_popup != null && m_popup.isShowing())
setPosition(m_posX, m_posY, m_buttons, m_cursorHandle, m_leftSelectionHandle, m_rightSelectionHandle);
setPosition(m_posX, m_posY, m_buttons, m_currentEditText);
return true;
}
@ -129,7 +121,7 @@ class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayout
{
if ((right - left != oldRight - oldLeft || bottom - top != oldBottom - oldTop) &&
m_popup != null && m_popup.isShowing())
setPosition(m_posX, m_posY, m_buttons, m_cursorHandle, m_leftSelectionHandle, m_rightSelectionHandle);
setPosition(m_posX, m_posY, m_buttons, m_currentEditText);
}
@Override

View File

@ -4,6 +4,7 @@
package org.qtproject.qt.android;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.text.InputType;
@ -49,6 +50,17 @@ class QtEditText extends View
private final QtInputConnectionListener m_qtInputConnectionListener;
// Values coming from QAndroidInputContext::CursorHandleShowMode
static final int CursorHandleNotShown = 0;
static final int CursorHandleShowNormal = 1;
static final int CursorHandleShowSelection = 2;
static final int CursorHandleShowEdit = 0x100;
private CursorHandle m_cursorHandle;
private CursorHandle m_leftSelectionHandle;
private CursorHandle m_rightSelectionHandle;
QtEditText(Context context, QtInputConnectionListener listener)
{
super(context);
@ -213,6 +225,84 @@ class QtEditText extends View
return imeOptions;
}
int getSelectionHandleBottom()
{
if (m_cursorHandle != null)
return m_cursorHandle.bottom();
if (m_leftSelectionHandle != null && m_rightSelectionHandle != null)
return Math.max(m_leftSelectionHandle.bottom(), m_rightSelectionHandle.bottom());
return 0;
}
int getSelectionHandleWidth()
{
if (m_leftSelectionHandle != null && m_rightSelectionHandle != null)
return Math.max(m_leftSelectionHandle.width(), m_rightSelectionHandle.width());
if (m_cursorHandle != null)
return m_cursorHandle.width();
return 0;
}
void updateHandles(int mode, int editX, int editY, int editButtons,
int x1, int y1, int x2, int y2, boolean rtl)
{
switch (mode & 0xff)
{
case CursorHandleNotShown:
if (m_cursorHandle != null) {
m_cursorHandle.hide();
m_cursorHandle = null;
}
if (m_rightSelectionHandle != null) {
m_rightSelectionHandle.hide();
m_leftSelectionHandle.hide();
m_rightSelectionHandle = null;
m_leftSelectionHandle = null;
}
break;
case CursorHandleShowNormal:
if (m_cursorHandle == null) {
// We pass this to the CursorHandle to use the QtEditText to calculate its
// position. This is OK as the QtEditText size matches the QtWindow size.
// If the size of the QtEditText is changed to not reflect the window's anymore,
// this should be changed to use getParent() instead of this.
m_cursorHandle = new CursorHandle((Activity) getContext(), this,
CursorHandle.IdCursorHandle,
android.R.attr.textSelectHandle, false);
}
m_cursorHandle.setPosition(x1, y1);
if (m_rightSelectionHandle != null) {
m_rightSelectionHandle.hide();
m_leftSelectionHandle.hide();
m_rightSelectionHandle = null;
m_leftSelectionHandle = null;
}
break;
case CursorHandleShowSelection:
if (m_rightSelectionHandle == null) {
m_leftSelectionHandle = new CursorHandle((Activity) getContext(), this,
CursorHandle.IdLeftHandle,
!rtl ? android.R.attr.textSelectHandleLeft :
android.R.attr.textSelectHandleRight,
rtl);
m_rightSelectionHandle = new CursorHandle((Activity) getContext(), this,
CursorHandle.IdRightHandle,
!rtl ? android.R.attr.textSelectHandleRight :
android.R.attr.textSelectHandleLeft,
rtl);
}
m_leftSelectionHandle.setPosition(x1,y1);
m_rightSelectionHandle.setPosition(x2,y2);
if (m_cursorHandle != null) {
m_cursorHandle.hide();
m_cursorHandle = null;
}
break;
}
}
private boolean isDisablePredictiveTextWorkaround(int inputHints)
{
return (inputHints & ImhNoPredictiveText) != 0 &&

View File

@ -51,24 +51,11 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
private int m_portraitKeyboardHeight = 0;
private int m_landscapeKeyboardHeight = 0;
private int m_probeKeyboardHeightDelayMs = 50;
private CursorHandle m_cursorHandle;
private CursorHandle m_leftSelectionHandle;
private CursorHandle m_rightSelectionHandle;
private EditPopupMenu m_editPopupMenu;
private int m_softInputMode = 0;
// Values coming from QAndroidInputContext::CursorHandleShowMode
private static final int CursorHandleNotShown = 0;
private static final int CursorHandleShowNormal = 1;
private static final int CursorHandleShowSelection = 2;
private static final int CursorHandleShowEdit = 0x100;
// Handle IDs
static final int IdCursorHandle = 1;
static final int IdLeftHandle = 2;
static final int IdRightHandle = 3;
private static Boolean m_tabletEventSupported = null;
private static int m_oldX, m_oldY;
@ -152,15 +139,9 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
}
@Override
public int getSelectHandleWidth()
public int getSelectionHandleWidth()
{
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;
return m_currentEditText == null ? 0 : m_currentEditText.getSelectionHandleWidth();
}
/* called from the C++ code when the position of the cursor or selection handles needs to
@ -375,55 +356,17 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
int editX, int editY, int editButtons,
int x1, int y1, int x2, int y2, boolean rtl)
{
if (m_currentEditText != null)
m_currentEditText.updateHandles(mode, editX, editY, editButtons, x1, y1, x2, y2, rtl);
switch (mode & 0xff)
{
case CursorHandleNotShown:
if (m_cursorHandle != null) {
m_cursorHandle.hide();
m_cursorHandle = null;
}
if (m_rightSelectionHandle != null) {
m_rightSelectionHandle.hide();
m_leftSelectionHandle.hide();
m_rightSelectionHandle = null;
m_leftSelectionHandle = null;
}
case QtEditText.CursorHandleNotShown:
if (m_editPopupMenu != null)
m_editPopupMenu.hide();
break;
case CursorHandleShowNormal:
if (m_cursorHandle == null) {
m_cursorHandle = new CursorHandle(activity, layout, IdCursorHandle,
android.R.attr.textSelectHandle, false);
}
m_cursorHandle.setPosition(x1, y1);
if (m_rightSelectionHandle != null) {
m_rightSelectionHandle.hide();
m_leftSelectionHandle.hide();
m_rightSelectionHandle = null;
m_leftSelectionHandle = null;
}
break;
case CursorHandleShowSelection:
if (m_rightSelectionHandle == null) {
m_leftSelectionHandle = new CursorHandle(activity, layout, IdLeftHandle,
!rtl ? android.R.attr.textSelectHandleLeft :
android.R.attr.textSelectHandleRight,
rtl);
m_rightSelectionHandle = new CursorHandle(activity, layout, IdRightHandle,
!rtl ? android.R.attr.textSelectHandleRight :
android.R.attr.textSelectHandleLeft,
rtl);
}
m_leftSelectionHandle.setPosition(x1,y1);
m_rightSelectionHandle.setPosition(x2,y2);
if (m_cursorHandle != null) {
m_cursorHandle.hide();
m_cursorHandle = null;
}
mode |= CursorHandleShowEdit;
case QtEditText.CursorHandleShowSelection:
mode |= QtEditText.CursorHandleShowEdit;
break;
}
@ -431,9 +374,9 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
editButtons &= ~EditContextView.PASTE_BUTTON;
if (m_editPopupMenu != null) {
if ((mode & CursorHandleShowEdit) == CursorHandleShowEdit && editButtons != 0) {
m_editPopupMenu.setPosition(editX, editY, editButtons,
m_cursorHandle, m_leftSelectionHandle, m_rightSelectionHandle);
if ((mode & QtEditText.CursorHandleShowEdit) == QtEditText.CursorHandleShowEdit &&
editButtons != 0) {
m_editPopupMenu.setPosition(editX, editY, editButtons, m_currentEditText);
} else {
m_editPopupMenu.hide();
}

View File

@ -14,7 +14,7 @@ interface QtInputInterface {
void resetSoftwareKeyboard();
void hideSoftwareKeyboard();
boolean isSoftwareKeyboardVisible();
int getSelectHandleWidth();
int getSelectionHandleWidth();
void updateHandles(Activity activity, QtLayout layout, int mode, int editX, int editY,
int editButtons, int x1, int y1, int x2, int y2, boolean rtl);
QtInputConnection.QtInputConnectionListener getInputConnectionListener();

View File

@ -84,7 +84,7 @@ namespace QtAndroidInput
int getSelectHandleWidth()
{
AndroidBackendRegister *reg = QtAndroid::backendRegister();
return reg->callInterface<QtJniTypes::QtInputInterface, jint>("getSelectHandleWidth");
return reg->callInterface<QtJniTypes::QtInputInterface, jint>("getSelectionHandleWidth");
}
void updateHandles(int mode, QPoint editMenuPos, uint32_t editButtons, QPoint cursor, QPoint anchor, bool rtl)