~eliasnaur/scatter

e956728fec02bf38d2cfc992e57ebaf9c4aeceb2 — Elias Naur 3 months ago 23bb2f4
cmd/scatter: update gio version

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

M cmd/scatter/ui.go
M go.mod
M go.sum
M cmd/scatter/ui.go => cmd/scatter/ui.go +264 -279
@@ 510,23 510,23 @@ func (p *contactsPage) Layout(gtx *layout.Context) {
	if l.Dragging() {
		key.HideInputOp{}.Add(gtx.Ops)
	}
	f := layout.Flex{Axis: layout.Vertical}
	c1 := f.Rigid(gtx, func() {
		p.topbar.Layout(gtx, p.env.insets, func() {
			e := theme.Editor("Email address")
			e.Font.Size = unit.Sp(20)
			e.Color = rgb(0xffffff)
			e.HintColor = rgb(0xbbbbbb)
			e.Layout(gtx, p.searchEdit)
		})
	})
	c2 := f.Flex(gtx, 1, func() {
		gtx.Constraints.Height.Min = gtx.Constraints.Height.Max
		l.Layout(gtx, len(p.contacts), func(i int) {
			p.contact(gtx, i)
		})
	})
	f.Layout(gtx, c1, c2)
	layout.Flex{Axis: layout.Vertical}.Layout(gtx,
		layout.Rigid(func() {
			p.topbar.Layout(gtx, p.env.insets, func() {
				e := theme.Editor("Email address")
				e.Font.Size = unit.Sp(20)
				e.Color = rgb(0xffffff)
				e.HintColor = rgb(0xbbbbbb)
				e.Layout(gtx, p.searchEdit)
			})
		}),
		layout.Flexed(1, func() {
			gtx.Constraints.Height.Min = gtx.Constraints.Height.Max
			l.Layout(gtx, len(p.contacts), func(i int) {
				p.contact(gtx, i)
			})
		}),
	)
}

func (p *contactsPage) contact(gtx *layout.Context, index int) {


@@ 539,23 539,22 @@ func (p *contactsPage) contact(gtx *layout.Context, index int) {
	contact := p.contacts[index]
	click := &p.clicks[index]
	in.Layout(gtx, func() {
		f := layout.Flex{Alignment: layout.Middle}
		c1 := f.Rigid(gtx, func() {
			in := layout.Inset{Right: unit.Dp(8)}
			in.Layout(gtx, func() {
				cc := clipCircle{}
				cc.Layout(gtx, func() {
					sz := image.Point{X: gtx.Px(unit.Dp(48)), Y: gtx.Px(unit.Dp(48))}
					gtx.Constraints = layout.RigidConstraints(gtx.Constraints.Constrain(sz))
					fill{theme.Color.Primary}.Layout(gtx)
		layout.Flex{Alignment: layout.Middle}.Layout(gtx,
			layout.Rigid(func() {
				in := layout.Inset{Right: unit.Dp(8)}
				in.Layout(gtx, func() {
					cc := clipCircle{}
					cc.Layout(gtx, func() {
						sz := image.Point{X: gtx.Px(unit.Dp(48)), Y: gtx.Px(unit.Dp(48))}
						gtx.Constraints = layout.RigidConstraints(gtx.Constraints.Constrain(sz))
						fill{theme.Color.Primary}.Layout(gtx)
					})
				})
			})
		})
		c2 := f.Flex(gtx, 1, func() {
			theme.H6(contact.Address).Layout(gtx)
		})

		f.Layout(gtx, c1, c2)
			}),
			layout.Flexed(1, func() {
				theme.H6(contact.Address).Layout(gtx)
			}),
		)
	})
	pointer.Rect(image.Rectangle{Max: gtx.Dimensions.Size}).Add(gtx.Ops)
	click.Add(gtx.Ops)


@@ 571,35 570,35 @@ func (t *Topbar) Event(gtx *layout.Context) interface{} {
}

func (t *Topbar) Layout(gtx *layout.Context, insets layout.Inset, w layout.Widget) {
	stack := layout.Stack{Alignment: layout.SW}
	insets = layout.Inset{
		Top:    unit.Add(gtx, insets.Top, unit.Dp(16)),
		Bottom: unit.Dp(16),
		Left:   unit.Max(gtx, insets.Left, unit.Dp(16)),
		Right:  unit.Max(gtx, insets.Right, unit.Dp(16)),
	}
	stackContent := stack.Rigid(gtx, func() {
		insets.Layout(gtx, func() {
			flex := layout.Flex{Alignment: layout.Middle}
			backChild := flex.Rigid(gtx, func() {
				if t.Back {
					ico := (&icon{src: icons.NavigationArrowBack, size: unit.Dp(24)}).image(gtx, rgb(0xffffff))
					ico.Add(gtx.Ops)
					paint.PaintOp{Rect: f32.Rectangle{Max: toPointF(ico.Size())}}.Add(gtx.Ops)
					gtx.Dimensions.Size = ico.Size()
					gtx.Dimensions.Size.X += gtx.Px(unit.Dp(4))
					pointer.Rect(image.Rectangle{Max: gtx.Dimensions.Size}).Add(gtx.Ops)
					t.backClick.Add(gtx.Ops)
				}
	layout.Stack{Alignment: layout.SW}.Layout(gtx,
		layout.Expanded(func() {
			fill{theme.Color.Primary}.Layout(gtx)
		}),
		layout.Stacked(func() {
			insets.Layout(gtx, func() {
				layout.Flex{Alignment: layout.Middle}.Layout(gtx,
					layout.Rigid(func() {
						if t.Back {
							ico := (&icon{src: icons.NavigationArrowBack, size: unit.Dp(24)}).image(gtx, rgb(0xffffff))
							ico.Add(gtx.Ops)
							paint.PaintOp{Rect: f32.Rectangle{Max: toPointF(ico.Size())}}.Add(gtx.Ops)
							gtx.Dimensions.Size = ico.Size()
							gtx.Dimensions.Size.X += gtx.Px(unit.Dp(4))
							pointer.Rect(image.Rectangle{Max: gtx.Dimensions.Size}).Add(gtx.Ops)
							t.backClick.Add(gtx.Ops)
						}
					}),
					layout.Flexed(1, w),
				)
			})
			content := flex.Flex(gtx, 1, w)
			flex.Layout(gtx, backChild, content)
		})
	})
	bg := stack.Expand(gtx, func() {
		fill{theme.Color.Primary}.Layout(gtx)
	})
	stack.Layout(gtx, bg, stackContent)
		}),
	)
}

func newSignInPage(env *Env) *signInPage {


@@ 646,21 645,19 @@ func (p *signInPage) Event(gtx *layout.Context) interface{} {
}

func (p *signInPage) Layout(gtx *layout.Context) {
	f := layout.Flex{Axis: layout.Vertical}

	c1 := f.Rigid(gtx, func() {
		var t Topbar
		t.Layout(gtx, p.env.insets, func() {
			lbl := theme.H6("Sign in")
			lbl.Color = rgb(0xffffff)
			lbl.Layout(gtx)
		})
	})

	c2 := f.Flex(gtx, 1, func() {
		p.layoutSigninForm(gtx)
	})
	f.Layout(gtx, c1, c2)
	layout.Flex{Axis: layout.Vertical}.Layout(gtx,
		layout.Rigid(func() {
			var t Topbar
			t.Layout(gtx, p.env.insets, func() {
				lbl := theme.H6("Sign in")
				lbl.Color = rgb(0xffffff)
				lbl.Layout(gtx)
			})
		}),
		layout.Flexed(1, func() {
			p.layoutSigninForm(gtx)
		}),
	)
}

func (p *signInPage) layoutSigninForm(gtx *layout.Context) {


@@ 692,19 689,18 @@ func (p *signInPage) layoutSigninForm(gtx *layout.Context) {
}

func (f *formField) Layout(gtx *layout.Context) {
	fl := layout.Flex{Axis: layout.Vertical}

	c1 := fl.Rigid(gtx, func() {
		gtx.Constraints.Width.Min = gtx.Constraints.Width.Max
		header := theme.Caption(f.Header)
		header.Font.Weight = text.Bold
		header.Layout(gtx)
		gtx.Dimensions.Size.Y += gtx.Px(unit.Dp(4))
	})
	c2 := fl.Rigid(gtx, func() {
		theme.Editor(f.Hint).Layout(gtx, f.edit)
	})
	fl.Layout(gtx, c1, c2)
	layout.Flex{Axis: layout.Vertical}.Layout(gtx,
		layout.Rigid(func() {
			gtx.Constraints.Width.Min = gtx.Constraints.Width.Max
			header := theme.Caption(f.Header)
			header.Font.Weight = text.Bold
			header.Layout(gtx)
			gtx.Dimensions.Size.Y += gtx.Px(unit.Dp(4))
		}),
		layout.Rigid(func() {
			theme.Editor(f.Hint).Layout(gtx, f.edit)
		}),
	)
}

type Background struct {


@@ 737,7 733,7 @@ func (b *Background) Layout(gtx *layout.Context, w layout.Widget) {
	}
	paint.ColorOp{Color: b.Color}.Add(gtx.Ops)
	paint.PaintOp{Rect: f32.Rectangle{Max: f32.Point{X: width, Y: height}}}.Add(gtx.Ops)
	macro.Add(gtx.Ops)
	macro.Add()
	stack.Pop()
}



@@ 800,36 796,34 @@ func (p *threadsPage) fetchThreads() {
}

func (p *threadsPage) Layout(gtx *layout.Context) {
	st := layout.Stack{Alignment: layout.SE}

	c1 := st.Rigid(gtx, func() {
		f := layout.Flex{Axis: layout.Vertical}

		c1 := f.Rigid(gtx, func() {
			var t Topbar
			t.Layout(gtx, p.env.insets, func() {
				lbl := theme.H6(p.account.User)
				lbl.Color = rgb(0xffffff)
				lbl.Layout(gtx)
			})
		})

		c2 := f.Flex(gtx, 1, func() {
			p.layoutThreads(gtx)
		})
		f.Layout(gtx, c1, c2)
	})
	c2 := st.Rigid(gtx, func() {
		layout.Align(layout.SE).Layout(gtx, func() {
			layout.Inset{
				Right:  unit.Max(gtx, unit.Dp(16), p.env.insets.Right),
				Bottom: unit.Max(gtx, unit.Dp(16), p.env.insets.Bottom),
			}.Layout(gtx, func() {
				theme.IconButton(iconLib.create).Layout(gtx, p.fab)
	layout.Stack{Alignment: layout.SE}.Layout(gtx,
		layout.Stacked(func() {
			layout.Flex{Axis: layout.Vertical}.Layout(gtx,
				layout.Rigid(func() {
					var t Topbar
					t.Layout(gtx, p.env.insets, func() {
						lbl := theme.H6(p.account.User)
						lbl.Color = rgb(0xffffff)
						lbl.Layout(gtx)
					})
				}),

				layout.Flexed(1, func() {
					p.layoutThreads(gtx)
				}),
			)
		}),
		layout.Stacked(func() {
			layout.Align(layout.SE).Layout(gtx, func() {
				layout.Inset{
					Right:  unit.Max(gtx, unit.Dp(16), p.env.insets.Right),
					Bottom: unit.Max(gtx, unit.Dp(16), p.env.insets.Bottom),
				}.Layout(gtx, func() {
					theme.IconButton(iconLib.create).Layout(gtx, p.fab)
				})
			})
		})
	})
	st.Layout(gtx, c1, c2)
		}),
	)
}

func (p *threadsPage) layoutThreads(gtx *layout.Context) {


@@ 874,81 868,75 @@ func (p *threadsPage) thread(gtx *layout.Context, index int) {
		Right: unit.Max(gtx, unit.Dp(16), p.env.insets.Right),
	}
	in.Layout(gtx, func() {
		elem := layout.Flex{Axis: layout.Vertical}
		c1 := elem.Rigid(gtx, func() {
			in := layout.Inset{Top: unit.Dp(8), Bottom: unit.Dp(8)}
			in.Layout(gtx, func() {
				f := centerRowOpts()
				c1 := f.Rigid(gtx, func() {
		in := layout.Inset{Top: unit.Dp(8), Bottom: unit.Dp(8)}
		in.Layout(gtx, func() {
			centerRowOpts().Layout(gtx,
				layout.Rigid(func() {
					in := layout.Inset{Right: unit.Dp(12)}
					cc := clipCircle{}
					in.Layout(gtx, func() {
						cc.Layout(gtx, func() {
							st := layout.Stack{Alignment: layout.Center}

							// Background color
							c1 := st.Rigid(gtx, func() {
								sz := image.Point{X: gtx.Px(unit.Dp(48)), Y: gtx.Px(unit.Dp(48))}
								gtx.Constraints = layout.RigidConstraints(gtx.Constraints.Constrain(sz))
								color := contactColors[index%len(contactColors)]
								fill{color}.Layout(gtx)
							})

							// Contact initial.
							c2 := st.Rigid(gtx, func() {
								initial := ""
								for _, c := range t.ID {
									initial = string(unicode.ToUpper(c))
									break
								}
								lbl := theme.H5(initial)
								lbl.Color = rgb(0xffffff)
								lbl.Layout(gtx)
							})
							st.Layout(gtx, c1, c2)
							layout.Stack{Alignment: layout.Center}.Layout(gtx,
								// Background color
								layout.Stacked(func() {
									sz := image.Point{X: gtx.Px(unit.Dp(48)), Y: gtx.Px(unit.Dp(48))}
									gtx.Constraints = layout.RigidConstraints(gtx.Constraints.Constrain(sz))
									color := contactColors[index%len(contactColors)]
									fill{color}.Layout(gtx)
								}),
								// Contact initial.
								layout.Stacked(func() {
									initial := ""
									for _, c := range t.ID {
										initial = string(unicode.ToUpper(c))
										break
									}
									lbl := theme.H5(initial)
									lbl.Color = rgb(0xffffff)
									lbl.Layout(gtx)
								}),
							)
						})
					})
				})
				c2 := f.Rigid(gtx, func() {
					f := column()
					c1 := f.Rigid(gtx, func() {
						f := baseline()
						c1 := f.Rigid(gtx, func() {
							lbl := theme.H6(t.ID)
							lbl.Font.Weight = fontWeight
							lbl.Layout(gtx)
						})
						c2 := f.Flex(gtx, 1, func() {
							gtx.Constraints.Width.Min = gtx.Constraints.Width.Max
							in := layout.Inset{Left: unit.Dp(2)}
				}),
				layout.Rigid(func() {
					column().Layout(gtx,
						layout.Rigid(func() {
							baseline().Layout(gtx,
								layout.Rigid(func() {
									lbl := theme.H6(t.ID)
									lbl.Font.Weight = fontWeight
									lbl.Layout(gtx)
								}),
								layout.Flexed(1, func() {
									gtx.Constraints.Width.Min = gtx.Constraints.Width.Max
									in := layout.Inset{Left: unit.Dp(2)}
									in.Layout(gtx, func() {
										lbl := theme.Caption(formatTime(t.Updated))
										lbl.Color = bgtexcol
										lbl.Alignment = text.End
										lbl.Font.Weight = fontWeight
										lbl.Layout(gtx)
									})
								}),
							)
						}),
						layout.Rigid(func() {
							in := layout.Inset{Top: unit.Dp(6)}
							in.Layout(gtx, func() {
								lbl := theme.Caption(formatTime(t.Updated))
								lbl := theme.Body2(t.Snippet)
								lbl.Color = bgtexcol
								lbl.Alignment = text.End
								lbl.Font.Weight = fontWeight
								lbl.MaxLines = 1
								lbl.Layout(gtx)
							})
						})
						f.Layout(gtx, c1, c2)
					})
					c2 := f.Rigid(gtx, func() {
						in := layout.Inset{Top: unit.Dp(6)}
						in.Layout(gtx, func() {
							lbl := theme.Body2(t.Snippet)
							lbl.Color = bgtexcol
							lbl.Font.Weight = fontWeight
							lbl.MaxLines = 1
							lbl.Layout(gtx)
						})
					})
					f.Layout(gtx, c1, c2)
				})
				f.Layout(gtx, c1, c2)
			})
			pointer.Rect(image.Rectangle{Max: gtx.Dimensions.Size}).Add(gtx.Ops)
			click.Add(gtx.Ops)
						}),
					)
				}),
			)
		})
		elem.Layout(gtx, c1)
		pointer.Rect(image.Rectangle{Max: gtx.Dimensions.Size}).Add(gtx.Ops)
		click.Add(gtx.Ops)
	})
}



@@ 1030,81 1018,80 @@ func (p *threadPage) Layout(gtx *layout.Context) {
	case p.messages = <-p.result:
	default:
	}
	f := layout.Flex{Axis: layout.Vertical}
	c1 := f.Rigid(gtx, func() {
		p.topbar.Layout(gtx, p.env.insets, func() {
			lbl := theme.H6(p.thread.ID)
			lbl.Color = rgb(0xffffff)
			lbl.Layout(gtx)
		})
	})
	layout.Flex{Axis: layout.Vertical}.Layout(gtx,
		layout.Rigid(func() {
			p.topbar.Layout(gtx, p.env.insets, func() {
				lbl := theme.H6(p.thread.ID)
				lbl.Color = rgb(0xffffff)
				lbl.Layout(gtx)
			})
		}),

	c3 := f.Rigid(gtx, func() {
		in := layout.Inset{
			Top:    unit.Dp(16),
			Left:   unit.Max(gtx, unit.Dp(16), p.env.insets.Left),
			Right:  unit.Max(gtx, unit.Dp(16), p.env.insets.Right),
			Bottom: unit.Max(gtx, unit.Dp(16), p.env.insets.Bottom),
		}
		in.Layout(gtx, func() {
			switch {
			case p.thread.PendingInvitation:
				theme.Button("Accept invitation").Layout(gtx, p.accept)
			case p.env.client.ContainsSession(p.thread.ID):
				p.layoutMessageBox(gtx)
			default:
				theme.Button("Send invitation").Layout(gtx, p.invite)
			}
		})
	})
		layout.Flexed(1, func() {
			gtx.Constraints.Height.Min = gtx.Constraints.Height.Max
			l.Layout(gtx, len(p.messages), func(i int) {
				p.message(gtx, i)
			})
		}),

	c2 := f.Flex(gtx, 1, func() {
		gtx.Constraints.Height.Min = gtx.Constraints.Height.Max
		l.Layout(gtx, len(p.messages), func(i int) {
			p.message(gtx, i)
		})
	})
	f.Layout(gtx, c1, c2, c3)
		layout.Rigid(func() {
			in := layout.Inset{
				Top:    unit.Dp(16),
				Left:   unit.Max(gtx, unit.Dp(16), p.env.insets.Left),
				Right:  unit.Max(gtx, unit.Dp(16), p.env.insets.Right),
				Bottom: unit.Max(gtx, unit.Dp(16), p.env.insets.Bottom),
			}
			in.Layout(gtx, func() {
				switch {
				case p.thread.PendingInvitation:
					theme.Button("Accept invitation").Layout(gtx, p.accept)
				case p.env.client.ContainsSession(p.thread.ID):
					p.layoutMessageBox(gtx)
				default:
					theme.Button("Send invitation").Layout(gtx, p.invite)
				}
			})
		}),
	)
}

func (p *threadPage) layoutMessageBox(gtx *layout.Context) {
	if mh := gtx.Px(unit.Dp(100)); gtx.Constraints.Height.Max > mh {
		gtx.Constraints.Height.Max = mh
	}
	f := layout.Flex{Alignment: layout.End}

	var sendHeight int
	c2 := f.Rigid(gtx, func() {
		in := layout.Inset{Left: unit.Dp(8)}
		in.Layout(gtx, func() {
			btn := theme.IconButton(iconLib.send)
			btn.Size = unit.Dp(48)
			btn.Padding = unit.Dp(12)
			btn.Layout(gtx, p.send)
			sendHeight = gtx.Dimensions.Size.Y
		})
	})

	c1 := f.Flex(gtx, 1, func() {
		gtx.Constraints.Width.Min = gtx.Constraints.Width.Max
		if gtx.Constraints.Height.Min < sendHeight {
			gtx.Constraints.Height.Min = sendHeight
		}
		bg := Background{
			Color:  rgb(0xeeeeee),
			Inset:  layout.Inset{Left: unit.Dp(8), Right: unit.Dp(8)},
			Radius: unit.Dp(10),
		}
		bg.Layout(gtx, func() {
			layout.Align(layout.W).Layout(gtx, func() {
				gtx.Constraints.Width.Min = gtx.Constraints.Width.Max
				ed := theme.Editor("Send a message")
				ed.Font.Size = unit.Sp(14)
				ed.Layout(gtx, p.msgEdit)
	layout.Flex{Alignment: layout.End}.Layout(gtx,
		layout.Flexed(1, func() {
			gtx.Constraints.Width.Min = gtx.Constraints.Width.Max
			if gtx.Constraints.Height.Min < sendHeight {
				gtx.Constraints.Height.Min = sendHeight
			}
			bg := Background{
				Color:  rgb(0xeeeeee),
				Inset:  layout.Inset{Left: unit.Dp(8), Right: unit.Dp(8)},
				Radius: unit.Dp(10),
			}
			bg.Layout(gtx, func() {
				layout.Align(layout.W).Layout(gtx, func() {
					gtx.Constraints.Width.Min = gtx.Constraints.Width.Max
					ed := theme.Editor("Send a message")
					ed.Font.Size = unit.Sp(14)
					ed.Layout(gtx, p.msgEdit)
				})
			})
		})
	})
	f.Layout(gtx, c1, c2)
		}),
		layout.Rigid(func() {
			in := layout.Inset{Left: unit.Dp(8)}
			in.Layout(gtx, func() {
				btn := theme.IconButton(iconLib.send)
				btn.Size = unit.Dp(48)
				btn.Padding = unit.Dp(12)
				btn.Layout(gtx, p.send)
				sendHeight = gtx.Dimensions.Size.Y
			})
		}),
	)
}

func (p *threadPage) message(gtx *layout.Context, index int) {


@@ 1131,49 1118,47 @@ func (p *threadPage) message(gtx *layout.Context, index int) {
				Radius: unit.Dp(10),
			}
			bg.Layout(gtx, func() {
				f := layout.Flex{Axis: layout.Vertical}

				var msgWidth int
				c1 := f.Rigid(gtx, func() {
					lbl := theme.Body2(msg.Message)
					lbl.Color = msgCol
					lbl.Layout(gtx)
					gtx.Dimensions.Size.Y += gtx.Px(unit.Dp(4))
					msgWidth = gtx.Dimensions.Size.X
				})

				c2 := f.Rigid(gtx, func() {
					gtx.Constraints.Width.Min = msgWidth
					f := layout.Flex{Axis: layout.Horizontal, Spacing: layout.SpaceBetween, Alignment: layout.Middle}

					var children []layout.FlexChild
					child := f.Rigid(gtx, func() {
						time := formatTime(msg.Time)
						lbl := theme.Caption(time)
						lbl.Color = timecol
				layout.Flex{Axis: layout.Vertical}.Layout(gtx,
					layout.Rigid(func() {
						lbl := theme.Body2(msg.Message)
						lbl.Color = msgCol
						lbl.Layout(gtx)
					})
					children = append(children, child)

					if msg.Own {
						child := f.Rigid(gtx, func() {
							in := layout.Inset{Left: unit.Dp(12)}
							in.Layout(gtx, func() {
								checkmark := p.checkmark.image(gtx, timecol)
								sz := checkmark.Size()
								if msg.Sent {
									checkmark.Add(gtx.Ops)
									paint.PaintOp{Rect: f32.Rectangle{Max: toPointF(sz)}}.Add(gtx.Ops)
								}
								gtx.Dimensions = layout.Dimensions{Size: sz}
							})
						gtx.Dimensions.Size.Y += gtx.Px(unit.Dp(4))
						msgWidth = gtx.Dimensions.Size.X
					}),

					layout.Rigid(func() {
						gtx.Constraints.Width.Min = msgWidth
						f := layout.Flex{Axis: layout.Horizontal, Spacing: layout.SpaceBetween, Alignment: layout.Middle}

						var children []layout.FlexChild
						child := layout.Rigid(func() {
							time := formatTime(msg.Time)
							lbl := theme.Caption(time)
							lbl.Color = timecol
							lbl.Layout(gtx)
						})
						children = append(children, child)
					}
					f.Layout(gtx, children...)
				})

				f.Layout(gtx, c1, c2)
						if msg.Own {
							child := layout.Rigid(func() {
								in := layout.Inset{Left: unit.Dp(12)}
								in.Layout(gtx, func() {
									checkmark := p.checkmark.image(gtx, timecol)
									sz := checkmark.Size()
									if msg.Sent {
										checkmark.Add(gtx.Ops)
										paint.PaintOp{Rect: f32.Rectangle{Max: toPointF(sz)}}.Add(gtx.Ops)
									}
									gtx.Dimensions = layout.Dimensions{Size: sz}
								})
							})
							children = append(children, child)
						}
						f.Layout(gtx, children...)
					}),
				)
			})
		})
	})


@@ 1275,7 1260,7 @@ func (cc *clipCircle) Layout(gtx *layout.Context, w layout.Widget) {
		Rect: f32.Rectangle{Max: f32.Point{X: szf, Y: szf}},
		NE:   rr, NW: rr, SE: rr, SW: rr,
	}.Op(gtx.Ops).Add(gtx.Ops)
	macro.Add(gtx.Ops)
	macro.Add()
	stack.Pop()
}


M go.mod => go.mod +1 -1
@@ 3,7 3,7 @@ module scatter.im
go 1.13

require (
	gioui.org v0.0.0-20191202122135-c0beeb5e77dc
	gioui.org v0.0.0-20191211234831-0bfcac97344d
	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 +2 -2
@@ 1,6 1,6 @@
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
gioui.org v0.0.0-20191202122135-c0beeb5e77dc h1:2eKdkpHtriwdbRvEXKDzukEE/w5cbQDaTJSHsXB+tT0=
gioui.org v0.0.0-20191202122135-c0beeb5e77dc/go.mod h1:KqFFi2Dq5gYA3FJ0sDOt8OBXoMsuxMtE8v2f0JExXAY=
gioui.org v0.0.0-20191211234831-0bfcac97344d h1:yxzaD2asbV2q/oGukWJ1JrIBp0zm45RIA8ngnY9L6Ic=
gioui.org v0.0.0-20191211234831-0bfcac97344d/go.mod h1:KqFFi2Dq5gYA3FJ0sDOt8OBXoMsuxMtE8v2f0JExXAY=
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=