slope/gui.go

176 lines
5.3 KiB
Go
Raw Normal View History

// +build !nogui
package main
import (
"fmt"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
)
type GUI struct {
gui fyne.App
windows map[string]fyne.Window
}
func (g GUI) String() string {
return "GUI"
}
type guiWidget fyne.Widget
type guiContainer fyne.Container
var guiLib = vars{
"gui-create": func(a ...expression) expression {
return &GUI{app.New(), make(map[string]fyne.Window)}
},
"gui-add-window": func(a ...expression) expression {
if len(a) < 2 {
return exception("'gui-add-window' expects a GUI and a string as arguments, too few arguments were given")
}
g, ok := a[0].(*GUI)
if !ok {
return exception("'gui-add-window' was given a non-GUI value as its first argument")
}
s := String(a[1], false)
g.windows[s] = g.gui.NewWindow(s)
return true
},
"gui-list-windows": func(a ...expression) expression {
if len(a) == 0 {
return exception("'gui-list-windows' expects a GUI as an argument, no arguments were given")
}
g, ok := a[0].(*GUI)
if !ok {
return exception("'gui-list-windows' was given a non-GUI argument")
}
out := make([]expression, 0, len(g.windows))
for k := range g.windows {
out = append(out, k)
}
return out
},
"window-set-content": func(a ...expression) expression {
// (window-set-content window-id content...)
if len(a) < 3 {
return exception("'window-set-content' expects a GUI and a string as arguments, too few arguments were given")
}
g, ok := a[0].(*GUI)
if !ok {
return exception("'window-set-content' was given a non-GUI value as its first argument")
}
s := String(a[1], false)
w, ok := g.windows[s]
if !ok {
return exception("'window-show-and-run' was given a window ID that does not exist: " + s)
}
w.SetContent(a[2].(fyne.CanvasObject))
return true
},
"window-show-and-run": func(a ...expression) expression {
// (window-show-and-run window-id)
if len(a) < 2 {
return exception("'window-show-and-run' expects a GUI and a string as arguments, too few arguments were given")
}
g, ok := a[0].(*GUI)
if !ok {
return exception("'window-show-and-run' was given a non-GUI value as its first argument")
}
s := String(a[1], false)
w, ok := g.windows[s]
if !ok {
return exception("'window-show-and-run' was given a window ID that does not exist: " + s)
}
w.ShowAndRun()
return true
},
"widget-label": func(a ...expression) expression {
// (widget-label text:string alignment:number wrap:bool)
if len(a) == 0 {
return exception("'widget-label' expects at least one argument, a string representing the text of the label, no arguments were given")
}
var l guiWidget = widget.NewLabel(String(a[0], false))
if len(a) >= 2 {
align, ok := a[1].(number)
if !ok {
return exception("'widget-label' expects a number (-1, 0, or 1) as its optional second argument (alignment), a non-number value was given")
}
switch int(align) {
case -1:
l.(*widget.Label).Alignment = fyne.TextAlignLeading
case 0:
l.(*widget.Label).Alignment = fyne.TextAlignCenter
case 1:
l.(*widget.Label).Alignment = fyne.TextAlignTrailing
default:
return exception("'widget-label' expects a number (-1, 0, or 1) as its optional second argument (alignment), a number outside of the range was given")
}
}
if len(a) >= 3 {
wrap, ok := a[2].(bool)
if !ok {
return exception("'widget-label' expects a bool as its optional third argument (wrap), a non-bool value was given")
}
if wrap {
l.(*widget.Label).Wrapping = fyne.TextWrapWord
}
}
return l
},
"widget-button": func(a ...expression) expression {
// (widget-label text:string alignment:number wrap:bool)
if len(a) < 2 {
return exception("'widget-button' expects at least one argument, a string representing the text of the label, no arguments were given")
}
var b guiWidget
switch f := a[1].(type) {
case func(...expression) expression:
b = widget.NewButton(String(a[0], false), func() { f() })
case Callback:
b = widget.NewButton(String(a[0], false), func() { apply(f.p, []expression{}) })
default:
return exception("'widget-button' was given a non-procedure value as its second argument")
}
if len(a) >= 3 {
align, ok := a[2].(number)
if !ok {
return exception("'widget-label' expects a number (-1, 0, or 1) as its optional third argument (alignment), a non-number value was given")
}
switch int(align) {
case -1:
b.(*widget.Button).Alignment = widget.ButtonAlignLeading
case 0:
b.(*widget.Button).Alignment = widget.ButtonAlignCenter
case 1:
b.(*widget.Button).Alignment = widget.ButtonAlignTrailing
default:
return exception("'widget-button' expects a number (-1, 0, or 1) as its optional third argument (alignment), a number outside of the range was given")
}
}
return b
},
"container-vertical-box": func(a ...expression) expression {
list, err := ExpToCanvasObjectList(a)
if err != nil {
return exception("'container-vertical-box' was given a list that contained a non widget value")
}
return container.NewVBox(list...)
},
}
func ExpToCanvasObjectList(e []expression) ([]fyne.CanvasObject, error) {
out := make([]fyne.CanvasObject, len(e))
for i, v := range e {
wid, ok := v.(guiWidget)
if !ok {
return out, fmt.Errorf("Invalid list")
}
out[i] = wid.(fyne.Widget).(fyne.CanvasObject)
}
return out, nil
}