-
-
Notifications
You must be signed in to change notification settings - Fork 197
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP/POC] Libscroll Integration #766
base: master
Are you sure you want to change the base?
Changes from 8 commits
32d3a8c
9b80ce6
fef8273
81223fe
d538a89
110bd8f
d349008
52c120e
9e15386
f5451c1
06c7a9d
a1bbd2e
2a12b58
7acd3f1
8863d53
b03b8a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -5,6 +5,8 @@ open Revery_UI_Primitives; | |||||||||||||||
|
||||||||||||||||
module Hooks = Revery_UI_Hooks; | ||||||||||||||||
|
||||||||||||||||
module Log = (val Log.withNamespace("Revery.ScrollView")); | ||||||||||||||||
|
||||||||||||||||
type bouncingState = | ||||||||||||||||
| Bouncing(int) | ||||||||||||||||
| Idle; | ||||||||||||||||
|
@@ -57,6 +59,19 @@ let%component make = | |||||||||||||||
let%hook (actualScrollLeft, setScrollLeft) = Hooks.state(scrollLeft); | ||||||||||||||||
let%hook (bouncingState, setBouncingState) = Hooks.state(Idle); | ||||||||||||||||
|
||||||||||||||||
//let%hook (scrollview, setScrollview) = Hooks.state(() => Libscroll.scrollview_new()); | ||||||||||||||||
//setScrollview(_ => scrollview); | ||||||||||||||||
let%hook (scrollViewRef) = Hooks.ref(None); | ||||||||||||||||
let%hook () = Hooks.effect(OnMount, () => { | ||||||||||||||||
let scrollView = Libscroll.scrollview_new(); | ||||||||||||||||
scrollViewRef := Some(scrollView); | ||||||||||||||||
|
||||||||||||||||
let dispose = () => { | ||||||||||||||||
scrollViewRef := None; | ||||||||||||||||
}; | ||||||||||||||||
Some(dispose); | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
let%hook (actualScrollTop, _bounceAnimationState, resetBouncingAnimation) = | ||||||||||||||||
switch (bouncingState) { | ||||||||||||||||
| Idle => | ||||||||||||||||
|
@@ -154,25 +169,80 @@ let%component make = | |||||||||||||||
thumbColor=scrollThumbColor | ||||||||||||||||
/> | ||||||||||||||||
: empty; | ||||||||||||||||
|
||||||||||||||||
/*let pan = (panEvent: NodeEvents.panEventParams) => { | ||||||||||||||||
switch (scrollViewRef^) { | ||||||||||||||||
| None => () | ||||||||||||||||
| Some(scrollview) => { | ||||||||||||||||
let timestamp = wheelEvent.timestamp; | ||||||||||||||||
let delta = wheelEvent.delta; | ||||||||||||||||
let axis = wheelEvent.axis; | ||||||||||||||||
} | ||||||||||||||||
}*/ | ||||||||||||||||
|
||||||||||||||||
let scrollForFrameFlip = (timestamp: int) => { | ||||||||||||||||
// call into libscroll to sample new position | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
let scroll = (wheelEvent: NodeEvents.mouseWheelEventParams) => { | ||||||||||||||||
let delta = int_of_float(wheelEvent.deltaY *. 25.); | ||||||||||||||||
switch (scrollViewRef^) { | ||||||||||||||||
| Some(scrollview) => {//Libscroll.push_pan(scrollview, Libscroll.Axis.Vertical, 10.0, 0) | ||||||||||||||||
Log.info("Scrollview existed"); | ||||||||||||||||
|
||||||||||||||||
Libscroll.set_source(scrollview, wheelEvent.source); | ||||||||||||||||
|
||||||||||||||||
switch(wheelEvent.deltaX) { | ||||||||||||||||
| Some(delta) => { | ||||||||||||||||
Libscroll.push_pan(scrollview, Libscroll.Axis.Horizontal, delta, wheelEvent.timestamp); | ||||||||||||||||
} | ||||||||||||||||
| None => () | ||||||||||||||||
}; | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If it wasn't doing interpolation/prediction then yes, but with both enabled it would mean that acceleration goes to infinity and velocity drops to zero, which would cause weird stuttering if event ordering isn't consistent (and also make it so that fling sometimes wouldn't work) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you not just weed out the Like, if it was not an option, would this not be equivalent? if (wheelEvent.deltaX != 0) {
Libscroll.push_pan(scrollview, Libscroll.Axis.Horizontal, wheelEvent.deltaX, wheelEvent.timestamp);
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably, at least on Wayland I never seem to get a zero delta. I still need to figure out how to drag prediction toward zero if velocity drops but no zero event or fling event comes in. It seems semantically odd to special case zero delta to me but it might be fine There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find it odd that it needs to be special-cased too, but I would consider both using an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If these were polymorphic variants, you wouldn't even need to do the mapping. It's a good use case for it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, how would that work? Am not super familiar with them There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Polymorphic variants are the structurally typed equivalents of ordinary variants. Their identity is derived from the type itself, not from any definition. In this case specifically that means SDL and libscroll can share a polymorphic variant type without either library knowing about the other. By example, it looks like this: let functionTakingPolyVariant = (poly: [`Number(int) | `Text(string)]) =>
switch (poly) {
| `Number(num) => "Number: " ++ string_of_int(num)
| `Text(text) => "Text: " ++ text
};
let str = functionTakingPolyVariant(`Number(42)); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something I'm also remembering here, is that wayland sends events for when the source axis changes for a pan, and that contains an undefined delta. I probably need a way of excluding the delta as well. Might make sense to have a more general axis enum indicating horizontal, vertical, or undefined (undefined meaning the delta is meaningless, and shouldn't be interpreted) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looking at how this interacts with scroll stop events makes me want to bring back the guard, for single accesses. Effectively what I want to encode is the variant/enum Info(Source) in a way that is fairly ideomatic in c and translates well across to reasonml/rust code. What are your opinions on doing that nicely? I might be overfitting for the linux way of handling input, but afaik it's pretty similar on OSX and can be fully described for the Windows model (just compose multiple events) |
||||||||||||||||
|
||||||||||||||||
switch(wheelEvent.deltaY) { | ||||||||||||||||
| Some(delta) => { | ||||||||||||||||
Libscroll.push_pan(scrollview, Libscroll.Axis.Vertical, delta, wheelEvent.timestamp); | ||||||||||||||||
} | ||||||||||||||||
| None => () | ||||||||||||||||
}; | ||||||||||||||||
|
||||||||||||||||
switch(wheelEvent.isFling) { | ||||||||||||||||
| true => Libscroll.push_fling(scrollview, wheelEvent.timestamp); | ||||||||||||||||
| false => () | ||||||||||||||||
}; | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't use pattern matching for boolean conditionals. That's what
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, will change |
||||||||||||||||
|
||||||||||||||||
switch(wheelEvent.isInterrupt) { | ||||||||||||||||
| true => Libscroll.push_interrupt(scrollview, wheelEvent.timestamp); | ||||||||||||||||
| false => () | ||||||||||||||||
}; | ||||||||||||||||
|
||||||||||||||||
} | ||||||||||||||||
| None => Log.error("Scrollview not present on event dispatch"); | ||||||||||||||||
} | ||||||||||||||||
let delta = switch(wheelEvent.deltaY) { | ||||||||||||||||
| Some(value) => value *. 25. | ||||||||||||||||
| None => 0.0 | ||||||||||||||||
}; | ||||||||||||||||
//let delta = int_of_float(wheelEvent.deltaY *. 25.); | ||||||||||||||||
let delta_s = delta; | ||||||||||||||||
let delta = int_of_float(delta /. -400.0); | ||||||||||||||||
let newScrollTop = actualScrollTop - delta; | ||||||||||||||||
|
||||||||||||||||
let isAtTop = newScrollTop < 0; | ||||||||||||||||
let isAtBottom = newScrollTop > maxHeight; | ||||||||||||||||
|
||||||||||||||||
switch (bouncingState) { | ||||||||||||||||
| Bouncing(force) when force < 0 && wheelEvent.deltaY < 0. => | ||||||||||||||||
| Bouncing(force) when force < 0 && delta_s < 0. => | ||||||||||||||||
setBouncingState(_ => Idle) | ||||||||||||||||
| Bouncing(force) when force > 0 && wheelEvent.deltaY > 0. => | ||||||||||||||||
| Bouncing(force) when force > 0 && delta_s > 0. => | ||||||||||||||||
setBouncingState(_ => Idle) | ||||||||||||||||
| Bouncing(_) => () | ||||||||||||||||
| Idle when !bounce && (isAtTop || isAtBottom) => | ||||||||||||||||
let clampedScrollTop = isAtTop ? 0 : maxHeight; | ||||||||||||||||
dispatch(ScrollUpdated(clampedScrollTop)); | ||||||||||||||||
dispatch(ScrollUpdated(newScrollTop)); | ||||||||||||||||
//let clampedScrollTop = isAtTop ? 0 : maxHeight; | ||||||||||||||||
//dispatch(ScrollUpdated(clampedScrollTop)); | ||||||||||||||||
() | ||||||||||||||||
| Idle when bounce && (isAtTop || isAtBottom) => | ||||||||||||||||
setBouncingState(_ => Bouncing(- delta * 2)); | ||||||||||||||||
//setBouncingState(_ => Bouncing(- delta * 2)); | ||||||||||||||||
dispatch(ScrollUpdated(isAtTop ? 0 : maxHeight)); | ||||||||||||||||
| Idle => dispatch(ScrollUpdated(newScrollTop)) | ||||||||||||||||
}; | ||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're taking out
skia
and puttingfontkit
back?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@glennsl whoops, not intentionally. I think that file got left behind as I was jumping between branches