You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

223 lines
5.6 KiB

package main
import (
"fmt"
"image"
"image/color"
"log"
"os"
"strconv"
"gioui.org/app"
"gioui.org/f32"
"gioui.org/font/gofont"
"gioui.org/io/system"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/op/clip"
"gioui.org/op/paint"
"gioui.org/unit"
"gioui.org/widget"
"gioui.org/widget/material"
"gioui.org/x/outlay"
)
func main() {
go func() {
w := app.NewWindow(
app.Size(unit.Dp(800), unit.Dp(400)),
app.Title("Gio layouts"),
)
if err := loop(w); err != nil {
log.Fatal(err)
}
os.Exit(0)
}()
app.Main()
}
func loop(w *app.Window) error {
ui := newUI()
var ops op.Ops
for e := range w.Events() {
switch e := e.(type) {
case system.DestroyEvent:
return e.Err
case system.FrameEvent:
gtx := layout.NewContext(&ops, e)
ui.Layout(gtx)
e.Frame(gtx.Ops)
}
}
return nil
}
type UI struct {
theme *material.Theme
active int
tabs []uiTab
list layout.List
}
type uiTab struct {
name string
click widget.Clickable
text string
w func(tab *uiTab, gtx layout.Context) layout.Dimensions
num int
ed widget.Editor
}
var (
vWrap = outlay.GridWrap{
Axis: layout.Vertical,
Alignment: layout.End,
}
hWrap = outlay.GridWrap{
Axis: layout.Horizontal,
Alignment: layout.End,
}
vGrid = outlay.Grid{
Num: 11,
Axis: layout.Vertical,
}
hGrid = outlay.Grid{
Num: 11,
Axis: layout.Horizontal,
}
)
func newUI() *UI {
ui := &UI{
theme: material.NewTheme(gofont.Collection()),
list: layout.List{
Axis: layout.Horizontal,
Alignment: layout.Baseline,
},
}
ui.tabs = append(ui.tabs,
uiTab{
name: "V wrap",
text: "Lay out items vertically before wrapping to the next column.",
w: func(tab *uiTab, gtx layout.Context) layout.Dimensions {
return vWrap.Layout(gtx, tab.num, func(gtx layout.Context, i int) layout.Dimensions {
s := fmt.Sprintf("item %d", i)
return material.Body1(ui.theme, s).Layout(gtx)
})
},
},
uiTab{
name: "H wrap",
text: "Lay out items horizontally before wrapping to the next row.",
w: func(tab *uiTab, gtx layout.Context) layout.Dimensions {
return hWrap.Layout(gtx, tab.num, func(gtx layout.Context, i int) layout.Dimensions {
s := fmt.Sprintf("item %d", i)
return material.Body1(ui.theme, s).Layout(gtx)
})
},
},
uiTab{
name: "V grid",
text: fmt.Sprintf("Lay out %d items vertically before going to the next column.", vGrid.Num),
w: func(tab *uiTab, gtx layout.Context) layout.Dimensions {
return vGrid.Layout(gtx, tab.num, func(gtx layout.Context, i int) layout.Dimensions {
s := fmt.Sprintf("item %d", i)
return material.Body1(ui.theme, s).Layout(gtx)
})
},
},
uiTab{
name: "H grid",
text: fmt.Sprintf("Lay out %d items horizontally before going to the next row.", hGrid.Num),
w: func(tab *uiTab, gtx layout.Context) layout.Dimensions {
return hGrid.Layout(gtx, tab.num, func(gtx layout.Context, i int) layout.Dimensions {
s := fmt.Sprintf("item %d", i)
return material.Body1(ui.theme, s).Layout(gtx)
})
},
},
)
for i := range ui.tabs {
tab := &ui.tabs[i]
tab.ed = widget.Editor{
SingleLine: true,
Submit: true,
}
tab.num = 99
tab.ed.SetText(strconv.Itoa(tab.num))
}
return ui
}
func (ui *UI) Layout(gtx layout.Context) layout.Dimensions {
for i := range ui.tabs {
for ui.tabs[i].click.Clicked() {
ui.active = i
}
}
activeTab := &ui.tabs[ui.active]
return layout.Flex{
Axis: layout.Vertical,
}.Layout(gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return ui.list.Layout(gtx, len(ui.tabs), func(gtx layout.Context, idx int) layout.Dimensions {
tab := &ui.tabs[idx]
title := func(gtx layout.Context) layout.Dimensions {
return layout.UniformInset(unit.Dp(6)).Layout(gtx, material.H6(ui.theme, tab.name).Layout)
}
if idx != ui.active {
return material.Clickable(gtx, &tab.click, title)
}
return layout.Stack{}.Layout(gtx,
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
defer clip.UniformRRect(f32.Rectangle{
Max: layout.FPt(gtx.Constraints.Min),
}, 0).Push(gtx.Ops).Pop()
paint.Fill(gtx.Ops, color.NRGBA{A: 64})
return layout.Dimensions{}
}),
layout.Stacked(title),
)
})
}),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
pt := image.Point{X: gtx.Constraints.Max.X, Y: 4}
defer clip.UniformRRect(f32.Rectangle{
Max: layout.FPt(pt),
}, 0).Push(gtx.Ops).Pop()
paint.Fill(gtx.Ops, ui.theme.Palette.ContrastBg)
return layout.Dimensions{Size: pt}
}),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return layout.Stack{}.Layout(gtx,
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
defer clip.UniformRRect(f32.Rectangle{
Max: layout.FPt(image.Pt(gtx.Constraints.Max.X, gtx.Constraints.Min.Y)),
}, 0).Push(gtx.Ops).Pop()
paint.Fill(gtx.Ops, color.NRGBA{A: 24})
return layout.Dimensions{}
}),
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
return layout.UniformInset(unit.Dp(4)).Layout(gtx, func(gtx layout.Context) layout.Dimensions {
if x, _ := strconv.Atoi(activeTab.ed.Text()); x != activeTab.num {
activeTab.num = x
}
return layout.Flex{
Alignment: layout.Baseline,
}.Layout(gtx,
layout.Rigid(material.Body1(ui.theme, activeTab.text).Layout),
layout.Rigid(material.Body1(ui.theme, " Num = ").Layout),
layout.Rigid(material.Editor(ui.theme, &activeTab.ed, "").Layout),
)
})
}),
)
}),
layout.Flexed(1, func(gtx layout.Context) layout.Dimensions {
return activeTab.w(activeTab, gtx)
}),
)
}