Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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 public 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 private final View m_layout;
73 private CursorView m_cursorView = null;
74 private PopupWindow m_popup = null;
75 private final int m_id;
76 private final int m_attr;
77 private final Activity m_activity;
78 private int m_posX = 0;
79 private int m_posY = 0;
80 private int m_lastX;
81 private int m_lastY;
82 int tolerance;
83 private final boolean m_rtl;
84 int m_yShift;
85
86 public CursorHandle(Activity activity, View layout, int id, int attr, boolean rtl) {
87 m_activity = activity;
88 m_id = id;
89 m_attr = attr;
90 m_layout = layout;
91 DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
92 m_yShift = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1f, metrics);
93 tolerance = Math.min(1, (int)(m_yShift / 2f));
94 m_lastX = m_lastY = -1 - tolerance;
95 m_rtl = rtl;
96 }
97
98 private void initOverlay(){
99 if (m_popup != null)
100 return;
101
102 Context context = m_layout.getContext();
103 int[] attrs = {m_attr};
104 TypedArray a = context.getTheme().obtainStyledAttributes(attrs);
105 Drawable drawable = a.getDrawable(0);
106
107 m_cursorView = new CursorView(context, this);
108 m_cursorView.setImageDrawable(drawable);
109
110 m_popup = new PopupWindow(context, null, android.R.attr.textSelectHandleWindowStyle);
111 m_popup.setSplitTouchEnabled(true);
112 m_popup.setClippingEnabled(false);
113 m_popup.setContentView(m_cursorView);
114 if (drawable != null) {
115 m_popup.setWidth(drawable.getIntrinsicWidth());
116 m_popup.setHeight(drawable.getIntrinsicHeight());
117 } else {
118 Log.w(QtTag, "initOverlay(): cannot get width/height for popup " +
119 "from null drawable for attribute " + m_attr);
120 }
121
122 m_layout.getViewTreeObserver().addOnPreDrawListener(this);
123 }
124
125 // Show the handle at a given position (or move it if it is already shown)
126 public void setPosition(final int x, final int y){
127 initOverlay();
128
129 final int[] layoutLocation = new int[2];
130 m_layout.getLocationOnScreen(layoutLocation);
131
132 // These values are used for handling split screen case
133 final int[] activityLocation = new int[2];
134 final int[] activityLocationInWindow = new int[2];
135 m_activity.getWindow().getDecorView().getLocationOnScreen(activityLocation);
136 m_activity.getWindow().getDecorView().getLocationInWindow(activityLocationInWindow);
137
138 int x2 = x + layoutLocation[0] - activityLocation[0];
139 int y2 = y + layoutLocation[1] + m_yShift + (activityLocationInWindow[1] - activityLocation[1]);
140
141 if (m_id == QtInputDelegate.IdCursorHandle) {
142 x2 -= m_popup.getWidth() / 2 ;
143 } else if ((m_id == QtInputDelegate.IdLeftHandle && !m_rtl) || (m_id == QtInputDelegate.IdRightHandle && m_rtl)) {
144 x2 -= m_popup.getWidth() * 3 / 4;
145 } else {
146 x2 -= m_popup.getWidth() / 4;
147 }
148
149 if (m_popup.isShowing()) {
150 m_popup.update(x2, y2, -1, -1);
151 m_cursorView.adjusted(x - m_posX, y - m_posY);
152 } else {
153 m_popup.showAtLocation(m_layout, 0, x2, y2);
154 }
155
156 m_posX = x;
157 m_posY = y;
158 }
159
160 public int bottom()
161 {
162 initOverlay();
163 final int[] location = new int[2];
164 m_cursorView.getLocationOnScreen(location);
165 return location[1] + m_cursorView.getHeight();
166 }
167
168 public void hide() {
169 if (m_popup != null) {
170 m_popup.dismiss();
171 }
172 }
173
174 public int width()
175 {
176 return m_cursorView.getDrawable().getIntrinsicWidth();
177 }
178
179 // The handle was dragged by a given relative position
180 public void updatePosition(int x, int y) {
181 y -= m_yShift;
182 if (Math.abs(m_lastX - x) > tolerance || Math.abs(m_lastY - y) > tolerance) {
183 QtInputDelegate.handleLocationChanged(m_id, x + m_posX, y + m_posY);
184 m_lastX = x;
185 m_lastY = y;
186 }
187 }
188
189 @Override
190 public boolean onPreDraw() {
191 // This hook is called when the view location is changed
192 // For example if the keyboard appears.
193 // Adjust the position of the handle accordingly
194 if (m_popup != null && m_popup.isShowing())
195 setPosition(m_posX, m_posY);
196
197 return true;
198 }
199}
static void * context
static struct AttrInfo attrs[]
n void setPosition(void) \n\
GLint location
GLuint64 GLenum void * handle
GLint GLint GLint GLint GLint x
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint id
[7]
GLfloat GLfloat f
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
GLint GLsizei width
GLint GLint bottom
GLint y
GLfixed GLfixed GLfixed y2
GLfixed GLfixed x2
QVBoxLayout * layout