mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 23:55:39 +00:00
df791f2e9b
Layouts and path builders are transient and need an ops list for operation. However, instead of passing the ops list to every method, pass the list in an init method and store it for subsequent methods. Signed-off-by: Elias Naur <mail@eliasnaur.com>
194 lines
3.9 KiB
Go
194 lines
3.9 KiB
Go
// SPDX-License-Identifier: Unlicense OR MIT
|
|
|
|
package layout
|
|
|
|
import (
|
|
"image"
|
|
"math"
|
|
|
|
"gioui.org/ui"
|
|
)
|
|
|
|
type Constraints struct {
|
|
Width Constraint
|
|
Height Constraint
|
|
}
|
|
|
|
type Constraint struct {
|
|
Min, Max int
|
|
}
|
|
|
|
type Dimens struct {
|
|
Size image.Point
|
|
Baseline int
|
|
}
|
|
|
|
type Axis uint8
|
|
|
|
const (
|
|
Horizontal Axis = iota
|
|
Vertical
|
|
)
|
|
|
|
func (c Constraint) Constrain(v int) int {
|
|
if v < c.Min {
|
|
return c.Min
|
|
} else if v > c.Max {
|
|
return c.Max
|
|
}
|
|
return v
|
|
}
|
|
|
|
func (c Constraints) Constrain(p image.Point) image.Point {
|
|
return image.Point{X: c.Width.Constrain(p.X), Y: c.Height.Constrain(p.Y)}
|
|
}
|
|
|
|
func (c Constraints) Expand() Constraints {
|
|
return Constraints{Width: c.Width.Expand(), Height: c.Height.Expand()}
|
|
}
|
|
|
|
func (c Constraint) Expand() Constraint {
|
|
return Constraint{Min: c.Max, Max: c.Max}
|
|
}
|
|
func (c Constraints) Loose() Constraints {
|
|
return Constraints{Width: c.Width.Loose(), Height: c.Height.Loose()}
|
|
}
|
|
|
|
func (c Constraint) Loose() Constraint {
|
|
return Constraint{Max: c.Max}
|
|
}
|
|
|
|
// ExactConstraints returns the constraints that exactly represents the
|
|
// given dimensions.
|
|
func ExactConstraints(size image.Point) Constraints {
|
|
return Constraints{
|
|
Width: Constraint{Min: size.X, Max: size.X},
|
|
Height: Constraint{Min: size.Y, Max: size.Y},
|
|
}
|
|
}
|
|
|
|
type Insets struct {
|
|
Top, Right, Bottom, Left float32
|
|
|
|
ops *ui.Ops
|
|
cs Constraints
|
|
}
|
|
|
|
func (in *Insets) Begin(ops *ui.Ops, cs Constraints) Constraints {
|
|
in.ops = ops
|
|
in.cs = cs
|
|
mcs := cs
|
|
t, r, b, l := int(math.Round(float64(in.Top))), int(math.Round(float64(in.Right))), int(math.Round(float64(in.Bottom))), int(math.Round(float64(in.Left)))
|
|
if mcs.Width.Max != ui.Inf {
|
|
mcs.Width.Min -= l + r
|
|
mcs.Width.Max -= l + r
|
|
if mcs.Width.Min < 0 {
|
|
mcs.Width.Min = 0
|
|
}
|
|
if mcs.Width.Max < mcs.Width.Min {
|
|
mcs.Width.Max = mcs.Width.Min
|
|
}
|
|
}
|
|
if mcs.Height.Max != ui.Inf {
|
|
mcs.Height.Min -= t + b
|
|
mcs.Height.Max -= t + b
|
|
if mcs.Height.Min < 0 {
|
|
mcs.Height.Min = 0
|
|
}
|
|
if mcs.Height.Max < mcs.Height.Min {
|
|
mcs.Height.Max = mcs.Height.Min
|
|
}
|
|
}
|
|
ui.OpPush{}.Add(ops)
|
|
ui.OpTransform{Transform: ui.Offset(toPointF(image.Point{X: l, Y: t}))}.Add(ops)
|
|
return mcs
|
|
}
|
|
|
|
func (in *Insets) End(dims Dimens) Dimens {
|
|
ops := in.ops
|
|
ui.OpPop{}.Add(ops)
|
|
t, r, b, l := int(math.Round(float64(in.Top))), int(math.Round(float64(in.Right))), int(math.Round(float64(in.Bottom))), int(math.Round(float64(in.Left)))
|
|
return Dimens{
|
|
Size: in.cs.Constrain(dims.Size.Add(image.Point{X: r + l, Y: t + b})),
|
|
Baseline: dims.Baseline + t,
|
|
}
|
|
}
|
|
|
|
func EqualInsets(v float32) Insets {
|
|
return Insets{Top: v, Right: v, Bottom: v, Left: v}
|
|
}
|
|
|
|
func isInf(v ui.Value) bool {
|
|
return math.IsInf(float64(v.V), 1)
|
|
}
|
|
|
|
type Sized struct {
|
|
Width, Height float32
|
|
}
|
|
|
|
func (s Sized) Constrain(cs Constraints) Constraints {
|
|
if h := int(s.Height + 0.5); h != 0 {
|
|
if cs.Height.Min < h {
|
|
cs.Height.Min = h
|
|
}
|
|
if h < cs.Height.Max {
|
|
cs.Height.Max = h
|
|
}
|
|
}
|
|
if w := int(s.Width + .5); w != 0 {
|
|
if cs.Width.Min < w {
|
|
cs.Width.Min = w
|
|
}
|
|
if w < cs.Width.Max {
|
|
cs.Width.Max = w
|
|
}
|
|
}
|
|
return cs
|
|
}
|
|
|
|
type Align struct {
|
|
ops *ui.Ops
|
|
Alignment Direction
|
|
cs Constraints
|
|
}
|
|
|
|
func (a *Align) Begin(ops *ui.Ops, cs Constraints) Constraints {
|
|
a.ops = ops
|
|
a.cs = cs
|
|
ops.Begin()
|
|
return cs.Loose()
|
|
}
|
|
|
|
func (a *Align) End(dims Dimens) Dimens {
|
|
ops := a.ops
|
|
block := ops.End()
|
|
sz := dims.Size
|
|
if a.cs.Width.Max != ui.Inf {
|
|
sz.X = a.cs.Width.Max
|
|
}
|
|
if a.cs.Height.Max != ui.Inf {
|
|
sz.Y = a.cs.Height.Max
|
|
}
|
|
var p image.Point
|
|
switch a.Alignment {
|
|
case N, S, Center:
|
|
p.X = (sz.X - dims.Size.X) / 2
|
|
case NE, SE, E:
|
|
p.X = sz.X - dims.Size.X
|
|
}
|
|
switch a.Alignment {
|
|
case W, Center, E:
|
|
p.Y = (sz.Y - dims.Size.Y) / 2
|
|
case SW, S, SE:
|
|
p.Y = sz.Y - dims.Size.Y
|
|
}
|
|
ui.OpPush{}.Add(ops)
|
|
ui.OpTransform{Transform: ui.Offset(toPointF(p))}.Add(ops)
|
|
block.Add(ops)
|
|
ui.OpPop{}.Add(ops)
|
|
return Dimens{
|
|
Size: sz,
|
|
Baseline: dims.Baseline,
|
|
}
|
|
}
|