966f1abb7672a3e13a6f0abc60205054f588718b — Elias Naur 10 days ago 91079f1 master
cmd/scatter: handle safe area insets correctly

Signed-off-by: Elias Naur <mail@eliasnaur.com>
3 files changed, 69 insertions(+), 82 deletions(-)

M cmd/scatter/ui.go
M go.mod
M go.sum
M cmd/scatter/ui.go => cmd/scatter/ui.go +62 -75
@@ 40,7 40,7 @@ )
  
  type Env struct {
- 	insets app.Insets
+ 	insets layout.Inset
  	faces  measure.Faces
  	client *Client
  	redraw func()


@@ 91,13 91,12 @@ type Topbar struct {
  	Back bool
  
+ 	ops       *ui.Ops
  	backClick gesture.Click
  	stack     layout.Stack
  	insets    layout.Inset
- 	insets2   layout.Inset
  	flex      layout.Flex
  	backChild layout.FlexChild
- 	bg        layout.StackChild
  }
  
  type formField struct {


@@ 282,7 281,12 @@ cfg = &e.Config
  				q := a.w.Queue()
  				a.env.faces.Reset(cfg)
- 				a.env.insets = e.Insets
+ 				a.env.insets = layout.Inset{
+ 					Top:    e.Insets.Top,
+ 					Left:   e.Insets.Left,
+ 					Right:  e.Insets.Right,
+ 					Bottom: e.Insets.Bottom,
+ 				}
  				cs := layout.RigidConstraints(e.Size)
  				a.Layout(cfg, q, ops, cs)
  				if a.profiling {


@@ 451,13 455,11 @@ a.lastMallocs = mstats.Mallocs
  	al := layout.Align{Alignment: layout.NE}
  	cs = al.Begin(ops, cs)
- 	in := layout.Inset{Top: ui.Dp(16)}
- 	in2 := layout.Inset{Top: a.env.insets.Top}
+ 	in := a.env.insets
+ 	in.Top = ui.Max(c, ui.Dp(16), in.Top)
  	cs = in.Begin(c, ops, cs)
- 	cs = in2.Begin(c, ops, cs)
  	txt := fmt.Sprintf("m: %d %s", mallocs, a.profile.Timings)
  	dims := text.Label{Material: theme.text, Face: a.env.faces.For(fonts.mono, ui.Sp(10)), Text: txt}.Layout(ops, cs)
- 	dims = in2.End(dims)
  	dims = in.End(dims)
  	return al.End(dims)
  }


@@ 560,24 562,23 @@ c1 := f.End(dims)
  	cs = f.Flexible(1)
  	cs.Height.Min = cs.Height.Max
- 	sysInset := layout.Inset{
- 		Left:  p.env.insets.Left,
- 		Right: p.env.insets.Right,
- 	}
- 	cs = sysInset.Begin(c, ops, cs)
  	for l.Init(c, q, ops, cs, len(p.contacts)); l.More(); l.Next() {
  		l.End(p.contact(c, ops, l.Constraints(), l.Index()))
  	}
  	dims = l.Layout()
- 	dims = sysInset.End(dims)
  	c2 := f.End(dims)
  	return f.Layout(c1, c2)
  }
  
  func (p *contactsPage) contact(c ui.Config, ops *ui.Ops, cs layout.Constraints, index int) layout.Dimensions {
+ 	in := layout.Inset{
+ 		Top:    ui.Dp(16),
+ 		Bottom: ui.Dp(16),
+ 		Left:   ui.Max(c, ui.Dp(16), p.env.insets.Left),
+ 		Right:  ui.Max(c, ui.Dp(16), p.env.insets.Right),
+ 	}
  	contact := p.contacts[index]
  	click := &p.clicks[index]
- 	in := layout.UniformInset(ui.Dp(8))
  	cs = in.Begin(c, ops, cs)
  	f := (&layout.Flex{Alignment: layout.Middle}).Init(ops, cs)
  	var dims layout.Dimensions


@@ 614,50 615,42 @@ return nil
  }
  
- func (t *Topbar) Begin(c ui.Config, insets app.Insets, ops *ui.Ops, cs layout.Constraints) layout.Constraints {
- 	t.stack = layout.Stack{Alignment: layout.W}
- 	topInset := insets.Top
- 	t.insets2 = layout.Inset{
- 		Top:   topInset,
- 		Left:  insets.Left,
- 		Right: insets.Right,
+ func (t *Topbar) Begin(c ui.Config, insets layout.Inset, ops *ui.Ops, cs layout.Constraints) layout.Constraints {
+ 	t.ops = ops
+ 	t.stack = layout.Stack{Alignment: layout.SW}
+ 	t.insets = layout.Inset{
+ 		Top:    ui.Add(c, insets.Top, ui.Dp(16)),
+ 		Bottom: ui.Dp(16),
+ 		Left:   ui.Max(c, insets.Left, ui.Dp(16)),
+ 		Right:  ui.Max(c, insets.Right, ui.Dp(16)),
  	}
  	t.stack.Init(ops, cs)
  	cs = t.stack.Rigid()
- 	if h := c.Px(topInset) + c.Px(ui.Dp(56)); h < cs.Height.Max {
- 		cs.Height.Max = h
- 	}
- 	dims := fill{theme.brand}.Layout(ops, cs)
- 	t.bg = t.stack.End(dims)
- 	cs = t.stack.Rigid()
- 	cs = t.insets2.Begin(c, ops, cs)
+ 	cs = t.insets.Begin(c, ops, cs)
  	t.flex = layout.Flex{Alignment: layout.Middle}
  	t.flex.Init(ops, cs)
  	cs = t.flex.Rigid()
- 	dims = layout.Dimensions{}
- 	t.insets = layout.UniformInset(ui.Dp(12))
+ 	dims := layout.Dimensions{}
  	if t.Back {
- 		t.insets.Left = ui.Px(0)
  		ico := (&icon{src: icons.NavigationArrowBack, size: ui.Dp(24)}).image(c, rgb(0xffffff))
- 		in := layout.UniformInset(ui.Dp(8))
- 		cs = in.Begin(c, ops, cs)
  		dims = widget.Image{Src: ico, Rect: ico.Bounds(), Scale: 1}.Layout(c, ops, cs)
- 		dims = in.End(dims)
+ 		dims.Size.X += c.Px(ui.Dp(4))
  		pointer.RectAreaOp{Rect: image.Rectangle{Max: dims.Size}}.Add(ops)
  		t.backClick.Add(ops)
  	}
  	t.backChild = t.flex.End(dims)
- 	cs = t.flex.Flexible(1)
- 	return t.insets.Begin(c, ops, cs)
+ 	return t.flex.Flexible(1)
  }
  
  func (t *Topbar) End(dims layout.Dimensions) layout.Dimensions {
- 	dims = t.insets.End(dims)
  	content := t.flex.End(dims)
  	dims = t.flex.Layout(t.backChild, content)
- 	dims = t.insets2.End(dims)
+ 	dims = t.insets.End(dims)
  	stackContent := t.stack.End(dims)
- 	return t.stack.Layout(t.bg, stackContent)
+ 	cs := t.stack.Expand()
+ 	dims = fill{theme.brand}.Layout(t.ops, cs)
+ 	bg := t.stack.End(dims)
+ 	return t.stack.Layout(bg, stackContent)
  }
  
  func newSignInPage(env *Env) *signInPage {


@@ 726,22 719,19 @@ c1 := f.End(dims)
  
  	cs = f.Flexible(1)
- 	sysInset := layout.Inset{
- 		Left:   p.env.insets.Left,
- 		Right:  p.env.insets.Right,
- 		Bottom: p.env.insets.Bottom,
- 	}
- 	cs = sysInset.Begin(c, ops, cs)
  	dims = p.layoutSigninForm(c, q, ops, cs)
- 	dims = sysInset.End(dims)
  	c2 := f.End(dims)
  	return f.Layout(c1, c2)
  }
  
  func (p *signInPage) layoutSigninForm(c ui.Config, q input.Queue, ops *ui.Ops, cs layout.Constraints) layout.Dimensions {
  	l := p.list
+ 	inset := layout.Inset{
+ 		Left:  ui.Max(c, ui.Dp(32), p.env.insets.Left),
+ 		Right: ui.Max(c, ui.Dp(32), p.env.insets.Right),
+ 	}
  	for l.Init(c, q, ops, cs, len(p.fields)+1); l.More(); l.Next() {
- 		in := layout.Inset{Left: ui.Dp(32), Right: ui.Dp(32)}
+ 		in := inset
  		var dims layout.Dimensions
  		switch {
  		case l.Index() < len(p.fields):


@@ 753,7 743,7 @@ dims = p.fields[l.Index()].Layout(c, q, ops, cs)
  			dims = in.End(dims)
  		default:
- 			in.Bottom = ui.Dp(32)
+ 			in.Bottom = ui.Max(c, ui.Dp(32), p.env.insets.Bottom)
  			align := layout.Align{Alignment: layout.E}
  			cs = in.Begin(c, ops, align.Begin(ops, cs))
  			dims = p.submit.Layout(c, p.env, ops, cs)


@@ 904,10 894,6 @@ st := layout.Stack{Alignment: layout.Center}
  	st.Init(ops, cs)
  
- 	sysInset := layout.Inset{
- 		Left:  p.env.insets.Left,
- 		Right: p.env.insets.Right,
- 	}
  	var dims layout.Dimensions
  	cs = st.Rigid()
  	{


@@ 924,22 910,20 @@ c3 := f.End(dims)
  
  		cs = f.Flexible(1)
- 		cs = sysInset.Begin(c, ops, cs)
  		dims = p.layoutThreads(c, q, ops, cs)
- 		dims = sysInset.End(dims)
  		c4 := f.End(dims)
  		dims = f.Layout(c3, c4)
  	}
  	c1 := st.End(dims)
  	cs = st.Rigid()
- 	sysInset.Bottom = p.env.insets.Bottom
- 	cs = sysInset.Begin(c, ops, cs)
  	al := layout.Align{Alignment: layout.SE}
- 	in := layout.UniformInset(ui.Dp(16))
+ 	in := layout.Inset{
+ 		Right:  ui.Max(c, ui.Dp(16), p.env.insets.Right),
+ 		Bottom: ui.Max(c, ui.Dp(16), p.env.insets.Bottom),
+ 	}
  	cs = in.Begin(c, ops, al.Begin(ops, cs))
  	dims = p.fab.Layout(c, p.env, ops, cs)
  	dims = al.End(in.End(dims))
- 	dims = sysInset.End(dims)
  	c2 := st.End(dims)
  	dims = st.Layout(c1, c2)
  	return dims


@@ 956,7 940,7 @@ case 0:
  			in.Top = ui.Dp(4)
  		case len(p.threads) - 1:
- 			in.Bottom = ui.Dp(4)
+ 			in.Bottom = ui.Max(c, ui.Dp(4), p.env.insets.Bottom)
  		}
  		cs := in.Begin(c, ops, l.Constraints())
  		dims := p.thread(c, ops, cs, l.Index())


@@ 985,18 969,23 @@ font = fonts.bold
  	}
  	click := &p.clicks[index]
+ 	in := layout.Inset{
+ 		Left:  ui.Max(c, ui.Dp(16), p.env.insets.Left),
+ 		Right: ui.Max(c, ui.Dp(16), p.env.insets.Right),
+ 	}
+ 	cs = in.Begin(c, ops, cs)
  	elem := layout.Flex{Axis: layout.Vertical}
  	elem.Init(ops, cs)
  	cs = elem.Rigid()
  	var dims layout.Dimensions
  	{
- 		in := layout.UniformInset(ui.Dp(8))
+ 		in := layout.Inset{Top: ui.Dp(8), Bottom: ui.Dp(8)}
  		cs = in.Begin(c, ops, cs)
  		f := centerRowOpts()
  		f.Init(ops, cs)
  		cs = f.Rigid()
  		{
- 			in := layout.Inset{Right: ui.Dp(12), Left: ui.Dp(4)}
+ 			in := layout.Inset{Right: ui.Dp(12)}
  			cc := clipCircle{}
  			cs = cc.Begin(ops, in.Begin(c, ops, cs))
  


@@ 1069,7 1058,8 @@ click.Add(ops)
  	}
  	c1 := elem.End(dims)
- 	return elem.Layout(c1)
+ 	dims = elem.Layout(c1)
+ 	return in.End(dims)
  }
  
  func newThreadPage(env *Env, threadID string) *threadPage {


@@ 1180,16 1170,14 @@ }
  	c1 := f.End(dims)
  
- 	sysInset := layout.Inset{
- 		Left:  p.env.insets.Left,
- 		Right: p.env.insets.Right,
- 	}
  	{
  		cs = f.Rigid()
- 		sysInset := sysInset
- 		sysInset.Bottom = p.env.insets.Bottom
- 		cs = sysInset.Begin(c, ops, cs)
- 		in := layout.Inset{Top: ui.Dp(8), Bottom: ui.Dp(8), Left: ui.Dp(12), Right: ui.Dp(12)}
+ 		in := layout.Inset{
+ 			Top:    ui.Dp(16),
+ 			Left:   ui.Max(c, ui.Dp(16), p.env.insets.Left),
+ 			Right:  ui.Max(c, ui.Dp(16), p.env.insets.Right),
+ 			Bottom: ui.Max(c, ui.Dp(16), p.env.insets.Bottom),
+ 		}
  		cs = in.Begin(c, ops, cs)
  		switch {
  		case p.thread.PendingInvitation:


@@ 1200,19 1188,16 @@ dims = p.invite.Layout(c, p.env, ops, cs)
  		}
  		dims = in.End(dims)
- 		dims = sysInset.End(dims)
  	}
  	c3 := f.End(dims)
  
  	{
  		cs = f.Flexible(1)
  		cs.Height.Min = cs.Height.Max
- 		cs = sysInset.Begin(c, ops, cs)
  		for l.Init(c, q, ops, cs, len(p.messages)); l.More(); l.Next() {
  			l.End(p.message(c, ops, l.Constraints(), l.Index()))
  		}
  		dims = l.Layout()
- 		dims = sysInset.End(dims)
  	}
  	c2 := f.End(dims)
  	return f.Layout(c1, c2, c3)


@@ 1262,7 1247,7 @@ func (p *threadPage) message(c ui.Config, ops *ui.Ops, cs layout.Constraints, index int) layout.Dimensions {
  	msg := p.messages[index]
  	var dims layout.Dimensions
- 	in := layout.Inset{Top: ui.Dp(8), Left: ui.Dp(8), Right: ui.Dp(40)}
+ 	in := layout.Inset{Top: ui.Dp(16), Left: ui.Dp(16), Right: ui.Dp(40)}
  	align := layout.Align{Alignment: layout.W}
  	msgMat := colorMaterial(ops, rgb(0xffffff))
  	bgcol := theme.brand


@@ 1274,6 1259,8 @@ msgMat = theme.text
  		timecol = rgb(0x888888)
  	}
+ 	in.Left = ui.Max(c, in.Left, p.env.insets.Left)
+ 	in.Right = ui.Max(c, in.Right, p.env.insets.Right)
  	cs = in.Begin(c, ops, cs)
  	{
  		cs = align.Begin(ops, cs)

M go.mod => go.mod +2 -2
@@ 3,8 3,8 @@ go 1.13
  
  require (
- 	gioui.org/cmd v0.0.0-20190905191537-6ad154419b2d // indirect
- 	gioui.org/ui v0.0.0-20190905191537-6ad154419b2d
+ 	gioui.org/cmd v0.0.0-20190909155013-86b231ca287a // indirect
+ 	gioui.org/ui v0.0.0-20190909155013-86b231ca287a
  	github.com/eliasnaur/libsignal-protocol-go v0.0.0-20190626062856-3295f72b181e
  	github.com/emersion/go-imap v1.0.0-rc.1
  	github.com/emersion/go-imap-idle v0.0.0-20190519112320-2704abd7050e

M go.sum => go.sum +5 -5
@@ 1,8 1,8 @@-gioui.org v0.0.0-20190905191537-6ad154419b2d h1:lSY1y1oKdLzz8VLzYoyxeKj0B5uSf8/AW4KdLq/RUtQ=
- gioui.org/cmd v0.0.0-20190905191537-6ad154419b2d h1:TSoXJ1a0DFWmDhP6VbwdFbry2N6tp3o0T4+tStesPNU=
- gioui.org/cmd v0.0.0-20190905191537-6ad154419b2d/go.mod h1:rn6q3wa1gugvIB50m0JxJ4krKQAfc0sQHJKvsuZW8+c=
- gioui.org/ui v0.0.0-20190905191537-6ad154419b2d h1:7MAtTBqpH81f7iHtVi1etPXQEpaQWuSO6LM0TTW8Who=
- gioui.org/ui v0.0.0-20190905191537-6ad154419b2d/go.mod h1:dmqi7kyK1sZ03VAkEqzKKpKWfRPCuqrd1eDtSqyhjzY=
+ gioui.org v0.0.0-20190909155013-86b231ca287a h1:Fn4zEWPu9exc2GE1SFTEpJNRXnFXqueLoAm8/ZCWubA=
+ gioui.org/cmd v0.0.0-20190909155013-86b231ca287a h1:7H7HPKR+9wPQTgYzRuR9v8nDYwzHmM/oetPfPwuOo8w=
+ gioui.org/cmd v0.0.0-20190909155013-86b231ca287a/go.mod h1:kMRzpXdArk4aGFuBDFqLSax2l/DhbnFWtEZJOPmrAX0=
+ gioui.org/ui v0.0.0-20190909155013-86b231ca287a h1:hMJBZPoLd5pxH+mtuqAgE6WB23U9h0YVChHWDcm+KYc=
+ gioui.org/ui v0.0.0-20190909155013-86b231ca287a/go.mod h1:PssKPKlqVIeyaed+0w492Xc2NgX5M3n6oZKOAj5rxoE=
  github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
  github.com/RadicalApp/complete v0.0.0-20170329192659-17e6c0ee499b h1:cAULFohNVfNzco0flF4okSPg3s7/tCj+hMIldtYZo4c=
  github.com/RadicalApp/complete v0.0.0-20170329192659-17e6c0ee499b/go.mod h1:zZ3+l0EkpT2ZPnoamPBG50PBUtQrXwwyJ6elQZMmqgk=