Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
CursorHandle.java
Go to the documentation of this file.
1// Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4package org.qtproject.qt.android;
5
6import android.annotation.SuppressLint;
7import android.app.Activity;
8import android.content.Context;
9import android.content.res.TypedArray;
10import android.graphics.drawable.Drawable;
11import android.util.DisplayMetrics;
12import android.util.Log;
13import android.util.TypedValue;
14import android.view.MotionEvent;
15import android.view.View;
16import android.view.ViewTreeObserver;
17import android.widget.ImageView;
18import android.widget.PopupWindow;
19
20/* This view represents one of the handle (selection or cursor handle) */
21@SuppressLint("ViewConstructor")
22class CursorView extends ImageView
23{
24 private final CursorHandle mHandle;
25 // The coordinate which where clicked
26 private float m_offsetX;
27 private float m_offsetY;
28 private boolean m_pressed = false;
29
30 CursorView (Context context, CursorHandle handle) {
31 super(context);
32 mHandle = handle;
33 }
34
35 // Called when the handle was moved programmatically , with the delta amount in pixels
36 void adjusted(int dx, int dy) {
37 m_offsetX += dx;
38 m_offsetY += dy;
39 }
40
41 @Override
42 public boolean onTouchEvent(MotionEvent ev) {
43 switch (ev.getActionMasked()) {
44 case MotionEvent.ACTION_DOWN: {
45 m_offsetX = ev.getRawX();
46 m_offsetY = ev.getRawY() + (float) getHeight() / 2;
47 m_pressed = true;
48 break;
49 }
50
51 case MotionEvent.ACTION_MOVE: {
52 if (!m_pressed)
53 return false;
54 mHandle.updatePosition(Math.round(ev.getRawX() - m_offsetX),
55 Math.round(ev.getRawY() - m_offsetY));
56 break;
57 }
58
59 case MotionEvent.ACTION_UP:
60 case MotionEvent.ACTION_CANCEL:
61 m_pressed = false;
62 break;
63 }
64 return true;
65 }
66}
67
68// Helper class that manages a cursor or selection handle
69class CursorHandle implements ViewTreeObserver.OnPreDrawListener
70{
71 private static final String QtTag = "QtCursorHandle";
72
73 // Handle IDs
74 static final int IdCursorHandle = 1;
75 static final int IdLeftHandle = 2;
76 static final int IdRightHandle = 3;
77
78 private final View m_layout;
79 private CursorView m_cursorView = null;
80 private PopupWindow m_popup = null;
81 private final int m_id;
82 private final int m_attr;
83 private final Activity m_activity;
84 private int m_posX = 0;
85 private int m_posY = 0;
86 private int m_lastX;
87 private int m_lastY;
88 int tolerance;
89 private final boolean m_rtl;
90 int m_yShift;
91
92 CursorHandle(Activity activity, View layout, int id, int attr, boolean rtl) {
93 m_activity = activity;
94 m_id = id;
95 m_attr = attr;
96 m_layout = layout;
97 DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
98 m_yShift = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1f, metrics);
99 tolerance = Math.min(1, (int)(m_yShift / 2f));
100 m_lastX = m_lastY = -1 - tolerance;
101 m_rtl = rtl;
102 }
103
104 private void initOverlay(){
105 if (m_popup != null)
106 return;
107
108 Context context = m_layout.getContext();
109 int[] attrs = {m_attr};
110 Drawable drawable;
111 TypedArray a = context.getTheme().obtainStyledAttributes(attrs);
112 try {
113 drawable = a.getDrawable(0);
114 } finally {
115 a.recycle();
116 }
117
118 m_cursorView = new CursorView(context, this);
119 m_cursorView.setImageDrawable(drawable);
120
121 m_popup = new PopupWindow(context, null, android.R.attr.textSelectHandleWindowStyle);
122 m_popup.setSplitTouchEnabled(true);
123 m_popup.setClippingEnabled(false);
124 m_popup.setContentView(m_cursorView);
125 if (drawable != null) {
126 m_popup.setWidth(drawable.getIntrinsicWidth());
127 m_popup.setHeight(drawable.getIntrinsicHeight());
128 } else {
129 Log.w(QtTag, "initOverlay(): cannot get width/height for popup " +
130 "from null drawable for attribute " + m_attr);
131 }
132
133 m_layout.getViewTreeObserver().addOnPreDrawListener(this);
134 }
135
136 // Show the handle at a given position (or move it if it is already shown)
137 void setPosition(final int x, final int y){
138 initOverlay();
139
140 final int[] layoutLocation = new int[2];
141
142 // m_layout is QtEditText. Since it doesn't match the QtWindow size, we should use its
143 // parent for cursorHandle positioning. However, there may be cases where the parent is
144 // not set. In such cases, we need to use QtEditText instead.
145 View positioningView = (View) m_layout.getParent();
146 if (positioningView == null)
147 positioningView = m_layout;
148
149 positioningView.getLocationOnScreen(layoutLocation);
150
151 // These values are used for handling split screen case
152 final int[] activityLocation = new int[2];
153 final int[] activityLocationInWindow = new int[2];
154 m_activity.getWindow().getDecorView().getLocationOnScreen(activityLocation);
155 m_activity.getWindow().getDecorView().getLocationInWindow(activityLocationInWindow);
156
157 int x2 = x + layoutLocation[0] - activityLocation[0];
158 int y2 = y + layoutLocation[1] + m_yShift + (activityLocationInWindow[1] - activityLocation[1]);
159
160 if (m_id == IdCursorHandle) {
161 x2 -= m_popup.getWidth() / 2 ;
162 } else if ((m_id == IdLeftHandle && !m_rtl) || (m_id == IdRightHandle && m_rtl)) {
163 x2 -= m_popup.getWidth() * 3 / 4;
164 } else {
165 x2 -= m_popup.getWidth() / 4;
166 }
167
168 if (m_popup.isShowing()) {
169 m_popup.update(x2, y2, -1, -1);
170 m_cursorView.adjusted(x - m_posX, y - m_posY);
171 } else {
172 m_popup.showAtLocation(positioningView, 0, x2, y2);
173 }
174
175 m_posX = x;
176 m_posY = y;
177 }
178
179 int bottom()
180 {
181 initOverlay();
182 final int[] location = new int[2];
183 m_cursorView.getLocationOnScreen(location);
184 return location[1] + m_cursorView.getHeight();
185 }
186
187 void hide() {
188 if (m_popup != null) {
189 m_popup.dismiss();
190 }
191 }
192
193 int width()
194 {
195 if (m_cursorView == null)
196 return 0;
197
198 return m_cursorView.getDrawable().getIntrinsicWidth();
199 }
200
201 // The handle was dragged by a given relative position
202 void updatePosition(int x, int y) {
203 y -= m_yShift;
204 if (Math.abs(m_lastX - x) > tolerance || Math.abs(m_lastY - y) > tolerance) {
205 QtInputDelegate.handleLocationChanged(m_id, x + m_posX, y + m_posY);
206 m_lastX = x;
207 m_lastY = y;
208 }
209 }
210
211 @Override
212 public boolean onPreDraw() {
213 // This hook is called when the view location is changed
214 // For example if the keyboard appears.
215 // Adjust the position of the handle accordingly
216 if (m_popup != null && m_popup.isShowing())
217 setPosition(m_posX, m_posY);
218
219 return true;
220 }
221}
QPainter Context
static const QString context()
Definition java.cpp:398
Q_CORE_EXPORT QtJniTypes::Activity activity()
static struct AttrInfo attrs[]
n void setPosition(void) \n\
GLenum GLuint id
GLint GLint GLint GLint GLint x
GLboolean GLboolean GLboolean GLboolean a
GLint GLint bottom
GLfloat GLfloat f
[26]
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
GLint GLsizei width
GLint location
GLint y
GLfixed GLfixed GLfixed y2
GLfixed GLfixed x2
EGLImageKHR EGLint EGLint * handle
QGraphicsGridLayout * layout
edit hide()