Open kkoreilly opened 1 year ago
some key logic issues:
preemption style func logic means that a map with style param key must be used to get the final transition style -- could be set and overridden in diff funcs.
key = style param enum -- could auto-gen from struct or maybe easier to just manually auto-gen by pasting field names..
all transitions must operate on style params -- e.g., for texfield under-border anim, need a new SizePct style param on border side that specifies % of border size to actually render (assuming centered -- could be even more complex if you want to have arbitrary start / end / size but let's not go there)
post-stylefunc general-purpose transition code uses param field enum and prev, new value and just increments value over time and calls UpdateSig on widget -- in a time.Timer goroutine.
if want full generic ability to transition anything, then need a SetStyleField and GetStyleField that take the enum, and return Any value. Then switch on actual value type to deal with color vs. float etc.
Could impl Set / Get via either reflection or a generated code. The generate could be put into goki tool as a general facility for creating such things, which might be useful in other contexts (e.g., paint styling using props!). Use the existing xml tags + default rules (or new special tag?) for naming enums.
I implemented a basic version of transitions previously, but it still needs to be cleaned up. Also, we need to decide when, if ever, we want to use basic property transitions, and we still need to support more general animations.
Basic property transitions only make things look slow and do not improve the end-user experience. The only transitions that it makes sense to implement are real animations, which are more difficult and not a critical thing that we need to implement for v1. Therefore, we will work on implementing this eventually, but it will not be part of the v1 milestone.
For reference, this is what the previous transition API was:
// todo: store a map of [value]ticker -- close the ticker if existing.
// Transition transitions the given pointer value (typically a pointer to a style property
// that is a number, unit value, or color) to the given destination value (typically not a pointer)
// over the given duration, using the given timing function. The timing function takes the proportion
// of the time of the transition that has taken place (0-1) and returns the total proportion of the
// difference between the starting and ending value that should be applied at that point in time (0-1).
// For example, a standard linear timing function would just return the value it gets. The transition runs
// at the FPS of the window, and it tells the widget to render on every FPS tick. If the starting and ending
// value are the same, it does nothing. If not, it runs the transition in a separate goroutine.
func (wb *WidgetBase) Transition(value any, to any, duration time.Duration, timingFunc func(prop float32) float32) {
vn := grr.Log1(laser.ToFloat32(value))
tn := grr.Log1(laser.ToFloat32(to))
diff := tn - vn
if diff == 0 {
return
}
rate := time.Second / 60
propPer := float32(rate) / float32(duration)
tick := time.NewTicker(rate)
go func() {
for i := 0; i < int(duration/rate); i++ {
<-tick.C
// fmt.Println("transitioning", wb)
prop := float32(i) * propPer
inc := timingFunc(prop)
nv := vn + inc*diff
grr.Log(laser.SetRobust(value, nv))
wb.SetNeedsRender(true)
}
tick.Stop()
}()
}
// LinearTransition is a simple, linear, 1 to 1 timing function that can be passed to [WidgetBase.Transition]
func LinearTransition(prop float32) float32 {
return prop
}
For example, to transition the background color of a button on hover.