Add text components 021-040 with demos and behavior tests
This commit is contained in:
30 files changed
+1702
-7
No files matched your search
@@ -0,0 +1,89 @@
|
||||
package text
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/egoist/mygo/ui"
|
||||
|
||||
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/pixel"
|
||||
)
|
||||
|
||||
type OdometerOptions struct {
|
||||
// Digits is zero for as many as value has.
|
||||
Digits int
|
||||
Slot pixel.Slot
|
||||
}
|
||||
|
||||
type odoKey struct{}
|
||||
|
||||
type odoState struct {
|
||||
shown float64
|
||||
last int
|
||||
}
|
||||
|
||||
const odoCell = 10
|
||||
|
||||
// Odometer rolls its digits toward value, step by step.
|
||||
func Odometer(c *ui.Context, value int, o OdometerOptions) *ui.Element {
|
||||
if value < 0 {
|
||||
panic(fmt.Sprintf("text: Odometer value %d is negative", value))
|
||||
}
|
||||
k := pixel.K(c)
|
||||
digits := orDef("Odometer Digits", o.Digits, len(strconv.Itoa(value)))
|
||||
if value >= int(math.Pow10(digits)) {
|
||||
panic(fmt.Sprintf("text: Odometer value %d needs more than %d digits", value, digits))
|
||||
}
|
||||
h := pixel.LineHeight + 2
|
||||
e := ui.Box(c).Size(k.D(digits*odoCell), k.D(h)).Label(strconv.Itoa(value)).Role(ui.RoleText)
|
||||
st := ui.Local(e, odoKey{}, func() odoState { return odoState{shown: float64(value), last: -1} })
|
||||
target := float64(value)
|
||||
switch {
|
||||
case k.Reduce() || st.shown == target:
|
||||
st.shown, st.last = target, -1
|
||||
default:
|
||||
tick := k.Tick(c, 30)
|
||||
if st.last >= 0 {
|
||||
for range tick - st.last {
|
||||
st.shown = roll(st.shown, target)
|
||||
}
|
||||
}
|
||||
st.last = tick
|
||||
}
|
||||
shown := st.shown
|
||||
return e.Draw(func(p *ui.Painter, r ui.Rect) {
|
||||
g := k.Canvas(p, r)
|
||||
for i := range digits {
|
||||
x := (digits - 1 - i) * odoCell
|
||||
d, frac := wheel(shown, i)
|
||||
g.Frame(x, 0, odoCell-1, h, pixel.Sunken, pixel.Well)
|
||||
g.Clip(x+2, 2, odoCell-5, h-4, func() {
|
||||
y := 1 - int(frac*float64(h))
|
||||
g.Text(x+2, y, strconv.Itoa(d), o.Slot, 1)
|
||||
g.Text(x+2, y+h, strconv.Itoa((d+1)%10), o.Slot, 1)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// roll moves shown a step toward target, faster when far.
|
||||
func roll(shown, target float64) float64 {
|
||||
diff := target - shown
|
||||
stride := max(0.25, math.Abs(diff)/6)
|
||||
if math.Abs(diff) <= stride {
|
||||
return target
|
||||
}
|
||||
return shown + math.Copysign(stride, diff)
|
||||
}
|
||||
|
||||
// wheel is digit i of shown and its roll.
|
||||
func wheel(shown float64, i int) (d int, frac float64) {
|
||||
place := math.Pow10(i)
|
||||
v := shown / place
|
||||
d = int(math.Floor(v)) % 10
|
||||
if lower := math.Mod(shown, place); lower > place-1 {
|
||||
frac = lower - (place - 1)
|
||||
}
|
||||
return d, frac
|
||||
}
|
||||
Reference in new issue
Block a user