summaryrefslogtreecommitdiff
path: root/src/ui/touch.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/touch.c')
-rw-r--r--src/ui/touch.c85
1 files changed, 40 insertions, 45 deletions
diff --git a/src/ui/touch.c b/src/ui/touch.c
index d7d2bca1..8c39793e 100644
--- a/src/ui/touch.c
+++ b/src/ui/touch.c
@@ -50,7 +50,7 @@ struct Impl_Touch {
50 iFloat3 startPos; 50 iFloat3 startPos;
51 uint32_t posTime[numHistory_Touch_]; 51 uint32_t posTime[numHistory_Touch_];
52 iFloat3 pos[numHistory_Touch_]; 52 iFloat3 pos[numHistory_Touch_];
53 iFloat3 remainder; 53 iFloat3 accum;
54}; 54};
55 55
56iLocalDef void pushPos_Touch_(iTouch *d, const iFloat3 pos, uint32_t time) { 56iLocalDef void pushPos_Touch_(iTouch *d, const iFloat3 pos, uint32_t time) {
@@ -103,7 +103,7 @@ static iBool isStationary_Touch_(const iTouch *d) {
103} 103}
104 104
105static void dispatchClick_Touch_(const iTouch *d, int button) { 105static void dispatchClick_Touch_(const iTouch *d, int button) {
106 const iFloat3 tapPos = d->pos[0]; //divf_F3(add_F3(d->pos[0], d->startPos), 2); 106 const iFloat3 tapPos = d->pos[0];
107 SDL_MouseButtonEvent btn = { 107 SDL_MouseButtonEvent btn = {
108 .type = SDL_MOUSEBUTTONDOWN, 108 .type = SDL_MOUSEBUTTONDOWN,
109 .button = button, 109 .button = button,
@@ -151,13 +151,14 @@ static void update_TouchState_(void *ptr) {
151 } 151 }
152 /* Update/cancel momentum scrolling. */ { 152 /* Update/cancel momentum scrolling. */ {
153 const float minSpeed = 15.0f; 153 const float minSpeed = 15.0f;
154 const float momFriction = 0.98f; /* per step */ 154 const float momFriction = 0.985f; /* per step */
155 const float stepDurationMs = 1000.0f / 120.0f; 155 const float stepDurationMs = 1000.0f / 120.0f;
156 double momAvailMs = nowTime - d->lastMomTime; 156 double momAvailMs = nowTime - d->lastMomTime;
157 int numSteps = (int) (momAvailMs / stepDurationMs); 157 int numSteps = (int) (momAvailMs / stepDurationMs);
158 d->lastMomTime += numSteps * stepDurationMs; 158 d->lastMomTime += numSteps * stepDurationMs;
159 numSteps = iMin(numSteps, 10); /* don't spend too much time here */ 159 numSteps = iMin(numSteps, 10); /* don't spend too much time here */
160// printf("mom steps:%d\n", numSteps); 160// printf("mom steps:%d\n", numSteps);
161 iWindow *window = get_Window();
161 iForEach(Array, m, d->moms) { 162 iForEach(Array, m, d->moms) {
162 if (numSteps == 0) break; 163 if (numSteps == 0) break;
163 iMomentum *mom = m.value; 164 iMomentum *mom = m.value;
@@ -165,15 +166,15 @@ static void update_TouchState_(void *ptr) {
165 mulvf_F3(&mom->velocity, momFriction); 166 mulvf_F3(&mom->velocity, momFriction);
166 addv_F3(&mom->accum, mulf_F3(mom->velocity, stepDurationMs / 1000.0f)); 167 addv_F3(&mom->accum, mulf_F3(mom->velocity, stepDurationMs / 1000.0f));
167 } 168 }
168 const iInt2 pixels = initF3_I2(mom->accum); 169 const iInt2 points = initF3_I2(mom->accum);
169 if (pixels.x || pixels.y) { 170 if (points.x || points.y) {
170 subv_F3(&mom->accum, initI2_F3(pixels)); 171 subv_F3(&mom->accum, initI2_F3(points));
171 dispatchEvent_Widget(mom->affinity, (SDL_Event *) &(SDL_MouseWheelEvent){ 172 dispatchEvent_Widget(mom->affinity, (SDL_Event *) &(SDL_MouseWheelEvent){
172 .type = SDL_MOUSEWHEEL, 173 .type = SDL_MOUSEWHEEL,
173 .timestamp = nowTime, 174 .timestamp = nowTime,
174 .which = 0, /* means "precise scrolling" in DocumentWidget */ 175 .which = 0, /* means "precise scrolling" in DocumentWidget */
175 .x = pixels.x, 176 .x = points.x,
176 .y = pixels.y 177 .y = points.y
177 }); 178 });
178 } 179 }
179 if (length_F3(mom->velocity) < minSpeed) { 180 if (length_F3(mom->velocity) < minSpeed) {
@@ -187,6 +188,17 @@ static void update_TouchState_(void *ptr) {
187 } 188 }
188} 189}
189 190
191static void dispatchMotion_Touch_(iFloat3 pos, int buttonState) {
192 dispatchEvent_Widget(get_Window()->root, (SDL_Event *) &(SDL_MouseMotionEvent){
193 .type = SDL_MOUSEMOTION,
194 .timestamp = SDL_GetTicks(),
195 .which = SDL_TOUCH_MOUSEID,
196 .state = buttonState,
197 .x = x_F3(pos),
198 .y = y_F3(pos)
199 });
200}
201
190static void dispatchButtonUp_Touch_(iFloat3 pos) { 202static void dispatchButtonUp_Touch_(iFloat3 pos) {
191 dispatchEvent_Widget(get_Window()->root, (SDL_Event *) &(SDL_MouseButtonEvent){ 203 dispatchEvent_Widget(get_Window()->root, (SDL_Event *) &(SDL_MouseButtonEvent){
192 .type = SDL_MOUSEBUTTONUP, 204 .type = SDL_MOUSEBUTTONUP,
@@ -206,12 +218,10 @@ iBool processEvent_Touch(const SDL_Event *ev) {
206 return iFalse; 218 return iFalse;
207 } 219 }
208 iTouchState *d = touchState_(); 220 iTouchState *d = touchState_();
209 const SDL_TouchFingerEvent *fing = &ev->tfinger;
210 iWindow *window = get_Window(); 221 iWindow *window = get_Window();
211 const iInt2 rootSize = rootSize_Window(window); 222 const iInt2 rootSize = rootSize_Window(window);
212 const iFloat3 pos = init_F3(fing->x * rootSize.x, fing->y * rootSize.y, 0); 223 const SDL_TouchFingerEvent *fing = &ev->tfinger;
213 //printf("%2d: %f: touch %f, %f\n", ev->type, z_F3(pos), x_F3(pos), y_F3(pos)); 224 const iFloat3 pos = init_F3(fing->x * rootSize.x, fing->y * rootSize.y, 0); /* pixels */
214 //fflush(stdout);
215 const uint32_t nowTime = SDL_GetTicks(); 225 const uint32_t nowTime = SDL_GetTicks();
216 if (ev->type == SDL_FINGERDOWN) { 226 if (ev->type == SDL_FINGERDOWN) {
217 /* Register the new touch. */ 227 /* Register the new touch. */
@@ -225,6 +235,9 @@ iBool processEvent_Touch(const SDL_Event *ev) {
225 edge = right_TouchEdge; 235 edge = right_TouchEdge;
226 } 236 }
227 iWidget *aff = hitChild_Widget(window->root, init_I2(iRound(x), iRound(y_F3(pos)))); 237 iWidget *aff = hitChild_Widget(window->root, init_I2(iRound(x), iRound(y_F3(pos))));
238 /* TODO: We must retain a reference to the affinity widget, or otherwise it might
239 be destroyed during the gesture. */
240// printf("aff:%p (%s)\n", aff, aff ? class_Widget(aff)->name : "-");
228 if (flags_Widget(aff) & touchDrag_WidgetFlag) { 241 if (flags_Widget(aff) & touchDrag_WidgetFlag) {
229 dispatchEvent_Widget(window->root, (SDL_Event *) &(SDL_MouseButtonEvent){ 242 dispatchEvent_Widget(window->root, (SDL_Event *) &(SDL_MouseButtonEvent){
230 .type = SDL_MOUSEBUTTONDOWN, 243 .type = SDL_MOUSEBUTTONDOWN,
@@ -248,46 +261,24 @@ iBool processEvent_Touch(const SDL_Event *ev) {
248 .pos = pos 261 .pos = pos
249 }); 262 });
250 /* Some widgets rely on hover state. */ 263 /* Some widgets rely on hover state. */
251 dispatchEvent_Widget(window->root, (SDL_Event *) &(SDL_MouseMotionEvent){ 264 dispatchMotion_Touch_(pos, 0);
252 .type = SDL_MOUSEMOTION,
253 .timestamp = fing->timestamp,
254 .which = SDL_TOUCH_MOUSEID,
255 .x = x_F3(pos),
256 .y = y_F3(pos)
257 });
258 addTicker_App(update_TouchState_, d); 265 addTicker_App(update_TouchState_, d);
259 } 266 }
260 else if (ev->type == SDL_FINGERMOTION) { 267 else if (ev->type == SDL_FINGERMOTION) {
261 iTouch *touch = find_TouchState_(d, fing->fingerId); 268 iTouch *touch = find_TouchState_(d, fing->fingerId);
262 if (touch && touch->affinity) { 269 if (touch && touch->affinity) {
263 if (flags_Widget(touch->affinity) & touchDrag_WidgetFlag) { 270 if (flags_Widget(touch->affinity) & touchDrag_WidgetFlag) {
264 dispatchEvent_Widget(window->root, (SDL_Event *) &(SDL_MouseMotionEvent){ 271 dispatchMotion_Touch_(pos, SDL_BUTTON_LMASK);
265 .type = SDL_MOUSEMOTION,
266 .timestamp = fing->timestamp,
267 .which = SDL_TOUCH_MOUSEID,
268 .state = SDL_BUTTON_LMASK,
269 .x = x_F3(pos),
270 .y = y_F3(pos)
271 });
272 return iTrue; 272 return iTrue;
273 } 273 }
274 /*dispatchEvent_Widget(window->root, (SDL_Event *) &(SDL_MouseMotionEvent){
275 .type = SDL_MOUSEMOTION,
276 .timestamp = fing->timestamp,
277 .which = SDL_TOUCH_MOUSEID,
278 .x = x_F3(pos),
279 .y = y_F3(pos)
280 });*/
281 /* Update touch position. */ 274 /* Update touch position. */
282 pushPos_Touch_(touch, pos, nowTime); 275 pushPos_Touch_(touch, pos, nowTime);
283 const iFloat3 amount = add_F3(touch->remainder, 276 const iFloat3 amount = mul_F3(init_F3(fing->dx, fing->dy, 0),
284 divf_F3(mul_F3(init_F3(fing->dx, fing->dy, 0), 277 init_F3(rootSize.x, rootSize.y, 0));
285 init_F3(rootSize.x, rootSize.y, 0)), 278 addv_F3(&touch->accum, amount);
286 window->pixelRatio)); 279 iInt2 pixels = initF3_I2(touch->accum);
287 iInt2 pixels = init_I2(iRound(x_F3(amount)), iRound(y_F3(amount)));
288 /* We're reporting scrolling as full points, so keep track of the precise distance. */ 280 /* We're reporting scrolling as full points, so keep track of the precise distance. */
289 iFloat3 remainder = sub_F3(amount, initI2_F3(pixels)); 281 subv_F3(&touch->accum, initI2_F3(pixels));
290 touch->remainder = remainder;
291 if (!touch->hasMoved && !isStationary_Touch_(touch)) { 282 if (!touch->hasMoved && !isStationary_Touch_(touch)) {
292 touch->hasMoved = iTrue; 283 touch->hasMoved = iTrue;
293 } 284 }
@@ -301,15 +292,17 @@ iBool processEvent_Touch(const SDL_Event *ev) {
301 if (touch->edge) { 292 if (touch->edge) {
302 pixels.y = 0; 293 pixels.y = 0;
303 } 294 }
295// printf("%p (%s) py: %i wy: %f acc: %f\n",
296// touch->affinity,
297// class_Widget(touch->affinity)->name,
298// pixels.y, y_F3(amount), y_F3(touch->accum));
304 if (pixels.x || pixels.y) { 299 if (pixels.x || pixels.y) {
305// printf("%p (%s) wy: %f\n", touch->affinity, class_Widget(touch->affinity)->name,
306// fing->dy * rootSize.y / window->pixelRatio);
307 dispatchEvent_Widget(touch->affinity, (SDL_Event *) &(SDL_MouseWheelEvent){ 300 dispatchEvent_Widget(touch->affinity, (SDL_Event *) &(SDL_MouseWheelEvent){
308 .type = SDL_MOUSEWHEEL, 301 .type = SDL_MOUSEWHEEL,
309 .timestamp = SDL_GetTicks(), 302 .timestamp = SDL_GetTicks(),
310 .which = 0, /* means "precise scrolling" in DocumentWidget */ 303 .which = 0, /* means "precise scrolling" in DocumentWidget */
311 .x = pixels.x, 304 .x = pixels.x,
312 .y = pixels.y 305 .y = pixels.y,
313 }); 306 });
314 /* TODO: Keep increasing movement if the direction is the same. */ 307 /* TODO: Keep increasing movement if the direction is the same. */
315 clearWidgetMomentum_TouchState_(d, touch->affinity); 308 clearWidgetMomentum_TouchState_(d, touch->affinity);
@@ -340,7 +333,7 @@ iBool processEvent_Touch(const SDL_Event *ev) {
340 else { 333 else {
341 const uint32_t elapsed = fing->timestamp - touch->posTime[lastIndex_Touch_]; 334 const uint32_t elapsed = fing->timestamp - touch->posTime[lastIndex_Touch_];
342 const float minVelocity = 400.0f; 335 const float minVelocity = 400.0f;
343 if (elapsed < 40) { 336 if (elapsed < 75) {
344 velocity = divf_F3(sub_F3(pos, touch->pos[lastIndex_Touch_]), 337 velocity = divf_F3(sub_F3(pos, touch->pos[lastIndex_Touch_]),
345 (float) elapsed / 1000.0f); 338 (float) elapsed / 1000.0f);
346 if (fabsf(x_F3(velocity)) < minVelocity) { 339 if (fabsf(x_F3(velocity)) < minVelocity) {
@@ -350,9 +343,11 @@ iBool processEvent_Touch(const SDL_Event *ev) {
350 setY_F3(&velocity, 0.0f); 343 setY_F3(&velocity, 0.0f);
351 } 344 }
352 } 345 }
346// printf("elap:%ums vel:%f\n", elapsed, length_F3(velocity));
353 pushPos_Touch_(touch, pos, nowTime); 347 pushPos_Touch_(touch, pos, nowTime);
354 /* If short and didn't move far, do a tap (left click). */ 348 /* If short and didn't move far, do a tap (left click). */
355 if (duration < longPressSpanMs_ && isStationary_Touch_(touch)) { 349 if (duration < longPressSpanMs_ && isStationary_Touch_(touch)) {
350 dispatchMotion_Touch_(pos, SDL_BUTTON_LMASK);
356 dispatchClick_Touch_(touch, SDL_BUTTON_LEFT); 351 dispatchClick_Touch_(touch, SDL_BUTTON_LEFT);
357 } 352 }
358 else if (length_F3(velocity) > 0.0f) { 353 else if (length_F3(velocity) > 0.0f) {