Functional options.
This commit is contained in:
parent
b9514a08ff
commit
716cd6b562
|
@ -16,6 +16,12 @@ import (
|
||||||
"golang.org/x/image/font/gofont/goregular"
|
"golang.org/x/image/font/gofont/goregular"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func NewButton(face text.Face, t string, c color.RGBA) giowrap.Clickable {
|
||||||
|
lbl := giowrap.NewLabel(t, giowrap.LabelFace(face), giowrap.LabelAlignment(text.Center))
|
||||||
|
bg := giowrap.NewBackground(giowrap.BgColor(c), giowrap.BgRadius(ui.Dp(4)))
|
||||||
|
return giowrap.AsClickable(bg(lbl))
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
go func() {
|
go func() {
|
||||||
w := app.NewWindow(nil)
|
w := app.NewWindow(nil)
|
||||||
|
@ -25,24 +31,21 @@ func main() {
|
||||||
}
|
}
|
||||||
ctx := giowrap.NewContext(w)
|
ctx := giowrap.NewContext(w)
|
||||||
t := time.NewTicker(time.Second/30)
|
t := time.NewTicker(time.Second/30)
|
||||||
e1 := giowrap.NewEditor(ctx.Faces.For(regular, ui.Sp(24)), true)
|
e1 := giowrap.NewEditor("text 1",giowrap.EditorFace(ctx.Faces.For(regular, ui.Sp(24))))
|
||||||
e1.SetText("text 1")
|
|
||||||
e1.Focus()
|
e1.Focus()
|
||||||
|
|
||||||
e2 := giowrap.NewEditor(ctx.Faces.For(regular, ui.Sp(24)), true)
|
e2 := giowrap.NewEditor("text 2",giowrap.EditorFace(ctx.Faces.For(regular, ui.Sp(24))))
|
||||||
e2.SetText("text 2")
|
|
||||||
|
|
||||||
f := giowrap.NewFlex(layout.Vertical, layout.Start, layout.Start)
|
f1 := giowrap.NewFlex(giowrap.FlexAxis(layout.Vertical))
|
||||||
OuterInset := giowrap.NewInset(ui.Dp(10),ui.Dp(10),ui.Dp(10),ui.Dp(10))
|
OuterInset := giowrap.NewInset(giowrap.InsetSize(ui.Dp(10)))
|
||||||
InnerInset := giowrap.NewInset(ui.Dp(10),ui.Dp(10),ui.Dp(10),ui.Dp(10))
|
InnerInset := giowrap.NewInset(giowrap.InsetSize(ui.Dp(10)))
|
||||||
|
|
||||||
lbl := giowrap.NewLabel(
|
f2 := giowrap.NewFlex(giowrap.FlexAxis(layout.Horizontal))
|
||||||
ctx.Faces.For(regular, ui.Sp(24)),
|
|
||||||
"push",
|
btn1 := NewButton(ctx.Faces.For(regular, ui.Sp(24)),
|
||||||
text.Center,
|
"push1", color.RGBA{A: 0xff, R: 0x3c, G: 0x98, B: 0xc6})
|
||||||
)
|
btn2 := NewButton(ctx.Faces.For(regular, ui.Sp(24)),
|
||||||
bg := giowrap.NewBackground(color.RGBA{A: 0xff, R: 0x3c, G: 0x98, B: 0xc6}, ui.Dp(4))
|
"push2", color.RGBA{A: 0xff, R: 0x3c, G: 0x98, B: 0xc6})
|
||||||
btn := giowrap.Clickable(bg(lbl))
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
@ -55,15 +58,22 @@ func main() {
|
||||||
case app.DrawEvent:
|
case app.DrawEvent:
|
||||||
ctx = ctx.Reset(e)
|
ctx = ctx.Reset(e)
|
||||||
ctx = OuterInset(
|
ctx = OuterInset(
|
||||||
f(
|
f1(
|
||||||
e1,
|
e1,
|
||||||
giowrap.Flexible(5),
|
giowrap.Flexible(5),
|
||||||
InnerInset(e2),
|
InnerInset(e2),
|
||||||
giowrap.Flexible(10),
|
giowrap.Flexible(10),
|
||||||
btn,
|
f2(
|
||||||
|
InnerInset(btn1),
|
||||||
|
giowrap.Flexible(1),
|
||||||
|
InnerInset(btn2),
|
||||||
|
),
|
||||||
)).Layout(ctx)
|
)).Layout(ctx)
|
||||||
ctx.Draw()
|
ctx.Draw()
|
||||||
if btn.Clicked(ctx) {
|
if btn1.Clicked(ctx) {
|
||||||
|
log.Print("Clicked: " + e1.Text() )
|
||||||
|
}
|
||||||
|
if btn2.Clicked(ctx) {
|
||||||
log.Print("Clicked: " + e2.Text() )
|
log.Print("Clicked: " + e2.Text() )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
180
main.go
180
main.go
|
@ -2,7 +2,8 @@ package giowrap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"image/color"
|
"image/color"
|
||||||
"log"
|
//"log"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"gioui.org/ui"
|
"gioui.org/ui"
|
||||||
"gioui.org/ui/app"
|
"gioui.org/ui/app"
|
||||||
|
@ -17,6 +18,24 @@ import (
|
||||||
"gioui.org/ui/pointer"
|
"gioui.org/ui/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Extra struct {
|
||||||
|
cur, max int
|
||||||
|
sync.Mutex
|
||||||
|
data []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var extra Extra
|
||||||
|
|
||||||
|
func (e *Extra) New() int {
|
||||||
|
e.Lock()
|
||||||
|
if e.data == nil { e.data = make([]interface{},0) }
|
||||||
|
ret := e.max
|
||||||
|
e.max = e.max + 1
|
||||||
|
e.data = append(e.data,nil)
|
||||||
|
e.Unlock()
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
type Context struct {
|
type Context struct {
|
||||||
Faces measure.Faces
|
Faces measure.Faces
|
||||||
|
|
||||||
|
@ -26,16 +45,15 @@ type Context struct {
|
||||||
ops *ui.Ops
|
ops *ui.Ops
|
||||||
cs layout.Constraints
|
cs layout.Constraints
|
||||||
dims layout.Dimens
|
dims layout.Dimens
|
||||||
extra map[string]interface{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewContext(w *app.Window) Context {
|
func NewContext(w *app.Window) Context {
|
||||||
return Context{
|
ret := Context{
|
||||||
w: w,
|
w: w,
|
||||||
ops: new(ui.Ops),
|
ops: new(ui.Ops),
|
||||||
q: w.Queue(),
|
q: w.Queue(),
|
||||||
extra: make(map[string]interface{}),
|
|
||||||
}
|
}
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx Context) Reset(e app.DrawEvent) Context {
|
func (ctx Context) Reset(e app.DrawEvent) Context {
|
||||||
|
@ -62,12 +80,26 @@ type Label struct {
|
||||||
l *text.Label
|
l *text.Label
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLabel(face text.Face, t string, alignment text.Alignment) *Label {
|
type LabelOpts struct {
|
||||||
|
face text.Face
|
||||||
|
alignment text.Alignment
|
||||||
|
}
|
||||||
|
type LabelOption func(*LabelOpts)
|
||||||
|
func LabelFace(x text.Face) LabelOption {
|
||||||
|
return func(o *LabelOpts) { o.face = x }
|
||||||
|
}
|
||||||
|
func LabelAlignment(x text.Alignment) LabelOption {
|
||||||
|
return func(o *LabelOpts) { o.alignment = x }
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLabel(t string, lops ...LabelOption) *Label {
|
||||||
ret := &Label{}
|
ret := &Label{}
|
||||||
|
opts := &LabelOpts{}
|
||||||
|
for _,o := range lops { o(opts) }
|
||||||
ret.l = &text.Label{
|
ret.l = &text.Label{
|
||||||
Face: face,
|
Face: opts.face,
|
||||||
Text: t,
|
Text: t,
|
||||||
Alignment: alignment,
|
Alignment: opts.alignment,
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
@ -81,9 +113,24 @@ type Editor struct {
|
||||||
e *text.Editor
|
e *text.Editor
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEditor(face text.Face, singleline bool) *Editor {
|
type EditorOpts struct {
|
||||||
|
face text.Face
|
||||||
|
singleline bool
|
||||||
|
}
|
||||||
|
type EditorOption func(*EditorOpts)
|
||||||
|
func EditorFace(x text.Face) EditorOption {
|
||||||
|
return func(o *EditorOpts) { o.face = x }
|
||||||
|
}
|
||||||
|
func EditorSingleline() EditorOption {
|
||||||
|
return func(o *EditorOpts) { o.singleline = true }
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEditor(t string, eops ...EditorOption) *Editor {
|
||||||
ret := &Editor{}
|
ret := &Editor{}
|
||||||
ret.e = &text.Editor{ Face: face, SingleLine: singleline }
|
opts := &EditorOpts{}
|
||||||
|
for _,o := range eops { o(opts) }
|
||||||
|
ret.e = &text.Editor{ Face: opts.face, SingleLine: opts.singleline }
|
||||||
|
ret.SetText(t)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,33 +157,56 @@ func (fw fWidget) Layout(ctx Context) Context {
|
||||||
|
|
||||||
type Flex WidgetCombinator
|
type Flex WidgetCombinator
|
||||||
|
|
||||||
// This "Widget" does nothing except set the Flexible key of ctx.extra.
|
// This "Widget" does nothing except set the Flexible field of a FlexOpts
|
||||||
|
// struct within the Extra data structure
|
||||||
func Flexible(v float32) Widget {
|
func Flexible(v float32) Widget {
|
||||||
return NewfWidget(func(ctx Context) Context {
|
return NewfWidget(func(ctx Context) Context {
|
||||||
ctx.extra["Flexible"] = v
|
extra.data[extra.cur].(*FlexOpts).flexible = v
|
||||||
return ctx
|
return ctx
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FlexOpts struct {
|
||||||
|
axis layout.Axis
|
||||||
|
mainAxisAlignment layout.MainAxisAlignment
|
||||||
|
crossAxisAlignment layout.CrossAxisAlignment
|
||||||
|
flexible float32
|
||||||
|
}
|
||||||
|
|
||||||
|
type FlexOption func(*FlexOpts)
|
||||||
|
|
||||||
|
func FlexAxis(x layout.Axis) FlexOption {
|
||||||
|
return func(o *FlexOpts) { o.axis = x }
|
||||||
|
}
|
||||||
|
|
||||||
|
func MainAxisAlignment(x layout.MainAxisAlignment) FlexOption {
|
||||||
|
return func(o *FlexOpts) { o.mainAxisAlignment = x }
|
||||||
|
}
|
||||||
|
func CrossAxisAlignment(x layout.CrossAxisAlignment) FlexOption {
|
||||||
|
return func(o *FlexOpts) { o.crossAxisAlignment = x }
|
||||||
|
}
|
||||||
|
|
||||||
// NewFlex returns a WidgetCombinator that wraps the layout.Flex element.
|
// NewFlex returns a WidgetCombinator that wraps the layout.Flex element.
|
||||||
func NewFlex(axis layout.Axis, mainAxisAlignment layout.MainAxisAlignment, crossAxisAlignment layout.CrossAxisAlignment) Flex {
|
func NewFlex(fos ...FlexOption) Flex {
|
||||||
|
opts := &FlexOpts{}
|
||||||
|
for _,o := range fos { o(opts) }
|
||||||
f := layout.Flex{
|
f := layout.Flex{
|
||||||
Axis: axis,
|
Axis: opts.axis,
|
||||||
MainAxisAlignment: mainAxisAlignment,
|
MainAxisAlignment: opts.mainAxisAlignment,
|
||||||
CrossAxisAlignment: crossAxisAlignment,
|
CrossAxisAlignment: opts.crossAxisAlignment,
|
||||||
}
|
}
|
||||||
|
index := extra.New()
|
||||||
|
extra.data[index] = opts
|
||||||
|
|
||||||
return func(ws ...Widget) Widget {
|
return func(ws ...Widget) Widget {
|
||||||
return NewfWidget(func(ctx Context) Context {
|
return NewfWidget(func(ctx Context) Context {
|
||||||
|
extra.cur = index
|
||||||
|
opts := extra.data[index].(*FlexOpts)
|
||||||
f.Init(ctx.ops, ctx.cs)
|
f.Init(ctx.ops, ctx.cs)
|
||||||
fcs := make([]layout.FlexChild,len(ws))
|
fcs := make([]layout.FlexChild,len(ws))
|
||||||
for i, w := range ws {
|
for i, w := range ws {
|
||||||
if v,ok := ctx.extra["Flexible"]; ok {
|
if v := opts.flexible; v != 0 {
|
||||||
switch v := v.(type) {
|
ctx.cs = f.Flexible(v)
|
||||||
case float32:
|
|
||||||
ctx.cs = f.Flexible(v)
|
|
||||||
default:
|
|
||||||
log.Fatal("Type error")
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ctx.cs = f.Rigid()
|
ctx.cs = f.Rigid()
|
||||||
}
|
}
|
||||||
|
@ -144,15 +214,43 @@ func NewFlex(axis layout.Axis, mainAxisAlignment layout.MainAxisAlignment, cross
|
||||||
fcs[i] = f.End(ctx.dims)
|
fcs[i] = f.End(ctx.dims)
|
||||||
}
|
}
|
||||||
ctx.dims = f.Layout(fcs...)
|
ctx.dims = f.Layout(fcs...)
|
||||||
delete(ctx.extra, "Flexible")
|
|
||||||
return ctx
|
return ctx
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InsetOpts struct {
|
||||||
|
top, right, bottom, left ui.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
type InsetOption func(*InsetOpts)
|
||||||
|
|
||||||
|
func InsetTop(x ui.Value) InsetOption {
|
||||||
|
return func(o *InsetOpts) { o.top = x }
|
||||||
|
}
|
||||||
|
func InsetRight(x ui.Value) InsetOption {
|
||||||
|
return func(o *InsetOpts) { o.right = x }
|
||||||
|
}
|
||||||
|
func InsetBottom(x ui.Value) InsetOption {
|
||||||
|
return func(o *InsetOpts) { o.bottom = x }
|
||||||
|
}
|
||||||
|
func InsetLeft(x ui.Value) InsetOption {
|
||||||
|
return func(o *InsetOpts) { o.left = x }
|
||||||
|
}
|
||||||
|
func InsetSize(x ui.Value) InsetOption {
|
||||||
|
return func(o *InsetOpts) {
|
||||||
|
o.top = x
|
||||||
|
o.right = x
|
||||||
|
o.bottom = x
|
||||||
|
o.left = x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//NewInset returns a WidgetCombinator that wraps the layout.Inset element.
|
//NewInset returns a WidgetCombinator that wraps the layout.Inset element.
|
||||||
func NewInset(top, right, bottom, left ui.Value) WidgetCombinator {
|
func NewInset(insos ...InsetOption) WidgetCombinator {
|
||||||
ins := layout.Inset{ Top: top, Right: right, Bottom: bottom, Left: left }
|
opts := &InsetOpts{}
|
||||||
|
for _,o := range insos { o(opts) }
|
||||||
|
ins := layout.Inset{ Top: opts.top, Right: opts.right, Bottom: opts.bottom, Left: opts.left }
|
||||||
return func(ws ...Widget) Widget {
|
return func(ws ...Widget) Widget {
|
||||||
return NewfWidget(func(ctx Context) Context {
|
return NewfWidget(func(ctx Context) Context {
|
||||||
ctx.cs = ins.Begin(ctx.c, ctx.ops, ctx.cs)
|
ctx.cs = ins.Begin(ctx.c, ctx.ops, ctx.cs)
|
||||||
|
@ -190,12 +288,27 @@ func Enclose(e Enclosure, ws ...Widget) Widget {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBackground(color color.RGBA, radius ui.Value) WidgetCombinator {
|
type BackgroundOpts struct {
|
||||||
|
c color.RGBA
|
||||||
|
radius ui.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
type BackgroundOption func(*BackgroundOpts)
|
||||||
|
func BgColor(c color.RGBA) BackgroundOption {
|
||||||
|
return func(o *BackgroundOpts) { o.c = c }
|
||||||
|
}
|
||||||
|
func BgRadius(x ui.Value) BackgroundOption {
|
||||||
|
return func(o *BackgroundOpts) { o.radius = x }
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBackground(bos ...BackgroundOption) WidgetCombinator {
|
||||||
|
opts := &BackgroundOpts{}
|
||||||
|
for _,o := range bos { o(opts) }
|
||||||
bg := &Background{
|
bg := &Background{
|
||||||
Color: color,
|
Color: opts.c,
|
||||||
Radius: radius,
|
Radius: opts.radius,
|
||||||
Inset: layout.UniformInset(radius), // FIXME: need to be able to
|
Inset: layout.UniformInset(opts.radius),
|
||||||
} // do math ops on Values
|
}
|
||||||
return func(ws ...Widget) Widget {
|
return func(ws ...Widget) Widget {
|
||||||
return Enclose(bg, ws...)
|
return Enclose(bg, ws...)
|
||||||
}
|
}
|
||||||
|
@ -244,6 +357,11 @@ func rrect(ops *ui.Ops, width, height, se, sw, nw, ne float32) {
|
||||||
b.End()
|
b.End()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Clickable interface {
|
||||||
|
Widget
|
||||||
|
Clicked(Context) bool
|
||||||
|
}
|
||||||
|
|
||||||
//cWidget is a clickable Widget that provides the Clicked() method.
|
//cWidget is a clickable Widget that provides the Clicked() method.
|
||||||
type cWidget struct {
|
type cWidget struct {
|
||||||
w Widget
|
w Widget
|
||||||
|
@ -267,6 +385,6 @@ func (w cWidget) Clicked(ctx Context) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
//Clickable converts any Widget into a clickable Widget.
|
//Clickable converts any Widget into a clickable Widget.
|
||||||
func Clickable(w Widget) cWidget {
|
func AsClickable(w Widget) cWidget {
|
||||||
return cWidget{ w: w, click: new(gesture.Click) }
|
return cWidget{ w: w, click: new(gesture.Click) }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user