doesnt look as cool, but for sure feels simpler

This commit is contained in:
2026-02-26 00:41:03 +00:00
parent 34120f10af
commit fe5505435b
12 changed files with 671 additions and 617 deletions
-45
View File
@@ -1,45 +0,0 @@
// Package controllers defines the controller stuff for our TUI
package controllers
import (
"esdi/tui/internal/dom"
"esdi/tui/internal/events"
"log/slog"
"github.com/rivo/tview"
)
type Controller struct {
Logger *slog.Logger
Bus *events.Bus
App *tview.Application
Dom *dom.DOM
}
type ControlPanel struct {
*Controller
DeviceController *DeviceController
}
func NewControlPanel(logger *slog.Logger) *ControlPanel {
baseController := &Controller{
Logger: logger,
Bus: events.NewBus(),
App: tview.NewApplication(),
Dom: dom.NewDOM(),
}
return &ControlPanel{
Controller: baseController,
DeviceController: NewDeviceController(baseController),
}
}
func (cp *ControlPanel) Run() error {
if err := cp.DeviceController.Main(); err != nil {
return err
}
return cp.App.Run()
}
+17
View File
@@ -0,0 +1,17 @@
// Package controllers defines the controller stuff for our TUI
package controllers
import (
"esdi/tui/internal/dom"
"esdi/tui/internal/events"
"log/slog"
"github.com/rivo/tview"
)
type Controller struct {
Logger *slog.Logger
Bus *events.Bus
App *tview.Application
Dom *dom.DOM
}
+125 -178
View File
@@ -2,15 +2,10 @@
package controllers
import (
"esdi/cdashdisplay"
helper "esdi/helpers"
"esdi/peripheral"
"esdi/tui/internal/dom"
"esdi/tui/internal/events"
serv "esdi/tui/internal/services"
"esdi/tui/internal/ui"
"esdi/tui/internal/views"
"fmt"
"io"
"github.com/gdamore/tcell/v2"
)
@@ -18,16 +13,16 @@ import (
type DeviceController struct {
*Controller
DeviceAPIView *views.DeviceAPIView
DevClerk *peripheral.PeripheralDeviceClerk
CDash *cdashdisplay.CDashDisplay
LayoutCtrl *LayoutController
StreamStrl *StreamingCtrl
DevService *serv.CDashService
}
func NewDeviceController(base *Controller) *DeviceController {
func NewDeviceController(base *Controller, devService *serv.CDashService) *DeviceController {
mc := &DeviceController{
Controller: base,
DevClerk: peripheral.NewPeripheralDeviceClerk(),
CDash: nil,
LayoutCtrl: NewLayoutController(base),
DevService: devService,
StreamStrl: NewStreamingCtrl(),
}
@@ -58,122 +53,92 @@ func NewDeviceController(base *Controller) *DeviceController {
}()
})
mc.Bus.On(ui.CreateWindowEv{}, func(e any) {
win := e.(ui.CreateWindowEv).Window
// mc.Bus.On(ui.CreateWindowEv{}, func(e any) {
// })
winDecor := cdashdisplay.DefaultDecorations
winDecor.TextSize = win.TextSize
winDecor.TitleSize = win.TitleSize
// mc.Bus.On(ui.UpdateWindowEv{}, func(e any) {
// winModel := e.(ui.UpdateWindowEv)
//
// // Build a new UIWindow here I guess
// curWindow, ok := mc.CDash.State.Layout.Windows[winModel.ID]
// if !ok {
// mc.Bus.Emit(ui.PrintLogEv{Log: "could not acquire window from display state"})
// return
// }
//
// // Need to use a better interface for this me things
// // Update the dimensions
// curWindow.Dims.X0 = winModel.Window.X
// curWindow.Dims.Y0 = winModel.Window.Y
// curWindow.Dims.Width = winModel.Window.Width
// curWindow.Dims.Height = winModel.Window.Height
// // Update the opts
// curWindow.Opts.ShowID = winModel.Window.ShowID
// curWindow.Opts.WinType = winModel.Window.Type
// curWindow.Opts.PreviewValue = helper.B32(winModel.Window.PreviewValue)
// // Update the decorations
// curWindow.Decor.TitleSize = winModel.Window.TitleSize
// curWindow.Decor.TextSize = winModel.Window.TextSize
// // Update the title
// curWindow.Title = helper.B32(winModel.Window.Title)
//
// err := mc.CDash.UpdateWindow(winModel.ID, curWindow)
// if err != nil {
// mc.Bus.Emit(ui.PrintLogEv{Log: "failed to update window"})
// }
// })
uiWindow := cdashdisplay.UIWindow{
Dims: cdashdisplay.UIDimensions{
X0: win.X,
Y0: win.Y,
Width: win.Width,
Height: win.Height,
},
Opts: cdashdisplay.UIWindowOpts{
WinType: win.Type, // NOTE: values aren't implemented yet
ShowID: win.ShowID,
PreviewValue: helper.B32(win.PreviewValue),
},
Decor: winDecor,
Title: helper.B32(win.Title),
}
// mc.Bus.On(ui.DestroyWindowEv{}, func(e any) {
// mc.Logger.Info(fmt.Sprintf("Called in to destroy win: %d", e.(ui.DestroyWindowEv).ID))
// mc.CDash.DestroyWindow(e.(ui.DestroyWindowEv).ID)
//
// mc.Bus.Emit(ui.WindowDestroyedEv{ID: e.(ui.DestroyWindowEv).ID})
// })
wID, err := mc.CDash.CreateWindow(uiWindow)
if err != nil {
mc.Bus.Emit(ui.PrintLogEv{Log: "failed to create window\n"})
return
}
// mc.Bus.On(ui.MoveWindowEv{}, func(e any) {
// mvData := e.(ui.MoveWindowEv)
// mc.Logger.Debug(fmt.Sprintf("request to move window '%d'", mvData.WindowID))
//
// newDims, err := mc.CDash.MoveWindow(mvData.WindowID, mvData.Delta)
// if err != nil && err != io.EOF {
// mc.Logger.Debug(fmt.Sprintf("failed to move window '%d' %s", mvData.WindowID, err.Error()))
// return
// }
//
// mc.Bus.Emit(ui.WindowMovedEv{ID: mvData.WindowID, Dims: newDims})
// })
mc.Bus.Emit(ui.WindowCreatedEv{ID: wID, Win: uiWindow})
mc.Bus.Emit(ui.PrintLogEv{Log: "Window created!\n"})
})
// mc.Bus.On(ui.ResizeWindowEv{}, func(e any) {
// mvData := e.(ui.ResizeWindowEv)
// mc.Logger.Debug(fmt.Sprintf("requested to resize window '%d'", mvData.WindowID))
// err := mc.CDash.ResizeWindow(mvData.WindowID, mvData.Delta)
// if err != nil && err != io.EOF {
// mc.Logger.Debug(fmt.Sprintf("failed to resize window '%d' %s", mvData.WindowID, err.Error()))
// return
// }
// })
mc.Bus.On(ui.UpdateWindowEv{}, func(e any) {
winModel := e.(ui.UpdateWindowEv)
// mc.Bus.On(ui.SaveLayoutEv{}, func(e any) {
// mc.CDash.SaveLayout()
// })
// Build a new UIWindow here I guess
curWindow, ok := mc.CDash.State.Layout.Windows[winModel.ID]
if !ok {
mc.Bus.Emit(ui.PrintLogEv{Log: "could not acquire window from display state"})
return
}
// mc.Bus.On(ui.LoadLayoutEv{}, func(e any) {
// mc.CDash.LoadLayout()
// mc.Bus.Emit(ui.RegisterLoadedLayout{*mc.CDash.State.Layout})
// })
// Need to use a better interface for this me things
// Update the dimensions
curWindow.Dims.X0 = winModel.Window.X
curWindow.Dims.Y0 = winModel.Window.Y
curWindow.Dims.Width = winModel.Window.Width
curWindow.Dims.Height = winModel.Window.Height
// Update the opts
curWindow.Opts.ShowID = winModel.Window.ShowID
curWindow.Opts.WinType = winModel.Window.Type
curWindow.Opts.PreviewValue = helper.B32(winModel.Window.PreviewValue)
// Update the decorations
curWindow.Decor.TitleSize = winModel.Window.TitleSize
curWindow.Decor.TextSize = winModel.Window.TextSize
// Update the title
curWindow.Title = helper.B32(winModel.Window.Title)
// mc.Bus.On(ui.ForceRedraw{}, func(e any) {
// // mc.App.QueueUpdateDraw(func() {})
// mc.App.Draw()
// })
err := mc.CDash.UpdateWindow(winModel.ID, curWindow)
if err != nil {
mc.Bus.Emit(ui.PrintLogEv{Log: "failed to update window"})
}
})
// mc.Bus.On(ui.StartStreamingReqEv{}, func(e any) {
// mc.StreamStrl.Start(mc.Bus)
// })
mc.Bus.On(ui.DestroyWindowEv{}, func(e any) {
mc.Logger.Info(fmt.Sprintf("Called in to destroy win: %d", e.(ui.DestroyWindowEv).ID))
mc.CDash.DestroyWindow(e.(ui.DestroyWindowEv).ID)
mc.Bus.Emit(ui.WindowDestroyedEv{ID: e.(ui.DestroyWindowEv).ID})
})
mc.Bus.On(ui.MoveWindowEv{}, func(e any) {
mvData := e.(ui.MoveWindowEv)
mc.Logger.Debug(fmt.Sprintf("request to move window '%d'", mvData.WindowID))
newDims, err := mc.CDash.MoveWindow(mvData.WindowID, mvData.Delta)
if err != nil && err != io.EOF {
mc.Logger.Debug(fmt.Sprintf("failed to move window '%d' %s", mvData.WindowID, err.Error()))
return
}
mc.Bus.Emit(ui.WindowMovedEv{ID: mvData.WindowID, Dims: newDims})
})
mc.Bus.On(ui.ResizeWindowEv{}, func(e any) {
mvData := e.(ui.ResizeWindowEv)
mc.Logger.Debug(fmt.Sprintf("requested to resize window '%d'", mvData.WindowID))
err := mc.CDash.ResizeWindow(mvData.WindowID, mvData.Delta)
if err != nil && err != io.EOF {
mc.Logger.Debug(fmt.Sprintf("failed to resize window '%d' %s", mvData.WindowID, err.Error()))
return
}
})
mc.Bus.On(ui.SaveLayoutEv{}, func(e any) {
mc.CDash.SaveLayout()
})
mc.Bus.On(ui.LoadLayoutEv{}, func(e any) {
mc.CDash.LoadLayout()
mc.Bus.Emit(ui.RegisterLoadedLayout{*mc.CDash.State.Layout})
})
mc.Bus.On(ui.ForceRedraw{}, func(e any) {
// mc.App.QueueUpdateDraw(func() {})
mc.App.Draw()
})
mc.Bus.On(ui.StartStreamingReqEv{}, func(e any) {
mc.StreamStrl.Start(mc.Bus)
})
mc.Bus.On(ui.StopStreamingReqEv{}, func(e any) {
mc.StreamStrl.Stop(mc.Bus)
})
// mc.Bus.On(ui.StopStreamingReqEv{}, func(e any) {
// mc.StreamStrl.Stop(mc.Bus)
// })
return mc
}
@@ -185,24 +150,6 @@ func (mc *DeviceController) PrintToOutputWindow(msg string) {
})
}
func (mc *DeviceController) findCDashDisplay() {
mc.PrintToOutputWindow("looking for cdash display\n")
mc.Logger.Info("Looking for CDashDisplay")
cdashdisplay.SetLogger(mc.Logger.With("[device]", "cdashdisplay"))
display, err := cdashdisplay.NewCDashDisplay()
if err != nil {
mc.Logger.Info("didn't find cdashdisplay")
mc.PrintToOutputWindow("didn't find cdash display\n")
return
}
mc.CDash = display
mc.Logger.Info("found cdashdisplay on: " + display.WT.Cfg.Name)
mc.PrintToOutputWindow("found cdashdisplay on: " + display.WT.Cfg.Name + "\n")
}
func (mc *DeviceController) setAppEventCapture() {
mc.App.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if event.Key() == tcell.KeyCtrlC || event.Rune() == 'q' {
@@ -215,43 +162,53 @@ func (mc *DeviceController) setAppEventCapture() {
}
func (mc *DeviceController) setDeviceAPIViewEvents() {
mc.DeviceAPIView.MainFlex.
// api list hooks
mc.DeviceAPIView.DevAPIList.List.
SetInputCapture(func(ev *tcell.EventKey) *tcell.EventKey {
switch ev.Rune() {
case 'r':
go mc.findCDashDisplay()
go mc.DevService.FindDevice()
}
return ev
})
}
func (mc *DeviceController) AddDeviceAPIListItems() {
mc.DeviceAPIView.DevAPIList.AddItem("layout", "build a layout for CDashDisplay",
func() {
// var err error
//
// // Get the api pages
// apiToolPages := mc.DeviceAPIView.DevAPIToolView
//
// layoutToolUINode := mc.Dom.GetNodeByID(views.LayoutToolFlexID)
// if layoutToolUINode == nil {
// layoutToolUINode, err = buildLayoutFlexComponent(mc.Bus, mc.Dom)
// if err != nil {
// mc.PrintToOutputWindow(
// fmt.Sprintf(" Failed to build layout tool UI: %s\n", err.Error()),
// )
// }
// }
//
// err = views.AddAndShowPage(apiToolPages.Pages, layoutToolUINode, true)
// if err == nil {
// mc.App.SetFocus(layoutToolUINode.Self)
// }
// Get the api pages
views.AddAndShowPage(
mc.DeviceAPIView.DevAPIToolView.Pages,
"layout-tool",
mc.LayoutCtrl.LayoutToolView.Flex,
)
mc.App.SetFocus(mc.LayoutCtrl.LayoutToolView.LayoutTree.Tree)
})
}
func layoutToolUIOnSelect(bus *events.Bus, doc *dom.DOM) {
func (mc *DeviceController) injectViewCallbacks() {
mc.setDeviceAPIViewEvents()
}
func (mc *DeviceController) injectControllerCallbacks() {
// Tell the layout controller what to do on exit
mc.LayoutCtrl.OnExit = func() {
mc.App.SetFocus(mc.DeviceAPIView.DevAPIList.List)
}
}
func (mc *DeviceController) injectChannels() {
go func() {
for msg := range mc.DevService.Messages {
mc.PrintToOutputWindow(msg)
}
}()
go func() {
for msg := range mc.LayoutCtrl.Messages {
mc.PrintToOutputWindow(msg)
}
}()
}
func (mc *DeviceController) mainUI() error {
@@ -263,37 +220,27 @@ func (mc *DeviceController) mainUI() error {
return err
}
mc.setDeviceAPIViewEvents()
// Inject the view hooks
mc.injectViewCallbacks()
// Inject controller callbacks
mc.injectControllerCallbacks()
// Run channels
mc.injectChannels()
// Add the API things to the deviceAPIListView
mc.AddDeviceAPIListItems()
rootNode, err := mc.Dom.NewUINode("root", nil, mc.DeviceAPIView.MainFlex)
if err != nil {
return err
}
mc.Dom.SetRoot(rootNode)
return nil
}
func (mc *DeviceController) Main() error {
mc.Logger.Debug("and then here")
err := mc.mainUI()
mc.Logger.Debug("and then here x2")
mc.setAppEventCapture()
// First focused element
mc.Logger.Debug("and then here x3")
firstFocus := mc.Dom.GetElemByID(views.DeviceAPIListID)
if firstFocus == nil {
return err
}
mc.Logger.Debug("and then here x4")
mc.App.SetRoot(mc.DeviceAPIView.MainFlex, true)
mc.App.SetFocus(firstFocus)
mc.App.SetFocus(mc.DeviceAPIView.DevAPIList.List)
return err
}
+212 -9
View File
@@ -1,17 +1,220 @@
package controllers
import "esdi/tui/internal/events"
import (
"esdi/cdashdisplay"
"esdi/tui/internal/views"
"github.com/gdamore/tcell/v2"
)
type LayoutController struct {
EvBus *events.Bus
LayoutToolView any
*Controller
OnExit func()
LayoutToolView *views.LayoutToolView
Messages chan string
}
func (lc *LayoutController) registerEvents() {
}
func NewLayoutController(bus *events.Bus) *LayoutController {
return &LayoutController{
EvBus: bus,
func NewLayoutController(base *Controller) *LayoutController {
lc := &LayoutController{
Controller: base,
LayoutToolView: views.NewLayoutToolView(),
Messages: make(chan string, 10),
}
lc.registerHooks()
return lc
}
func (lc *LayoutController) registerHooks() {
lc.LayoutToolView.LayoutTree.Tree.SetInputCapture(
func(ev *tcell.EventKey) *tcell.EventKey {
switch ev.Key() {
case tcell.KeyEsc:
lc.OnExit()
}
switch ev.Rune() {
case 'n':
// Create a new window
lc.Messages <- "calling new window form\n"
lc.newWindowAction()
case 'x':
lc.Messages <- "calling delete window\n"
// Delete selected window
// bus.Emit(ui.LogEv{Log: })
// wRef, err := getCurNodeRef(tree)
// if err != nil {
// bus.Emit(ui.LogEv{Log: " -> " + err.Error()})
// break
// }
// bus.Emit(ui.DestroyWindowEv{ID: wRef.ID})
case 'm':
lc.Messages <- "calling window manipulation tool\n"
// Go into move mode
// bus.Emit(ui.LogEv{Log: })
// wRef, err := getCurNodeRef(tree)
// if err != nil {
// bus.Emit(ui.LogEv{Log: " -> " + err.Error()})
// break
// }
// windowManipulationTool(bus, doc, wRef.ID)
case 'e':
// Go into edit mode
case 's':
// Save the current layout
// bus.Emit(ui.SaveLayoutEv{})
case 'l':
// Load the layout
// bus.Emit(ui.LoadLayoutEv{})
case 'g':
// Go -> launches the current set up source
// streamingWindow(bus, doc)
}
return ev
},
)
}
func (lc *LayoutController) parseCreateWindowInput() (*cdashdisplay.UIWindow, error) {
form := lc.LayoutToolView.LayoutActions.CreateWindowView
lc.Messages <- form.Form.X.GetText()
// xValue, err := strconv.ParseUint(x, 10, 64)
// if err != nil {
// return models.Window{}, err
// }
// yValue, err := strconv.ParseUint(y, 10, 64)
// if err != nil {
// return models.Window{}, err
// }
// widthValue, err := strconv.ParseUint(w, 10, 64)
// if err != nil {
// return models.Window{}, err
// }
// heightValue, err := strconv.ParseUint(h, 10, 64)
// if err != nil {
// return models.Window{}, err
// }
// titleSizeValue, err := strconv.ParseUint(titleSize, 10, 64)
// if err != nil {
// return models.Window{}, err
// }
// textSizeValue, err := strconv.ParseUint(textSize, 10, 64)
// if err != nil {
// return models.Window{}, err
// }
//
// showIDValue := cdashdisplay.ShowIDFalse
// if showID {
// showIDValue = cdashdisplay.ShowIDTrue
// }
// win := e.(ui.CreateWindowEv).Window
//
// winDecor := cdashdisplay.DefaultDecorations
// winDecor.TextSize = win.TextSize
// winDecor.TitleSize = win.TitleSize
//
// uiWindow := cdashdisplay.UIWindow{
// Dims: cdashdisplay.UIDimensions{
// X0: win.X,
// Y0: win.Y,
// Width: win.Width,
// Height: win.Height,
// },
// Opts: cdashdisplay.UIWindowOpts{
// WinType: win.Type, // NOTE: values aren't implemented yet
// ShowID: win.ShowID,
// PreviewValue: helper.B32(win.PreviewValue),
// },
// Decor: winDecor,
// Title: helper.B32(win.Title),
// }
//
// wID, err := mc.CDash.CreateWindow(uiWindow)
// if err != nil {
// mc.Bus.Emit(ui.PrintLogEv{Log: "failed to create window\n"})
// return
// }
//
// mc.Bus.Emit(ui.WindowCreatedEv{ID: wID, Win: uiWindow})
// mc.Bus.Emit(ui.PrintLogEv{Log: "Window created!\n"})
// return models.Window{
// X: uint16(xValue),
// Y: uint16(yValue),
// Width: uint16(widthValue),
// Height: uint16(heightValue),
// ShowID: showIDValue,
// TitleSize: uint8(titleSizeValue),
// TextSize: uint8(textSizeValue),
// PreviewValue: prev,
// Title: title,
// }, nil
return nil, nil
}
func (lc *LayoutController) newWindowAction() {
if lc.LayoutToolView.LayoutActions.CreateWindowView != nil {
// already exists, just change focus and leave
lc.App.SetFocus(lc.LayoutToolView.LayoutActions.CreateWindowView.Form.Form)
lc.Messages <- "already exists"
return
}
// Get the new window form view
newWindowForm := views.NewCreateWindowFormView()
lc.LayoutToolView.LayoutActions.CreateWindowView = newWindowForm
// Set the event capture for this form
newWindowForm.Form.Form.SetInputCapture(func(ev *tcell.EventKey) *tcell.EventKey {
switch ev.Key() {
case tcell.KeyEscape:
lc.App.SetFocus(lc.LayoutToolView.LayoutTree.Tree)
}
return ev
})
// Set the behaviour for when we press the create button
newWindowForm.CreateBtn.SetSelectedFunc(func() {
lc.Messages <- "am I here???"
lc.parseCreateWindowInput()
// _, titleSizeTxt := titleSize.GetCurrentOption()
// _, textSizeTxt := textSize.GetCurrentOption()
// // Validate the inputs
// window, err := validateFormInputs(
// x0.GetText(),
// y0.GetText(),
// width.GetText(),
// height.GetText(),
// title.GetText(),
// previewValue.GetText(),
// titleSizeTxt,
// textSizeTxt,
// showID.IsChecked(),
// )
// if err != nil {
// // bus.Emit(ui.LogEv{Log: fmt.Sprintf("failed to parse form: %s\n", err.Error())})
// return
// }
// bus.Emit(ui.LogEv{Log: fmt.Sprintf("showID: %d\n", window.ShowID)})
// bus.Emit(ui.CreateWindowEv{Window: window})
})
// Set this on the action page and change to it
views.AddAndShowPage(
lc.LayoutToolView.LayoutActions.Pages,
"new-window-action-form",
newWindowForm.Form.Form,
)
// Set its focus
lc.App.SetFocus(newWindowForm.Form.Form)
}
+41
View File
@@ -0,0 +1,41 @@
package services
import (
"esdi/cdashdisplay"
"esdi/peripheral"
"log/slog"
)
type CDashService struct {
Logger *slog.Logger
CDash *cdashdisplay.CDashDisplay
DevClerk *peripheral.PeripheralDeviceClerk
Messages chan string
}
func NewCDashService(logger *slog.Logger) *CDashService {
return &CDashService{
Logger: logger,
CDash: nil,
DevClerk: peripheral.NewPeripheralDeviceClerk(),
Messages: make(chan string, 10),
}
}
func (cds *CDashService) FindDevice() {
cds.Messages <- "looking for cdash display...\n"
cds.Logger.Info("Looking for CDashDisplay")
cdashdisplay.SetLogger(cds.Logger.With("[device]", "cdashdisplay"))
display, err := cdashdisplay.NewCDashDisplay()
if err != nil {
cds.Logger.Info("didn't find cdashdisplay")
cds.Messages <- "didn't find cdash display\n"
return
}
cds.CDash = display
cds.Logger.Info("found cdashdisplay on: " + display.WT.Cfg.Name)
cds.Messages <- "found cdashdisplay on: " + display.WT.Cfg.Name + "\n"
}
+4 -15
View File
@@ -1,27 +1,16 @@
package views
import (
"esdi/tui/internal/dom"
"slices"
"github.com/rivo/tview"
)
func AddAndShowPage(
pages *tview.Pages,
page *dom.UINode,
changeFocus bool,
) error {
if !slices.Contains(pages.GetPageNames(false), page.ID) {
pages.AddAndSwitchToPage(page.ID, page.Self, true)
func AddAndShowPage(pages *tview.Pages, pageID string, page tview.Primitive) {
if !slices.Contains(pages.GetPageNames(false), pageID) {
pages.AddAndSwitchToPage(pageID, page, true)
} else {
// Only change to page
pages.SwitchToPage(page.ID)
pages.SwitchToPage(pageID)
}
return nil
}
// func PageExists(pages *tview.Pages, needle string) bool {
// return slices.Contains(pages.GetPageNames(false), needle)
// }
+89 -125
View File
@@ -58,22 +58,22 @@ func FindNodeByID(
func appendWindow(bus *events.Bus, doc *dom.DOM, tree *tview.TreeView, idx int16,
win *cdashdisplay.UIWindow) {
root := tree.GetRoot()
if root == nil {
bus.Emit(ui.LogEv{Log: "unable to get root of tree view"})
return
}
// Create the update tool
updateForm := windowInfoForm(bus, doc, idx, win)
fmtTitle := fmt.Sprintf("%s [%2d]", win.Title.String(), idx)
ref := windowReference{
ID: idx,
Form: updateForm,
}
newWindow := tview.NewTreeNode(fmtTitle).SetReference(&ref)
root.AddChild(newWindow)
// root := tree.GetRoot()
// if root == nil {
// bus.Emit(ui.LogEv{Log: "unable to get root of tree view"})
// return
// }
//
// // Create the update tool
// updateForm := windowInfoForm(bus, doc, idx, win)
//
// fmtTitle := fmt.Sprintf("%s [%2d]", win.Title.String(), idx)
// ref := windowReference{
// ID: idx,
// Form: updateForm,
// }
// newWindow := tview.NewTreeNode(fmtTitle).SetReference(&ref)
// root.AddChild(newWindow)
}
func BindWindowEvents(
@@ -150,54 +150,6 @@ func getCurNodeRef(tree *tview.TreeView) (*windowReference, error) {
return winRef, nil
}
func layoutToolTreeViewEvCapture(bus *events.Bus, doc *dom.DOM,
tree *tview.TreeView) func(event *tcell.EventKey) *tcell.EventKey {
return func(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() {
case tcell.KeyEsc:
bus.Emit(ui.ChangeFocusEv{Target: doc.GetElemByID(DeviceAPIListID)})
}
switch event.Rune() {
case 'n':
// Create a new window
bus.Emit(ui.LogEv{Log: "calling new window form\n"})
createNewWindowForm(bus, doc)
case 'x':
// Delete selected window
bus.Emit(ui.LogEv{Log: "calling delete window\n"})
wRef, err := getCurNodeRef(tree)
if err != nil {
bus.Emit(ui.LogEv{Log: " -> " + err.Error()})
break
}
bus.Emit(ui.DestroyWindowEv{ID: wRef.ID})
case 'm':
// Go into move mode
bus.Emit(ui.LogEv{Log: "calling window manipulation tool\n"})
wRef, err := getCurNodeRef(tree)
if err != nil {
bus.Emit(ui.LogEv{Log: " -> " + err.Error()})
break
}
windowManipulationTool(bus, doc, wRef.ID)
case 'e':
// Go into edit mode
case 's':
// Save the current layout
bus.Emit(ui.SaveLayoutEv{})
case 'l':
// Load the layout
bus.Emit(ui.LoadLayoutEv{})
case 'g':
// Go -> launches the current set up source
streamingWindow(bus, doc)
}
return event
}
}
func layoutToolTreeViewOnChange(bus *events.Bus, doc *dom.DOM) func(node *tview.TreeNode) {
// Set focus to our new tool
// if changeFocus {
@@ -205,21 +157,21 @@ func layoutToolTreeViewOnChange(bus *events.Bus, doc *dom.DOM) func(node *tview.
// }
return func(node *tview.TreeNode) {
// Here we want to change the current existing form on the action pages
nodeRef := node.GetReference()
if nodeRef == nil {
// its probably root I guess, thats what I'll believe
return
}
nodeWinRef := nodeRef.(*windowReference)
bus.Emit(ui.LogEv{
Log: fmt.Sprintf("changing to -> %d | %s\n", nodeWinRef.ID, nodeWinRef.Form.ID),
})
pages := doc.GetElemByID(LayoutToolActionPagesID)
AddAndShowPage(pages.(*tview.Pages), nodeWinRef.Form, false)
// // Here we want to change the current existing form on the action pages
// nodeRef := node.GetReference()
// if nodeRef == nil {
// // its probably root I guess, thats what I'll believe
// return
// }
//
// nodeWinRef := nodeRef.(*windowReference)
//
// bus.Emit(ui.LogEv{
// Log: fmt.Sprintf("changing to -> %d | %s\n", nodeWinRef.ID, nodeWinRef.Form.ID),
// })
//
// pages := doc.GetElemByID(LayoutToolActionPagesID)
// AddAndShowPage(pages.(*tview.Pages), nodeWinRef.Form, false)
}
}
@@ -239,75 +191,87 @@ func layoutToolTreeViewOnSelect(bus *events.Bus) func(node *tview.TreeNode) {
}
}
func buildLayoutTreeComponent(bus *events.Bus, doc *dom.DOM) (*dom.UINode, error) {
layoutTree := tview.NewTreeView()
type LayoutTreeView struct {
Tree *tview.TreeView
InputCapture func(*tcell.EventKey) *tcell.EventKey
OnChange func(node *tview.TreeNode)
OnSelect func(node *tview.TreeNode)
}
layoutTree.SetBorder(true).SetTitle("Layout Tree").
SetInputCapture(layoutToolTreeViewEvCapture(bus, doc, layoutTree))
layoutTree.SetChangedFunc(layoutToolTreeViewOnChange(bus, doc))
layoutTree.SetSelectedFunc(layoutToolTreeViewOnSelect(bus))
layoutTreeUINode, err := doc.NewUINode(LayoutToolTreeID,
doc.GetElemByID(RightFlexID), layoutTree)
if err != nil {
return nil, err
func NewLayoutTreeView() *LayoutTreeView {
view := &LayoutTreeView{
InputCapture: blankInputCapture,
OnChange: blankTreeViewOnChange,
OnSelect: blankTreeViewOnChange,
}
view.Tree = tview.NewTreeView()
view.Tree.SetBorder(true).SetTitle("Layout Tree")
view.Tree.SetInputCapture(view.InputCapture)
view.Tree.SetChangedFunc(view.OnChange)
view.Tree.SetSelectedFunc(view.OnSelect)
// view.Tree.SetChangedFunc(layoutToolTreeViewOnChange(bus, doc))
// view.Tree.SetSelectedFunc(layoutToolTreeViewOnSelect(bus))
// Bind the events for the treeview
BindWindowEvents(bus, doc, layoutTreeUINode.Self.(*tview.TreeView))
// BindWindowEvents(bus, doc, layoutTreeUINode.Self.(*tview.TreeView))
// Create a root element
rootElem := tview.NewTreeNode(".")
layoutTree.SetRoot(rootElem).SetCurrentNode(rootElem)
view.Tree.SetRoot(rootElem).SetCurrentNode(rootElem)
return layoutTreeUINode, nil
return view
}
func buildLayoutActionPagesComponent(bus *events.Bus, doc *dom.DOM) (*dom.UINode, error) {
type LayoutToolActionView struct {
Pages *tview.Pages
CreateWindowView *CreateWindowFormView
}
func NewLayoutToolActionView() *LayoutToolActionView {
view := &LayoutToolActionView{
CreateWindowView: nil,
}
// Create an empty page for it
emptyPage := tview.NewTextView().
SetTextAlign(tview.AlignCenter).
SetChangedFunc(func() {
bus.Emit(ui.RedrawEv{})
})
SetChangedFunc(func() {}) // Need to hook here
emptyPage.SetBorder(true).SetTitle("-- Tool Area --")
fmt.Fprintf(emptyPage, "No tool selected")
actionPages := tview.NewPages().AddPage(EmptyPageName, emptyPage, true, true)
view.Pages = tview.NewPages().AddPage(EmptyPageName, emptyPage, true, true)
actionPagesUINode, err := doc.NewUINode(LayoutToolActionPagesID,
doc.GetElemByID("right-flex"), actionPages)
if err != nil {
return nil, err
}
return actionPagesUINode, nil
return view
}
func buildLayoutFlexComponent(bus *events.Bus, doc *dom.DOM) (*dom.UINode, error) {
type LayoutToolView struct {
Flex *tview.Flex
LayoutTree *LayoutTreeView
LayoutActions *LayoutToolActionView
}
func NewLayoutToolView() *LayoutToolView {
view := &LayoutToolView{}
// Want a TreeView at the top
layoutTreeUINode, err := buildLayoutTreeComponent(bus, doc)
if err != nil {
return nil, err
}
view.LayoutTree = NewLayoutTreeView()
// Want pages below to run actions
actionPagesUINode, err := buildLayoutActionPagesComponent(bus, doc)
if err != nil {
return nil, err
}
view.LayoutActions = NewLayoutToolActionView()
layoutToolFlex := tview.NewFlex().SetDirection(tview.FlexRow)
layoutToolFlexNode, err := doc.NewUINode(LayoutToolFlexID,
doc.GetElemByID(APIToolPagesID), layoutToolFlex)
if err != nil {
return nil, err
}
// Create the flex
view.Flex = tview.NewFlex().SetDirection(tview.FlexRow)
layoutToolFlex.
AddItem(layoutTreeUINode.Self, 0, 2, true).
AddItem(actionPagesUINode.Self, 0, 5, false)
view.Flex.
AddItem(view.LayoutTree.Tree, 0, 2, true).
AddItem(view.LayoutActions.Pages, 0, 5, false)
return layoutToolFlexNode, nil
return view
}
func (ltv *LayoutToolView) AddWindow() {
}
+133 -242
View File
@@ -2,274 +2,165 @@ package views
import (
"fmt"
"strconv"
"esdi/cdashdisplay"
"esdi/tui/internal/dom"
"esdi/tui/internal/events"
"esdi/tui/internal/models"
"esdi/tui/internal/ui"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
// Validate the form inputs
func validateFormInputs(x, y, w, h,
title, prev, titleSize, textSize string,
showID bool) (models.Window, error) {
xValue, err := strconv.ParseUint(x, 10, 64)
if err != nil {
return models.Window{}, err
}
yValue, err := strconv.ParseUint(y, 10, 64)
if err != nil {
return models.Window{}, err
}
widthValue, err := strconv.ParseUint(w, 10, 64)
if err != nil {
return models.Window{}, err
}
heightValue, err := strconv.ParseUint(h, 10, 64)
if err != nil {
return models.Window{}, err
}
titleSizeValue, err := strconv.ParseUint(titleSize, 10, 64)
if err != nil {
return models.Window{}, err
}
textSizeValue, err := strconv.ParseUint(textSize, 10, 64)
if err != nil {
return models.Window{}, err
}
showIDValue := cdashdisplay.ShowIDFalse
if showID {
showIDValue = cdashdisplay.ShowIDTrue
}
return models.Window{
X: uint16(xValue),
Y: uint16(yValue),
Width: uint16(widthValue),
Height: uint16(heightValue),
ShowID: showIDValue,
TitleSize: uint8(titleSizeValue),
TextSize: uint8(textSizeValue),
PreviewValue: prev,
Title: title,
}, nil
type CDashDisplayWindowFormView struct {
Form *tview.Form
X *tview.InputField
Y *tview.InputField
Width *tview.InputField
Height *tview.InputField
Title *tview.InputField
PreviewValue *tview.InputField
ShowID *tview.Checkbox
WinType *tview.DropDown
TitleSize *tview.DropDown
TextSize *tview.DropDown
}
func createNewWindowForm(bus *events.Bus, doc *dom.DOM) {
var err error
func NewCDashDisplayWindowFormView() *CDashDisplayWindowFormView {
view := &CDashDisplayWindowFormView{}
x0 := tview.NewInputField().SetLabel("x")
y0 := tview.NewInputField().SetLabel("y")
width := tview.NewInputField().SetLabel("width")
height := tview.NewInputField().SetLabel("height")
title := tview.NewInputField().SetLabel("title")
previewValue := tview.NewInputField().SetLabel("preview value")
showID := tview.NewCheckbox().SetLabel("show ID").SetChecked(true)
winType := tview.NewDropDown().SetLabel("type").
SetOptions([]string{"string", "bar"}, func(s string, id int) {
// Here we have to add extra options for the configuration of default
// values and so on
}).
SetCurrentOption(0)
titleSize := tview.NewDropDown().SetLabel("Title Size").
SetOptions([]string{"1", "2", "3", "4", "5", "6", "7", "8"}, func(s string, id int) {
}).
SetCurrentOption(0)
textSize := tview.NewDropDown().SetLabel("Text Size").
SetOptions([]string{"1", "2", "3", "4", "5", "6", "7", "8"}, func(s string, id int) {
}).
view.X = tview.NewInputField().SetLabel("x")
view.Y = tview.NewInputField().SetLabel("y")
view.Width = tview.NewInputField().SetLabel("width")
view.Height = tview.NewInputField().SetLabel("height")
view.Title = tview.NewInputField().SetLabel("title")
view.PreviewValue = tview.NewInputField().SetLabel("preview value")
view.ShowID = tview.NewCheckbox().SetLabel("show ID").SetChecked(true)
view.WinType = tview.NewDropDown().SetLabel("type").
SetOptions([]string{"string", "bar"}, func(s string, id int) {}).
SetCurrentOption(0)
view.TitleSize = tview.NewDropDown().SetLabel("Title Size").SetCurrentOption(0)
for k := range 20 {
view.TitleSize.AddOption(fmt.Sprintf("%d", k+1), blankDropdownOptionCallback)
}
view.TitleSize.SetCurrentOption(0)
form := tview.NewForm().
AddFormItem(x0).
AddFormItem(y0).
AddFormItem(width).
AddFormItem(height).
AddFormItem(title).
AddFormItem(previewValue).
AddFormItem(showID).
AddFormItem(winType).
AddFormItem(titleSize).
AddFormItem(textSize).
AddButton("Create", func() {
_, titleSizeTxt := titleSize.GetCurrentOption()
_, textSizeTxt := textSize.GetCurrentOption()
// Validate the inputs
window, err := validateFormInputs(
x0.GetText(),
y0.GetText(),
width.GetText(),
height.GetText(),
title.GetText(),
previewValue.GetText(),
titleSizeTxt,
textSizeTxt,
showID.IsChecked(),
)
view.TextSize = tview.NewDropDown().SetLabel("Text Size")
for k := range 20 {
view.TextSize.AddOption(fmt.Sprintf("%d", k+1), blankDropdownOptionCallback)
}
view.TitleSize.SetCurrentOption(0)
if err != nil {
bus.Emit(ui.LogEv{Log: fmt.Sprintf("failed to parse form: %s\n", err.Error())})
return
}
view.Form = tview.NewForm().
AddFormItem(view.X).
AddFormItem(view.Y).
AddFormItem(view.Width).
AddFormItem(view.Height).
AddFormItem(view.Title).
AddFormItem(view.PreviewValue).
AddFormItem(view.ShowID).
AddFormItem(view.WinType).
AddFormItem(view.TitleSize).
AddFormItem(view.TextSize)
bus.Emit(ui.LogEv{Log: fmt.Sprintf("showID: %d\n", window.ShowID)})
bus.Emit(ui.CreateWindowEv{Window: window})
})
view.Form.SetBorder(true).
SetTitle("New Window Form").
SetTitleAlign(tview.AlignLeft)
// Need to inject the event capture later
form.SetBorder(true).
SetTitle("new window form").
SetTitleAlign(tview.AlignLeft).
SetInputCapture(func(ev *tcell.EventKey) *tcell.EventKey {
switch ev.Key() {
case tcell.KeyEscape:
bus.Emit(ui.ChangeFocusEv{Target: doc.GetElemByID(LayoutToolFlexID)})
}
return view
}
return ev
})
type CreateWindowFormView struct {
Form *CDashDisplayWindowFormView
CreateBtn *tview.Button
}
var formNode *dom.UINode
formNode = doc.GetNodeByID("new-window-form")
if formNode == nil {
formNode, err = doc.NewUINode("new-window-form",
doc.GetElemByID(LayoutToolActionPagesID), form)
if err != nil {
panic("failed to create UI node for the new window form: " + err.Error())
}
func NewCreateWindowFormView() *CreateWindowFormView {
view := &CreateWindowFormView{
Form: NewCDashDisplayWindowFormView(),
}
AddAndShowPage(doc.GetElemByID(LayoutToolActionPagesID).(*tview.Pages), formNode, true)
view.CreateBtn = tview.NewButton("Create")
// Need to inject the button functionality later
view.Form.Form.AddButton("Create", func() {})
return view
}
func windowInfoPageID(idx int16) string {
return fmt.Sprintf("layout-tool-win-info-%d", idx)
type WindowFormView struct {
Form *CDashDisplayWindowFormView
UpdateBtn *tview.Button
}
func windowInfoForm(bus *events.Bus, doc *dom.DOM, idx int16,
win *cdashdisplay.UIWindow) *dom.UINode {
var err error
func NewWindowFormView(win *cdashdisplay.UIWindow) *WindowFormView {
view := &WindowFormView{
Form: NewCDashDisplayWindowFormView(),
}
x0 := tview.NewInputField().SetLabel("x").
SetText(fmt.Sprintf("%d", win.Dims.X0))
y0 := tview.NewInputField().SetLabel("y").
SetText(fmt.Sprintf("%d", win.Dims.Y0))
width := tview.NewInputField().SetLabel("width").
SetText(fmt.Sprintf("%d", win.Dims.Width))
height := tview.NewInputField().SetLabel("height").
SetText(fmt.Sprintf("%d", win.Dims.Height))
title := tview.NewInputField().SetLabel("title").
SetText(win.Title.String())
previewValue := tview.NewInputField().SetLabel("preview value").
SetText(win.Opts.PreviewValue.String())
showID := tview.NewCheckbox().SetLabel("show ID").SetChecked(true)
winType := tview.NewDropDown().SetLabel("type").
SetOptions([]string{"string", "bar"}, func(s string, id int) {
// Here we have to add extra options for the configuration of default
// values and so on
}).
SetCurrentOption(0)
// NOTE: put this thing into a loop that generate the numbers or something yo
titleSize := tview.NewDropDown().SetLabel("Title Size").
SetOptions([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"11", "12", "13", "14", "15", "16", "17", "18", "19", "20"},
func(s string, id int) {
}).
SetCurrentOption(int(win.Decor.TitleSize))
textSize := tview.NewDropDown().SetLabel("Text Size").
SetOptions([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"11", "12", "13", "14", "15", "16", "17", "18", "19", "20"},
func(s string, id int) {
}).
SetCurrentOption(int(win.Decor.TextSize))
form := tview.NewForm().
AddFormItem(x0).
AddFormItem(y0).
AddFormItem(width).
AddFormItem(height).
AddFormItem(title).
AddFormItem(previewValue).
AddFormItem(showID).
AddFormItem(titleSize).
AddFormItem(textSize).
AddFormItem(winType).
AddButton("Update", func() {
bus.Emit(ui.LogEv{Log: "update event was created\n"})
_, titleSizeTxt := titleSize.GetCurrentOption()
_, textSizeTxt := textSize.GetCurrentOption()
// Validate the inputs
window, err := validateFormInputs(
x0.GetText(),
y0.GetText(),
width.GetText(),
height.GetText(),
title.GetText(),
previewValue.GetText(),
titleSizeTxt,
textSizeTxt,
showID.IsChecked(),
)
if err != nil {
bus.Emit(ui.LogEv{Log: fmt.Sprintf("failed to parse form: %s\n", err.Error())})
return
}
bus.Emit(ui.LogEv{Log: fmt.Sprintf("showID: %d\n", window.ShowID)})
bus.Emit(ui.LogEv{Log: "sending update window ev\n"})
bus.Emit(ui.UpdateWindowEv{ID: idx, Window: window})
})
form.SetBorder(true).
SetTitle(fmt.Sprintf("Info - %s [%2d]", win.Title.String(), idx)).
SetTitleAlign(tview.AlignLeft).
SetInputCapture(func(ev *tcell.EventKey) *tcell.EventKey {
switch ev.Key() {
case tcell.KeyEscape:
bus.Emit(ui.ChangeFocusEv{Target: doc.GetElemByID(LayoutToolTreeID)})
}
return ev
})
view.UpdateBtn = tview.NewButton("Update")
// Need to inject the button functionality later
// AddButton("Update", func() {
// bus.Emit(ui.LogEv{Log: "update event was created\n"})
//
// _, titleSizeTxt := titleSize.GetCurrentOption()
// _, textSizeTxt := textSize.GetCurrentOption()
// // Validate the inputs
// window, err := validateFormInputs(
// x0.GetText(),
// y0.GetText(),
// width.GetText(),
// height.GetText(),
// title.GetText(),
// previewValue.GetText(),
// titleSizeTxt,
// textSizeTxt,
// showID.IsChecked(),
// )
//
// if err != nil {
// bus.Emit(ui.LogEv{Log: fmt.Sprintf("failed to parse form: %s\n", err.Error())})
// return
// }
//
// bus.Emit(ui.LogEv{Log: fmt.Sprintf("showID: %d\n", window.ShowID)})
// bus.Emit(ui.LogEv{Log: "sending update window ev\n"})
// bus.Emit(ui.UpdateWindowEv{ID: idx, Window: window})
// })
// In case the window is moved we need to update this form
bus.On(ui.WindowMovedEv{}, func(e any) {
data := e.(ui.WindowMovedEv)
// Only update the fields if the event is for this thing
if data.ID != idx {
return
}
// bus.On(ui.WindowMovedEv{}, func(e any) {
// data := e.(ui.WindowMovedEv)
// // Only update the fields if the event is for this thing
// if data.ID != idx {
// return
// }
//
// // Get the current window-info-page
// elem := doc.GetElemByID(windowInfoPageID(data.ID))
// if elem == nil {
// bus.Emit(ui.LogEv{Log: "could't get hold of info page"})
// return
// }
//
// x0.SetText(fmt.Sprintf("%d", data.Dims.X0))
// x0.SetText(fmt.Sprintf("%d", data.Dims.Y0))
// width.SetText(fmt.Sprintf("%d", data.Dims.Width))
// height.SetText(fmt.Sprintf("%d", data.Dims.Height))
// })
// Get the current window-info-page
elem := doc.GetElemByID(windowInfoPageID(data.ID))
if elem == nil {
bus.Emit(ui.LogEv{Log: "could't get hold of info page"})
return
}
// Set the fields data
view.Form.X.SetText(fmt.Sprintf("%d", win.Dims.X0))
view.Form.Y.SetText(fmt.Sprintf("%d", win.Dims.Y0))
view.Form.Width.SetText(fmt.Sprintf("%d", win.Dims.Width))
view.Form.Height.SetText(fmt.Sprintf("%d", win.Dims.Height))
view.Form.Title.SetText(win.Title.String())
view.Form.PreviewValue.SetText(win.Opts.PreviewValue.String())
view.Form.ShowID.SetChecked(win.Opts.ShowID == 1)
view.Form.WinType.SetCurrentOption(0) // NOTE: this needs to set the correct option
view.Form.TitleSize.SetCurrentOption(int(win.Decor.TitleSize))
view.Form.TextSize.SetCurrentOption(int(win.Decor.TextSize))
x0.SetText(fmt.Sprintf("%d", data.Dims.X0))
x0.SetText(fmt.Sprintf("%d", data.Dims.Y0))
width.SetText(fmt.Sprintf("%d", data.Dims.Width))
height.SetText(fmt.Sprintf("%d", data.Dims.Height))
})
return view
}
var formNode *dom.UINode
elemID := windowInfoPageID(idx)
formNode = doc.GetNodeByID(elemID)
layoutToolActionPagesElem := doc.GetElemByID(LayoutToolActionPagesID)
if formNode == nil {
formNode, err = doc.NewUINode(elemID, layoutToolActionPagesElem, form)
if err != nil {
panic("failed to create UI node for the new window form: " + err.Error())
}
}
return formNode
func WindowInfoPageID(idx int16) string {
return fmt.Sprintf("layout-tool-win-info-%d", idx)
}
@@ -168,5 +168,5 @@ func windowManipulationTool(bus *events.Bus, doc *dom.DOM, idx int16) {
}
box.SetInputCapture(windowManipulationEvCapture(bus, doc, idx, &state))
AddAndShowPage(actionPages, boxNode, true)
// AddAndShowPage(actionPages, boxNode, true)
}
+1 -1
View File
@@ -62,7 +62,7 @@ func streamingWindow(bus *events.Bus, doc *dom.DOM) {
}
// Add it to the action pages and view it
AddAndShowPage(actionPages, boxNode, true)
// AddAndShowPage(actionPages, boxNode, true)
bus.Emit(ui.StartStreamingReqEv{})
+12
View File
@@ -0,0 +1,12 @@
package views
import (
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
var (
blankInputCapture = func(ev *tcell.EventKey) *tcell.EventKey { return ev }
blankTreeViewOnChange = func(node *tview.TreeNode) {}
blankDropdownOptionCallback = func() {}
)
+36 -1
View File
@@ -3,10 +3,45 @@ package tui
import (
"esdi/tui/internal/controllers"
"esdi/tui/internal/dom"
"esdi/tui/internal/events"
"esdi/tui/internal/services"
"log/slog"
"github.com/rivo/tview"
)
type ControlPanel struct {
*controllers.Controller
DeviceController *controllers.DeviceController
}
func NewControlPanel(logger *slog.Logger) *ControlPanel {
baseController := &controllers.Controller{
Logger: logger,
Bus: events.NewBus(),
App: tview.NewApplication(),
Dom: dom.NewDOM(),
}
deviceService := services.NewCDashService(logger)
return &ControlPanel{
Controller: baseController,
DeviceController: controllers.NewDeviceController(baseController, deviceService),
}
}
func (cp *ControlPanel) Run() error {
if err := cp.DeviceController.Main(); err != nil {
return err
}
return cp.App.Run()
}
func Run(logger *slog.Logger) error {
progController := controllers.NewControlPanel(logger)
progController := NewControlPanel(logger)
return progController.Run()
}