all: make unit.Converter concrete and rename to Metric

An interface for scaling dp and sp is overkill, at least for all
current uses. Make it a concrete struct type, and rename it to the
shorter and more precise Metric.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2020-06-17 11:47:14 +02:00
parent 1603a6f3ee
commit 596e321610
15 changed files with 86 additions and 85 deletions
+3 -3
View File
@@ -396,9 +396,9 @@ func (w *window) draw(sync bool) {
Y: int(height), Y: int(height),
}, },
Insets: w.insets, Insets: w.insets,
Config: &config{ Metric: unit.Metric{
pxPerDp: ppdp, PxPerDp: ppdp,
pxPerSp: w.fontScale * ppdp, PxPerSp: w.fontScale * ppdp,
}, },
}, },
Sync: sync, Sync: sync,
+3 -3
View File
@@ -119,9 +119,9 @@ func (w *window) draw(sync bool) {
Bottom: unit.Px(float32(params.bottom)), Bottom: unit.Px(float32(params.bottom)),
Left: unit.Px(float32(params.left)), Left: unit.Px(float32(params.left)),
}, },
Config: &config{ Metric: unit.Metric{
pxPerDp: float32(params.dpi) * inchPrDp, PxPerDp: float32(params.dpi) * inchPrDp,
pxPerSp: float32(params.sdpi) * inchPrDp, PxPerSp: float32(params.sdpi) * inchPrDp,
}, },
}, },
Sync: sync, Sync: sync,
+7 -6
View File
@@ -15,6 +15,7 @@ import (
"gioui.org/io/key" "gioui.org/io/key"
"gioui.org/io/pointer" "gioui.org/io/pointer"
"gioui.org/io/system" "gioui.org/io/system"
"gioui.org/unit"
) )
type window struct { type window struct {
@@ -407,7 +408,7 @@ func (w *window) ShowTextInput(show bool) {
func (w *window) draw(sync bool) { func (w *window) draw(sync bool) {
width, height, scale, cfg := w.config() width, height, scale, cfg := w.config()
if cfg == (config{}) || width == 0 || height == 0 { if cfg == (unit.Metric{}) || width == 0 || height == 0 {
return return
} }
w.mu.Lock() w.mu.Lock()
@@ -420,13 +421,13 @@ func (w *window) draw(sync bool) {
X: width, X: width,
Y: height, Y: height,
}, },
Config: &cfg, Metric: cfg,
}, },
Sync: sync, Sync: sync,
}) })
} }
func (w *window) config() (int, int, float32, config) { func (w *window) config() (int, int, float32, unit.Metric) {
rect := w.cnv.Call("getBoundingClientRect") rect := w.cnv.Call("getBoundingClientRect")
width, height := rect.Get("width").Float(), rect.Get("height").Float() width, height := rect.Get("width").Float(), rect.Get("height").Float()
scale := w.window.Get("devicePixelRatio").Float() scale := w.window.Get("devicePixelRatio").Float()
@@ -438,9 +439,9 @@ func (w *window) config() (int, int, float32, config) {
w.cnv.Set("width", iw) w.cnv.Set("width", iw)
w.cnv.Set("height", ih) w.cnv.Set("height", ih)
} }
return iw, ih, float32(scale), config{ return iw, ih, float32(scale), unit.Metric{
pxPerDp: float32(scale), PxPerDp: float32(scale),
pxPerSp: float32(scale), PxPerSp: float32(scale),
} }
} }
+6 -5
View File
@@ -17,6 +17,7 @@ import (
"gioui.org/io/key" "gioui.org/io/key"
"gioui.org/io/pointer" "gioui.org/io/pointer"
"gioui.org/io/system" "gioui.org/io/system"
"gioui.org/unit"
_ "gioui.org/app/internal/cocoainit" _ "gioui.org/app/internal/cocoainit"
) )
@@ -236,16 +237,16 @@ func (w *window) draw() {
X: width, X: width,
Y: height, Y: height,
}, },
Config: &cfg, Metric: cfg,
}, },
Sync: true, Sync: true,
}) })
} }
func configFor(scale float32) config { func configFor(scale float32) unit.Metric {
return config{ return unit.Metric{
pxPerDp: scale, PxPerDp: scale,
pxPerSp: scale, PxPerSp: scale,
} }
} }
+8 -7
View File
@@ -25,6 +25,7 @@ import (
"gioui.org/io/key" "gioui.org/io/key"
"gioui.org/io/pointer" "gioui.org/io/pointer"
"gioui.org/io/system" "gioui.org/io/system"
"gioui.org/unit"
syscall "golang.org/x/sys/unix" syscall "golang.org/x/sys/unix"
) )
@@ -873,7 +874,7 @@ func (w *window) flushFling() {
w.fling.yExtrapolation = fling.Extrapolation{} w.fling.yExtrapolation = fling.Extrapolation{}
vel := float32(math.Sqrt(float64(estx.Velocity*estx.Velocity + esty.Velocity*esty.Velocity))) vel := float32(math.Sqrt(float64(estx.Velocity*estx.Velocity + esty.Velocity*esty.Velocity)))
_, _, c := w.config() _, _, c := w.config()
if !w.fling.anim.Start(&c, time.Now(), vel) { if !w.fling.anim.Start(c, time.Now(), vel) {
return return
} }
invDist := 1 / vel invDist := 1 / vel
@@ -1359,11 +1360,11 @@ func (w *window) updateOutputs() {
} }
} }
func (w *window) config() (int, int, config) { func (w *window) config() (int, int, unit.Metric) {
width, height := w.width*w.scale, w.height*w.scale width, height := w.width*w.scale, w.height*w.scale
return width, height, config{ return width, height, unit.Metric{
pxPerDp: w.ppdp * float32(w.scale), PxPerDp: w.ppdp * float32(w.scale),
pxPerSp: w.ppsp * float32(w.scale), PxPerSp: w.ppsp * float32(w.scale),
} }
} }
@@ -1377,7 +1378,7 @@ func (w *window) draw(sync bool) {
return return
} }
width, height, cfg := w.config() width, height, cfg := w.config()
if cfg == (config{}) { if cfg == (unit.Metric{}) {
return return
} }
if anim && w.lastFrameCallback == nil { if anim && w.lastFrameCallback == nil {
@@ -1392,7 +1393,7 @@ func (w *window) draw(sync bool) {
X: width, X: width,
Y: height, Y: height,
}, },
Config: &cfg, Metric: cfg,
}, },
Sync: sync, Sync: sync,
}) })
+6 -5
View File
@@ -19,6 +19,7 @@ import (
syscall "golang.org/x/sys/windows" syscall "golang.org/x/sys/windows"
"gioui.org/app/internal/windows" "gioui.org/app/internal/windows"
"gioui.org/unit"
"gioui.org/f32" "gioui.org/f32"
"gioui.org/io/key" "gioui.org/io/key"
@@ -377,7 +378,7 @@ func (w *window) draw(sync bool) {
X: w.width, X: w.width,
Y: w.height, Y: w.height,
}, },
Config: &cfg, Metric: cfg,
}, },
Sync: sync, Sync: sync,
}) })
@@ -586,12 +587,12 @@ func convertKeyCode(code uintptr) (string, bool) {
return r, true return r, true
} }
func configForDC() config { func configForDC() unit.Metric {
dpi := windows.GetSystemDPI() dpi := windows.GetSystemDPI()
const inchPrDp = 1.0 / 96.0 const inchPrDp = 1.0 / 96.0
ppdp := float32(dpi) * inchPrDp ppdp := float32(dpi) * inchPrDp
return config{ return unit.Metric{
pxPerDp: ppdp, PxPerDp: ppdp,
pxPerSp: ppdp, PxPerSp: ppdp,
} }
} }
+4 -3
View File
@@ -37,6 +37,7 @@ import (
"gioui.org/io/key" "gioui.org/io/key"
"gioui.org/io/pointer" "gioui.org/io/pointer"
"gioui.org/io/system" "gioui.org/io/system"
"gioui.org/unit"
"gioui.org/app/internal/xkb" "gioui.org/app/internal/xkb"
syscall "golang.org/x/sys/unix" syscall "golang.org/x/sys/unix"
@@ -64,7 +65,7 @@ type x11Window struct {
atom C.Atom atom C.Atom
} }
stage system.Stage stage system.Stage
cfg config cfg unit.Metric
width int width int
height int height int
notify struct { notify struct {
@@ -193,7 +194,7 @@ loop:
X: w.width, X: w.width,
Y: w.height, Y: w.height,
}, },
Config: &w.cfg, Metric: w.cfg,
}, },
Sync: syn, Sync: syn,
}) })
@@ -474,7 +475,7 @@ func newX11Window(gioWin Callbacks, opts *Options) error {
} }
ppsp := x11DetectUIScale(dpy) ppsp := x11DetectUIScale(dpy)
cfg := config{pxPerDp: ppsp, pxPerSp: ppsp} cfg := unit.Metric{PxPerDp: ppsp, PxPerSp: ppsp}
swa := C.XSetWindowAttributes{ swa := C.XSetWindowAttributes{
event_mask: C.ExposureMask | C.FocusChangeMask | // update event_mask: C.ExposureMask | C.FocusChangeMask | // update
C.KeyPressMask | C.KeyReleaseMask | // keyboard C.KeyPressMask | C.KeyReleaseMask | // keyboard
-24
View File
@@ -6,7 +6,6 @@ package window
import ( import (
"errors" "errors"
"math"
"gioui.org/gpu/backend" "gioui.org/gpu/backend"
"gioui.org/io/event" "gioui.org/io/event"
@@ -71,29 +70,6 @@ type windowAndOptions struct {
opts *Options opts *Options
} }
// config implements the system.Config interface.
type config struct {
// Device pixels per dp.
pxPerDp float32
// Device pixels per sp.
pxPerSp float32
}
func (c *config) Px(v unit.Value) int {
var r float32
switch v.U {
case unit.UnitPx:
r = v.V
case unit.UnitDp:
r = c.pxPerDp * v.V
case unit.UnitSp:
r = c.pxPerSp * v.V
default:
panic("unknown unit")
}
return int(math.Round(float64(r)))
}
func newWindowRendezvous() *windowRendezvous { func newWindowRendezvous() *windowRendezvous {
wr := &windowRendezvous{ wr := &windowRendezvous{
in: make(chan windowAndOptions), in: make(chan windowAndOptions),
+1 -1
View File
@@ -204,7 +204,7 @@ func (s *Scroll) Stop() {
// Scroll detects the scrolling distance from the available events and // Scroll detects the scrolling distance from the available events and
// ongoing fling gestures. // ongoing fling gestures.
func (s *Scroll) Scroll(cfg unit.Converter, q event.Queue, t time.Time, axis Axis) int { func (s *Scroll) Scroll(cfg unit.Metric, q event.Queue, t time.Time, axis Axis) int {
if s.axis != axis { if s.axis != axis {
s.axis = axis s.axis = axis
return 0 return 0
+1 -1
View File
@@ -31,7 +31,7 @@ const (
// Start a fling given a starting velocity. Returns whether a // Start a fling given a starting velocity. Returns whether a
// fling was started. // fling was started.
func (f *Animation) Start(c unit.Converter, now time.Time, velocity float32) bool { func (f *Animation) Start(c unit.Metric, now time.Time, velocity float32) bool {
min := float32(c.Px(minFlingVelocity)) min := float32(c.Px(minFlingVelocity))
v := velocity v := velocity
if -min <= v && v <= min { if -min <= v && v <= min {
+2 -7
View File
@@ -17,10 +17,11 @@ import (
// operations that describes what to display and how to handle // operations that describes what to display and how to handle
// input. // input.
type FrameEvent struct { type FrameEvent struct {
Config Config
// Now is the current animation. Use Now instead of time.Now to // Now is the current animation. Use Now instead of time.Now to
// synchronize animation and to avoid the time.Now call overhead. // synchronize animation and to avoid the time.Now call overhead.
Now time.Time Now time.Time
// Metric converts device independent dp and sp to device pixels.
Metric unit.Metric
// Size is the dimensions of the window. // Size is the dimensions of the window.
Size image.Point Size image.Point
// Insets is the insets to apply. // Insets is the insets to apply.
@@ -51,12 +52,6 @@ type FrameEvent struct {
Queue event.Queue Queue event.Queue
} }
// Config defines the essential properties of
// the environment.
type Config interface {
unit.Converter
}
// DestroyEvent is the last event sent through // DestroyEvent is the last event sent through
// a window event channel. // a window event channel.
type DestroyEvent struct { type DestroyEvent struct {
+4 -9
View File
@@ -3,7 +3,6 @@
package layout package layout
import ( import (
"math"
"time" "time"
"gioui.org/io/event" "gioui.org/io/event"
@@ -20,7 +19,7 @@ type Context struct {
// layout. // layout.
Constraints Constraints Constraints Constraints
Config system.Config Metric unit.Metric
// By convention, a nil Queue is a signal to widgets to draw themselves // By convention, a nil Queue is a signal to widgets to draw themselves
// in a disabled state. // in a disabled state.
Queue event.Queue Queue event.Queue
@@ -47,18 +46,14 @@ func NewContext(ops *op.Ops, e system.FrameEvent) Context {
Ops: ops, Ops: ops,
Now: e.Now, Now: e.Now,
Queue: e.Queue, Queue: e.Queue,
Config: e.Config, Metric: e.Metric,
Constraints: Exact(e.Size), Constraints: Exact(e.Size),
} }
} }
// Px maps the value to pixels. If no configuration is set, // Px maps the value to pixels.
// Px returns the rounded value of v.
func (c Context) Px(v unit.Value) int { func (c Context) Px(v unit.Value) int {
if c.Config == nil { return c.Metric.Px(v)
return int(math.Round(float64(v.V)))
}
return c.Config.Px(v)
} }
// Events returns the events available for the key. If no // Events returns the events available for the key. If no
+1 -1
View File
@@ -121,7 +121,7 @@ func (l *List) Dragging() bool {
} }
func (l *List) update() { func (l *List) update() {
d := l.scroll.Scroll(l.ctx, l.ctx, l.ctx.Now, gesture.Axis(l.Axis)) d := l.scroll.Scroll(l.ctx.Metric, l.ctx, l.ctx.Now, gesture.Axis(l.Axis))
l.scrollDelta = d l.scrollDelta = d
l.Position.Offset += d l.Position.Offset += d
} }
+37 -7
View File
@@ -22,7 +22,10 @@ values.
*/ */
package unit package unit
import "fmt" import (
"fmt"
"math"
)
// Value is a value with a unit. // Value is a value with a unit.
type Value struct { type Value struct {
@@ -33,9 +36,13 @@ type Value struct {
// Unit represents a unit for a Value. // Unit represents a unit for a Value.
type Unit uint8 type Unit uint8
// Converter converts Values to pixels. // Metric converts Values to device-dependent pixels, px. The zero
type Converter interface { // value represents a 1-to-1 scale from dp, sp to pixels.
Px(v Value) int type Metric struct {
// PxPerDp is the device-dependent pixels per dp.
PxPerDp float32
// PxPerSp is the device-dependent pixels per sp.
PxPerSp float32
} }
const ( const (
@@ -90,7 +97,7 @@ func (u Unit) String() string {
} }
// Add a list of Values. // Add a list of Values.
func Add(c Converter, values ...Value) Value { func Add(c Metric, values ...Value) Value {
var sum Value var sum Value
for _, v := range values { for _, v := range values {
sum, v = compatible(c, sum, v) sum, v = compatible(c, sum, v)
@@ -100,7 +107,7 @@ func Add(c Converter, values ...Value) Value {
} }
// Max returns the maximum of a list of Values. // Max returns the maximum of a list of Values.
func Max(c Converter, values ...Value) Value { func Max(c Metric, values ...Value) Value {
var max Value var max Value
for _, v := range values { for _, v := range values {
max, v = compatible(c, max, v) max, v = compatible(c, max, v)
@@ -111,7 +118,30 @@ func Max(c Converter, values ...Value) Value {
return max return max
} }
func compatible(c Converter, v1, v2 Value) (Value, Value) { func (c Metric) Px(v Value) int {
var r float32
switch v.U {
case UnitPx:
r = v.V
case UnitDp:
s := c.PxPerDp
if s == 0 {
s = 1
}
r = s * v.V
case UnitSp:
s := c.PxPerSp
if s == 0 {
s = 1
}
r = s * v.V
default:
panic("unknown unit")
}
return int(math.Round(float64(r)))
}
func compatible(c Metric, v1, v2 Value) (Value, Value) {
if v1.U == v2.U { if v1.U == v2.U {
return v1, v2 return v1, v2
} }
+3 -3
View File
@@ -129,7 +129,7 @@ func (e *Editor) processPointer(gtx layout.Context) {
axis = gesture.Vertical axis = gesture.Vertical
smin, smax = sbounds.Min.Y, sbounds.Max.Y smin, smax = sbounds.Min.Y, sbounds.Max.Y
} }
sdist := e.scroller.Scroll(gtx, gtx, gtx.Now, axis) sdist := e.scroller.Scroll(gtx.Metric, gtx, gtx.Now, axis)
var soff int var soff int
if e.SingleLine { if e.SingleLine {
e.scrollRel(sdist, 0) e.scrollRel(sdist, 0)
@@ -143,7 +143,7 @@ func (e *Editor) processPointer(gtx layout.Context) {
case evt.Type == gesture.TypePress && evt.Source == pointer.Mouse, case evt.Type == gesture.TypePress && evt.Source == pointer.Mouse,
evt.Type == gesture.TypeClick && evt.Source == pointer.Touch: evt.Type == gesture.TypeClick && evt.Source == pointer.Touch:
e.blinkStart = gtx.Now e.blinkStart = gtx.Now
e.moveCoord(gtx, image.Point{ e.moveCoord(gtx.Metric, image.Point{
X: int(math.Round(float64(evt.Position.X))), X: int(math.Round(float64(evt.Position.X))),
Y: int(math.Round(float64(evt.Position.Y))), Y: int(math.Round(float64(evt.Position.Y))),
}) })
@@ -426,7 +426,7 @@ func (e *Editor) scrollAbs(x, y int) {
} }
} }
func (e *Editor) moveCoord(c unit.Converter, pos image.Point) { func (e *Editor) moveCoord(c unit.Metric, pos image.Point) {
var ( var (
prevDesc fixed.Int26_6 prevDesc fixed.Int26_6
carLine int carLine int