Android: Fix positioning of text editor context menu

The old code in QtActivityDelegate.updateHandles() and
EditPopupMenu.setPosition() could use size of EditPopupMenu.m_view to
calculate position of context menu before that size was calculated
during an asynchronous layout pass. In particular m_view reports size
0x0 when context menu is opened for the first time after start of the
application. In this case the context menu was displayed on top of the
text editor instead of being displayed above it.

This patch fixes that problem by moving all positioning code from
QtActivityDelegate.updateHandles() to EditPopupMenu.setPosition() and
adding an OnLayoutChangeListener which calls setPosition() again each
time the size of m_view changes, including when it changes for the first
time from 0x0 to a real value.

Change-Id: I670fef811a4dcba5524f7520ea41a47978dd10f1
Reviewed-by: BogDan Vatra <bogdan@kdab.com>
This commit is contained in:
Vova Mshanetskiy 2019-04-25 20:34:13 +03:00
parent a04629d9c2
commit 5f4b03659b
2 changed files with 32 additions and 18 deletions

View File

@ -59,7 +59,8 @@ import android.view.ViewGroup;
import android.R; import android.R;
// Helper class that manages a cursor or selection handle // Helper class that manages a cursor or selection handle
public class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, EditContextView.OnClickListener public class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayoutChangeListener,
EditContextView.OnClickListener
{ {
private View m_layout = null; private View m_layout = null;
private EditContextView m_view = null; private EditContextView m_view = null;
@ -67,10 +68,15 @@ public class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, EditCo
private int m_posX; private int m_posX;
private int m_posY; private int m_posY;
private int m_buttons; private int m_buttons;
private CursorHandle m_cursorHandle;
private CursorHandle m_leftSelectionHandle;
private CursorHandle m_rightSelectionHandle;
public EditPopupMenu(Activity activity, View layout) public EditPopupMenu(Activity activity, View layout)
{ {
m_view = new EditContextView(activity, this); m_view = new EditContextView(activity, this);
m_view.addOnLayoutChangeListener(this);
m_layout = layout; m_layout = layout;
} }
@ -90,13 +96,9 @@ public class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, EditCo
m_layout.getViewTreeObserver().addOnPreDrawListener(this); m_layout.getViewTreeObserver().addOnPreDrawListener(this);
} }
public int getHeight()
{
return m_view.getHeight();
}
// Show the handle at a given position (or move it if it is already shown) // Show the handle at a given position (or move it if it is already shown)
public void setPosition(final int x, final int y, final int buttons) public void setPosition(final int x, final int y, final int buttons,
CursorHandle cursorHandle, CursorHandle leftSelectionHandle, CursorHandle rightSelectionHandle)
{ {
initOverlay(); initOverlay();
@ -109,6 +111,14 @@ public class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, EditCo
x2 -= m_view.getWidth() / 2 ; x2 -= m_view.getWidth() / 2 ;
y2 -= m_view.getHeight();
if (y2 < 0) {
if (cursorHandle != null)
y2 = cursorHandle.bottom();
else if (leftSelectionHandle != null && rightSelectionHandle != null)
y2 = Math.max(leftSelectionHandle.bottom(), rightSelectionHandle.bottom());
}
if (m_layout.getWidth() < x + m_view.getWidth() / 2) if (m_layout.getWidth() < x + m_view.getWidth() / 2)
x2 = m_layout.getWidth() - m_view.getWidth(); x2 = m_layout.getWidth() - m_view.getWidth();
@ -123,6 +133,9 @@ public class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, EditCo
m_posX = x; m_posX = x;
m_posY = y; m_posY = y;
m_buttons = buttons; m_buttons = buttons;
m_cursorHandle = cursorHandle;
m_leftSelectionHandle = leftSelectionHandle;
m_rightSelectionHandle = rightSelectionHandle;
} }
public void hide() { public void hide() {
@ -138,11 +151,20 @@ public class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, EditCo
// For example if the keyboard appears. // For example if the keyboard appears.
// Adjust the position of the handle accordingly // Adjust the position of the handle accordingly
if (m_popup != null && m_popup.isShowing()) if (m_popup != null && m_popup.isShowing())
setPosition(m_posX, m_posY, m_buttons); setPosition(m_posX, m_posY, m_buttons, m_cursorHandle, m_leftSelectionHandle, m_rightSelectionHandle);
return true; return true;
} }
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom)
{
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);
}
@Override @Override
public void contextButtonClicked(int buttonId) { public void contextButtonClicked(int buttonId) {
switch (buttonId) { switch (buttonId) {

View File

@ -553,16 +553,8 @@ public class QtActivityDelegate
editButtons &= ~EditContextView.PASTE_BUTTON; editButtons &= ~EditContextView.PASTE_BUTTON;
if ((mode & CursorHandleShowEdit) == CursorHandleShowEdit && editButtons != 0) { if ((mode & CursorHandleShowEdit) == CursorHandleShowEdit && editButtons != 0) {
editY -= m_editPopupMenu.getHeight(); m_editPopupMenu.setPosition(editX, editY, editButtons, m_cursorHandle, m_leftSelectionHandle,
if (editY < 0) { m_rightSelectionHandle);
if (m_cursorHandle != null)
editY = m_cursorHandle.bottom();
else if (m_leftSelectionHandle != null && m_rightSelectionHandle != null)
editY = Math.max(m_leftSelectionHandle.bottom(), m_rightSelectionHandle.bottom());
else
return;
}
m_editPopupMenu.setPosition(editX, editY, editButtons);
} else { } else {
if (m_editPopupMenu != null) if (m_editPopupMenu != null)
m_editPopupMenu.hide(); m_editPopupMenu.hide();