still working on the layout tool
- started doing it in a more adhoc way and will engineer it once I have a clear vision
This commit is contained in:
@@ -3,10 +3,8 @@ package views
|
||||
import (
|
||||
"esdi/tui/internal/dom"
|
||||
"esdi/tui/internal/events"
|
||||
"esdi/tui/internal/models"
|
||||
"esdi/tui/internal/ui"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
@@ -47,41 +45,64 @@ func BindWindowEvents(
|
||||
// I recon I have to change this for some type os event system that
|
||||
// triggers directly on the UINodes I want them to be triggered on
|
||||
bus.On(ui.WindowCreatedEv{}, func(e any) {
|
||||
bus.Emit(ui.LogEv{Log: "Received a window created event\n"})
|
||||
if tree == nil {
|
||||
bus.Emit(ui.LogEv{Log: "tree view is nil"})
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
bus.Emit(ui.LogEv{Log: "Received a window created event\n"})
|
||||
if tree == nil {
|
||||
bus.Emit(ui.LogEv{Log: "tree view is nil"})
|
||||
return
|
||||
}
|
||||
|
||||
root := tree.GetRoot()
|
||||
if root == nil {
|
||||
bus.Emit(ui.LogEv{Log: "unable to get root of tree view"})
|
||||
return
|
||||
}
|
||||
root := tree.GetRoot()
|
||||
if root == nil {
|
||||
bus.Emit(ui.LogEv{Log: "unable to get root of tree view"})
|
||||
return
|
||||
}
|
||||
|
||||
newWindow := tview.NewTreeNode(e.(ui.WindowCreatedEv).Title).
|
||||
SetReference(e.(ui.WindowCreatedEv).ID)
|
||||
root.AddChild(newWindow)
|
||||
newWindow := tview.NewTreeNode(e.(ui.WindowCreatedEv).Title).
|
||||
SetReference(e.(ui.WindowCreatedEv).ID)
|
||||
root.AddChild(newWindow)
|
||||
}()
|
||||
})
|
||||
|
||||
bus.On(ui.WindowDestroyedEv{}, func(e any) {
|
||||
go func() {
|
||||
root := tree.GetRoot()
|
||||
if root == nil {
|
||||
bus.Emit(ui.LogEv{Log: "unable to get current tree node"})
|
||||
}
|
||||
|
||||
node := FindNodeByReference(root, e.(ui.WindowDestroyedEv).ID)
|
||||
if node != nil {
|
||||
root.RemoveChild(node)
|
||||
}
|
||||
|
||||
// NODE: add a log here in case it fails so we know whats going on
|
||||
bus.Emit(ui.ForceRedraw{})
|
||||
}()
|
||||
})
|
||||
|
||||
bus.On(ui.RegisterLoadedLayout{}, func(e any) {
|
||||
root := tree.GetRoot()
|
||||
if root == nil {
|
||||
bus.Emit(ui.LogEv{Log: "unable to get current tree node"})
|
||||
return
|
||||
}
|
||||
|
||||
node := FindNodeByReference(root, e.(ui.WindowDestroyedEv).ID)
|
||||
if node != nil {
|
||||
root.RemoveChild(node)
|
||||
layout := e.(ui.RegisterLoadedLayout)
|
||||
for idx, w := range layout.Layout.Windows {
|
||||
newWindow := tview.NewTreeNode(w.Title.String()).SetReference(idx)
|
||||
root.AddChild(newWindow)
|
||||
}
|
||||
// NODE: add a log here in case it fails so we know whats going on
|
||||
|
||||
// bus.Emit(ui.ForceRedraw{})
|
||||
})
|
||||
|
||||
bus.On(ui.ErrorCreateWindowEv{}, func(e any) {
|
||||
bus.Emit(ui.LogEv{
|
||||
Log: fmt.Sprintf(
|
||||
"Error performing action: %s\n", e.(ui.ErrorCreateWindowEv).Error.Error(),
|
||||
)})
|
||||
go func() {
|
||||
bus.Emit(ui.LogEv{
|
||||
Log: fmt.Sprintf(
|
||||
"Error performing action: %s\n", e.(ui.ErrorCreateWindowEv).Error.Error(),
|
||||
)})
|
||||
}()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -121,8 +142,28 @@ func layoutToolTreeViewEvents(bus *events.Bus, doc *dom.DOM,
|
||||
bus.Emit(ui.DestroyWindowEv{ID: wID})
|
||||
case 'm':
|
||||
// Go into move mode
|
||||
curNode := tree.GetCurrentNode()
|
||||
if curNode == nil {
|
||||
bus.Emit(ui.LogEv{Log: "unable to get current tree node"})
|
||||
break
|
||||
}
|
||||
|
||||
ref := curNode.GetReference()
|
||||
wID, ok := ref.(int16)
|
||||
if !ok {
|
||||
// Whatever, do something better here
|
||||
break
|
||||
}
|
||||
|
||||
windowManipulationTool(bus, doc, wID)
|
||||
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{})
|
||||
}
|
||||
|
||||
return event
|
||||
@@ -218,92 +259,3 @@ func buildLayoutFlexComponent(bus *events.Bus, doc *dom.DOM) (*dom.UINode, error
|
||||
|
||||
return layoutToolFlexNode, nil
|
||||
}
|
||||
|
||||
// Layout tool actions
|
||||
|
||||
// Validate the form inputs
|
||||
func validateFormInputs(x, y, w, h, title string) (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
|
||||
}
|
||||
|
||||
return models.Window{
|
||||
X: uint16(xValue),
|
||||
Y: uint16(yValue),
|
||||
Width: uint16(widthValue),
|
||||
Height: uint16(heightValue),
|
||||
Title: title,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func createNewWindowForm(bus *events.Bus, doc *dom.DOM) {
|
||||
var err error
|
||||
|
||||
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")
|
||||
|
||||
form := tview.NewForm().
|
||||
AddFormItem(x0).
|
||||
AddFormItem(y0).
|
||||
AddFormItem(width).
|
||||
AddFormItem(height).
|
||||
AddFormItem(title).
|
||||
AddButton("Create", func() {
|
||||
// Validate the inputs
|
||||
window, err := validateFormInputs(
|
||||
x0.GetText(),
|
||||
y0.GetText(),
|
||||
width.GetText(),
|
||||
height.GetText(),
|
||||
title.GetText(),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
bus.Emit(ui.LogEv{Log: fmt.Sprintf("failed to parse form: %s\n", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
bus.Emit(ui.CreateWindowEv{Window: window})
|
||||
})
|
||||
|
||||
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 ev
|
||||
})
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
AddAndShowPage(bus, doc, doc.GetElemByID(layoutToolActionPagesID).(*tview.Pages),
|
||||
formNode)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package views
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"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 string) (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
|
||||
}
|
||||
|
||||
return models.Window{
|
||||
X: uint16(xValue),
|
||||
Y: uint16(yValue),
|
||||
Width: uint16(widthValue),
|
||||
Height: uint16(heightValue),
|
||||
Title: title,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func createNewWindowForm(bus *events.Bus, doc *dom.DOM) {
|
||||
var err error
|
||||
|
||||
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")
|
||||
|
||||
form := tview.NewForm().
|
||||
AddFormItem(x0).
|
||||
AddFormItem(y0).
|
||||
AddFormItem(width).
|
||||
AddFormItem(height).
|
||||
AddFormItem(title).
|
||||
AddButton("Create", func() {
|
||||
// Validate the inputs
|
||||
window, err := validateFormInputs(
|
||||
x0.GetText(),
|
||||
y0.GetText(),
|
||||
width.GetText(),
|
||||
height.GetText(),
|
||||
title.GetText(),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
bus.Emit(ui.LogEv{Log: fmt.Sprintf("failed to parse form: %s\n", err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
bus.Emit(ui.CreateWindowEv{Window: window})
|
||||
})
|
||||
|
||||
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 ev
|
||||
})
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
AddAndShowPage(bus, doc, doc.GetElemByID(layoutToolActionPagesID).(*tview.Pages),
|
||||
formNode)
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
package views
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
helper "esdi/helpers"
|
||||
"esdi/tui/internal/dom"
|
||||
"esdi/tui/internal/events"
|
||||
"esdi/tui/internal/ui"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
type ManipMode int
|
||||
|
||||
const (
|
||||
moveMode ManipMode = iota
|
||||
resizeMode
|
||||
)
|
||||
|
||||
type windowManipState struct {
|
||||
Mode ManipMode
|
||||
}
|
||||
|
||||
func keyToVector(r rune) (helper.Vector, bool) {
|
||||
var mult uint16 = 1
|
||||
|
||||
// Is uppercase? For fast movement
|
||||
if r >= 'A' && r <= 'Z' {
|
||||
mult = 10
|
||||
r += 'a' - 'A'
|
||||
}
|
||||
|
||||
switch r {
|
||||
case 'h':
|
||||
return helper.Vector{DX: -mult, DY: 0}, true
|
||||
case 'j':
|
||||
return helper.Vector{DX: 0, DY: mult}, true
|
||||
case 'k':
|
||||
return helper.Vector{DX: 0, DY: -mult}, true
|
||||
case 'l':
|
||||
return helper.Vector{DX: mult, DY: 0}, true
|
||||
}
|
||||
|
||||
return helper.Vector{}, false
|
||||
}
|
||||
|
||||
func handleMovementCapture(bus *events.Bus, id int16, ev *tcell.EventKey) *tcell.EventKey {
|
||||
vec, ok := keyToVector(ev.Rune())
|
||||
if !ok {
|
||||
return ev
|
||||
}
|
||||
|
||||
bus.Emit(ui.MoveWindowEv{
|
||||
WindowID: id,
|
||||
Delta: vec,
|
||||
})
|
||||
|
||||
return ev
|
||||
}
|
||||
|
||||
func handleResizeCapture(bus *events.Bus, id int16, ev *tcell.EventKey) *tcell.EventKey {
|
||||
vec, ok := keyToVector(ev.Rune())
|
||||
if !ok {
|
||||
return ev
|
||||
}
|
||||
|
||||
bus.Emit(ui.ResizeWindowEv{
|
||||
WindowID: id,
|
||||
Delta: vec,
|
||||
})
|
||||
|
||||
return ev
|
||||
}
|
||||
|
||||
type modeHandler func(*tcell.EventKey) *tcell.EventKey
|
||||
|
||||
func (s *windowManipState) CurrentHandler(
|
||||
bus *events.Bus,
|
||||
id int16,
|
||||
) modeHandler {
|
||||
switch s.Mode {
|
||||
case moveMode:
|
||||
return func(ev *tcell.EventKey) *tcell.EventKey {
|
||||
return handleMovementCapture(bus, id, ev)
|
||||
}
|
||||
case resizeMode:
|
||||
return func(ev *tcell.EventKey) *tcell.EventKey {
|
||||
return handleResizeCapture(bus, id, ev)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func windowManipulationEvCapture(
|
||||
bus *events.Bus,
|
||||
doc *dom.DOM,
|
||||
id int16,
|
||||
state *windowManipState,
|
||||
) func(ev *tcell.EventKey) *tcell.EventKey {
|
||||
return func(ev *tcell.EventKey) *tcell.EventKey {
|
||||
switch ev.Key() {
|
||||
case tcell.KeyEscape:
|
||||
bus.Emit(ui.ChangeFocusEv{
|
||||
Target: doc.GetElemByID(layoutToolFlexID),
|
||||
})
|
||||
return ev
|
||||
}
|
||||
|
||||
bus.Emit(ui.PrintLogEv{
|
||||
Log: fmt.Sprintf("-> IDX: %d\n", id),
|
||||
})
|
||||
|
||||
// Mode switching
|
||||
switch ev.Rune() {
|
||||
case 'r':
|
||||
state.Mode = resizeMode
|
||||
bus.Emit(ui.PrintLogEv{Log: "switched to resizeMode"})
|
||||
case 'm':
|
||||
state.Mode = moveMode
|
||||
bus.Emit(ui.PrintLogEv{Log: "switched to moveMode"})
|
||||
}
|
||||
|
||||
// Delegate the current handler input
|
||||
handler := state.CurrentHandler(bus, id)
|
||||
if handler != nil {
|
||||
return handler(ev)
|
||||
}
|
||||
|
||||
return ev
|
||||
}
|
||||
}
|
||||
|
||||
func windowManipulationTool(bus *events.Bus, doc *dom.DOM, idx int16) {
|
||||
bus.Emit(ui.PrintLogEv{Log: fmt.Sprintf("WID: %d\n", idx)})
|
||||
|
||||
// Get the ActionPages parent
|
||||
box := tview.NewBox().SetTitle("MOVE WINDOW TOOL")
|
||||
box.SetBorder(true)
|
||||
|
||||
var err error
|
||||
var boxNode *dom.UINode
|
||||
|
||||
// delete the currently existing move-window-box
|
||||
actionPages := doc.GetElemByID(layoutToolActionPagesID).(*tview.Pages)
|
||||
actionPages.RemovePage("move-window-box")
|
||||
|
||||
boxNode = doc.GetNodeByID("move-window-box")
|
||||
if boxNode != nil {
|
||||
doc.DeleteElem(boxNode)
|
||||
}
|
||||
|
||||
boxNode, err = doc.NewUINode(
|
||||
"move-window-box",
|
||||
doc.GetElemByID(layoutToolActionPagesID),
|
||||
box,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Create the state for this tool
|
||||
state := windowManipState{
|
||||
Mode: moveMode,
|
||||
}
|
||||
|
||||
box.SetInputCapture(windowManipulationEvCapture(bus, doc, idx, &state))
|
||||
AddAndShowPage(bus, doc, actionPages, boxNode)
|
||||
}
|
||||
Reference in New Issue
Block a user