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 <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-07-10 13:23:20 +02:00
parent bde04c68a2
commit ad4215a7eb
6 changed files with 26 additions and 22 deletions
+2 -2
View File
@@ -237,8 +237,8 @@ func createNativeWindow(opts *WindowOptions) (*window, error) {
C.free(unsafe.Pointer(title)) C.free(unsafe.Pointer(title))
_, _, cfg := w.config() _, _, cfg := w.config()
w.width = int(cfg.Val(opts.Width) + .5) w.width = cfg.Val(opts.Width)
w.height = int(cfg.Val(opts.Height) + .5) w.height = cfg.Val(opts.Height)
if conn.decor != nil { if conn.decor != nil {
// Request server side decorations. // Request server side decorations.
w.decor = C.zxdg_decoration_manager_v1_get_toplevel_decoration(conn.decor, w.topLvl) w.decor = C.zxdg_decoration_manager_v1_get_toplevel_decoration(conn.decor, w.topLvl)
+4 -4
View File
@@ -165,9 +165,9 @@ func (s *Scroll) Scroll(cfg *ui.Config, q input.Events, axis Axis) int {
break break
} }
fling := s.estimator.Estimate() fling := s.estimator.Estimate()
if slop, d := cfg.Val(touchSlop), fling.Distance; d >= slop || -slop >= d { if slop, d := float32(cfg.Val(touchSlop)), fling.Distance; d >= slop || -slop >= d {
if min, v := cfg.Val(minFlingVelocity), fling.Velocity; v >= min || -min >= v { if min, v := float32(cfg.Val(minFlingVelocity)), fling.Velocity; v >= min || -min >= v {
max := cfg.Val(maxFlingVelocity) max := float32(cfg.Val(maxFlingVelocity))
if v > max { if v > max {
v = max v = max
} else if 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 dist := s.last - v
if e.Priority < pointer.Grabbed { if e.Priority < pointer.Grabbed {
slop := cfg.Val(touchSlop) slop := cfg.Val(touchSlop)
if dist := float32(dist); dist >= slop || -slop >= dist { if dist := dist; dist >= slop || -slop >= dist {
s.grab = true s.grab = true
} }
} else { } else {
+2 -2
View File
@@ -102,7 +102,7 @@ func (f *Faces) init() {
} }
func (f *textFace) Layout(str string, opts text.LayoutOptions) *text.Layout { 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{ lk := layoutKey{
f: f.font.Font, f: f.font.Font,
ppem: ppem, 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 { 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{ pk := pathKey{
f: f.font.Font, f: f.font.Font,
ppem: ppem, ppem: ppem,
+2 -2
View File
@@ -153,7 +153,7 @@ func (e *Editor) Next() (EditorEvent, bool) {
} }
func (e *Editor) caretWidth() fixed.Int26_6 { 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) return fixed.Int26_6(oneDp * 64)
} }
@@ -167,7 +167,7 @@ func (e *Editor) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
break break
} }
} }
twoDp := int(e.Config.Val(ui.Dp(2)) + 0.5) twoDp := e.Config.Val(ui.Dp(2))
e.padLeft, e.padRight = twoDp, twoDp e.padLeft, e.padRight = twoDp, twoDp
maxWidth := cs.Width.Max maxWidth := cs.Width.Max
if e.SingleLine { if e.SingleLine {
+10 -8
View File
@@ -23,27 +23,29 @@ type Config struct {
} }
// Dp converts a value in dp units to pixels. // Dp converts a value in dp units to pixels.
func (c *Config) Dp(dp float32) float32 { func (c *Config) Dp(dp float32) int {
return c.PxPerDp * dp return c.Val(Dp(dp))
} }
// Sp converts a value in sp units to pixels. // Sp converts a value in sp units to pixels.
func (c *Config) Sp(sp float32) float32 { func (c *Config) Sp(sp float32) int {
return c.PxPerSp * sp return c.Val(Sp(sp))
} }
// Val converts a value to pixels. // 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 { switch v.U {
case UnitPx: case UnitPx:
return v.V r = v.V
case UnitDp: case UnitDp:
return c.PxPerDp * v.V r = c.PxPerDp * v.V
case UnitSp: case UnitSp:
return c.PxPerSp * v.V r = c.PxPerSp * v.V
default: default:
panic("unknown unit") panic("unknown unit")
} }
return int(math.Round(float64(r)))
} }
// LayerOp represents a semantic layer of UI. // LayerOp represents a semantic layer of UI.
+6 -4
View File
@@ -25,12 +25,14 @@ type Image struct {
func (im Image) Layout(c *ui.Config, ops *ui.Ops, cs layout.Constraints) layout.Dimens { func (im Image) Layout(c *ui.Config, ops *ui.Ops, cs layout.Constraints) layout.Dimens {
size := im.Src.Bounds() size := im.Src.Bounds()
scale := im.Scale wf, hf := float32(size.Dx()), float32(size.Dy())
if scale == 0 { var w, h int
if im.Scale == 0 {
const dpPrPx = 160 / 72 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)} d := image.Point{X: cs.Width.Constrain(w), Y: cs.Height.Constrain(h)}
aspect := float32(w) / float32(h) aspect := float32(w) / float32(h)
dw, dh := float32(d.X), float32(d.Y) dw, dh := float32(d.X), float32(d.Y)