mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
all: [API] replace unit.Value with separate unit.Dp, unit.Sp types
The unit.Value is a struct and thus more inconvenient to use than its
underlying float32 type. In addition, most uses don't need a general
value, but rather a specific unit given by the context. This change
replaces unit.Value with two float32 units, Dp and Sp. It also changes
variables and parameters of unit.Value to a specific unit type matching
the context. That is, unit.Dp everywhere except for text sizes which are
in Sp.
Switching to typed float32s has multiple advantages
- They can be constants:
const touchSlop = unit.Dp(16)
- Casting untyped constants is no longer necessary:
insets := layout.UniformInset(16)
- Calculation with values is natural:
func (s ScrollbarStyle) Width() unit.Dp {
return s.Indicator.MinorWidth + s.Track.MinorPadding + s.Track.MinorPadding
}
The main API change is that calls to gtx.Px must be replaced with either
gtx.Dp or gtx.Sp depending on the unit.
Idea by Christophe Meessen.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+2
-2
@@ -35,7 +35,7 @@ func FuzzIME(f *testing.F) {
|
|||||||
var r router.Router
|
var r router.Router
|
||||||
gtx := layout.Context{Ops: new(op.Ops), Queue: &r}
|
gtx := layout.Context{Ops: new(op.Ops), Queue: &r}
|
||||||
// Layout once to register focus.
|
// Layout once to register focus.
|
||||||
e.Layout(gtx, cache, text.Font{}, unit.Px(10), nil)
|
e.Layout(gtx, cache, text.Font{}, unit.Sp(10), nil)
|
||||||
r.Frame(gtx.Ops)
|
r.Frame(gtx.Ops)
|
||||||
|
|
||||||
var state editorState
|
var state editorState
|
||||||
@@ -103,7 +103,7 @@ func FuzzIME(f *testing.F) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmds = cmds[cmdLen:]
|
cmds = cmds[cmdLen:]
|
||||||
e.Layout(gtx, cache, text.Font{}, unit.Px(10), nil)
|
e.Layout(gtx, cache, text.Font{}, unit.Sp(10), nil)
|
||||||
r.Frame(gtx.Ops)
|
r.Frame(gtx.Ops)
|
||||||
newState := r.EditorState()
|
newState := r.EditorState()
|
||||||
// We don't track caret position.
|
// We don't track caret position.
|
||||||
|
|||||||
+10
-8
@@ -154,7 +154,7 @@ type window struct {
|
|||||||
|
|
||||||
dpi int
|
dpi int
|
||||||
fontScale float32
|
fontScale float32
|
||||||
insets system.Insets
|
insets image.Rectangle
|
||||||
|
|
||||||
stage system.Stage
|
stage system.Stage
|
||||||
started bool
|
started bool
|
||||||
@@ -586,12 +586,7 @@ func Java_org_gioui_GioView_onFocusChange(env *C.JNIEnv, class C.jclass, view C.
|
|||||||
//export Java_org_gioui_GioView_onWindowInsets
|
//export Java_org_gioui_GioView_onWindowInsets
|
||||||
func Java_org_gioui_GioView_onWindowInsets(env *C.JNIEnv, class C.jclass, view C.jlong, top, right, bottom, left C.jint) {
|
func Java_org_gioui_GioView_onWindowInsets(env *C.JNIEnv, class C.jclass, view C.jlong, top, right, bottom, left C.jint) {
|
||||||
w := cgo.Handle(view).Value().(*window)
|
w := cgo.Handle(view).Value().(*window)
|
||||||
w.insets = system.Insets{
|
w.insets = image.Rect(int(left), int(top), int(right), int(bottom))
|
||||||
Top: unit.Px(float32(top)),
|
|
||||||
Bottom: unit.Px(float32(bottom)),
|
|
||||||
Left: unit.Px(float32(left)),
|
|
||||||
Right: unit.Px(float32(right)),
|
|
||||||
}
|
|
||||||
if w.stage >= system.StageRunning {
|
if w.stage >= system.StageRunning {
|
||||||
w.draw(env, true)
|
w.draw(env, true)
|
||||||
}
|
}
|
||||||
@@ -830,11 +825,18 @@ func (w *window) draw(env *C.JNIEnv, sync bool) {
|
|||||||
}
|
}
|
||||||
const inchPrDp = 1.0 / 160
|
const inchPrDp = 1.0 / 160
|
||||||
ppdp := float32(w.dpi) * inchPrDp
|
ppdp := float32(w.dpi) * inchPrDp
|
||||||
|
dppp := unit.Dp(1.0 / ppdp)
|
||||||
|
insets := system.Insets{
|
||||||
|
Top: unit.Dp(w.insets.Min.Y) * dppp,
|
||||||
|
Bottom: unit.Dp(w.insets.Max.Y) * dppp,
|
||||||
|
Left: unit.Dp(w.insets.Min.X) * dppp,
|
||||||
|
Right: unit.Dp(w.insets.Max.X) * dppp,
|
||||||
|
}
|
||||||
w.callbacks.Event(frameEvent{
|
w.callbacks.Event(frameEvent{
|
||||||
FrameEvent: system.FrameEvent{
|
FrameEvent: system.FrameEvent{
|
||||||
Now: time.Now(),
|
Now: time.Now(),
|
||||||
Size: w.config.Size,
|
Size: w.config.Size,
|
||||||
Insets: w.insets,
|
Insets: insets,
|
||||||
Metric: unit.Metric{
|
Metric: unit.Metric{
|
||||||
PxPerDp: ppdp,
|
PxPerDp: ppdp,
|
||||||
PxPerSp: w.fontScale * ppdp,
|
PxPerSp: w.fontScale * ppdp,
|
||||||
|
|||||||
+10
-8
@@ -150,6 +150,11 @@ func (w *window) draw(sync bool) {
|
|||||||
w.w.Event(system.StageEvent{Stage: system.StageRunning})
|
w.w.Event(system.StageEvent{Stage: system.StageRunning})
|
||||||
}
|
}
|
||||||
const inchPrDp = 1.0 / 163
|
const inchPrDp = 1.0 / 163
|
||||||
|
m := unit.Metric{
|
||||||
|
PxPerDp: float32(params.dpi) * inchPrDp,
|
||||||
|
PxPerSp: float32(params.sdpi) * inchPrDp,
|
||||||
|
}
|
||||||
|
dppp := unit.Dp(1. / m.PxPerDp)
|
||||||
w.w.Event(frameEvent{
|
w.w.Event(frameEvent{
|
||||||
FrameEvent: system.FrameEvent{
|
FrameEvent: system.FrameEvent{
|
||||||
Now: time.Now(),
|
Now: time.Now(),
|
||||||
@@ -158,15 +163,12 @@ func (w *window) draw(sync bool) {
|
|||||||
Y: int(params.height + .5),
|
Y: int(params.height + .5),
|
||||||
},
|
},
|
||||||
Insets: system.Insets{
|
Insets: system.Insets{
|
||||||
Top: unit.Px(float32(params.top)),
|
Top: unit.Dp(params.top) * dppp,
|
||||||
Bottom: unit.Px(float32(params.bottom)),
|
Bottom: unit.Dp(params.bottom) * dppp,
|
||||||
Left: unit.Px(float32(params.left)),
|
Left: unit.Dp(params.left) * dppp,
|
||||||
Right: unit.Px(float32(params.right)),
|
Right: unit.Dp(params.right) * dppp,
|
||||||
},
|
|
||||||
Metric: unit.Metric{
|
|
||||||
PxPerDp: float32(params.dpi) * inchPrDp,
|
|
||||||
PxPerSp: float32(params.sdpi) * inchPrDp,
|
|
||||||
},
|
},
|
||||||
|
Metric: m,
|
||||||
},
|
},
|
||||||
Sync: sync,
|
Sync: sync,
|
||||||
})
|
})
|
||||||
|
|||||||
+3
-2
@@ -643,10 +643,11 @@ func (w *window) draw(sync bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) getConfig() (image.Point, system.Insets, unit.Metric) {
|
func (w *window) getConfig() (image.Point, system.Insets, unit.Metric) {
|
||||||
|
invscale := unit.Dp(1. / w.scale)
|
||||||
return image.Pt(w.config.Size.X, w.config.Size.Y),
|
return image.Pt(w.config.Size.X, w.config.Size.Y),
|
||||||
system.Insets{
|
system.Insets{
|
||||||
Bottom: unit.Px(w.inset.Y),
|
Bottom: unit.Dp(w.inset.Y) * invscale,
|
||||||
Right: unit.Px(w.inset.X),
|
Right: unit.Dp(w.inset.X) * invscale,
|
||||||
}, unit.Metric{
|
}, unit.Metric{
|
||||||
PxPerDp: w.scale,
|
PxPerDp: w.scale,
|
||||||
PxPerSp: w.scale,
|
PxPerSp: w.scale,
|
||||||
|
|||||||
+22
-22
@@ -138,7 +138,7 @@ var ackEvent event.Event
|
|||||||
// iOS, Android, WebAssembly.
|
// iOS, Android, WebAssembly.
|
||||||
func NewWindow(options ...Option) *Window {
|
func NewWindow(options ...Option) *Window {
|
||||||
defaultOptions := []Option{
|
defaultOptions := []Option{
|
||||||
Size(unit.Dp(800), unit.Dp(600)),
|
Size(800, 600),
|
||||||
Title("Gio"),
|
Title("Gio"),
|
||||||
}
|
}
|
||||||
options = append(defaultOptions, options...)
|
options = append(defaultOptions, options...)
|
||||||
@@ -546,8 +546,8 @@ func (w *Window) moveFocus(dir router.FocusDirection, d driver) {
|
|||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const scrollABit = 50
|
const scrollABit = unit.Dp(50)
|
||||||
dist := v.Mul(w.metric.Px(unit.Dp(scrollABit)))
|
dist := v.Mul(int(w.metric.Dp(scrollABit)))
|
||||||
w.queue.q.ScrollFocus(dist)
|
w.queue.q.ScrollFocus(dist)
|
||||||
}
|
}
|
||||||
w.setNextFrame(time.Time{})
|
w.setNextFrame(time.Time{})
|
||||||
@@ -805,12 +805,12 @@ func (w *Window) processEvent(d driver, e event.Event) bool {
|
|||||||
wrapper.Reset()
|
wrapper.Reset()
|
||||||
viewport := image.Rectangle{
|
viewport := image.Rectangle{
|
||||||
Min: image.Point{
|
Min: image.Point{
|
||||||
X: e2.Metric.Px(e2.Insets.Left),
|
X: e2.Metric.Dp(e2.Insets.Left),
|
||||||
Y: e2.Metric.Px(e2.Insets.Top),
|
Y: e2.Metric.Dp(e2.Insets.Top),
|
||||||
},
|
},
|
||||||
Max: image.Point{
|
Max: image.Point{
|
||||||
X: e2.Size.X - e2.Metric.Px(e2.Insets.Right),
|
X: e2.Size.X - e2.Metric.Dp(e2.Insets.Right),
|
||||||
Y: e2.Size.Y - e2.Metric.Px(e2.Insets.Bottom),
|
Y: e2.Size.Y - e2.Metric.Dp(e2.Insets.Bottom),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Scroll to focus if viewport is shrinking in any dimension.
|
// Scroll to focus if viewport is shrinking in any dimension.
|
||||||
@@ -1034,50 +1034,50 @@ func Title(t string) Option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Size sets the size of the window. The mode will be changed to Windowed.
|
// Size sets the size of the window. The mode will be changed to Windowed.
|
||||||
func Size(w, h unit.Value) Option {
|
func Size(w, h unit.Dp) Option {
|
||||||
if w.V <= 0 {
|
if w <= 0 {
|
||||||
panic("width must be larger than or equal to 0")
|
panic("width must be larger than or equal to 0")
|
||||||
}
|
}
|
||||||
if h.V <= 0 {
|
if h <= 0 {
|
||||||
panic("height must be larger than or equal to 0")
|
panic("height must be larger than or equal to 0")
|
||||||
}
|
}
|
||||||
return func(m unit.Metric, cnf *Config) {
|
return func(m unit.Metric, cnf *Config) {
|
||||||
cnf.Mode = Windowed
|
cnf.Mode = Windowed
|
||||||
cnf.Size = image.Point{
|
cnf.Size = image.Point{
|
||||||
X: m.Px(w),
|
X: m.Dp(w),
|
||||||
Y: m.Px(h),
|
Y: m.Dp(h),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MaxSize sets the maximum size of the window.
|
// MaxSize sets the maximum size of the window.
|
||||||
func MaxSize(w, h unit.Value) Option {
|
func MaxSize(w, h unit.Dp) Option {
|
||||||
if w.V <= 0 {
|
if w <= 0 {
|
||||||
panic("width must be larger than or equal to 0")
|
panic("width must be larger than or equal to 0")
|
||||||
}
|
}
|
||||||
if h.V <= 0 {
|
if h <= 0 {
|
||||||
panic("height must be larger than or equal to 0")
|
panic("height must be larger than or equal to 0")
|
||||||
}
|
}
|
||||||
return func(m unit.Metric, cnf *Config) {
|
return func(m unit.Metric, cnf *Config) {
|
||||||
cnf.MaxSize = image.Point{
|
cnf.MaxSize = image.Point{
|
||||||
X: m.Px(w),
|
X: m.Dp(w),
|
||||||
Y: m.Px(h),
|
Y: m.Dp(h),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MinSize sets the minimum size of the window.
|
// MinSize sets the minimum size of the window.
|
||||||
func MinSize(w, h unit.Value) Option {
|
func MinSize(w, h unit.Dp) Option {
|
||||||
if w.V <= 0 {
|
if w <= 0 {
|
||||||
panic("width must be larger than or equal to 0")
|
panic("width must be larger than or equal to 0")
|
||||||
}
|
}
|
||||||
if h.V <= 0 {
|
if h <= 0 {
|
||||||
panic("height must be larger than or equal to 0")
|
panic("height must be larger than or equal to 0")
|
||||||
}
|
}
|
||||||
return func(m unit.Metric, cnf *Config) {
|
return func(m unit.Metric, cnf *Config) {
|
||||||
cnf.MinSize = image.Point{
|
cnf.MinSize = image.Point{
|
||||||
X: m.Px(w),
|
X: m.Dp(w),
|
||||||
Y: m.Px(h),
|
Y: m.Dp(h),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -157,7 +157,7 @@ const (
|
|||||||
StateFlinging
|
StateFlinging
|
||||||
)
|
)
|
||||||
|
|
||||||
var touchSlop = unit.Dp(3)
|
const touchSlop = unit.Dp(3)
|
||||||
|
|
||||||
// Add the handler to the operation list to receive click events.
|
// Add the handler to the operation list to receive click events.
|
||||||
func (c *Click) Add(ops *op.Ops) {
|
func (c *Click) Add(ops *op.Ops) {
|
||||||
@@ -303,7 +303,7 @@ func (s *Scroll) Scroll(cfg unit.Metric, q event.Queue, t time.Time, axis Axis)
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
fling := s.estimator.Estimate()
|
fling := s.estimator.Estimate()
|
||||||
if slop, d := float32(cfg.Px(touchSlop)), fling.Distance; d < -slop || d > slop {
|
if slop, d := float32(cfg.Dp(touchSlop)), fling.Distance; d < -slop || d > slop {
|
||||||
s.flinger.Start(cfg, t, fling.Velocity)
|
s.flinger.Start(cfg, t, fling.Velocity)
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
@@ -329,7 +329,7 @@ func (s *Scroll) Scroll(cfg unit.Metric, q event.Queue, t time.Time, axis Axis)
|
|||||||
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.Px(touchSlop)
|
slop := cfg.Dp(touchSlop)
|
||||||
if dist := dist; dist >= slop || -slop >= dist {
|
if dist := dist; dist >= slop || -slop >= dist {
|
||||||
s.grab = true
|
s.grab = true
|
||||||
}
|
}
|
||||||
@@ -407,7 +407,7 @@ func (d *Drag) Events(cfg unit.Metric, q event.Queue, axis Axis) []pointer.Event
|
|||||||
}
|
}
|
||||||
if e.Priority < pointer.Grabbed {
|
if e.Priority < pointer.Grabbed {
|
||||||
diff := e.Position.Sub(d.start)
|
diff := e.Position.Sub(d.start)
|
||||||
slop := cfg.Px(touchSlop)
|
slop := cfg.Dp(touchSlop)
|
||||||
if diff.X*diff.X+diff.Y*diff.Y > float32(slop*slop) {
|
if diff.X*diff.X+diff.Y*diff.Y > float32(slop*slop) {
|
||||||
d.grab = true
|
d.grab = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,25 +19,22 @@ type Animation struct {
|
|||||||
v0 float32
|
v0 float32
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
// Pixels/second.
|
|
||||||
minFlingVelocity = unit.Dp(50)
|
|
||||||
maxFlingVelocity = unit.Dp(8000)
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// dp/second.
|
||||||
|
minFlingVelocity = unit.Dp(50)
|
||||||
|
maxFlingVelocity = unit.Dp(8000)
|
||||||
thresholdVelocity = 1
|
thresholdVelocity = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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.Metric, 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.Dp(minFlingVelocity))
|
||||||
v := velocity
|
v := velocity
|
||||||
if -min <= v && v <= min {
|
if -min <= v && v <= min {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
max := float32(c.Px(maxFlingVelocity))
|
max := float32(c.Dp(maxFlingVelocity))
|
||||||
if v > max {
|
if v > max {
|
||||||
v = max
|
v = max
|
||||||
} else if v < -max {
|
} else if v < -max {
|
||||||
|
|||||||
+2
-1
@@ -45,7 +45,8 @@ type DestroyEvent struct {
|
|||||||
// system decoration such as translucent
|
// system decoration such as translucent
|
||||||
// system bars and software keyboards.
|
// system bars and software keyboards.
|
||||||
type Insets struct {
|
type Insets struct {
|
||||||
Top, Bottom, Left, Right unit.Value
|
// Values are in pixels.
|
||||||
|
Top, Bottom, Left, Right unit.Dp
|
||||||
}
|
}
|
||||||
|
|
||||||
// A StageEvent is generated whenever the stage of a
|
// A StageEvent is generated whenever the stage of a
|
||||||
|
|||||||
+12
-7
@@ -52,15 +52,15 @@ func NewContext(ops *op.Ops, e system.FrameEvent) Context {
|
|||||||
size := e.Size
|
size := e.Size
|
||||||
|
|
||||||
if e.Insets != (system.Insets{}) {
|
if e.Insets != (system.Insets{}) {
|
||||||
left := e.Metric.Px(e.Insets.Left)
|
left := e.Metric.Dp(e.Insets.Left)
|
||||||
top := e.Metric.Px(e.Insets.Top)
|
top := e.Metric.Dp(e.Insets.Top)
|
||||||
op.Offset(image.Point{
|
op.Offset(image.Point{
|
||||||
X: left,
|
X: left,
|
||||||
Y: top,
|
Y: top,
|
||||||
}).Add(ops)
|
}).Add(ops)
|
||||||
|
|
||||||
size.X -= left + e.Metric.Px(e.Insets.Right)
|
size.X -= left + e.Metric.Dp(e.Insets.Right)
|
||||||
size.Y -= top + e.Metric.Px(e.Insets.Bottom)
|
size.Y -= top + e.Metric.Dp(e.Insets.Bottom)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Context{
|
return Context{
|
||||||
@@ -72,9 +72,14 @@ func NewContext(ops *op.Ops, e system.FrameEvent) Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Px maps the value to pixels.
|
// Dp converts v to pixels.
|
||||||
func (c Context) Px(v unit.Value) int {
|
func (c Context) Dp(v unit.Dp) int {
|
||||||
return c.Metric.Px(v)
|
return c.Metric.Dp(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sp converts v to pixels.
|
||||||
|
func (c Context) Sp(v unit.Sp) int {
|
||||||
|
return c.Metric.Sp(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Events returns the events available for the key. If no
|
// Events returns the events available for the key. If no
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ For example, to add space above a widget:
|
|||||||
var gtx layout.Context
|
var gtx layout.Context
|
||||||
|
|
||||||
// Configure a top inset.
|
// Configure a top inset.
|
||||||
inset := layout.Inset{Top: unit.Dp(8), ...}
|
inset := layout.Inset{Top: 8, ...}
|
||||||
// Use the inset to lay out a widget.
|
// Use the inset to lay out a widget.
|
||||||
inset.Layout(gtx, func() {
|
inset.Layout(gtx, func() {
|
||||||
// Lay out widget and determine its size given the constraints
|
// Lay out widget and determine its size given the constraints
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
|
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/op"
|
"gioui.org/op"
|
||||||
"gioui.org/unit"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleInset() {
|
func ExampleInset() {
|
||||||
@@ -19,7 +18,7 @@ func ExampleInset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Inset all edges by 10.
|
// Inset all edges by 10.
|
||||||
inset := layout.UniformInset(unit.Dp(10))
|
inset := layout.UniformInset(10)
|
||||||
dims := inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
dims := inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
// Lay out a 50x50 sized widget.
|
// Lay out a 50x50 sized widget.
|
||||||
dims := layoutWidget(gtx, 50, 50)
|
dims := layoutWidget(gtx, 50, 50)
|
||||||
|
|||||||
+9
-9
@@ -113,15 +113,15 @@ func (c Constraints) Constrain(size image.Point) image.Point {
|
|||||||
// constraints. The minimum constraints will be adjusted to ensure
|
// constraints. The minimum constraints will be adjusted to ensure
|
||||||
// they do not exceed the maximum.
|
// they do not exceed the maximum.
|
||||||
type Inset struct {
|
type Inset struct {
|
||||||
Top, Bottom, Left, Right unit.Value
|
Top, Bottom, Left, Right unit.Dp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Layout a widget.
|
// Layout a widget.
|
||||||
func (in Inset) Layout(gtx Context, w Widget) Dimensions {
|
func (in Inset) Layout(gtx Context, w Widget) Dimensions {
|
||||||
top := gtx.Px(in.Top)
|
top := gtx.Dp(in.Top)
|
||||||
right := gtx.Px(in.Right)
|
right := gtx.Dp(in.Right)
|
||||||
bottom := gtx.Px(in.Bottom)
|
bottom := gtx.Dp(in.Bottom)
|
||||||
left := gtx.Px(in.Left)
|
left := gtx.Dp(in.Left)
|
||||||
mcs := gtx.Constraints
|
mcs := gtx.Constraints
|
||||||
mcs.Max.X -= left + right
|
mcs.Max.X -= left + right
|
||||||
if mcs.Max.X < 0 {
|
if mcs.Max.X < 0 {
|
||||||
@@ -153,7 +153,7 @@ func (in Inset) Layout(gtx Context, w Widget) Dimensions {
|
|||||||
|
|
||||||
// UniformInset returns an Inset with a single inset applied to all
|
// UniformInset returns an Inset with a single inset applied to all
|
||||||
// edges.
|
// edges.
|
||||||
func UniformInset(v unit.Value) Inset {
|
func UniformInset(v unit.Dp) Inset {
|
||||||
return Inset{Top: v, Right: v, Bottom: v, Left: v}
|
return Inset{Top: v, Right: v, Bottom: v, Left: v}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,14 +213,14 @@ func (d Direction) Position(widget, bounds image.Point) image.Point {
|
|||||||
|
|
||||||
// Spacer adds space between widgets.
|
// Spacer adds space between widgets.
|
||||||
type Spacer struct {
|
type Spacer struct {
|
||||||
Width, Height unit.Value
|
Width, Height unit.Dp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Spacer) Layout(gtx Context) Dimensions {
|
func (s Spacer) Layout(gtx Context) Dimensions {
|
||||||
return Dimensions{
|
return Dimensions{
|
||||||
Size: image.Point{
|
Size: image.Point{
|
||||||
X: gtx.Px(s.Width),
|
X: gtx.Dp(s.Width),
|
||||||
Y: gtx.Px(s.Height),
|
Y: gtx.Dp(s.Height),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-114
@@ -2,9 +2,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Package unit implements device independent units and values.
|
Package unit implements device independent units.
|
||||||
|
|
||||||
A Value is a value with a Unit attached.
|
|
||||||
|
|
||||||
Device independent pixel, or dp, is the unit for sizes independent of
|
Device independent pixel, or dp, is the unit for sizes independent of
|
||||||
the underlying display device.
|
the underlying display device.
|
||||||
@@ -23,19 +21,9 @@ values.
|
|||||||
package unit
|
package unit
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Value is a value with a unit.
|
|
||||||
type Value struct {
|
|
||||||
V float32
|
|
||||||
U Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unit represents a unit for a Value.
|
|
||||||
type Unit uint8
|
|
||||||
|
|
||||||
// Metric converts Values to device-dependent pixels, px. The zero
|
// Metric converts Values to device-dependent pixels, px. The zero
|
||||||
// value represents a 1-to-1 scale from dp, sp to pixels.
|
// value represents a 1-to-1 scale from dp, sp to pixels.
|
||||||
type Metric struct {
|
type Metric struct {
|
||||||
@@ -45,113 +33,29 @@ type Metric struct {
|
|||||||
PxPerSp float32
|
PxPerSp float32
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
type (
|
||||||
// UnitPx represent device pixels in the resolution of
|
// Dp represents device independent pixels. 1 dp will
|
||||||
// the underlying display.
|
|
||||||
UnitPx Unit = iota
|
|
||||||
// UnitDp represents device independent pixels. 1 dp will
|
|
||||||
// have the same apparent size across platforms and
|
// have the same apparent size across platforms and
|
||||||
// display resolutions.
|
// display resolutions.
|
||||||
UnitDp
|
Dp float32
|
||||||
// UnitSp is like UnitDp but for font sizes.
|
// Sp is like UnitDp but for font sizes.
|
||||||
UnitSp
|
Sp float32
|
||||||
)
|
)
|
||||||
|
|
||||||
// Px returns the Value for v device pixels.
|
// Dp converts v to pixels, rounded to the nearest integer value.
|
||||||
func Px(v float32) Value {
|
func (c Metric) Dp(v Dp) int {
|
||||||
return Value{V: v, U: UnitPx}
|
s := c.PxPerDp
|
||||||
}
|
if s == 0. {
|
||||||
|
s = 1.
|
||||||
// Dp returns the Value for v device independent
|
|
||||||
// pixels.
|
|
||||||
func Dp(v float32) Value {
|
|
||||||
return Value{V: v, U: UnitDp}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sp returns the Value for v scaled dps.
|
|
||||||
func Sp(v float32) Value {
|
|
||||||
return Value{V: v, U: UnitSp}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scale returns the value scaled by s.
|
|
||||||
func (v Value) Scale(s float32) Value {
|
|
||||||
v.V *= s
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v Value) String() string {
|
|
||||||
return fmt.Sprintf("%g%s", v.V, v.U)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u Unit) String() string {
|
|
||||||
switch u {
|
|
||||||
case UnitPx:
|
|
||||||
return "px"
|
|
||||||
case UnitDp:
|
|
||||||
return "dp"
|
|
||||||
case UnitSp:
|
|
||||||
return "sp"
|
|
||||||
default:
|
|
||||||
panic("unknown unit")
|
|
||||||
}
|
}
|
||||||
|
return int(math.Round(float64(s) * float64(v)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a list of Values.
|
// Sp converts v to pixels, rounded to the nearest integer value.
|
||||||
func Add(c Metric, values ...Value) Value {
|
func (c Metric) Sp(v Sp) int {
|
||||||
var sum Value
|
s := c.PxPerSp
|
||||||
for _, v := range values {
|
if s == 0. {
|
||||||
sum, v = compatible(c, sum, v)
|
s = 1.
|
||||||
sum.V += v.V
|
|
||||||
}
|
}
|
||||||
return sum
|
return int(math.Round(float64(s) * float64(v)))
|
||||||
}
|
|
||||||
|
|
||||||
// Max returns the maximum of a list of Values.
|
|
||||||
func Max(c Metric, values ...Value) Value {
|
|
||||||
var max Value
|
|
||||||
for _, v := range values {
|
|
||||||
max, v = compatible(c, max, v)
|
|
||||||
if v.V > max.V {
|
|
||||||
max.V = v.V
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return max
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
return v1, v2
|
|
||||||
}
|
|
||||||
if v1.V == 0 {
|
|
||||||
v1.U = v2.U
|
|
||||||
return v1, v2
|
|
||||||
}
|
|
||||||
if v2.V == 0 {
|
|
||||||
v2.U = v1.U
|
|
||||||
return v1, v2
|
|
||||||
}
|
|
||||||
return Px(float32(c.Px(v1))), Px(float32(c.Px(v2)))
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -15,16 +15,16 @@ import (
|
|||||||
// Border lays out a widget and draws a border inside it.
|
// Border lays out a widget and draws a border inside it.
|
||||||
type Border struct {
|
type Border struct {
|
||||||
Color color.NRGBA
|
Color color.NRGBA
|
||||||
CornerRadius unit.Value
|
CornerRadius unit.Dp
|
||||||
Width unit.Value
|
Width unit.Dp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b Border) Layout(gtx layout.Context, w layout.Widget) layout.Dimensions {
|
func (b Border) Layout(gtx layout.Context, w layout.Widget) layout.Dimensions {
|
||||||
dims := w(gtx)
|
dims := w(gtx)
|
||||||
sz := dims.Size
|
sz := dims.Size
|
||||||
|
|
||||||
rr := gtx.Px(b.CornerRadius)
|
rr := gtx.Dp(b.CornerRadius)
|
||||||
width := gtx.Px(b.Width)
|
width := gtx.Dp(b.Width)
|
||||||
sz.X -= width
|
sz.X -= width
|
||||||
sz.Y -= width
|
sz.Y -= width
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"gioui.org/io/system"
|
"gioui.org/io/system"
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/op/clip"
|
"gioui.org/op/clip"
|
||||||
"gioui.org/unit"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Decorations handles the states of window decorations.
|
// Decorations handles the states of window decorations.
|
||||||
@@ -67,7 +66,7 @@ func (d *Decorations) Clickable(action system.Action) *Clickable {
|
|||||||
// LayoutResize lays out the resize actions.
|
// LayoutResize lays out the resize actions.
|
||||||
func (d *Decorations) LayoutResize(gtx layout.Context, actions system.Action) {
|
func (d *Decorations) LayoutResize(gtx layout.Context, actions system.Action) {
|
||||||
cs := gtx.Constraints.Max
|
cs := gtx.Constraints.Max
|
||||||
wh := gtx.Px(unit.Dp(10))
|
wh := gtx.Dp(10)
|
||||||
s := []struct {
|
s := []struct {
|
||||||
system.Action
|
system.Action
|
||||||
image.Rectangle
|
image.Rectangle
|
||||||
|
|||||||
+3
-3
@@ -497,12 +497,12 @@ func (e *Editor) calculateViewSize(gtx layout.Context) image.Point {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Layout lays out the editor. If content is not nil, it is laid out on top.
|
// Layout lays out the editor. If content is not nil, it is laid out on top.
|
||||||
func (e *Editor) Layout(gtx layout.Context, sh text.Shaper, font text.Font, size unit.Value, content layout.Widget) layout.Dimensions {
|
func (e *Editor) Layout(gtx layout.Context, sh text.Shaper, font text.Font, size unit.Sp, content layout.Widget) layout.Dimensions {
|
||||||
if e.locale != gtx.Locale {
|
if e.locale != gtx.Locale {
|
||||||
e.locale = gtx.Locale
|
e.locale = gtx.Locale
|
||||||
e.invalidate()
|
e.invalidate()
|
||||||
}
|
}
|
||||||
textSize := fixed.I(gtx.Px(size))
|
textSize := fixed.I(gtx.Sp(size))
|
||||||
if e.font != font || e.textSize != textSize {
|
if e.font != font || e.textSize != textSize {
|
||||||
e.invalidate()
|
e.invalidate()
|
||||||
e.font = font
|
e.font = font
|
||||||
@@ -776,7 +776,7 @@ func (e *Editor) PaintText(gtx layout.Context) {
|
|||||||
// caretWidth returns the width occupied by the caret for the current
|
// caretWidth returns the width occupied by the caret for the current
|
||||||
// gtx.
|
// gtx.
|
||||||
func (e *Editor) caretWidth(gtx layout.Context) int {
|
func (e *Editor) caretWidth(gtx layout.Context) int {
|
||||||
carWidth2 := gtx.Px(unit.Dp(1)) / 2
|
carWidth2 := gtx.Dp(1) / 2
|
||||||
if carWidth2 < 1 {
|
if carWidth2 < 1 {
|
||||||
carWidth2 = 1
|
carWidth2 = 1
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-12
@@ -47,7 +47,7 @@ func TestEditorZeroDimensions(t *testing.T) {
|
|||||||
Locale: english,
|
Locale: english,
|
||||||
}
|
}
|
||||||
cache := text.NewCache(gofont.Collection())
|
cache := text.NewCache(gofont.Collection())
|
||||||
fontSize := unit.Px(10)
|
fontSize := unit.Sp(10)
|
||||||
font := text.Font{}
|
font := text.Font{}
|
||||||
e := new(Editor)
|
e := new(Editor)
|
||||||
dims := e.Layout(gtx, cache, font, fontSize, nil)
|
dims := e.Layout(gtx, cache, font, fontSize, nil)
|
||||||
@@ -63,7 +63,7 @@ func TestEditorConfigurations(t *testing.T) {
|
|||||||
Locale: english,
|
Locale: english,
|
||||||
}
|
}
|
||||||
cache := text.NewCache(gofont.Collection())
|
cache := text.NewCache(gofont.Collection())
|
||||||
fontSize := unit.Px(10)
|
fontSize := unit.Sp(10)
|
||||||
font := text.Font{}
|
font := text.Font{}
|
||||||
sentence := "\n\n\n\n\n\n\n\n\n\n\n\nthe quick brown fox jumps over the lazy dog"
|
sentence := "\n\n\n\n\n\n\n\n\n\n\n\nthe quick brown fox jumps over the lazy dog"
|
||||||
runes := len([]rune(sentence))
|
runes := len([]rune(sentence))
|
||||||
@@ -103,7 +103,7 @@ func TestEditor(t *testing.T) {
|
|||||||
Locale: english,
|
Locale: english,
|
||||||
}
|
}
|
||||||
cache := text.NewCache(gofont.Collection())
|
cache := text.NewCache(gofont.Collection())
|
||||||
fontSize := unit.Px(10)
|
fontSize := unit.Sp(10)
|
||||||
font := text.Font{}
|
font := text.Font{}
|
||||||
|
|
||||||
// Regression test for bad in-cluster rune offset math.
|
// Regression test for bad in-cluster rune offset math.
|
||||||
@@ -206,7 +206,7 @@ func TestEditorRTL(t *testing.T) {
|
|||||||
Locale: arabic,
|
Locale: arabic,
|
||||||
}
|
}
|
||||||
cache := text.NewCache(arabicCollection)
|
cache := text.NewCache(arabicCollection)
|
||||||
fontSize := unit.Px(10)
|
fontSize := unit.Sp(10)
|
||||||
font := text.Font{}
|
font := text.Font{}
|
||||||
|
|
||||||
e.SetCaret(0, 0) // shouldn't panic
|
e.SetCaret(0, 0) // shouldn't panic
|
||||||
@@ -282,7 +282,7 @@ func TestEditorLigature(t *testing.T) {
|
|||||||
Face: face,
|
Face: face,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
fontSize := unit.Px(10)
|
fontSize := unit.Sp(10)
|
||||||
font := text.Font{}
|
font := text.Font{}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -399,7 +399,7 @@ func TestEditorDimensions(t *testing.T) {
|
|||||||
Locale: english,
|
Locale: english,
|
||||||
}
|
}
|
||||||
cache := text.NewCache(gofont.Collection())
|
cache := text.NewCache(gofont.Collection())
|
||||||
fontSize := unit.Px(10)
|
fontSize := unit.Sp(10)
|
||||||
font := text.Font{}
|
font := text.Font{}
|
||||||
dims := e.Layout(gtx, cache, font, fontSize, nil)
|
dims := e.Layout(gtx, cache, font, fontSize, nil)
|
||||||
if dims.Size.X == 0 {
|
if dims.Size.X == 0 {
|
||||||
@@ -446,7 +446,7 @@ func TestEditorCaretConsistency(t *testing.T) {
|
|||||||
Locale: english,
|
Locale: english,
|
||||||
}
|
}
|
||||||
cache := text.NewCache(gofont.Collection())
|
cache := text.NewCache(gofont.Collection())
|
||||||
fontSize := unit.Px(10)
|
fontSize := unit.Sp(10)
|
||||||
font := text.Font{}
|
font := text.Font{}
|
||||||
for _, a := range []text.Alignment{text.Start, text.Middle, text.End} {
|
for _, a := range []text.Alignment{text.Start, text.Middle, text.End} {
|
||||||
e := &Editor{
|
e := &Editor{
|
||||||
@@ -539,7 +539,7 @@ func TestEditorMoveWord(t *testing.T) {
|
|||||||
Locale: english,
|
Locale: english,
|
||||||
}
|
}
|
||||||
cache := text.NewCache(gofont.Collection())
|
cache := text.NewCache(gofont.Collection())
|
||||||
fontSize := unit.Px(10)
|
fontSize := unit.Sp(10)
|
||||||
font := text.Font{}
|
font := text.Font{}
|
||||||
e.SetText(t)
|
e.SetText(t)
|
||||||
e.Layout(gtx, cache, font, fontSize, nil)
|
e.Layout(gtx, cache, font, fontSize, nil)
|
||||||
@@ -644,7 +644,7 @@ func TestEditorInsert(t *testing.T) {
|
|||||||
Locale: english,
|
Locale: english,
|
||||||
}
|
}
|
||||||
cache := text.NewCache(gofont.Collection())
|
cache := text.NewCache(gofont.Collection())
|
||||||
fontSize := unit.Px(10)
|
fontSize := unit.Sp(10)
|
||||||
font := text.Font{}
|
font := text.Font{}
|
||||||
e.SetText(t)
|
e.SetText(t)
|
||||||
e.Layout(gtx, cache, font, fontSize, nil)
|
e.Layout(gtx, cache, font, fontSize, nil)
|
||||||
@@ -734,7 +734,7 @@ func TestEditorDeleteWord(t *testing.T) {
|
|||||||
Locale: english,
|
Locale: english,
|
||||||
}
|
}
|
||||||
cache := text.NewCache(gofont.Collection())
|
cache := text.NewCache(gofont.Collection())
|
||||||
fontSize := unit.Px(10)
|
fontSize := unit.Sp(10)
|
||||||
font := text.Font{}
|
font := text.Font{}
|
||||||
e.SetText(t)
|
e.SetText(t)
|
||||||
e.Layout(gtx, cache, font, fontSize, nil)
|
e.Layout(gtx, cache, font, fontSize, nil)
|
||||||
@@ -789,7 +789,7 @@ g 2 4 6 8 g
|
|||||||
}
|
}
|
||||||
cache := text.NewCache(gofont.Collection())
|
cache := text.NewCache(gofont.Collection())
|
||||||
font := text.Font{}
|
font := text.Font{}
|
||||||
fontSize := unit.Px(10)
|
fontSize := unit.Sp(10)
|
||||||
|
|
||||||
selected := func(start, end int) string {
|
selected := func(start, end int) string {
|
||||||
// Layout once with no events; populate e.lines.
|
// Layout once with no events; populate e.lines.
|
||||||
@@ -879,7 +879,7 @@ func TestSelectMove(t *testing.T) {
|
|||||||
}
|
}
|
||||||
cache := text.NewCache(gofont.Collection())
|
cache := text.NewCache(gofont.Collection())
|
||||||
font := text.Font{}
|
font := text.Font{}
|
||||||
fontSize := unit.Px(10)
|
fontSize := unit.Sp(10)
|
||||||
|
|
||||||
// Layout once to populate e.lines and get focus.
|
// Layout once to populate e.lines and get focus.
|
||||||
gtx.Queue = newQueue(key.FocusEvent{Focus: true})
|
gtx.Queue = newQueue(key.FocusEvent{Focus: true})
|
||||||
|
|||||||
+2
-2
@@ -24,7 +24,7 @@ type Icon struct {
|
|||||||
imgColor color.NRGBA
|
imgColor color.NRGBA
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultIconSize = unit.Dp(24)
|
const defaultIconSize = unit.Dp(24)
|
||||||
|
|
||||||
// NewIcon returns a new Icon from IconVG data.
|
// NewIcon returns a new Icon from IconVG data.
|
||||||
func NewIcon(data []byte) (*Icon, error) {
|
func NewIcon(data []byte) (*Icon, error) {
|
||||||
@@ -39,7 +39,7 @@ func NewIcon(data []byte) (*Icon, error) {
|
|||||||
func (ic *Icon) Layout(gtx layout.Context, color color.NRGBA) layout.Dimensions {
|
func (ic *Icon) Layout(gtx layout.Context, color color.NRGBA) layout.Dimensions {
|
||||||
sz := gtx.Constraints.Min.X
|
sz := gtx.Constraints.Min.X
|
||||||
if sz == 0 {
|
if sz == 0 {
|
||||||
sz = gtx.Metric.Px(defaultIconSize)
|
sz = gtx.Dp(defaultIconSize)
|
||||||
}
|
}
|
||||||
size := gtx.Constraints.Constrain(image.Pt(sz, sz))
|
size := gtx.Constraints.Constrain(image.Pt(sz, sz))
|
||||||
defer clip.Rect{Max: size}.Push(gtx.Ops).Pop()
|
defer clip.Rect{Max: size}.Push(gtx.Ops).Pop()
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@ func (im Image) Layout(gtx layout.Context) layout.Dimensions {
|
|||||||
|
|
||||||
size := im.Src.Size()
|
size := im.Src.Size()
|
||||||
wf, hf := float32(size.X), float32(size.Y)
|
wf, hf := float32(size.X), float32(size.Y)
|
||||||
w, h := gtx.Px(unit.Dp(wf*scale)), gtx.Px(unit.Dp(hf*scale))
|
w, h := gtx.Dp(unit.Dp(wf*scale)), gtx.Dp(unit.Dp(hf*scale))
|
||||||
|
|
||||||
dims, trans := im.Fit.scale(gtx.Constraints, im.Position, layout.Dimensions{Size: image.Pt(w, h)})
|
dims, trans := im.Fit.scale(gtx.Constraints, im.Position, layout.Dimensions{Size: image.Pt(w, h)})
|
||||||
defer clip.Rect{Max: dims.Size}.Push(gtx.Ops).Pop()
|
defer clip.Rect{Max: dims.Size}.Push(gtx.Ops).Pop()
|
||||||
|
|||||||
+2
-2
@@ -96,9 +96,9 @@ func (p1 screenPos) Less(p2 screenPos) bool {
|
|||||||
return p1.Y < p2.Y || (p1.Y == p2.Y && p1.X < p2.X)
|
return p1.Y < p2.Y || (p1.Y == p2.Y && p1.X < p2.X)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l Label) Layout(gtx layout.Context, s text.Shaper, font text.Font, size unit.Value, txt string) layout.Dimensions {
|
func (l Label) Layout(gtx layout.Context, s text.Shaper, font text.Font, size unit.Sp, txt string) layout.Dimensions {
|
||||||
cs := gtx.Constraints
|
cs := gtx.Constraints
|
||||||
textSize := fixed.I(gtx.Px(size))
|
textSize := fixed.I(gtx.Sp(size))
|
||||||
lines := s.LayoutString(font, textSize, cs.Max.X, gtx.Locale, txt)
|
lines := s.LayoutString(font, textSize, cs.Max.X, gtx.Locale, txt)
|
||||||
if max := l.MaxLines; max > 0 && len(lines) > max {
|
if max := l.MaxLines; max > 0 && len(lines) > max {
|
||||||
lines = lines[:max]
|
lines = lines[:max]
|
||||||
|
|||||||
+13
-13
@@ -23,9 +23,9 @@ type ButtonStyle struct {
|
|||||||
// Color is the text color.
|
// Color is the text color.
|
||||||
Color color.NRGBA
|
Color color.NRGBA
|
||||||
Font text.Font
|
Font text.Font
|
||||||
TextSize unit.Value
|
TextSize unit.Sp
|
||||||
Background color.NRGBA
|
Background color.NRGBA
|
||||||
CornerRadius unit.Value
|
CornerRadius unit.Dp
|
||||||
Inset layout.Inset
|
Inset layout.Inset
|
||||||
Button *widget.Clickable
|
Button *widget.Clickable
|
||||||
shaper text.Shaper
|
shaper text.Shaper
|
||||||
@@ -33,7 +33,7 @@ type ButtonStyle struct {
|
|||||||
|
|
||||||
type ButtonLayoutStyle struct {
|
type ButtonLayoutStyle struct {
|
||||||
Background color.NRGBA
|
Background color.NRGBA
|
||||||
CornerRadius unit.Value
|
CornerRadius unit.Dp
|
||||||
Button *widget.Clickable
|
Button *widget.Clickable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ type IconButtonStyle struct {
|
|||||||
Color color.NRGBA
|
Color color.NRGBA
|
||||||
Icon *widget.Icon
|
Icon *widget.Icon
|
||||||
// Size is the icon size.
|
// Size is the icon size.
|
||||||
Size unit.Value
|
Size unit.Dp
|
||||||
Inset layout.Inset
|
Inset layout.Inset
|
||||||
Button *widget.Clickable
|
Button *widget.Clickable
|
||||||
Description string
|
Description string
|
||||||
@@ -53,12 +53,12 @@ func Button(th *Theme, button *widget.Clickable, txt string) ButtonStyle {
|
|||||||
return ButtonStyle{
|
return ButtonStyle{
|
||||||
Text: txt,
|
Text: txt,
|
||||||
Color: th.Palette.ContrastFg,
|
Color: th.Palette.ContrastFg,
|
||||||
CornerRadius: unit.Dp(4),
|
CornerRadius: 4,
|
||||||
Background: th.Palette.ContrastBg,
|
Background: th.Palette.ContrastBg,
|
||||||
TextSize: th.TextSize.Scale(14.0 / 16.0),
|
TextSize: th.TextSize * 14.0 / 16.0,
|
||||||
Inset: layout.Inset{
|
Inset: layout.Inset{
|
||||||
Top: unit.Dp(10), Bottom: unit.Dp(10),
|
Top: 10, Bottom: 10,
|
||||||
Left: unit.Dp(12), Right: unit.Dp(12),
|
Left: 12, Right: 12,
|
||||||
},
|
},
|
||||||
Button: button,
|
Button: button,
|
||||||
shaper: th.Shaper,
|
shaper: th.Shaper,
|
||||||
@@ -69,7 +69,7 @@ func ButtonLayout(th *Theme, button *widget.Clickable) ButtonLayoutStyle {
|
|||||||
return ButtonLayoutStyle{
|
return ButtonLayoutStyle{
|
||||||
Button: button,
|
Button: button,
|
||||||
Background: th.Palette.ContrastBg,
|
Background: th.Palette.ContrastBg,
|
||||||
CornerRadius: unit.Dp(4),
|
CornerRadius: 4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,8 +78,8 @@ func IconButton(th *Theme, button *widget.Clickable, icon *widget.Icon, descript
|
|||||||
Background: th.Palette.ContrastBg,
|
Background: th.Palette.ContrastBg,
|
||||||
Color: th.Palette.ContrastFg,
|
Color: th.Palette.ContrastFg,
|
||||||
Icon: icon,
|
Icon: icon,
|
||||||
Size: unit.Dp(24),
|
Size: 24,
|
||||||
Inset: layout.UniformInset(unit.Dp(12)),
|
Inset: layout.UniformInset(12),
|
||||||
Button: button,
|
Button: button,
|
||||||
Description: description,
|
Description: description,
|
||||||
}
|
}
|
||||||
@@ -129,7 +129,7 @@ func (b ButtonLayoutStyle) Layout(gtx layout.Context, w layout.Widget) layout.Di
|
|||||||
semantic.Button.Add(gtx.Ops)
|
semantic.Button.Add(gtx.Ops)
|
||||||
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
||||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||||
rr := gtx.Px(b.CornerRadius)
|
rr := gtx.Dp(b.CornerRadius)
|
||||||
defer clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, rr).Push(gtx.Ops).Pop()
|
defer clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, rr).Push(gtx.Ops).Pop()
|
||||||
background := b.Background
|
background := b.Background
|
||||||
switch {
|
switch {
|
||||||
@@ -178,7 +178,7 @@ func (b IconButtonStyle) Layout(gtx layout.Context) layout.Dimensions {
|
|||||||
}),
|
}),
|
||||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||||
return b.Inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
return b.Inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
size := gtx.Px(b.Size)
|
size := gtx.Dp(b.Size)
|
||||||
if b.Icon != nil {
|
if b.Icon != nil {
|
||||||
gtx.Constraints.Min = image.Point{X: size}
|
gtx.Constraints.Min = image.Point{X: size}
|
||||||
b.Icon.Layout(gtx, b.Color)
|
b.Icon.Layout(gtx, b.Color)
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ type checkable struct {
|
|||||||
Label string
|
Label string
|
||||||
Color color.NRGBA
|
Color color.NRGBA
|
||||||
Font text.Font
|
Font text.Font
|
||||||
TextSize unit.Value
|
TextSize unit.Sp
|
||||||
IconColor color.NRGBA
|
IconColor color.NRGBA
|
||||||
Size unit.Value
|
Size unit.Dp
|
||||||
shaper text.Shaper
|
shaper text.Shaper
|
||||||
checkedStateIcon *widget.Icon
|
checkedStateIcon *widget.Icon
|
||||||
uncheckedStateIcon *widget.Icon
|
uncheckedStateIcon *widget.Icon
|
||||||
@@ -39,7 +39,7 @@ func (c *checkable) layout(gtx layout.Context, checked, hovered bool) layout.Dim
|
|||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
||||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||||
size := gtx.Px(c.Size) * 4 / 3
|
size := gtx.Dp(c.Size) * 4 / 3
|
||||||
dims := layout.Dimensions{
|
dims := layout.Dimensions{
|
||||||
Size: image.Point{X: size, Y: size},
|
Size: image.Point{X: size, Y: size},
|
||||||
}
|
}
|
||||||
@@ -55,8 +55,8 @@ func (c *checkable) layout(gtx layout.Context, checked, hovered bool) layout.Dim
|
|||||||
return dims
|
return dims
|
||||||
}),
|
}),
|
||||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||||
return layout.UniformInset(unit.Dp(2)).Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
return layout.UniformInset(2).Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
size := gtx.Px(c.Size)
|
size := gtx.Dp(c.Size)
|
||||||
col := c.IconColor
|
col := c.IconColor
|
||||||
if gtx.Queue == nil {
|
if gtx.Queue == nil {
|
||||||
col = f32color.Disabled(col)
|
col = f32color.Disabled(col)
|
||||||
@@ -72,7 +72,7 @@ func (c *checkable) layout(gtx layout.Context, checked, hovered bool) layout.Dim
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
return layout.UniformInset(unit.Dp(2)).Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
return layout.UniformInset(2).Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
paint.ColorOp{Color: c.Color}.Add(gtx.Ops)
|
paint.ColorOp{Color: c.Color}.Add(gtx.Ops)
|
||||||
return widget.Label{}.Layout(gtx, c.shaper, c.Font, c.TextSize, c.Label)
|
return widget.Label{}.Layout(gtx, c.shaper, c.Font, c.TextSize, c.Label)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ package material
|
|||||||
import (
|
import (
|
||||||
"gioui.org/io/semantic"
|
"gioui.org/io/semantic"
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/unit"
|
|
||||||
"gioui.org/widget"
|
"gioui.org/widget"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,8 +20,8 @@ func CheckBox(th *Theme, checkBox *widget.Bool, label string) CheckBoxStyle {
|
|||||||
Label: label,
|
Label: label,
|
||||||
Color: th.Palette.Fg,
|
Color: th.Palette.Fg,
|
||||||
IconColor: th.Palette.ContrastBg,
|
IconColor: th.Palette.ContrastBg,
|
||||||
TextSize: th.TextSize.Scale(14.0 / 16.0),
|
TextSize: th.TextSize * 14.0 / 16.0,
|
||||||
Size: unit.Dp(26),
|
Size: 26,
|
||||||
shaper: th.Shaper,
|
shaper: th.Shaper,
|
||||||
checkedStateIcon: th.Icon.CheckBoxChecked,
|
checkedStateIcon: th.Icon.CheckBoxChecked,
|
||||||
uncheckedStateIcon: th.Icon.CheckBoxUnchecked,
|
uncheckedStateIcon: th.Icon.CheckBoxUnchecked,
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func (d *DecorationsStyle) Layout(gtx layout.Context) layout.Dimensions {
|
|||||||
|
|
||||||
func (d *DecorationsStyle) layoutDecorations(gtx layout.Context) layout.Dimensions {
|
func (d *DecorationsStyle) layoutDecorations(gtx layout.Context) layout.Dimensions {
|
||||||
gtx.Constraints.Min.Y = 0
|
gtx.Constraints.Min.Y = 0
|
||||||
inset := layout.UniformInset(unit.Dp(10))
|
inset := layout.UniformInset(10)
|
||||||
return layout.Flex{
|
return layout.Flex{
|
||||||
Axis: layout.Horizontal,
|
Axis: layout.Horizontal,
|
||||||
Alignment: layout.Middle,
|
Alignment: layout.Middle,
|
||||||
@@ -116,7 +116,7 @@ func (d *DecorationsStyle) layoutDecorations(gtx layout.Context) layout.Dimensio
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
const (
|
||||||
winIconSize = unit.Dp(20)
|
winIconSize = unit.Dp(20)
|
||||||
winIconMargin = unit.Dp(4)
|
winIconMargin = unit.Dp(4)
|
||||||
winIconStroke = unit.Dp(2)
|
winIconStroke = unit.Dp(2)
|
||||||
@@ -124,10 +124,10 @@ var (
|
|||||||
|
|
||||||
// minimizeWindows draws a line icon representing the minimize action.
|
// minimizeWindows draws a line icon representing the minimize action.
|
||||||
func minimizeWindow(gtx layout.Context) layout.Dimensions {
|
func minimizeWindow(gtx layout.Context) layout.Dimensions {
|
||||||
size := gtx.Px(winIconSize)
|
size := gtx.Dp(winIconSize)
|
||||||
size32 := float32(size)
|
size32 := float32(size)
|
||||||
margin := float32(gtx.Px(winIconMargin))
|
margin := float32(gtx.Dp(winIconMargin))
|
||||||
width := float32(gtx.Px(winIconStroke))
|
width := float32(gtx.Dp(winIconStroke))
|
||||||
var p clip.Path
|
var p clip.Path
|
||||||
p.Begin(gtx.Ops)
|
p.Begin(gtx.Ops)
|
||||||
p.MoveTo(f32.Point{X: margin, Y: size32 - margin})
|
p.MoveTo(f32.Point{X: margin, Y: size32 - margin})
|
||||||
@@ -143,9 +143,9 @@ func minimizeWindow(gtx layout.Context) layout.Dimensions {
|
|||||||
|
|
||||||
// maximizeWindow draws a rectangle representing the maximize action.
|
// maximizeWindow draws a rectangle representing the maximize action.
|
||||||
func maximizeWindow(gtx layout.Context) layout.Dimensions {
|
func maximizeWindow(gtx layout.Context) layout.Dimensions {
|
||||||
size := gtx.Px(winIconSize)
|
size := gtx.Dp(winIconSize)
|
||||||
margin := gtx.Px(winIconMargin)
|
margin := gtx.Dp(winIconMargin)
|
||||||
width := gtx.Px(winIconStroke)
|
width := gtx.Dp(winIconStroke)
|
||||||
r := clip.RRect{
|
r := clip.RRect{
|
||||||
Rect: image.Rect(margin, margin, size-margin, size-margin),
|
Rect: image.Rect(margin, margin, size-margin, size-margin),
|
||||||
}
|
}
|
||||||
@@ -166,9 +166,9 @@ func maximizeWindow(gtx layout.Context) layout.Dimensions {
|
|||||||
|
|
||||||
// maximizedWindow draws interleaved rectangles representing the un-maximize action.
|
// maximizedWindow draws interleaved rectangles representing the un-maximize action.
|
||||||
func maximizedWindow(gtx layout.Context) layout.Dimensions {
|
func maximizedWindow(gtx layout.Context) layout.Dimensions {
|
||||||
size := gtx.Px(winIconSize)
|
size := gtx.Dp(winIconSize)
|
||||||
margin := gtx.Px(winIconMargin)
|
margin := gtx.Dp(winIconMargin)
|
||||||
width := gtx.Px(winIconStroke)
|
width := gtx.Dp(winIconStroke)
|
||||||
r := clip.RRect{
|
r := clip.RRect{
|
||||||
Rect: image.Rect(margin, margin, size-2*margin, size-2*margin),
|
Rect: image.Rect(margin, margin, size-2*margin, size-2*margin),
|
||||||
}
|
}
|
||||||
@@ -192,10 +192,10 @@ func maximizedWindow(gtx layout.Context) layout.Dimensions {
|
|||||||
|
|
||||||
// closeWindow draws a cross representing the close action.
|
// closeWindow draws a cross representing the close action.
|
||||||
func closeWindow(gtx layout.Context) layout.Dimensions {
|
func closeWindow(gtx layout.Context) layout.Dimensions {
|
||||||
size := gtx.Px(winIconSize)
|
size := gtx.Dp(winIconSize)
|
||||||
size32 := float32(size)
|
size32 := float32(size)
|
||||||
margin := float32(gtx.Px(winIconMargin))
|
margin := float32(gtx.Dp(winIconMargin))
|
||||||
width := float32(gtx.Px(winIconStroke))
|
width := float32(gtx.Dp(winIconStroke))
|
||||||
var p clip.Path
|
var p clip.Path
|
||||||
p.Begin(gtx.Ops)
|
p.Begin(gtx.Ops)
|
||||||
p.MoveTo(f32.Point{X: margin, Y: margin})
|
p.MoveTo(f32.Point{X: margin, Y: margin})
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
|
|
||||||
type EditorStyle struct {
|
type EditorStyle struct {
|
||||||
Font text.Font
|
Font text.Font
|
||||||
TextSize unit.Value
|
TextSize unit.Sp
|
||||||
// Color is the text color.
|
// Color is the text color.
|
||||||
Color color.NRGBA
|
Color color.NRGBA
|
||||||
// Hint contains the text displayed when the editor is empty.
|
// Hint contains the text displayed when the editor is empty.
|
||||||
|
|||||||
+13
-13
@@ -22,47 +22,47 @@ type LabelStyle struct {
|
|||||||
// MaxLines limits the number of lines. Zero means no limit.
|
// MaxLines limits the number of lines. Zero means no limit.
|
||||||
MaxLines int
|
MaxLines int
|
||||||
Text string
|
Text string
|
||||||
TextSize unit.Value
|
TextSize unit.Sp
|
||||||
|
|
||||||
shaper text.Shaper
|
shaper text.Shaper
|
||||||
}
|
}
|
||||||
|
|
||||||
func H1(th *Theme, txt string) LabelStyle {
|
func H1(th *Theme, txt string) LabelStyle {
|
||||||
label := Label(th, th.TextSize.Scale(96.0/16.0), txt)
|
label := Label(th, th.TextSize*96.0/16.0, txt)
|
||||||
label.Font.Weight = text.Light
|
label.Font.Weight = text.Light
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
|
|
||||||
func H2(th *Theme, txt string) LabelStyle {
|
func H2(th *Theme, txt string) LabelStyle {
|
||||||
label := Label(th, th.TextSize.Scale(60.0/16.0), txt)
|
label := Label(th, th.TextSize*60.0/16.0, txt)
|
||||||
label.Font.Weight = text.Light
|
label.Font.Weight = text.Light
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
|
|
||||||
func H3(th *Theme, txt string) LabelStyle {
|
func H3(th *Theme, txt string) LabelStyle {
|
||||||
return Label(th, th.TextSize.Scale(48.0/16.0), txt)
|
return Label(th, th.TextSize*48.0/16.0, txt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func H4(th *Theme, txt string) LabelStyle {
|
func H4(th *Theme, txt string) LabelStyle {
|
||||||
return Label(th, th.TextSize.Scale(34.0/16.0), txt)
|
return Label(th, th.TextSize*34.0/16.0, txt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func H5(th *Theme, txt string) LabelStyle {
|
func H5(th *Theme, txt string) LabelStyle {
|
||||||
return Label(th, th.TextSize.Scale(24.0/16.0), txt)
|
return Label(th, th.TextSize*24.0/16.0, txt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func H6(th *Theme, txt string) LabelStyle {
|
func H6(th *Theme, txt string) LabelStyle {
|
||||||
label := Label(th, th.TextSize.Scale(20.0/16.0), txt)
|
label := Label(th, th.TextSize*20.0/16.0, txt)
|
||||||
label.Font.Weight = text.Medium
|
label.Font.Weight = text.Medium
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
|
|
||||||
func Subtitle1(th *Theme, txt string) LabelStyle {
|
func Subtitle1(th *Theme, txt string) LabelStyle {
|
||||||
return Label(th, th.TextSize.Scale(16.0/16.0), txt)
|
return Label(th, th.TextSize*16.0/16.0, txt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Subtitle2(th *Theme, txt string) LabelStyle {
|
func Subtitle2(th *Theme, txt string) LabelStyle {
|
||||||
label := Label(th, th.TextSize.Scale(14.0/16.0), txt)
|
label := Label(th, th.TextSize*14.0/16.0, txt)
|
||||||
label.Font.Weight = text.Medium
|
label.Font.Weight = text.Medium
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
@@ -72,18 +72,18 @@ func Body1(th *Theme, txt string) LabelStyle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Body2(th *Theme, txt string) LabelStyle {
|
func Body2(th *Theme, txt string) LabelStyle {
|
||||||
return Label(th, th.TextSize.Scale(14.0/16.0), txt)
|
return Label(th, th.TextSize*14.0/16.0, txt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Caption(th *Theme, txt string) LabelStyle {
|
func Caption(th *Theme, txt string) LabelStyle {
|
||||||
return Label(th, th.TextSize.Scale(12.0/16.0), txt)
|
return Label(th, th.TextSize*12.0/16.0, txt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Overline(th *Theme, txt string) LabelStyle {
|
func Overline(th *Theme, txt string) LabelStyle {
|
||||||
return Label(th, th.TextSize.Scale(10.0/16.0), txt)
|
return Label(th, th.TextSize*10.0/16.0, txt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Label(th *Theme, size unit.Value, txt string) LabelStyle {
|
func Label(th *Theme, size unit.Sp, txt string) LabelStyle {
|
||||||
return LabelStyle{
|
return LabelStyle{
|
||||||
Text: txt,
|
Text: txt,
|
||||||
Color: th.Palette.Fg,
|
Color: th.Palette.Fg,
|
||||||
|
|||||||
+16
-16
@@ -50,7 +50,7 @@ type ScrollTrackStyle struct {
|
|||||||
// MajorPadding and MinorPadding along the major and minor axis of the
|
// MajorPadding and MinorPadding along the major and minor axis of the
|
||||||
// scrollbar's track. This is used to keep the scrollbar from touching
|
// scrollbar's track. This is used to keep the scrollbar from touching
|
||||||
// the edges of the content area.
|
// the edges of the content area.
|
||||||
MajorPadding, MinorPadding unit.Value
|
MajorPadding, MinorPadding unit.Dp
|
||||||
// Color of the track background.
|
// Color of the track background.
|
||||||
Color color.NRGBA
|
Color color.NRGBA
|
||||||
}
|
}
|
||||||
@@ -59,16 +59,16 @@ type ScrollTrackStyle struct {
|
|||||||
type ScrollIndicatorStyle struct {
|
type ScrollIndicatorStyle struct {
|
||||||
// MajorMinLen is the smallest that the scroll indicator is allowed to
|
// MajorMinLen is the smallest that the scroll indicator is allowed to
|
||||||
// be along the major axis.
|
// be along the major axis.
|
||||||
MajorMinLen unit.Value
|
MajorMinLen unit.Dp
|
||||||
// MinorWidth is the width of the scroll indicator across the minor axis.
|
// MinorWidth is the width of the scroll indicator across the minor axis.
|
||||||
MinorWidth unit.Value
|
MinorWidth unit.Dp
|
||||||
// Color and HoverColor are the normal and hovered colors of the scroll
|
// Color and HoverColor are the normal and hovered colors of the scroll
|
||||||
// indicator.
|
// indicator.
|
||||||
Color, HoverColor color.NRGBA
|
Color, HoverColor color.NRGBA
|
||||||
// CornerRadius is the corner radius of the rectangular indicator. 0
|
// CornerRadius is the corner radius of the rectangular indicator. 0
|
||||||
// will produce square corners. 0.5*MinorWidth will produce perfectly
|
// will produce square corners. 0.5*MinorWidth will produce perfectly
|
||||||
// round corners.
|
// round corners.
|
||||||
CornerRadius unit.Value
|
CornerRadius unit.Dp
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScrollbarStyle configures the presentation of a scrollbar.
|
// ScrollbarStyle configures the presentation of a scrollbar.
|
||||||
@@ -89,13 +89,13 @@ func Scrollbar(th *Theme, state *widget.Scrollbar) ScrollbarStyle {
|
|||||||
return ScrollbarStyle{
|
return ScrollbarStyle{
|
||||||
Scrollbar: state,
|
Scrollbar: state,
|
||||||
Track: ScrollTrackStyle{
|
Track: ScrollTrackStyle{
|
||||||
MajorPadding: unit.Dp(2),
|
MajorPadding: 2,
|
||||||
MinorPadding: unit.Dp(2),
|
MinorPadding: 2,
|
||||||
},
|
},
|
||||||
Indicator: ScrollIndicatorStyle{
|
Indicator: ScrollIndicatorStyle{
|
||||||
MajorMinLen: unit.Dp(8),
|
MajorMinLen: 8,
|
||||||
MinorWidth: unit.Dp(6),
|
MinorWidth: 6,
|
||||||
CornerRadius: unit.Dp(3),
|
CornerRadius: 3,
|
||||||
Color: lightFg,
|
Color: lightFg,
|
||||||
HoverColor: darkFg,
|
HoverColor: darkFg,
|
||||||
},
|
},
|
||||||
@@ -104,8 +104,8 @@ func Scrollbar(th *Theme, state *widget.Scrollbar) ScrollbarStyle {
|
|||||||
|
|
||||||
// Width returns the minor axis width of the scrollbar in its current
|
// Width returns the minor axis width of the scrollbar in its current
|
||||||
// configuration (taking padding for the scroll track into account).
|
// configuration (taking padding for the scroll track into account).
|
||||||
func (s ScrollbarStyle) Width(metric unit.Metric) unit.Value {
|
func (s ScrollbarStyle) Width() unit.Dp {
|
||||||
return unit.Add(metric, s.Indicator.MinorWidth, s.Track.MinorPadding, s.Track.MinorPadding)
|
return s.Indicator.MinorWidth + s.Track.MinorPadding + s.Track.MinorPadding
|
||||||
}
|
}
|
||||||
|
|
||||||
// Layout the scrollbar.
|
// Layout the scrollbar.
|
||||||
@@ -119,7 +119,7 @@ func (s ScrollbarStyle) Layout(gtx layout.Context, axis layout.Axis, viewportSta
|
|||||||
convert := axis.Convert
|
convert := axis.Convert
|
||||||
maxMajorAxis := convert(gtx.Constraints.Max).X
|
maxMajorAxis := convert(gtx.Constraints.Max).X
|
||||||
gtx.Constraints.Min.X = maxMajorAxis
|
gtx.Constraints.Min.X = maxMajorAxis
|
||||||
gtx.Constraints.Min.Y = gtx.Px(s.Width(gtx.Metric))
|
gtx.Constraints.Min.Y = gtx.Dp(s.Width())
|
||||||
gtx.Constraints.Min = convert(gtx.Constraints.Min)
|
gtx.Constraints.Min = convert(gtx.Constraints.Min)
|
||||||
gtx.Constraints.Max = gtx.Constraints.Min
|
gtx.Constraints.Max = gtx.Constraints.Min
|
||||||
|
|
||||||
@@ -179,15 +179,15 @@ func (s ScrollbarStyle) layout(gtx layout.Context, axis layout.Axis, viewportSta
|
|||||||
trackLen := gtx.Constraints.Min.X
|
trackLen := gtx.Constraints.Min.X
|
||||||
viewStart := int(math.Round(float64(viewportStart) * float64(trackLen)))
|
viewStart := int(math.Round(float64(viewportStart) * float64(trackLen)))
|
||||||
viewEnd := int(math.Round(float64(viewportEnd) * float64(trackLen)))
|
viewEnd := int(math.Round(float64(viewportEnd) * float64(trackLen)))
|
||||||
indicatorLen := max(viewEnd-viewStart, gtx.Px(s.Indicator.MajorMinLen))
|
indicatorLen := max(viewEnd-viewStart, gtx.Dp(s.Indicator.MajorMinLen))
|
||||||
if viewStart+indicatorLen > trackLen {
|
if viewStart+indicatorLen > trackLen {
|
||||||
viewStart = trackLen - indicatorLen
|
viewStart = trackLen - indicatorLen
|
||||||
}
|
}
|
||||||
indicatorDims := axis.Convert(image.Point{
|
indicatorDims := axis.Convert(image.Point{
|
||||||
X: indicatorLen,
|
X: indicatorLen,
|
||||||
Y: gtx.Px(s.Indicator.MinorWidth),
|
Y: gtx.Dp(s.Indicator.MinorWidth),
|
||||||
})
|
})
|
||||||
radius := gtx.Px(s.Indicator.CornerRadius)
|
radius := gtx.Dp(s.Indicator.CornerRadius)
|
||||||
|
|
||||||
// Lay out the indicator.
|
// Lay out the indicator.
|
||||||
offset := axis.Convert(image.Pt(viewStart, 0))
|
offset := axis.Convert(image.Pt(viewStart, 0))
|
||||||
@@ -247,7 +247,7 @@ func (l ListStyle) Layout(gtx layout.Context, length int, w layout.ListElement)
|
|||||||
originalConstraints := gtx.Constraints
|
originalConstraints := gtx.Constraints
|
||||||
|
|
||||||
// Determine how much space the scrollbar occupies.
|
// Determine how much space the scrollbar occupies.
|
||||||
barWidth := gtx.Px(l.Width(gtx.Metric))
|
barWidth := gtx.Dp(l.Width())
|
||||||
|
|
||||||
if l.AnchorStrategy == Occupy {
|
if l.AnchorStrategy == Occupy {
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func TestListAnchorStrategies(t *testing.T) {
|
|||||||
}
|
}
|
||||||
return layout.Dimensions{Size: image.Point{
|
return layout.Dimensions{Size: image.Point{
|
||||||
X: gtx.Constraints.Max.X,
|
X: gtx.Constraints.Max.X,
|
||||||
Y: gtx.Px(unit.Dp(20)),
|
Y: gtx.Dp(20),
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ func TestListAnchorStrategies(t *testing.T) {
|
|||||||
elements := 100
|
elements := 100
|
||||||
th := material.NewTheme(gofont.Collection())
|
th := material.NewTheme(gofont.Collection())
|
||||||
materialList := material.List(th, &list)
|
materialList := material.List(th, &list)
|
||||||
indicatorWidth := gtx.Px(materialList.Width(gtx.Metric))
|
indicatorWidth := gtx.Dp(materialList.Width())
|
||||||
|
|
||||||
materialList.AnchorStrategy = material.Occupy
|
materialList.AnchorStrategy = material.Occupy
|
||||||
occupyDims := materialList.Layout(gtx, elements, space)
|
occupyDims := materialList.Layout(gtx, elements, space)
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
"gioui.org/op"
|
"gioui.org/op"
|
||||||
"gioui.org/op/clip"
|
"gioui.org/op/clip"
|
||||||
"gioui.org/op/paint"
|
"gioui.org/op/paint"
|
||||||
"gioui.org/unit"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type LoaderStyle struct {
|
type LoaderStyle struct {
|
||||||
@@ -32,7 +31,7 @@ func (l LoaderStyle) Layout(gtx layout.Context) layout.Dimensions {
|
|||||||
diam = minY
|
diam = minY
|
||||||
}
|
}
|
||||||
if diam == 0 {
|
if diam == 0 {
|
||||||
diam = gtx.Px(unit.Dp(24))
|
diam = gtx.Dp(24)
|
||||||
}
|
}
|
||||||
sz := gtx.Constraints.Constrain(image.Pt(diam, diam))
|
sz := gtx.Constraints.Constrain(image.Pt(diam, diam))
|
||||||
radius := sz.X / 2
|
radius := sz.X / 2
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ func ProgressBar(th *Theme, progress float32) ProgressBarStyle {
|
|||||||
|
|
||||||
func (p ProgressBarStyle) Layout(gtx layout.Context) layout.Dimensions {
|
func (p ProgressBarStyle) Layout(gtx layout.Context) layout.Dimensions {
|
||||||
shader := func(width int, color color.NRGBA) layout.Dimensions {
|
shader := func(width int, color color.NRGBA) layout.Dimensions {
|
||||||
var maxHeight = unit.Dp(4)
|
const maxHeight = unit.Dp(4)
|
||||||
rr := gtx.Px(unit.Dp(2))
|
rr := gtx.Dp(2)
|
||||||
|
|
||||||
d := image.Point{X: width, Y: gtx.Px(maxHeight)}
|
d := image.Point{X: width, Y: gtx.Dp(maxHeight)}
|
||||||
|
|
||||||
defer clip.UniformRRect(image.Rectangle{Max: image.Pt(width, d.Y)}, rr).Push(gtx.Ops).Pop()
|
defer clip.UniformRRect(image.Rectangle{Max: image.Pt(width, d.Y)}, rr).Push(gtx.Ops).Pop()
|
||||||
paint.ColorOp{Color: color}.Add(gtx.Ops)
|
paint.ColorOp{Color: color}.Add(gtx.Ops)
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/op"
|
"gioui.org/op"
|
||||||
"gioui.org/op/paint"
|
"gioui.org/op/paint"
|
||||||
"gioui.org/unit"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProgressCircleStyle struct {
|
type ProgressCircleStyle struct {
|
||||||
@@ -31,7 +30,7 @@ func (p ProgressCircleStyle) Layout(gtx layout.Context) layout.Dimensions {
|
|||||||
diam = minY
|
diam = minY
|
||||||
}
|
}
|
||||||
if diam == 0 {
|
if diam == 0 {
|
||||||
diam = gtx.Px(unit.Dp(24))
|
diam = gtx.Dp(24)
|
||||||
}
|
}
|
||||||
sz := gtx.Constraints.Constrain(image.Pt(diam, diam))
|
sz := gtx.Constraints.Constrain(image.Pt(diam, diam))
|
||||||
radius := sz.X / 2
|
radius := sz.X / 2
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ package material
|
|||||||
import (
|
import (
|
||||||
"gioui.org/io/semantic"
|
"gioui.org/io/semantic"
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/unit"
|
|
||||||
"gioui.org/widget"
|
"gioui.org/widget"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -25,8 +24,8 @@ func RadioButton(th *Theme, group *widget.Enum, key, label string) RadioButtonSt
|
|||||||
|
|
||||||
Color: th.Palette.Fg,
|
Color: th.Palette.Fg,
|
||||||
IconColor: th.Palette.ContrastBg,
|
IconColor: th.Palette.ContrastBg,
|
||||||
TextSize: th.TextSize.Scale(14.0 / 16.0),
|
TextSize: th.TextSize * 14.0 / 16.0,
|
||||||
Size: unit.Dp(26),
|
Size: 26,
|
||||||
shaper: th.Shaper,
|
shaper: th.Shaper,
|
||||||
checkedStateIcon: th.Icon.RadioChecked,
|
checkedStateIcon: th.Icon.RadioChecked,
|
||||||
uncheckedStateIcon: th.Icon.RadioUnchecked,
|
uncheckedStateIcon: th.Icon.RadioUnchecked,
|
||||||
|
|||||||
@@ -31,19 +31,19 @@ type SliderStyle struct {
|
|||||||
Color color.NRGBA
|
Color color.NRGBA
|
||||||
Float *widget.Float
|
Float *widget.Float
|
||||||
|
|
||||||
FingerSize unit.Value
|
FingerSize unit.Dp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions {
|
func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions {
|
||||||
thumbRadius := gtx.Px(unit.Dp(6))
|
thumbRadius := gtx.Dp(6)
|
||||||
trackWidth := gtx.Px(unit.Dp(2))
|
trackWidth := gtx.Dp(2)
|
||||||
|
|
||||||
axis := s.Float.Axis
|
axis := s.Float.Axis
|
||||||
// Keep a minimum length so that the track is always visible.
|
// Keep a minimum length so that the track is always visible.
|
||||||
minLength := thumbRadius + 3*thumbRadius + thumbRadius
|
minLength := thumbRadius + 3*thumbRadius + thumbRadius
|
||||||
// Try to expand to finger size, but only if the constraints
|
// Try to expand to finger size, but only if the constraints
|
||||||
// allow for it.
|
// allow for it.
|
||||||
touchSizePx := min(gtx.Px(s.FingerSize), axis.Convert(gtx.Constraints.Max).Y)
|
touchSizePx := min(gtx.Dp(s.FingerSize), axis.Convert(gtx.Constraints.Max).Y)
|
||||||
sizeMain := max(axis.Convert(gtx.Constraints.Min).X, minLength)
|
sizeMain := max(axis.Convert(gtx.Constraints.Min).X, minLength)
|
||||||
sizeCross := max(2*thumbRadius, touchSizePx)
|
sizeCross := max(2*thumbRadius, touchSizePx)
|
||||||
size := axis.Convert(image.Pt(sizeMain, sizeCross))
|
size := axis.Convert(image.Pt(sizeMain, sizeCross))
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
"gioui.org/op"
|
"gioui.org/op"
|
||||||
"gioui.org/op/clip"
|
"gioui.org/op/clip"
|
||||||
"gioui.org/op/paint"
|
"gioui.org/op/paint"
|
||||||
"gioui.org/unit"
|
|
||||||
"gioui.org/widget"
|
"gioui.org/widget"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -40,9 +39,9 @@ func Switch(th *Theme, swtch *widget.Bool, description string) SwitchStyle {
|
|||||||
|
|
||||||
// Layout updates the switch and displays it.
|
// Layout updates the switch and displays it.
|
||||||
func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions {
|
func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions {
|
||||||
trackWidth := gtx.Px(unit.Dp(36))
|
trackWidth := gtx.Dp(36)
|
||||||
trackHeight := gtx.Px(unit.Dp(16))
|
trackHeight := gtx.Dp(16)
|
||||||
thumbSize := gtx.Px(unit.Dp(20))
|
thumbSize := gtx.Dp(20)
|
||||||
trackOff := (thumbSize - trackHeight) / 2
|
trackOff := (thumbSize - trackHeight) / 2
|
||||||
|
|
||||||
// Draw track.
|
// Draw track.
|
||||||
@@ -67,7 +66,7 @@ func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions {
|
|||||||
t.Pop()
|
t.Pop()
|
||||||
|
|
||||||
// Draw thumb ink.
|
// Draw thumb ink.
|
||||||
inkSize := gtx.Px(unit.Dp(44))
|
inkSize := gtx.Dp(44)
|
||||||
rr := inkSize / 2
|
rr := inkSize / 2
|
||||||
inkOff := image.Point{
|
inkOff := image.Point{
|
||||||
X: trackWidth/2 - rr,
|
X: trackWidth/2 - rr,
|
||||||
@@ -107,13 +106,13 @@ func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions {
|
|||||||
// Draw thumb shadow, a translucent disc slightly larger than the
|
// Draw thumb shadow, a translucent disc slightly larger than the
|
||||||
// thumb itself.
|
// thumb itself.
|
||||||
// Center shadow horizontally and slightly adjust its Y.
|
// Center shadow horizontally and slightly adjust its Y.
|
||||||
paint.FillShape(gtx.Ops, argb(0x55000000), circle(thumbRadius, thumbRadius+gtx.Px(unit.Dp(.25)), thumbRadius+1))
|
paint.FillShape(gtx.Ops, argb(0x55000000), circle(thumbRadius, thumbRadius+gtx.Dp(.25), thumbRadius+1))
|
||||||
|
|
||||||
// Draw thumb.
|
// Draw thumb.
|
||||||
paint.FillShape(gtx.Ops, col, circle(thumbRadius, thumbRadius, thumbRadius))
|
paint.FillShape(gtx.Ops, col, circle(thumbRadius, thumbRadius, thumbRadius))
|
||||||
|
|
||||||
// Set up click area.
|
// Set up click area.
|
||||||
clickSize := gtx.Px(unit.Dp(40))
|
clickSize := gtx.Dp(40)
|
||||||
clickOff := image.Point{
|
clickOff := image.Point{
|
||||||
X: (thumbSize - clickSize) / 2,
|
X: (thumbSize - clickSize) / 2,
|
||||||
Y: (trackHeight-clickSize)/2 + trackOff,
|
Y: (trackHeight-clickSize)/2 + trackOff,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ type Palette struct {
|
|||||||
type Theme struct {
|
type Theme struct {
|
||||||
Shaper text.Shaper
|
Shaper text.Shaper
|
||||||
Palette
|
Palette
|
||||||
TextSize unit.Value
|
TextSize unit.Sp
|
||||||
Icon struct {
|
Icon struct {
|
||||||
CheckBoxChecked *widget.Icon
|
CheckBoxChecked *widget.Icon
|
||||||
CheckBoxUnchecked *widget.Icon
|
CheckBoxUnchecked *widget.Icon
|
||||||
@@ -43,7 +43,7 @@ type Theme struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FingerSize is the minimum touch target size.
|
// FingerSize is the minimum touch target size.
|
||||||
FingerSize unit.Value
|
FingerSize unit.Dp
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTheme(fontCollection []text.FontFace) *Theme {
|
func NewTheme(fontCollection []text.FontFace) *Theme {
|
||||||
@@ -56,7 +56,7 @@ func NewTheme(fontCollection []text.FontFace) *Theme {
|
|||||||
ContrastBg: rgb(0x3f51b5),
|
ContrastBg: rgb(0x3f51b5),
|
||||||
ContrastFg: rgb(0xffffff),
|
ContrastFg: rgb(0xffffff),
|
||||||
}
|
}
|
||||||
t.TextSize = unit.Sp(16)
|
t.TextSize = 16
|
||||||
|
|
||||||
t.Icon.CheckBoxChecked = mustIcon(widget.NewIcon(icons.ToggleCheckBox))
|
t.Icon.CheckBoxChecked = mustIcon(widget.NewIcon(icons.ToggleCheckBox))
|
||||||
t.Icon.CheckBoxUnchecked = mustIcon(widget.NewIcon(icons.ToggleCheckBoxOutlineBlank))
|
t.Icon.CheckBoxUnchecked = mustIcon(widget.NewIcon(icons.ToggleCheckBoxOutlineBlank))
|
||||||
@@ -64,7 +64,7 @@ func NewTheme(fontCollection []text.FontFace) *Theme {
|
|||||||
t.Icon.RadioUnchecked = mustIcon(widget.NewIcon(icons.ToggleRadioButtonUnchecked))
|
t.Icon.RadioUnchecked = mustIcon(widget.NewIcon(icons.ToggleRadioButtonUnchecked))
|
||||||
|
|
||||||
// 38dp is on the lower end of possible finger size.
|
// 38dp is on the lower end of possible finger size.
|
||||||
t.FingerSize = unit.Dp(38)
|
t.FingerSize = 38
|
||||||
|
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user