From ad4215a7ebb19bf5063e01bb8f3162fa95c63696 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Wed, 10 Jul 2019 13:23:20 +0200 Subject: [PATCH] ui: use ints for unit conversions to pixels The dp and sp units are approximate and mostly used for layout dimensions that operate in whole pixels. This change alters the Config methods to return pixels in ints instead of floats, which results in smoother use for layout and emphasize the inexactness of the device independent units. Clients can still access to raw PxPrDp and PxPrSp factors from Config. Signed-off-by: Elias Naur --- ui/app/os_wayland.go | 4 ++-- ui/gesture/gestures.go | 8 ++++---- ui/measure/measure.go | 4 ++-- ui/text/editor.go | 4 ++-- ui/ui.go | 18 ++++++++++-------- ui/widget/image.go | 10 ++++++---- 6 files changed, 26 insertions(+), 22 deletions(-) diff --git a/ui/app/os_wayland.go b/ui/app/os_wayland.go index 1eaa5a97..f4f6e83f 100644 --- a/ui/app/os_wayland.go +++ b/ui/app/os_wayland.go @@ -237,8 +237,8 @@ func createNativeWindow(opts *WindowOptions) (*window, error) { C.free(unsafe.Pointer(title)) _, _, cfg := w.config() - w.width = int(cfg.Val(opts.Width) + .5) - w.height = int(cfg.Val(opts.Height) + .5) + w.width = cfg.Val(opts.Width) + w.height = cfg.Val(opts.Height) if conn.decor != nil { // Request server side decorations. w.decor = C.zxdg_decoration_manager_v1_get_toplevel_decoration(conn.decor, w.topLvl) diff --git a/ui/gesture/gestures.go b/ui/gesture/gestures.go index 7ea1f3de..26e657be 100644 --- a/ui/gesture/gestures.go +++ b/ui/gesture/gestures.go @@ -165,9 +165,9 @@ func (s *Scroll) Scroll(cfg *ui.Config, q input.Events, axis Axis) int { break } fling := s.estimator.Estimate() - if slop, d := cfg.Val(touchSlop), fling.Distance; d >= slop || -slop >= d { - if min, v := cfg.Val(minFlingVelocity), fling.Velocity; v >= min || -min >= v { - max := cfg.Val(maxFlingVelocity) + if slop, d := float32(cfg.Val(touchSlop)), fling.Distance; d >= slop || -slop >= d { + if min, v := float32(cfg.Val(minFlingVelocity)), fling.Velocity; v >= min || -min >= v { + max := float32(cfg.Val(maxFlingVelocity)) if v > max { v = max } else if v < -max { @@ -201,7 +201,7 @@ func (s *Scroll) Scroll(cfg *ui.Config, q input.Events, axis Axis) int { dist := s.last - v if e.Priority < pointer.Grabbed { slop := cfg.Val(touchSlop) - if dist := float32(dist); dist >= slop || -slop >= dist { + if dist := dist; dist >= slop || -slop >= dist { s.grab = true } } else { diff --git a/ui/measure/measure.go b/ui/measure/measure.go index 33346c37..b1c87223 100644 --- a/ui/measure/measure.go +++ b/ui/measure/measure.go @@ -102,7 +102,7 @@ func (f *Faces) init() { } func (f *textFace) Layout(str string, opts text.LayoutOptions) *text.Layout { - ppem := fixed.Int26_6(f.faces.Config.Val(f.size)*64 + .5) + ppem := fixed.Int26_6(f.faces.Config.Val(f.size) * 64) lk := layoutKey{ f: f.font.Font, ppem: ppem, @@ -120,7 +120,7 @@ func (f *textFace) Layout(str string, opts text.LayoutOptions) *text.Layout { } func (f *textFace) Path(str text.String) ui.BlockOp { - ppem := fixed.Int26_6(f.faces.Config.Val(f.size)*64 + .5) + ppem := fixed.Int26_6(f.faces.Config.Val(f.size) * 64) pk := pathKey{ f: f.font.Font, ppem: ppem, diff --git a/ui/text/editor.go b/ui/text/editor.go index 206b6fbe..2dea373a 100644 --- a/ui/text/editor.go +++ b/ui/text/editor.go @@ -153,7 +153,7 @@ func (e *Editor) Next() (EditorEvent, bool) { } func (e *Editor) caretWidth() fixed.Int26_6 { - oneDp := int(e.Config.Val(ui.Dp(1)) + .5) + oneDp := e.Config.Val(ui.Dp(1)) return fixed.Int26_6(oneDp * 64) } @@ -167,7 +167,7 @@ func (e *Editor) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens { break } } - twoDp := int(e.Config.Val(ui.Dp(2)) + 0.5) + twoDp := e.Config.Val(ui.Dp(2)) e.padLeft, e.padRight = twoDp, twoDp maxWidth := cs.Width.Max if e.SingleLine { diff --git a/ui/ui.go b/ui/ui.go index aaa03ea4..f8fd5c77 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -23,27 +23,29 @@ type Config struct { } // Dp converts a value in dp units to pixels. -func (c *Config) Dp(dp float32) float32 { - return c.PxPerDp * dp +func (c *Config) Dp(dp float32) int { + return c.Val(Dp(dp)) } // Sp converts a value in sp units to pixels. -func (c *Config) Sp(sp float32) float32 { - return c.PxPerSp * sp +func (c *Config) Sp(sp float32) int { + return c.Val(Sp(sp)) } // Val converts a value to pixels. -func (c *Config) Val(v Value) float32 { +func (c *Config) Val(v Value) int { + var r float32 switch v.U { case UnitPx: - return v.V + r = v.V case UnitDp: - return c.PxPerDp * v.V + r = c.PxPerDp * v.V case UnitSp: - return c.PxPerSp * v.V + r = c.PxPerSp * v.V default: panic("unknown unit") } + return int(math.Round(float64(r))) } // LayerOp represents a semantic layer of UI. diff --git a/ui/widget/image.go b/ui/widget/image.go index ffffed84..dc706b56 100644 --- a/ui/widget/image.go +++ b/ui/widget/image.go @@ -25,12 +25,14 @@ type Image struct { func (im Image) Layout(c *ui.Config, ops *ui.Ops, cs layout.Constraints) layout.Dimens { size := im.Src.Bounds() - scale := im.Scale - if scale == 0 { + wf, hf := float32(size.Dx()), float32(size.Dy()) + var w, h int + if im.Scale == 0 { const dpPrPx = 160 / 72 - scale = c.Val(ui.Dp(dpPrPx)) + w, h = c.Dp(wf*dpPrPx), c.Dp(hf*dpPrPx) + } else { + w, h = int(wf*im.Scale+.5), int(hf*im.Scale+.5) } - w, h := int(float32(size.Dx())*scale+.5), int(float32(size.Dy())*scale+.5) d := image.Point{X: cs.Width.Constrain(w), Y: cs.Height.Constrain(h)} aspect := float32(w) / float32(h) dw, dh := float32(d.X), float32(d.Y)