very bare bones layout selectable menu
This commit is contained in:
+23
-1
@@ -8,6 +8,7 @@ import (
|
||||
"log/slog"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
helper "esdi/helpers"
|
||||
"esdi/peripheral/communication"
|
||||
@@ -298,7 +299,7 @@ func (d *CDashDisplay) ResizeWindow(wID int16, delta *helper.Vector) error {
|
||||
|
||||
func (d *CDashDisplay) SaveLayout(outputPath string) error {
|
||||
file, err := os.OpenFile(path.Join(layoutsDir, outputPath),
|
||||
os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755)
|
||||
os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -339,6 +340,27 @@ func (d *CDashDisplay) LoadLayout(layoutName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *CDashDisplay) UnloadLayout() error {
|
||||
var err error
|
||||
for _, w := range d.State.Layout.Windows {
|
||||
pLogger.Debug(fmt.Sprintf("= Removing %d ==============================================",
|
||||
w.UIData.IDX))
|
||||
|
||||
err = d.DestroyWindow(w.UIData.IDX)
|
||||
time.Sleep(75 * time.Millisecond)
|
||||
if err != nil {
|
||||
pLogger.Error(fmt.Sprintf("failed to destroy window: %+v", err))
|
||||
// NOTE: Add a way to handle multiple errors ?
|
||||
return err
|
||||
}
|
||||
|
||||
pLogger.Debug(fmt.Sprintf("= Removing %d ==============================================",
|
||||
w.UIData.IDX))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *CDashDisplay) SendData(data *telemetry.TelemetryData) {
|
||||
packet := data.Pack()
|
||||
|
||||
|
||||
Executable
+193
@@ -0,0 +1,193 @@
|
||||
Windows:
|
||||
2:
|
||||
uiwindow:
|
||||
Dims:
|
||||
X0: 470
|
||||
Y0: 71
|
||||
Width: 322
|
||||
Height: 57
|
||||
Decor:
|
||||
BGColour: 4161
|
||||
FGColour: 65535
|
||||
TitleColour: 65535
|
||||
BorderColour: 63488
|
||||
TitleSize: 2
|
||||
TextSize: 4
|
||||
HasBorder: 1
|
||||
Padding: 0
|
||||
Opts:
|
||||
ShowID: 0
|
||||
WinType: 2
|
||||
PreviewValue: "9999"
|
||||
Title: Dig Tacho
|
||||
uidata:
|
||||
WID: 2
|
||||
TelemetryField: RPM
|
||||
4:
|
||||
uiwindow:
|
||||
Dims:
|
||||
X0: 321
|
||||
Y0: 195
|
||||
Width: 134
|
||||
Height: 80
|
||||
Decor:
|
||||
BGColour: 4161
|
||||
FGColour: 65535
|
||||
TitleColour: 65535
|
||||
BorderColour: 63488
|
||||
TitleSize: 2
|
||||
TextSize: 7
|
||||
HasBorder: 1
|
||||
Padding: 0
|
||||
Opts:
|
||||
ShowID: 0
|
||||
WinType: 2
|
||||
PreviewValue: "234"
|
||||
Title: SPEEDO
|
||||
uidata:
|
||||
WID: 4
|
||||
TelemetryField: Speed
|
||||
5:
|
||||
uiwindow:
|
||||
Dims:
|
||||
X0: 590
|
||||
Y0: 367
|
||||
Width: 100
|
||||
Height: 50
|
||||
Decor:
|
||||
BGColour: 4161
|
||||
FGColour: 65535
|
||||
TitleColour: 65535
|
||||
BorderColour: 63488
|
||||
TitleSize: 2
|
||||
TextSize: 3
|
||||
HasBorder: 1
|
||||
Padding: 0
|
||||
Opts:
|
||||
ShowID: 0
|
||||
WinType: 2
|
||||
PreviewValue: "101.5"
|
||||
Title: Water T
|
||||
uidata:
|
||||
WID: 5
|
||||
TelemetryField: Water Temperature
|
||||
10:
|
||||
uiwindow:
|
||||
Dims:
|
||||
X0: 470
|
||||
Y0: 132
|
||||
Width: 169
|
||||
Height: 50
|
||||
Decor:
|
||||
BGColour: 4161
|
||||
FGColour: 65535
|
||||
TitleColour: 65535
|
||||
BorderColour: 63488
|
||||
TitleSize: 2
|
||||
TextSize: 3
|
||||
HasBorder: 1
|
||||
Padding: 0
|
||||
Opts:
|
||||
ShowID: 0
|
||||
WinType: 2
|
||||
PreviewValue: "123.4"
|
||||
Title: Fuel Level
|
||||
uidata:
|
||||
WID: 10
|
||||
TelemetryField: Fuel Level
|
||||
11:
|
||||
uiwindow:
|
||||
Dims:
|
||||
X0: 321
|
||||
Y0: 73
|
||||
Width: 134
|
||||
Height: 111
|
||||
Decor:
|
||||
BGColour: 4161
|
||||
FGColour: 65535
|
||||
TitleColour: 65535
|
||||
BorderColour: 63488
|
||||
TitleSize: 2
|
||||
TextSize: 12
|
||||
HasBorder: 1
|
||||
Padding: 0
|
||||
Opts:
|
||||
ShowID: 0
|
||||
WinType: 2
|
||||
PreviewValue: R
|
||||
Title: Box
|
||||
uidata:
|
||||
WID: 11
|
||||
TelemetryField: Gear
|
||||
16:
|
||||
uiwindow:
|
||||
Dims:
|
||||
X0: 694
|
||||
Y0: 423
|
||||
Width: 100
|
||||
Height: 50
|
||||
Decor:
|
||||
BGColour: 4161
|
||||
FGColour: 65535
|
||||
TitleColour: 65535
|
||||
BorderColour: 63488
|
||||
TitleSize: 2
|
||||
TextSize: 3
|
||||
HasBorder: 1
|
||||
Padding: 0
|
||||
Opts:
|
||||
ShowID: 0
|
||||
WinType: 2
|
||||
PreviewValue: "4.56"
|
||||
Title: Oil P
|
||||
uidata:
|
||||
WID: 16
|
||||
TelemetryField: Oil Pressure
|
||||
17:
|
||||
uiwindow:
|
||||
Dims:
|
||||
X0: 694
|
||||
Y0: 367
|
||||
Width: 100
|
||||
Height: 50
|
||||
Decor:
|
||||
BGColour: 4161
|
||||
FGColour: 65535
|
||||
TitleColour: 65535
|
||||
BorderColour: 63488
|
||||
TitleSize: 2
|
||||
TextSize: 3
|
||||
HasBorder: 1
|
||||
Padding: 0
|
||||
Opts:
|
||||
ShowID: 0
|
||||
WinType: 2
|
||||
PreviewValue: "101.4"
|
||||
Title: Oil T
|
||||
uidata:
|
||||
WID: 17
|
||||
TelemetryField: Oil Temperature
|
||||
20:
|
||||
uiwindow:
|
||||
Dims:
|
||||
X0: 142
|
||||
Y0: 19
|
||||
Width: 500
|
||||
Height: 20
|
||||
Decor:
|
||||
BGColour: 4161
|
||||
FGColour: 65535
|
||||
TitleColour: 65535
|
||||
BorderColour: 63488
|
||||
TitleSize: 1
|
||||
TextSize: 2
|
||||
HasBorder: 1
|
||||
Padding: 0
|
||||
Opts:
|
||||
ShowID: 0
|
||||
WinType: 1
|
||||
PreviewValue: "5678"
|
||||
Title: TACHO
|
||||
uidata:
|
||||
WID: 20
|
||||
TelemetryField: RPM
|
||||
@@ -2,6 +2,7 @@ package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"esdi/cdashdisplay"
|
||||
@@ -20,6 +21,7 @@ type LayoutController struct {
|
||||
Messages chan string
|
||||
DevService *services.CDashService
|
||||
MoveToolState *windowManipState
|
||||
SelectedLayout string // NOTE: This should be a struct to handle its own things
|
||||
}
|
||||
|
||||
func NewLayoutController(base *Controller, service *services.CDashService) *LayoutController {
|
||||
@@ -29,6 +31,7 @@ func NewLayoutController(base *Controller, service *services.CDashService) *Layo
|
||||
Messages: make(chan string, 10),
|
||||
DevService: service,
|
||||
MoveToolState: &windowManipState{Mode: moveMode},
|
||||
SelectedLayout: "layout.yaml",
|
||||
}
|
||||
|
||||
lc.registerHooks()
|
||||
@@ -56,6 +59,9 @@ func (lc *LayoutController) registerHooks() {
|
||||
case 'm':
|
||||
lc.Messages <- "calling window manipulation tool\n"
|
||||
lc.moveWindow()
|
||||
case 'c':
|
||||
lc.Messages <- "calling change selected layout tool\n"
|
||||
lc.changeSelectedLoadout()
|
||||
case 's':
|
||||
// Save the current layout
|
||||
lc.Messages <- "calling save layout\n"
|
||||
@@ -64,6 +70,10 @@ func (lc *LayoutController) registerHooks() {
|
||||
// Load the layout
|
||||
lc.Messages <- "calling load layout\n"
|
||||
lc.loadLayout()
|
||||
case 'u':
|
||||
// Unload the layout
|
||||
lc.Messages <- "calling unload layout\n"
|
||||
lc.unloadLayout()
|
||||
case 'g':
|
||||
// Go -> launches the current set up source
|
||||
// streamingWindow(bus, doc)
|
||||
@@ -339,7 +349,7 @@ func (lc *LayoutController) getCurrentTreeNodeModel() (*tview.TreeNode, int16, e
|
||||
|
||||
func (lc *LayoutController) loadLayout() {
|
||||
// We would get the layout path from somewhere but for nots its layout.yaml
|
||||
err := lc.DevService.LoadLayout("layout.yaml")
|
||||
err := lc.DevService.LoadLayout(lc.SelectedLayout)
|
||||
if err != nil {
|
||||
lc.Messages <- "failed to load layout: " + err.Error()
|
||||
return
|
||||
@@ -348,8 +358,16 @@ func (lc *LayoutController) loadLayout() {
|
||||
lc.displayLoadedLayouts()
|
||||
}
|
||||
|
||||
func (lc *LayoutController) unloadLayout() {
|
||||
err := lc.DevService.UnloadLayout()
|
||||
if err != nil {
|
||||
lc.Logger.Error(fmt.Sprintf("Failed to unload layout: %+v", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (lc *LayoutController) saveLayout() {
|
||||
err := lc.DevService.SaveLayout("layout.yaml")
|
||||
err := lc.DevService.SaveLayout(lc.SelectedLayout)
|
||||
if err != nil {
|
||||
lc.Messages <- "failed to save layout: " + err.Error()
|
||||
return
|
||||
@@ -423,3 +441,50 @@ func (lc *LayoutController) moveWindow() {
|
||||
|
||||
lc.App.SetFocus(formView.Form)
|
||||
}
|
||||
|
||||
// changeSelectedLoadout is used to change the currently selected loadout
|
||||
// its a very bare bones utility to aid development
|
||||
// NOTE: FOR THE LOVE OF WHATS HOLY ACTUALLY MAKE THIS GOOD BEFORE ADDING MORE FEATURES
|
||||
func (lc *LayoutController) changeSelectedLoadout() {
|
||||
// First we get the files in the layouts directory
|
||||
entries, err := os.ReadDir("./layouts")
|
||||
if err != nil {
|
||||
lc.Logger.Error(fmt.Sprintf("Failed to read directory: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
// Then we open a modal and pass that list there
|
||||
lc.Logger.Debug(fmt.Sprintf("Found layouts: %+v", entries))
|
||||
|
||||
layoutSelection := views.NewLayoutToolLayoutsList()
|
||||
layoutSelection.AddEntries(entries)
|
||||
layoutSelection.Tree.SetInputCapture(func(ev *tcell.EventKey) *tcell.EventKey {
|
||||
switch ev.Key() {
|
||||
case tcell.KeyESC:
|
||||
// We have to destroy this window, but first we tell the pages to show something else
|
||||
// NOTE: will this be left hanging and then given to GC? Can we improve that?
|
||||
lc.LayoutToolView.LayoutActions.LayoutSelection = nil
|
||||
lc.LayoutToolView.DeleteLayoutList()
|
||||
lc.App.SetFocus(lc.LayoutToolView.LayoutTree.Tree)
|
||||
}
|
||||
|
||||
return ev
|
||||
})
|
||||
|
||||
layoutSelection.Tree.SetSelectedFunc(func(node *tview.TreeNode) {
|
||||
ref := node.GetReference()
|
||||
if ref == nil {
|
||||
return
|
||||
}
|
||||
|
||||
lc.Messages <- "User selected " + fmt.Sprintf("%+v", ref) + "\n"
|
||||
lc.SelectedLayout = ref.(string)
|
||||
|
||||
lc.LayoutToolView.LayoutTree.Tree.SetTitle(fmt.Sprintf("%s [%s]",
|
||||
views.LayoutToolTreeViewTitle, ref.(string)))
|
||||
})
|
||||
|
||||
lc.LayoutToolView.LayoutActions.LayoutSelection = layoutSelection
|
||||
lc.LayoutToolView.ShowLayoutList()
|
||||
lc.App.SetFocus(lc.LayoutToolView.LayoutActions.LayoutSelection.Tree)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync/atomic"
|
||||
|
||||
"esdi/cdashdisplay"
|
||||
helper "esdi/helpers"
|
||||
"esdi/peripheral"
|
||||
"esdi/telemetry"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type CDashService struct {
|
||||
@@ -65,6 +66,10 @@ func (cds *CDashService) SaveLayout(layoutPath string) error {
|
||||
return cds.CDash.SaveLayout(layoutPath)
|
||||
}
|
||||
|
||||
func (cds *CDashService) UnloadLayout() error {
|
||||
return cds.CDash.UnloadLayout()
|
||||
}
|
||||
|
||||
func (cds *CDashService) UpdateWindow(win *cdashdisplay.DesktopUIWindow) error {
|
||||
cds.Messages <- fmt.Sprintf("Updating a window:\n%+v\n", win)
|
||||
return cds.CDash.UpdateWindow(win)
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
LayoutToolTreeViewTitle = "Layout Tree"
|
||||
LayoutToolFlexID = "layout-tool-flex"
|
||||
LayoutToolTreeID = "layout-tool-tree"
|
||||
LayoutToolActionPagesID = "layout-tool-action-pages"
|
||||
@@ -30,7 +31,7 @@ func NewLayoutTreeView() *LayoutTreeView {
|
||||
|
||||
view.Tree = tview.NewTreeView()
|
||||
|
||||
view.Tree.SetBorder(true).SetTitle("Layout Tree")
|
||||
view.Tree.SetBorder(true).SetTitle(LayoutToolTreeViewTitle)
|
||||
view.Tree.SetInputCapture(view.InputCapture)
|
||||
// Inject ChangedFunc
|
||||
// Inject SelectedFunc
|
||||
@@ -61,6 +62,7 @@ func (lt *LayoutTreeView) AddWindow(win *cdashdisplay.DesktopUIWindow) error {
|
||||
type LayoutToolActionView struct {
|
||||
Pages *tview.Pages
|
||||
CreateWindowView *CreateWindowFormView
|
||||
LayoutSelection *LayoutToolLayoutsList
|
||||
}
|
||||
|
||||
func NewLayoutToolActionView() *LayoutToolActionView {
|
||||
@@ -154,6 +156,18 @@ func (ltv *LayoutToolView) ShowWindowFormByID(idx int16) {
|
||||
)
|
||||
}
|
||||
|
||||
func (ltv *LayoutToolView) ShowLayoutList() {
|
||||
AddAndShowPage(
|
||||
ltv.LayoutActions.Pages,
|
||||
"available-layouts-list",
|
||||
ltv.LayoutActions.LayoutSelection.Tree,
|
||||
)
|
||||
}
|
||||
|
||||
func (ltv *LayoutToolView) DeleteLayoutList() {
|
||||
ltv.LayoutActions.Pages.RemovePage("available-layouts-list")
|
||||
}
|
||||
|
||||
func (ltv *LayoutToolView) DeleteWindowByNode(node *tview.TreeNode) {
|
||||
root := ltv.LayoutTree.Tree.GetRoot()
|
||||
if root == nil {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package views
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
type LayoutToolLayoutsList struct {
|
||||
Tree *tview.TreeView
|
||||
}
|
||||
|
||||
func NewLayoutToolLayoutsList() *LayoutToolLayoutsList {
|
||||
view := &LayoutToolLayoutsList{}
|
||||
|
||||
view.Tree = tview.NewTreeView()
|
||||
|
||||
view.Tree.SetBorder(true).SetTitle("Layout List")
|
||||
// Inject InputCapture
|
||||
// Inject ChangedFunc
|
||||
// Inject SelectedFunc
|
||||
|
||||
// Create a root element
|
||||
rootElem := tview.NewTreeNode(".")
|
||||
view.Tree.SetRoot(rootElem).SetCurrentNode(rootElem)
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
// AddEntries adds the list of files we wish the user to select from
|
||||
// For now we will send just a list of []string but in the future this should
|
||||
// receive (or have an alternative to receive) a directory structure
|
||||
func (ltll *LayoutToolLayoutsList) AddEntries(entries []os.DirEntry) {
|
||||
root := ltll.Tree.GetRoot()
|
||||
if root == nil {
|
||||
// NOTE: shouldn't happen at all
|
||||
return
|
||||
}
|
||||
|
||||
for _, e := range entries {
|
||||
node := tview.NewTreeNode(e.Name()).
|
||||
SetReference(e.Name())
|
||||
root.AddChild(node)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user