tg/screen.go
2023-10-22 20:41:01 +03:00

128 lines
2.3 KiB
Go

package tg
import (
"path"
)
// The type implements changing screen to the underlying ScreenId
type ScreenGo struct {
Path Path
Args []any
}
func (sc ScreenGo) Act(c *Context) {
c.Go(sc.Path, sc.Args...)
}
// The same as Act.
func (sc ScreenGo) Serve(c *Context) {
sc.Act(c)
}
// Unique identifier for the screen
// and relative paths to the screen.
type Path string
// Returns true if the path is empty.
func (p Path) IsEmpty() bool {
return p == ""
}
// Returns true if the path is absolute.
func (p Path) IsAbs() bool {
if len(p) == 0 {
return false
}
return p[0] == '/'
}
func (p Path) Dir() Path {
return Path(path.Dir(string(p)))
}
// Clean the path deleting exceed ., .. and / .
func (p Path) Clean() Path {
return Path(path.Clean(string(p)))
}
// Screen statement of the bot.
// Mostly what buttons to show.
type Screen struct {
// The widget to run when reaching the screen.
Widget Widget
}
// The first node with the "/" path.
type RootNode struct {
Screen *Screen
Subs []*Node
}
// The node is a simple way to represent
// tree-like structured applications.
type Node struct {
Path Path
Screen *Screen
Subs []*Node
}
// Return new root node with the specified widget in the screen.
func NewRootNode(widget Widget, subs ...*Node) *RootNode {
ret := &RootNode{}
ret.Screen = NewScreen(widget)
ret.Subs = subs
return ret
}
func NewNode(relPath Path, widget Widget, subs ...*Node) *Node {
ret := &Node{}
ret.Path = relPath
ret.Screen = NewScreen(widget)
ret.Subs = subs
return ret
}
func (n *RootNode) ScreenMap() ScreenMap {
m := make(ScreenMap)
var root Path = "/"
m[root] = n.Screen
for _, sub := range n.Subs {
buf := sub.ScreenMap(root)
for k, v := range buf {
_, ok := m[k]
if ok {
panic("duplicate paths in node definition")
}
m[k] = v
}
}
return m
}
func (n *Node) ScreenMap(root Path) ScreenMap {
m := make(ScreenMap)
pth := (root + n.Path).Clean()
m[pth] = n.Screen
for _, sub := range n.Subs {
buf := sub.ScreenMap(pth + "/")
for k, v := range buf {
_, ok := m[k]
if ok {
panic("duplicate paths in node definition")
}
m[k] = v
}
}
return m
}
// Map structure for the screens.
type ScreenMap map[Path] *Screen
// Returns the new screen with specified name and widget.
func NewScreen(widget Widget) *Screen {
return &Screen{
Widget: widget,
}
}