Files
osui-go/osui.go
T
2024-10-12 17:49:55 +02:00

174 lines
3.5 KiB
Go

package osui
import (
"fmt"
"os"
"strings"
"github.com/orus-dev/osui/colors"
"golang.org/x/term"
)
type Style struct {
Background string `json:"background"`
Foreground string `json:"foreground"`
Outline string `json:"outline"`
ActiveBackground string `json:"activeBackground"`
ActiveForeground string `json:"activeForeground"`
ActiveOutline string `json:"activeOutline"`
ClickedBackground string `json:"clickedBackground"`
ClickedForeground string `json:"clickedForeground"`
ClickedOutline string `json:"clickedOutline"`
SelectedBackground string `json:"selectedBackground"`
SelectedForeground string `json:"selectedForeground"`
SelectedOutline string `json:"selectedOutline"`
Cursor string `json:"cursor"`
InactiveCursor string `json:"inactiveCursor"`
}
func (s *Style) SetDefaults() {
if s.Cursor != "" {
s.Cursor = "> "
}
}
func (s *Style) UseStyle() {
s.Background = colors.AsBg(s.Background)
s.Foreground = colors.AsBg(s.Foreground)
s.Outline = colors.AsBg(s.Outline)
s.ActiveBackground = colors.AsBg(s.ActiveBackground)
s.ActiveForeground = colors.AsBg(s.ActiveForeground)
s.ActiveOutline = colors.AsBg(s.ActiveOutline)
s.ClickedBackground = colors.AsBg(s.ClickedBackground)
s.ClickedForeground = colors.AsFg(s.ClickedForeground)
s.ClickedOutline = colors.AsFg(s.ClickedOutline)
}
type Param struct {
Style Style `json:"style"`
X int `json:"y"`
Y int `json:"x"`
Width int `json:"width"`
Height int `json:"height"`
OnClick func()
OnUpdate func(ctx *Context)
Toggle bool `json:"useToggle"`
}
func (p *Param) UseParam(c Component) Component {
data := c.GetComponentData()
p.Style.SetDefaults()
data.Style = p.Style
data.X = p.X
data.Y = p.Y
if p.Height != 0 {
data.Height = p.Height
}
if p.Width != 0 {
data.Width = p.Width
}
if p.OnClick != nil {
data.OnClick = p.OnClick
} else {
data.OnClick = func() {}
}
if p.OnUpdate != nil {
data.OnUpdate = p.OnUpdate
} else {
data.OnUpdate = func(ctx *Context) { ctx.Response = 0 }
}
data.Toggle = p.Toggle
return c
}
type Context struct {
Key string
Response int
}
type ComponentData struct {
X int
Y int
Width int
Height int
DefaultColor string
IsActive bool
Style Style
OnClick func()
OnUpdate func(ctx *Context)
Toggle bool
Screen *Screen
}
type Component interface {
Render() string
GetComponentData() *ComponentData
Update(string) bool
}
type Screen struct {
Component Component
}
func NewScreen() *Screen {
return &Screen{}
}
func (s *Screen) Render() {
width, height := GetTerminalSize()
data := s.Component.GetComponentData()
if data.Height == 0 {
data.Height = height
}
if data.Width == 0 {
data.Width = width
}
frame := NewFrame(width, height)
RenderOnFrame(s.Component, &frame)
Clear()
fmt.Print(strings.Join(frame, ""))
}
func (s *Screen) Run(c Component) {
s.SetComponent(c)
HideCursor()
oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
if err != nil {
panic(err)
}
defer term.Restore(int(os.Stdin.Fd()), oldState)
for {
s.Render()
k, _ := ReadKey()
if s.Component.Update(k) {
ShowCursor()
return
}
}
}
func (s *Screen) SetComponent(c Component) {
s.Component = c
width, height := GetTerminalSize()
data := s.Component.GetComponentData()
if data.Height == 0 {
data.Height = height
}
if data.Width == 0 {
data.Width = width
}
data.Screen = s
data.IsActive = true
data.DefaultColor = colors.Reset
}