forked from joejulian/gio
ui,ui/app: convert Config to an interface
To keep the interface slim, remove the helper methods and shorten the essential method, Pixels, to Px. Add and use unexported Config implementation in the app package. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+34
-1
@@ -4,8 +4,10 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"gioui.org/ui"
|
"gioui.org/ui"
|
||||||
)
|
)
|
||||||
@@ -15,7 +17,7 @@ type Event interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DrawEvent struct {
|
type DrawEvent struct {
|
||||||
Config ui.Config
|
Config Config
|
||||||
Size image.Point
|
Size image.Point
|
||||||
// Insets is the window space taken up by
|
// Insets is the window space taken up by
|
||||||
// system decoration such as translucent
|
// system decoration such as translucent
|
||||||
@@ -131,3 +133,34 @@ func init() {
|
|||||||
func DataDir() (string, error) {
|
func DataDir() (string, error) {
|
||||||
return dataDir()
|
return dataDir()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Config implements the ui.Config interface.
|
||||||
|
type Config struct {
|
||||||
|
// Device pixels per dp.
|
||||||
|
pxPerDp float32
|
||||||
|
// Device pixels per sp.
|
||||||
|
pxPerSp float32
|
||||||
|
now time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) Now() time.Time {
|
||||||
|
return c.now
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) Px(v ui.Value) int {
|
||||||
|
var r float32
|
||||||
|
switch v.U {
|
||||||
|
case ui.UnitPx:
|
||||||
|
r = v.V
|
||||||
|
case ui.UnitDp:
|
||||||
|
r = c.pxPerDp * v.V
|
||||||
|
case ui.UnitSp:
|
||||||
|
r = c.pxPerSp * v.V
|
||||||
|
default:
|
||||||
|
panic("unknown unit")
|
||||||
|
}
|
||||||
|
if math.IsInf(float64(r), +1) {
|
||||||
|
return ui.Inf
|
||||||
|
}
|
||||||
|
return int(math.Round(float64(r)))
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"gioui.org/ui"
|
|
||||||
"gioui.org/ui/f32"
|
"gioui.org/ui/f32"
|
||||||
"gioui.org/ui/key"
|
"gioui.org/ui/key"
|
||||||
"gioui.org/ui/pointer"
|
"gioui.org/ui/pointer"
|
||||||
@@ -289,10 +288,10 @@ func (w *window) draw(sync bool) {
|
|||||||
Y: int(height),
|
Y: int(height),
|
||||||
},
|
},
|
||||||
Insets: w.insets,
|
Insets: w.insets,
|
||||||
Config: ui.Config{
|
Config: Config{
|
||||||
PxPerDp: ppdp,
|
pxPerDp: ppdp,
|
||||||
PxPerSp: w.fontScale * ppdp,
|
pxPerSp: w.fontScale * ppdp,
|
||||||
Now: time.Now(),
|
now: time.Now(),
|
||||||
},
|
},
|
||||||
sync: sync,
|
sync: sync,
|
||||||
})
|
})
|
||||||
|
|||||||
+4
-5
@@ -22,7 +22,6 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gioui.org/ui"
|
|
||||||
"gioui.org/ui/f32"
|
"gioui.org/ui/f32"
|
||||||
"gioui.org/ui/key"
|
"gioui.org/ui/key"
|
||||||
"gioui.org/ui/pointer"
|
"gioui.org/ui/pointer"
|
||||||
@@ -87,10 +86,10 @@ func onDraw(view C.CFTypeRef, dpi, sdpi, width, height C.CGFloat, sync C.int, to
|
|||||||
Min: image.Point{X: int(left + .5), Y: int(top + .5)},
|
Min: image.Point{X: int(left + .5), Y: int(top + .5)},
|
||||||
Max: image.Point{X: int(right + .5), Y: int(bottom + .5)},
|
Max: image.Point{X: int(right + .5), Y: int(bottom + .5)},
|
||||||
},
|
},
|
||||||
Config: ui.Config{
|
Config: Config{
|
||||||
PxPerDp: float32(dpi) * inchPrDp,
|
pxPerDp: float32(dpi) * inchPrDp,
|
||||||
PxPerSp: float32(sdpi) * inchPrDp,
|
pxPerSp: float32(sdpi) * inchPrDp,
|
||||||
Now: time.Now(),
|
now: time.Now(),
|
||||||
},
|
},
|
||||||
sync: isSync,
|
sync: isSync,
|
||||||
})
|
})
|
||||||
|
|||||||
+6
-7
@@ -7,7 +7,6 @@ import (
|
|||||||
"syscall/js"
|
"syscall/js"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gioui.org/ui"
|
|
||||||
"gioui.org/ui/f32"
|
"gioui.org/ui/f32"
|
||||||
"gioui.org/ui/key"
|
"gioui.org/ui/key"
|
||||||
"gioui.org/ui/pointer"
|
"gioui.org/ui/pointer"
|
||||||
@@ -329,13 +328,13 @@ func (w *window) setTextInput(s key.TextInputState) {
|
|||||||
|
|
||||||
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 == (ui.Config{}) {
|
if cfg == (Config{}) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.mu.Lock()
|
w.mu.Lock()
|
||||||
w.scale = float32(scale)
|
w.scale = float32(scale)
|
||||||
w.mu.Unlock()
|
w.mu.Unlock()
|
||||||
cfg.Now = time.Now()
|
cfg.now = time.Now()
|
||||||
w.w.event(DrawEvent{
|
w.w.event(DrawEvent{
|
||||||
Size: image.Point{
|
Size: image.Point{
|
||||||
X: width,
|
X: width,
|
||||||
@@ -346,7 +345,7 @@ func (w *window) draw(sync bool) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) config() (int, int, float32, ui.Config) {
|
func (w *window) config() (int, int, float32, Config) {
|
||||||
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()
|
||||||
@@ -359,9 +358,9 @@ func (w *window) config() (int, int, float32, ui.Config) {
|
|||||||
w.cnv.Set("height", ih)
|
w.cnv.Set("height", ih)
|
||||||
}
|
}
|
||||||
const ppdp = 96 * inchPrDp * monitorScale
|
const ppdp = 96 * inchPrDp * monitorScale
|
||||||
return iw, ih, float32(scale), ui.Config{
|
return iw, ih, float32(scale), Config{
|
||||||
PxPerDp: ppdp * float32(scale),
|
pxPerDp: ppdp * float32(scale),
|
||||||
PxPerSp: ppdp * float32(scale),
|
pxPerSp: ppdp * float32(scale),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-8
@@ -19,7 +19,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"gioui.org/ui"
|
|
||||||
"gioui.org/ui/f32"
|
"gioui.org/ui/f32"
|
||||||
"gioui.org/ui/key"
|
"gioui.org/ui/key"
|
||||||
"gioui.org/ui/pointer"
|
"gioui.org/ui/pointer"
|
||||||
@@ -142,7 +141,7 @@ func (w *window) draw(sync bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
cfg := getConfig()
|
cfg := getConfig()
|
||||||
cfg.Now = time.Now()
|
cfg.now = time.Now()
|
||||||
w.setStage(StageRunning)
|
w.setStage(StageRunning)
|
||||||
w.w.event(DrawEvent{
|
w.w.event(DrawEvent{
|
||||||
Size: image.Point{
|
Size: image.Point{
|
||||||
@@ -154,15 +153,15 @@ func (w *window) draw(sync bool) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func getConfig() ui.Config {
|
func getConfig() Config {
|
||||||
ppdp := float32(C.gio_getPixelsPerDP())
|
ppdp := float32(C.gio_getPixelsPerDP())
|
||||||
ppdp *= monitorScale
|
ppdp *= monitorScale
|
||||||
if ppdp < minDensity {
|
if ppdp < minDensity {
|
||||||
ppdp = minDensity
|
ppdp = minDensity
|
||||||
}
|
}
|
||||||
return ui.Config{
|
return Config{
|
||||||
PxPerDp: ppdp,
|
pxPerDp: ppdp,
|
||||||
PxPerSp: ppdp,
|
pxPerSp: ppdp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,8 +215,8 @@ func Main() {
|
|||||||
}
|
}
|
||||||
cfg := getConfig()
|
cfg := getConfig()
|
||||||
opts := singleWindow.opts
|
opts := singleWindow.opts
|
||||||
w := cfg.Pixels(opts.Width)
|
w := cfg.Px(opts.Width)
|
||||||
h := cfg.Pixels(opts.Height)
|
h := cfg.Px(opts.Height)
|
||||||
title := C.CString(opts.Title)
|
title := C.CString(opts.Title)
|
||||||
defer C.free(unsafe.Pointer(title))
|
defer C.free(unsafe.Pointer(title))
|
||||||
C.gio_main(view, title, C.CGFloat(w), C.CGFloat(h))
|
C.gio_main(view, title, C.CGFloat(w), C.CGFloat(h))
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import (
|
|||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"gioui.org/ui"
|
|
||||||
"gioui.org/ui/f32"
|
"gioui.org/ui/f32"
|
||||||
"gioui.org/ui/key"
|
"gioui.org/ui/key"
|
||||||
"gioui.org/ui/pointer"
|
"gioui.org/ui/pointer"
|
||||||
@@ -237,8 +236,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 = cfg.Pixels(opts.Width)
|
w.width = cfg.Px(opts.Width)
|
||||||
w.height = cfg.Pixels(opts.Height)
|
w.height = cfg.Px(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)
|
||||||
@@ -1020,11 +1019,11 @@ func (w *window) updateOutputs() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) config() (int, int, ui.Config) {
|
func (w *window) config() (int, int, Config) {
|
||||||
width, height := w.width*w.scale, w.height*w.scale
|
width, height := w.width*w.scale, w.height*w.scale
|
||||||
return width, height, ui.Config{
|
return width, height, Config{
|
||||||
PxPerDp: w.ppdp * float32(w.scale),
|
pxPerDp: w.ppdp * float32(w.scale),
|
||||||
PxPerSp: w.ppsp * float32(w.scale),
|
pxPerSp: w.ppsp * float32(w.scale),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1036,7 +1035,7 @@ func (w *window) draw(sync bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
width, height, cfg := w.config()
|
width, height, cfg := w.config()
|
||||||
if cfg == (ui.Config{}) {
|
if cfg == (Config{}) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if animating && w.lastFrameCallback == nil {
|
if animating && w.lastFrameCallback == nil {
|
||||||
@@ -1044,7 +1043,7 @@ func (w *window) draw(sync bool) {
|
|||||||
// Use the surface as listener data for gio_onFrameDone.
|
// Use the surface as listener data for gio_onFrameDone.
|
||||||
C.gio_wl_callback_add_listener(w.lastFrameCallback, unsafe.Pointer(w.surf))
|
C.gio_wl_callback_add_listener(w.lastFrameCallback, unsafe.Pointer(w.surf))
|
||||||
}
|
}
|
||||||
cfg.Now = time.Now()
|
cfg.now = time.Now()
|
||||||
w.w.event(DrawEvent{
|
w.w.event(DrawEvent{
|
||||||
Size: image.Point{
|
Size: image.Point{
|
||||||
X: width,
|
X: width,
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
|
|
||||||
syscall "golang.org/x/sys/windows"
|
syscall "golang.org/x/sys/windows"
|
||||||
|
|
||||||
"gioui.org/ui"
|
|
||||||
"gioui.org/ui/f32"
|
"gioui.org/ui/f32"
|
||||||
"gioui.org/ui/key"
|
"gioui.org/ui/key"
|
||||||
"gioui.org/ui/pointer"
|
"gioui.org/ui/pointer"
|
||||||
@@ -220,8 +219,8 @@ func createNativeWindow(opts *WindowOptions) (*window, error) {
|
|||||||
}
|
}
|
||||||
defer unregisterClass(cls, hInst)
|
defer unregisterClass(cls, hInst)
|
||||||
wr := rect{
|
wr := rect{
|
||||||
right: int32(cfg.Pixels(opts.Width)),
|
right: int32(cfg.Px(opts.Width)),
|
||||||
bottom: int32(cfg.Pixels(opts.Height)),
|
bottom: int32(cfg.Px(opts.Height)),
|
||||||
}
|
}
|
||||||
dwStyle := uint32(_WS_OVERLAPPEDWINDOW)
|
dwStyle := uint32(_WS_OVERLAPPEDWINDOW)
|
||||||
dwExStyle := uint32(_WS_EX_APPWINDOW | _WS_EX_WINDOWEDGE)
|
dwExStyle := uint32(_WS_EX_APPWINDOW | _WS_EX_WINDOWEDGE)
|
||||||
@@ -419,7 +418,7 @@ func (w *window) draw(sync bool) {
|
|||||||
w.width = int(r.right - r.left)
|
w.width = int(r.right - r.left)
|
||||||
w.height = int(r.bottom - r.top)
|
w.height = int(r.bottom - r.top)
|
||||||
cfg := configForDC(w.hdc)
|
cfg := configForDC(w.hdc)
|
||||||
cfg.Now = time.Now()
|
cfg.now = time.Now()
|
||||||
w.w.event(DrawEvent{
|
w.w.event(DrawEvent{
|
||||||
Size: image.Point{
|
Size: image.Point{
|
||||||
X: w.width,
|
X: w.width,
|
||||||
@@ -487,16 +486,16 @@ func convertKeyCode(code uintptr) (rune, bool) {
|
|||||||
return r, true
|
return r, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func configForDC(hdc syscall.Handle) ui.Config {
|
func configForDC(hdc syscall.Handle) Config {
|
||||||
dpi := getDeviceCaps(hdc, _LOGPIXELSX)
|
dpi := getDeviceCaps(hdc, _LOGPIXELSX)
|
||||||
ppdp := float32(dpi) * inchPrDp * monitorScale
|
ppdp := float32(dpi) * inchPrDp * monitorScale
|
||||||
// Force a minimum density to keep text legible and to handle bogus output geometry.
|
// Force a minimum density to keep text legible and to handle bogus output geometry.
|
||||||
if ppdp < minDensity {
|
if ppdp < minDensity {
|
||||||
ppdp = minDensity
|
ppdp = minDensity
|
||||||
}
|
}
|
||||||
return ui.Config{
|
return Config{
|
||||||
PxPerDp: ppdp,
|
pxPerDp: ppdp,
|
||||||
PxPerSp: ppdp,
|
pxPerSp: ppdp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ func (s *Scroll) Dragging() bool {
|
|||||||
return s.dragging
|
return s.dragging
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scroll) Scroll(cfg *ui.Config, q input.Events, axis Axis) int {
|
func (s *Scroll) Scroll(cfg ui.Config, q input.Events, axis Axis) int {
|
||||||
if s.axis != axis {
|
if s.axis != axis {
|
||||||
s.axis = axis
|
s.axis = axis
|
||||||
return 0
|
return 0
|
||||||
@@ -165,15 +165,15 @@ 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 := float32(cfg.Pixels(touchSlop)), fling.Distance; d >= slop || -slop >= d {
|
if slop, d := float32(cfg.Px(touchSlop)), fling.Distance; d >= slop || -slop >= d {
|
||||||
if min, v := float32(cfg.Pixels(minFlingVelocity)), fling.Velocity; v >= min || -min >= v {
|
if min, v := float32(cfg.Px(minFlingVelocity)), fling.Velocity; v >= min || -min >= v {
|
||||||
max := float32(cfg.Pixels(maxFlingVelocity))
|
max := float32(cfg.Px(maxFlingVelocity))
|
||||||
if v > max {
|
if v > max {
|
||||||
v = max
|
v = max
|
||||||
} else if v < -max {
|
} else if v < -max {
|
||||||
v = -max
|
v = -max
|
||||||
}
|
}
|
||||||
s.flinger.Init(cfg.Now, v)
|
s.flinger.Init(cfg.Now(), v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
@@ -200,7 +200,7 @@ func (s *Scroll) Scroll(cfg *ui.Config, q input.Events, axis Axis) int {
|
|||||||
v := int(math.Round(float64(val)))
|
v := int(math.Round(float64(val)))
|
||||||
dist := s.last - v
|
dist := s.last - v
|
||||||
if e.Priority < pointer.Grabbed {
|
if e.Priority < pointer.Grabbed {
|
||||||
slop := cfg.Pixels(touchSlop)
|
slop := cfg.Px(touchSlop)
|
||||||
if dist := dist; dist >= slop || -slop >= dist {
|
if dist := dist; dist >= slop || -slop >= dist {
|
||||||
s.grab = true
|
s.grab = true
|
||||||
}
|
}
|
||||||
@@ -210,7 +210,7 @@ func (s *Scroll) Scroll(cfg *ui.Config, q input.Events, axis Axis) int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
total += s.flinger.Tick(cfg.Now)
|
total += s.flinger.Tick(cfg.Now())
|
||||||
return total
|
return total
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -96,14 +96,14 @@ type Insets struct {
|
|||||||
cs Constraints
|
cs Constraints
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *Insets) Begin(c *ui.Config, ops *ui.Ops, cs Constraints) Constraints {
|
func (in *Insets) Begin(c ui.Config, ops *ui.Ops, cs Constraints) Constraints {
|
||||||
if in.begun {
|
if in.begun {
|
||||||
panic("must End before Begin")
|
panic("must End before Begin")
|
||||||
}
|
}
|
||||||
in.top = c.Pixels(in.Top)
|
in.top = c.Px(in.Top)
|
||||||
in.right = c.Pixels(in.Right)
|
in.right = c.Px(in.Right)
|
||||||
in.bottom = c.Pixels(in.Bottom)
|
in.bottom = c.Px(in.Bottom)
|
||||||
in.left = c.Pixels(in.Left)
|
in.left = c.Px(in.Left)
|
||||||
in.begun = true
|
in.begun = true
|
||||||
in.ops = ops
|
in.ops = ops
|
||||||
in.cs = cs
|
in.cs = cs
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ type scrollChild struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type List struct {
|
type List struct {
|
||||||
Config *ui.Config
|
Config ui.Config
|
||||||
Inputs input.Events
|
Inputs input.Events
|
||||||
Axis Axis
|
Axis Axis
|
||||||
Invert bool
|
Invert bool
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Faces struct {
|
type Faces struct {
|
||||||
Config *ui.Config
|
Config ui.Config
|
||||||
faceCache map[faceKey]*textFace
|
faceCache map[faceKey]*textFace
|
||||||
layoutCache map[layoutKey]cachedLayout
|
layoutCache map[layoutKey]cachedLayout
|
||||||
pathCache map[pathKey]cachedPath
|
pathCache map[pathKey]cachedPath
|
||||||
@@ -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.Pixels(f.size) * 64)
|
ppem := fixed.Int26_6(f.faces.Config.Px(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.Pixels(f.size) * 64)
|
ppem := fixed.Int26_6(f.faces.Config.Px(f.size) * 64)
|
||||||
pk := pathKey{
|
pk := pathKey{
|
||||||
f: f.font.Font,
|
f: f.font.Font,
|
||||||
ppem: ppem,
|
ppem: ppem,
|
||||||
|
|||||||
+10
-9
@@ -21,7 +21,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Editor struct {
|
type Editor struct {
|
||||||
Config *ui.Config
|
Config ui.Config
|
||||||
Inputs input.Events
|
Inputs input.Events
|
||||||
Face Face
|
Face Face
|
||||||
Alignment Alignment
|
Alignment Alignment
|
||||||
@@ -32,7 +32,7 @@ type Editor struct {
|
|||||||
Hint string
|
Hint string
|
||||||
HintMaterial ui.BlockOp
|
HintMaterial ui.BlockOp
|
||||||
|
|
||||||
oldCfg ui.Config
|
oldScale int
|
||||||
blinkStart time.Time
|
blinkStart time.Time
|
||||||
focused bool
|
focused bool
|
||||||
rr editBuffer
|
rr editBuffer
|
||||||
@@ -73,9 +73,10 @@ func (s ChangeEvent) isEditorEvent() {}
|
|||||||
func (s SubmitEvent) isEditorEvent() {}
|
func (s SubmitEvent) isEditorEvent() {}
|
||||||
|
|
||||||
func (e *Editor) Next() (EditorEvent, bool) {
|
func (e *Editor) Next() (EditorEvent, bool) {
|
||||||
if cfg := *e.Config; cfg != e.oldCfg {
|
// Crude configuration change detection.
|
||||||
|
if scale := e.Config.Px(ui.Sp(100)); scale != e.oldScale {
|
||||||
e.invalidate()
|
e.invalidate()
|
||||||
e.oldCfg = cfg
|
e.oldScale = scale
|
||||||
}
|
}
|
||||||
sbounds := e.scrollBounds()
|
sbounds := e.scrollBounds()
|
||||||
var smin, smax int
|
var smin, smax int
|
||||||
@@ -104,7 +105,7 @@ func (e *Editor) Next() (EditorEvent, bool) {
|
|||||||
switch {
|
switch {
|
||||||
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 = e.Config.Now
|
e.blinkStart = e.Config.Now()
|
||||||
e.moveCoord(image.Point{
|
e.moveCoord(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))),
|
||||||
@@ -123,7 +124,7 @@ func (e *Editor) Next() (EditorEvent, bool) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
e.blinkStart = e.Config.Now
|
e.blinkStart = e.Config.Now()
|
||||||
switch ke := ke.(type) {
|
switch ke := ke.(type) {
|
||||||
case key.FocusEvent:
|
case key.FocusEvent:
|
||||||
e.focused = ke.Focus
|
e.focused = ke.Focus
|
||||||
@@ -153,7 +154,7 @@ func (e *Editor) Next() (EditorEvent, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *Editor) caretWidth() fixed.Int26_6 {
|
func (e *Editor) caretWidth() fixed.Int26_6 {
|
||||||
oneDp := e.Config.Dp(1)
|
oneDp := e.Config.Px(ui.Dp(1))
|
||||||
return fixed.Int26_6(oneDp * 64)
|
return fixed.Int26_6(oneDp * 64)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +168,7 @@ func (e *Editor) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
twoDp := e.Config.Dp(2)
|
twoDp := e.Config.Px(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 {
|
||||||
@@ -225,7 +226,7 @@ func (e *Editor) Layout(ops *ui.Ops, cs layout.Constraints) layout.Dimens {
|
|||||||
ui.PopOp{}.Add(ops)
|
ui.PopOp{}.Add(ops)
|
||||||
}
|
}
|
||||||
if e.focused {
|
if e.focused {
|
||||||
now := e.Config.Now
|
now := e.Config.Now()
|
||||||
dt := now.Sub(e.blinkStart)
|
dt := now.Sub(e.blinkStart)
|
||||||
blinking := dt < maxBlinkDuration
|
blinking := dt < maxBlinkDuration
|
||||||
const timePerBlink = time.Second / blinksPerSecond
|
const timePerBlink = time.Second / blinksPerSecond
|
||||||
|
|||||||
@@ -11,41 +11,13 @@ import (
|
|||||||
"gioui.org/ui/internal/ops"
|
"gioui.org/ui/internal/ops"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config contains the essential configuration for
|
// Config represents the essential configuration for
|
||||||
// updating and drawing a user interface.
|
// updating and drawing a user interface.
|
||||||
type Config struct {
|
type Config interface {
|
||||||
// Device pixels per dp.
|
// Now returns the current animation time.
|
||||||
PxPerDp float32
|
Now() time.Time
|
||||||
// Device pixels per sp.
|
// Px converts a Value to pixels.
|
||||||
PxPerSp float32
|
Px(v Value) int
|
||||||
// The current time for animation.
|
|
||||||
Now time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dp converts a value in dp units to pixels.
|
|
||||||
func (c *Config) Dp(dp float32) int {
|
|
||||||
return c.Pixels(Dp(dp))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sp converts a value in sp units to pixels.
|
|
||||||
func (c *Config) Sp(sp float32) int {
|
|
||||||
return c.Pixels(Sp(sp))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pixels converts a value to pixels.
|
|
||||||
func (c *Config) Pixels(v Value) int {
|
|
||||||
var r float32
|
|
||||||
switch v.U {
|
|
||||||
case UnitPx:
|
|
||||||
r = v.V
|
|
||||||
case UnitDp:
|
|
||||||
r = c.PxPerDp * v.V
|
|
||||||
case UnitSp:
|
|
||||||
r = c.PxPerSp * v.V
|
|
||||||
default:
|
|
||||||
panic("unknown unit")
|
|
||||||
}
|
|
||||||
return int(math.Round(float64(r)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LayerOp represents a semantic layer of UI.
|
// LayerOp represents a semantic layer of UI.
|
||||||
|
|||||||
+2
-2
@@ -23,13 +23,13 @@ type Image struct {
|
|||||||
Scale float32
|
Scale float32
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
||||||
wf, hf := float32(size.Dx()), float32(size.Dy())
|
wf, hf := float32(size.Dx()), float32(size.Dy())
|
||||||
var w, h int
|
var w, h int
|
||||||
if im.Scale == 0 {
|
if im.Scale == 0 {
|
||||||
const dpPrPx = 160 / 72
|
const dpPrPx = 160 / 72
|
||||||
w, h = c.Dp(wf*dpPrPx), c.Dp(hf*dpPrPx)
|
w, h = c.Px(ui.Dp(wf*dpPrPx)), c.Px(ui.Dp(hf*dpPrPx))
|
||||||
} else {
|
} else {
|
||||||
w, h = int(wf*im.Scale+.5), int(hf*im.Scale+.5)
|
w, h = int(wf*im.Scale+.5), int(hf*im.Scale+.5)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user