Files
esdi/peripheral/devices/cdash_display.go
T

273 lines
5.3 KiB
Go

package devices
import (
"fmt"
"os"
"strconv"
"unicode/utf8"
helper "esdi/helpers"
"esdi/peripheral/types"
"golang.org/x/term"
)
const (
newWindowCMDID types.Command = 3
destroyWindowCMDID types.Command = 4
moveWindowCMDID types.Command = 5
newLayoutCMDID types.Command = 6
)
var (
DefaultDecorations = UIDecorations{
HasBorder: 1,
BGColour: 0x1041, // Look in the eslabsCurses library for these colours
FGColour: 0xffff,
TitleColour: 0xffff,
BorderColour: 0xf800,
TitleSize: 2,
TextSize: 4,
Padding: 0x00,
}
)
type UIDimensions struct {
X0 uint16
Y0 uint16
Width uint16
Height uint16
}
type UIDecorations struct {
BGColour uint16
FGColour uint16
TitleColour uint16
BorderColour uint16
TitleSize uint8
TextSize uint8
HasBorder uint8
Padding uint8
}
type UIWindow struct {
Dims UIDimensions
Decor UIDecorations
Title [32]byte
}
type LayoutTree struct {
Windows map[int]UIWindow
}
func (l *LayoutTree) AddWindow(idx int, w UIWindow) {
l.Windows[idx] = w
}
func NewLayoutTree() *LayoutTree {
return &LayoutTree{
Windows: make(map[int]UIWindow),
}
}
type CDashState struct {
Layout *LayoutTree
}
// Well fuck it really, this will make do for now really lmao
var (
state *CDashState
)
var CDashDisplay = Device{
ID: CDashDisplayDevID,
Name: helper.B32("ESLabs CDashDisplay"),
API: map[string]DeviceCMD{
"new-window": {
Identifier: newWindowCMDID,
Name: "new-window",
Desc: "Creates a new window - pass the window name and dimensions",
ArgCheck: createWindowArgCheck,
Fn: createWindow,
},
"destroy-window": {
Identifier: destroyWindowCMDID,
Name: "destroy-window",
Desc: "Destroys a window by its ID",
ArgCheck: destroyWindowArgCheck,
Fn: destroyWindow,
},
"move-window": {
Identifier: moveWindowCMDID,
Name: "move-window",
Desc: "moves a window by its ID",
ArgCheck: moveWindowArgCheck,
Fn: moveWindow,
},
"new-layout": {
Identifier: newLayoutCMDID,
Name: "new-layout",
Desc: "creates a new layout",
ArgCheck: nil,
Fn: nil,
},
},
}
func createWindowArgCheck(args []string) error {
if len(args) != 5 {
return fmt.Errorf("wrong parameters, got %d, want %d. "+
"Command asks for: x0 y0 width height title", len(args), 5)
}
return nil
}
func createWindow(dCMD *DeviceCMD, args []string) (types.Command, []byte, error) {
// Parse the command
// x0, y0, width, height, title # add other decorations later on
// fmt.Printf("%s command called: %+v\n", dCMD.GetName(), args)
x0, err := strconv.ParseInt(args[0], 10, 0)
if err != nil {
return 0, []byte{}, err
}
y0, err := strconv.ParseInt(args[1], 10, 0)
if err != nil {
return 0, []byte{}, err
}
width, err := strconv.ParseInt(args[2], 10, 0)
if err != nil {
return 0, []byte{}, err
}
height, err := strconv.ParseInt(args[3], 10, 0)
if err != nil {
return 0, []byte{}, err
}
data := UIWindow{
Dims: UIDimensions{
X0: uint16(x0),
Y0: uint16(y0),
Width: uint16(width),
Height: uint16(height),
},
Decor: DefaultDecorations,
Title: helper.B32(args[4]),
}
bytes, err := helper.StructToBytes(data)
if err != nil {
return 0, []byte{}, err
}
// All went well so far so we can update the state
if state == nil {
state = &CDashState{Layout: NewLayoutTree()}
}
state.Layout.AddWindow(0, data)
return dCMD.GetIdentifier(), bytes, nil
}
func destroyWindowArgCheck(args []string) error {
if len(args) != 1 {
return fmt.Errorf("wrong parameters, got %d, want %d. "+
"Command asks for: winID", len(args), 1)
}
return nil
}
func destroyWindow(dCMD *DeviceCMD, args []string) (types.Command, []byte, error) {
// Parse the command
fmt.Printf("%s command called: %+v\n", dCMD.GetName(), args)
type UIWindowDestructPacket struct {
WinID int16
}
id, err := strconv.ParseInt(args[0], 10, 0)
if err != nil {
return 0, []byte{}, err
}
packet := UIWindowDestructPacket{
WinID: int16(id),
}
bytes, err := helper.StructToBytes(packet)
if err != nil {
return 0, []byte{}, err
}
return dCMD.GetIdentifier(), bytes, nil
}
func moveWindowArgCheck(args []string) error {
if len(args) != 1 {
return fmt.Errorf("wrong parameters, got %d, want %d. "+
"Command asks for: winID", len(args), 1)
}
return nil
}
func moveWindow(dCMD *DeviceCMD, args []string) (types.Command, []byte, error) {
// Create an interactive mode to move the window or whatever
fd := int(os.Stdin.Fd())
oldState, err := term.MakeRaw(fd)
if err != nil {
return dCMD.GetIdentifier(), []byte{}, err
}
defer term.Restore(fd, oldState)
buf := make([]byte, 8)
// var buffer []byte
for {
var stop = false
// We read the input on stdin and capture all types of inputs!
n, err := os.Stdin.Read(buf)
if err != nil {
return dCMD.GetIdentifier(), []byte{}, err
}
data := buf[:n]
if len(data) <= 0 {
continue
}
if data[0] == 0x1b {
continue
}
r, _ := utf8.DecodeRune(data)
if r == utf8.RuneError {
return dCMD.GetIdentifier(), []byte{}, err
}
switch r {
case 'q':
stop = true
case 'h':
fmt.Printf("←")
case 'l':
fmt.Printf("→")
case 'k':
fmt.Printf("↑")
case 'j':
fmt.Printf("↓")
}
if stop {
break
}
}
return dCMD.GetIdentifier(), []byte{}, fmt.Errorf("do nothing")
}