174 lines
3.5 KiB
Go
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
|
|
}
|