diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-04-22 10:48:20 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-04-22 10:48:20 +0300 |
commit | c56870ab69b71887d703f51881c26ac79f4b7969 (patch) | |
tree | 9c8e70f49b15265d773c55f29056808b40963ee3 /src/ui | |
parent | 4b7c4ef2659d75ece4d63100a55c278f7c810c9e (diff) |
SmoothScroll is a UI utility; moved it
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/documentwidget.c | 117 | ||||
-rw-r--r-- | src/ui/util.c | 103 | ||||
-rw-r--r-- | src/ui/util.h | 25 |
3 files changed, 128 insertions, 117 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 635bf3e6..1298dda9 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -198,123 +198,6 @@ static void prerender_DocumentWidget_ (iAny *); | |||
198 | static void scrollBegan_DocumentWidget_ (iAnyObject *, int, uint32_t); | 198 | static void scrollBegan_DocumentWidget_ (iAnyObject *, int, uint32_t); |
199 | 199 | ||
200 | static const int smoothDuration_DocumentWidget_ = 600; /* milliseconds */ | 200 | static const int smoothDuration_DocumentWidget_ = 600; /* milliseconds */ |
201 | static const int outlineMinWidth_DocumentWdiget_ = 45; /* times gap_UI */ | ||
202 | static const int outlineMaxWidth_DocumentWidget_ = 65; /* times gap_UI */ | ||
203 | static const int outlinePadding_DocumentWidget_ = 3; /* times gap_UI */ | ||
204 | |||
205 | |||
206 | iDeclareType(SmoothScroll) | ||
207 | |||
208 | typedef void (*iSmoothScrollNotifyFunc)(iAnyObject *, int offset, uint32_t span); | ||
209 | |||
210 | struct Impl_SmoothScroll { | ||
211 | iWidget *widget; | ||
212 | iSmoothScrollNotifyFunc notify; | ||
213 | iAnim pos; | ||
214 | int max; | ||
215 | int overscroll; | ||
216 | }; | ||
217 | |||
218 | void reset_SmoothScroll(iSmoothScroll *d) { | ||
219 | init_Anim(&d->pos, 0); | ||
220 | d->max = 0; | ||
221 | d->overscroll = (deviceType_App() != desktop_AppDeviceType ? 100 * gap_UI : 0); | ||
222 | } | ||
223 | |||
224 | void init_SmoothScroll(iSmoothScroll *d, iWidget *owner, iSmoothScrollNotifyFunc notify) { | ||
225 | d->widget = owner; | ||
226 | d->notify = notify; | ||
227 | reset_SmoothScroll(d); | ||
228 | } | ||
229 | |||
230 | void setMax_SmoothScroll(iSmoothScroll *d, int max) { | ||
231 | max = iMax(0, max); | ||
232 | if (max != d->max) { | ||
233 | d->max = max; | ||
234 | if (targetValue_Anim(&d->pos) > d->max) { | ||
235 | d->pos.to = d->max; | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | |||
240 | static int overscroll_SmoothScroll_(const iSmoothScroll *d) { | ||
241 | if (d->overscroll) { | ||
242 | const int y = value_Anim(&d->pos); | ||
243 | if (y <= 0) { | ||
244 | return y; | ||
245 | } | ||
246 | if (y >= d->max) { | ||
247 | return y - d->max; | ||
248 | } | ||
249 | } | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | float pos_SmoothScroll(const iSmoothScroll *d) { | ||
254 | return value_Anim(&d->pos) - overscroll_SmoothScroll_(d) * 0.667f; | ||
255 | } | ||
256 | |||
257 | iBool isFinished_SmoothScroll(const iSmoothScroll *d) { | ||
258 | return isFinished_Anim(&d->pos); | ||
259 | } | ||
260 | |||
261 | void moveSpan_SmoothScroll(iSmoothScroll *d, int offset, uint32_t span) { | ||
262 | #if !defined (iPlatformMobile) | ||
263 | if (!prefs_App()->smoothScrolling) { | ||
264 | span = 0; /* always instant */ | ||
265 | } | ||
266 | #endif | ||
267 | int destY = targetValue_Anim(&d->pos) + offset; | ||
268 | if (destY < -d->overscroll) { | ||
269 | destY = -d->overscroll; | ||
270 | } | ||
271 | if (d->max > 0) { | ||
272 | if (destY >= d->max + d->overscroll) { | ||
273 | destY = d->max + d->overscroll; | ||
274 | } | ||
275 | } | ||
276 | else { | ||
277 | destY = 0; | ||
278 | } | ||
279 | if (span) { | ||
280 | setValueEased_Anim(&d->pos, destY, span); | ||
281 | } | ||
282 | else { | ||
283 | setValue_Anim(&d->pos, destY, 0); | ||
284 | } | ||
285 | if (d->overscroll && widgetMode_Touch(d->widget) == momentum_WidgetTouchMode) { | ||
286 | const int osDelta = overscroll_SmoothScroll_(d); | ||
287 | if (osDelta) { | ||
288 | const float remaining = stopWidgetMomentum_Touch(d->widget); | ||
289 | span = iMini(1000, 50 * sqrt(remaining / gap_UI)); | ||
290 | setValue_Anim(&d->pos, osDelta < 0 ? 0 : d->max, span); | ||
291 | d->pos.flags = bounce_AnimFlag | easeOut_AnimFlag | softer_AnimFlag; | ||
292 | // printf("remaining: %f dur: %d\n", remaining, duration); | ||
293 | d->pos.bounce = (osDelta < 0 ? -1 : 1) * | ||
294 | iMini(5 * d->overscroll, remaining * remaining * 0.00005f); | ||
295 | } | ||
296 | } | ||
297 | if (d->notify) { | ||
298 | d->notify(d->widget, offset, span); | ||
299 | } | ||
300 | } | ||
301 | |||
302 | void move_SmoothScroll(iSmoothScroll *d, int offset) { | ||
303 | moveSpan_SmoothScroll(d, offset, 0 /* instantly */); | ||
304 | } | ||
305 | |||
306 | iBool processEvent_SmoothScroll(iSmoothScroll *d, const SDL_Event *ev) { | ||
307 | if (ev->type == SDL_USEREVENT && ev->user.code == widgetTouchEnds_UserEventCode) { | ||
308 | const int osDelta = overscroll_SmoothScroll_(d); | ||
309 | if (osDelta) { | ||
310 | moveSpan_SmoothScroll(d, -osDelta, 100 * sqrt(iAbs(osDelta) / gap_UI)); | ||
311 | d->pos.flags = easeOut_AnimFlag | muchSofter_AnimFlag; | ||
312 | } | ||
313 | return iTrue; | ||
314 | } | ||
315 | return iFalse; | ||
316 | } | ||
317 | |||
318 | 201 | ||
319 | enum iRequestState { | 202 | enum iRequestState { |
320 | blank_RequestState, | 203 | blank_RequestState, |
diff --git a/src/ui/util.c b/src/ui/util.c index 877ec7c1..8d1430f8 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -36,6 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
36 | #include "keys.h" | 36 | #include "keys.h" |
37 | #include "widget.h" | 37 | #include "widget.h" |
38 | #include "text.h" | 38 | #include "text.h" |
39 | #include "touch.h" | ||
39 | #include "window.h" | 40 | #include "window.h" |
40 | 41 | ||
41 | #if defined (iPlatformAppleMobile) | 42 | #if defined (iPlatformAppleMobile) |
@@ -444,6 +445,108 @@ iInt2 delta_Click(const iClick *d) { | |||
444 | return sub_I2(d->pos, d->startPos); | 445 | return sub_I2(d->pos, d->startPos); |
445 | } | 446 | } |
446 | 447 | ||
448 | /*----------------------------------------------------------------------------------------------*/ | ||
449 | |||
450 | void init_SmoothScroll(iSmoothScroll *d, iWidget *owner, iSmoothScrollNotifyFunc notify) { | ||
451 | reset_SmoothScroll(d); | ||
452 | d->widget = owner; | ||
453 | d->notify = notify; | ||
454 | } | ||
455 | |||
456 | void reset_SmoothScroll(iSmoothScroll *d) { | ||
457 | init_Anim(&d->pos, 0); | ||
458 | d->max = 0; | ||
459 | d->overscroll = (deviceType_App() != desktop_AppDeviceType ? 100 * gap_UI : 0); | ||
460 | } | ||
461 | |||
462 | void setMax_SmoothScroll(iSmoothScroll *d, int max) { | ||
463 | max = iMax(0, max); | ||
464 | if (max != d->max) { | ||
465 | d->max = max; | ||
466 | if (targetValue_Anim(&d->pos) > d->max) { | ||
467 | d->pos.to = d->max; | ||
468 | } | ||
469 | } | ||
470 | } | ||
471 | |||
472 | static int overscroll_SmoothScroll_(const iSmoothScroll *d) { | ||
473 | if (d->overscroll) { | ||
474 | const int y = value_Anim(&d->pos); | ||
475 | if (y <= 0) { | ||
476 | return y; | ||
477 | } | ||
478 | if (y >= d->max) { | ||
479 | return y - d->max; | ||
480 | } | ||
481 | } | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | float pos_SmoothScroll(const iSmoothScroll *d) { | ||
486 | return value_Anim(&d->pos) - overscroll_SmoothScroll_(d) * 0.667f; | ||
487 | } | ||
488 | |||
489 | iBool isFinished_SmoothScroll(const iSmoothScroll *d) { | ||
490 | return isFinished_Anim(&d->pos); | ||
491 | } | ||
492 | |||
493 | void moveSpan_SmoothScroll(iSmoothScroll *d, int offset, uint32_t span) { | ||
494 | #if !defined (iPlatformMobile) | ||
495 | if (!prefs_App()->smoothScrolling) { | ||
496 | span = 0; /* always instant */ | ||
497 | } | ||
498 | #endif | ||
499 | int destY = targetValue_Anim(&d->pos) + offset; | ||
500 | if (destY < -d->overscroll) { | ||
501 | destY = -d->overscroll; | ||
502 | } | ||
503 | if (d->max > 0) { | ||
504 | if (destY >= d->max + d->overscroll) { | ||
505 | destY = d->max + d->overscroll; | ||
506 | } | ||
507 | } | ||
508 | else { | ||
509 | destY = 0; | ||
510 | } | ||
511 | if (span) { | ||
512 | setValueEased_Anim(&d->pos, destY, span); | ||
513 | } | ||
514 | else { | ||
515 | setValue_Anim(&d->pos, destY, 0); | ||
516 | } | ||
517 | if (d->overscroll && widgetMode_Touch(d->widget) == momentum_WidgetTouchMode) { | ||
518 | const int osDelta = overscroll_SmoothScroll_(d); | ||
519 | if (osDelta) { | ||
520 | const float remaining = stopWidgetMomentum_Touch(d->widget); | ||
521 | span = iMini(1000, 50 * sqrt(remaining / gap_UI)); | ||
522 | setValue_Anim(&d->pos, osDelta < 0 ? 0 : d->max, span); | ||
523 | d->pos.flags = bounce_AnimFlag | easeOut_AnimFlag | softer_AnimFlag; | ||
524 | // printf("remaining: %f dur: %d\n", remaining, duration); | ||
525 | d->pos.bounce = (osDelta < 0 ? -1 : 1) * | ||
526 | iMini(5 * d->overscroll, remaining * remaining * 0.00005f); | ||
527 | } | ||
528 | } | ||
529 | if (d->notify) { | ||
530 | d->notify(d->widget, offset, span); | ||
531 | } | ||
532 | } | ||
533 | |||
534 | void move_SmoothScroll(iSmoothScroll *d, int offset) { | ||
535 | moveSpan_SmoothScroll(d, offset, 0 /* instantly */); | ||
536 | } | ||
537 | |||
538 | iBool processEvent_SmoothScroll(iSmoothScroll *d, const SDL_Event *ev) { | ||
539 | if (ev->type == SDL_USEREVENT && ev->user.code == widgetTouchEnds_UserEventCode) { | ||
540 | const int osDelta = overscroll_SmoothScroll_(d); | ||
541 | if (osDelta) { | ||
542 | moveSpan_SmoothScroll(d, -osDelta, 100 * sqrt(iAbs(osDelta) / gap_UI)); | ||
543 | d->pos.flags = easeOut_AnimFlag | muchSofter_AnimFlag; | ||
544 | } | ||
545 | return iTrue; | ||
546 | } | ||
547 | return iFalse; | ||
548 | } | ||
549 | |||
447 | /*-----------------------------------------------------------------------------------------------*/ | 550 | /*-----------------------------------------------------------------------------------------------*/ |
448 | 551 | ||
449 | iWidget *makePadding_Widget(int size) { | 552 | iWidget *makePadding_Widget(int size) { |
diff --git a/src/ui/util.h b/src/ui/util.h index 191b8a87..223982a8 100644 --- a/src/ui/util.h +++ b/src/ui/util.h | |||
@@ -163,6 +163,31 @@ iInt2 delta_Click (const iClick *); | |||
163 | 163 | ||
164 | /*-----------------------------------------------------------------------------------------------*/ | 164 | /*-----------------------------------------------------------------------------------------------*/ |
165 | 165 | ||
166 | iDeclareType(SmoothScroll) | ||
167 | |||
168 | typedef void (*iSmoothScrollNotifyFunc)(iAnyObject *, int offset, uint32_t span); | ||
169 | |||
170 | struct Impl_SmoothScroll { | ||
171 | iAnim pos; | ||
172 | int max; | ||
173 | int overscroll; | ||
174 | iWidget *widget; | ||
175 | iSmoothScrollNotifyFunc notify; | ||
176 | }; | ||
177 | |||
178 | void init_SmoothScroll (iSmoothScroll *, iWidget *owner, iSmoothScrollNotifyFunc notify); | ||
179 | |||
180 | void reset_SmoothScroll (iSmoothScroll *); | ||
181 | void setMax_SmoothScroll (iSmoothScroll *, int max); | ||
182 | void move_SmoothScroll (iSmoothScroll *, int offset); | ||
183 | void moveSpan_SmoothScroll (iSmoothScroll *, int offset, uint32_t span); | ||
184 | iBool processEvent_SmoothScroll (iSmoothScroll *, const SDL_Event *ev); | ||
185 | |||
186 | float pos_SmoothScroll (const iSmoothScroll *); | ||
187 | iBool isFinished_SmoothScroll (const iSmoothScroll *); | ||
188 | |||
189 | /*-----------------------------------------------------------------------------------------------*/ | ||
190 | |||
166 | iWidget * makePadding_Widget (int size); | 191 | iWidget * makePadding_Widget (int size); |
167 | iLabelWidget * makeHeading_Widget (const char *text); | 192 | iLabelWidget * makeHeading_Widget (const char *text); |
168 | iWidget * makeHDiv_Widget (void); | 193 | iWidget * makeHDiv_Widget (void); |