diff options
Diffstat (limited to 'src/ui/touch.c')
-rw-r--r-- | src/ui/touch.c | 85 |
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 | ||
56 | iLocalDef void pushPos_Touch_(iTouch *d, const iFloat3 pos, uint32_t time) { | 56 | iLocalDef 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 | ||
105 | static void dispatchClick_Touch_(const iTouch *d, int button) { | 105 | static 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 | ||
191 | static 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 | |||
190 | static void dispatchButtonUp_Touch_(iFloat3 pos) { | 202 | static 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) { |