Files
esdi/tui/internal/controllers/device.go

169 lines
3.8 KiB
Go

// Package controllers defines our controller layer
package controllers
import (
"fmt"
"esdi/devices/cdashdisplay"
serv "esdi/services"
"esdi/tui/internal/views"
"github.com/gdamore/tcell/v2"
)
type DeviceController struct {
*Controller
DeviceAPIView *views.DeviceAPIView
LayoutCtrl *LayoutController
StreamCtrl *StreamingCtrl
Orchestrator *serv.Orchestrator
}
func NewDeviceController(
base *Controller,
orchestrator *serv.Orchestrator,
) *DeviceController {
mc := &DeviceController{
Controller: base,
LayoutCtrl: NewLayoutController(base, orchestrator.DeviceService),
Orchestrator: orchestrator,
StreamCtrl: NewStreamingCtrl(base, orchestrator.DeviceService, orchestrator.TelemetryService),
}
return mc
}
func (mc *DeviceController) PrintToOutputWindow(msg string) {
mc.App.QueueUpdateDraw(func() {
fmt.Fprintf(mc.DeviceAPIView.OutputWindow.TextArea, "%s", msg)
})
}
func (mc *DeviceController) setAppEventCapture() {
mc.App.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if event.Key() == tcell.KeyCtrlC || event.Rune() == 'q' {
mc.App.Stop()
return nil
}
return event
})
}
func (mc *DeviceController) setDeviceAPIViewEvents() {
// api list hooks
mc.DeviceAPIView.DevAPIList.List.
SetInputCapture(func(ev *tcell.EventKey) *tcell.EventKey {
switch ev.Rune() {
case 'r':
go mc.Orchestrator.DeviceService.FindDevices()
}
return ev
})
}
func (mc *DeviceController) AddDeviceAPIListItems() {
mc.DeviceAPIView.DevAPIList.
AddItem("layout", "build a layout for CDashDisplay", func() {
// This CDashDisplay specific, only load if we have a CDashDisplay
if !mc.Orchestrator.DeviceService.PeripheralExists(cdashdisplay.NAME) {
mc.Orchestrator.DeviceService.Messages <- "CDashDisplay it not loaded yet\n"
return
}
// Get the api pages
views.AddAndShowPage(
mc.DeviceAPIView.DevAPIToolView.Pages,
"layout-tool",
mc.LayoutCtrl.LayoutToolView.Flex,
)
mc.App.SetFocus(mc.LayoutCtrl.LayoutToolView.LayoutTree.Tree)
})
mc.DeviceAPIView.DevAPIList.
AddItem("stream", "stream data to the display", func() {
// If we don't have a CDashDisplay or data source, this should be blocked
if !mc.StreamCtrl.TelemServ.HasActiveProvider() {
mc.StreamCtrl.Messages <- "no active provider present\n"
return
}
views.AddAndShowPage(
mc.DeviceAPIView.DevAPIToolView.Pages,
"streaming-tool",
mc.StreamCtrl.StreamView.Flex,
)
// mc.StreamCtrl.SetInternalState()
mc.App.SetFocus(mc.StreamCtrl.StreamView.Options.Form)
})
}
func (mc *DeviceController) injectViewCallbacks() {
mc.setDeviceAPIViewEvents()
}
func (mc *DeviceController) injectControllerCallbacks() {
// Tell the layout controller what to do on exit
giveFocusToAPIList := func() {
mc.App.SetFocus(mc.DeviceAPIView.DevAPIList.List)
}
mc.LayoutCtrl.OnExit = giveFocusToAPIList
mc.StreamCtrl.OnExit = giveFocusToAPIList
}
func (mc *DeviceController) injectChannels() {
go func() {
for msg := range mc.Orchestrator.Messages {
mc.PrintToOutputWindow(msg)
}
}()
go func() {
for msg := range mc.LayoutCtrl.Messages {
mc.PrintToOutputWindow(msg)
}
}()
go func() {
for msg := range mc.StreamCtrl.Messages {
mc.PrintToOutputWindow(msg)
}
}()
}
func (mc *DeviceController) mainUI() error {
var err error
// Set the main view
mc.DeviceAPIView, err = views.NewDeviceAPIView()
if err != nil {
return err
}
// Inject the view hooks
mc.injectViewCallbacks()
// Inject controller callbacks
mc.injectControllerCallbacks()
// Run channels
mc.injectChannels()
// Add the API things to the deviceAPIListView
mc.AddDeviceAPIListItems()
return nil
}
func (mc *DeviceController) Main() error {
err := mc.mainUI()
mc.setAppEventCapture()
mc.App.SetRoot(mc.DeviceAPIView.MainFlex, true)
mc.App.SetFocus(mc.DeviceAPIView.DevAPIList.List)
return err
}