diff --git a/internal/dynamo-browse/controllers/events.go b/internal/dynamo-browse/controllers/events.go index 63c79a6..9e1bbae 100644 --- a/internal/dynamo-browse/controllers/events.go +++ b/internal/dynamo-browse/controllers/events.go @@ -6,6 +6,10 @@ import ( "github.com/lmika/audax/internal/dynamo-browse/models" ) +type SetTableItemView struct { + ViewIndex int +} + type NewResultSet struct { ResultSet *models.ResultSet currentFilter string diff --git a/internal/dynamo-browse/ui/model.go b/internal/dynamo-browse/ui/model.go index 7d62e0a..9d7d5e7 100644 --- a/internal/dynamo-browse/ui/model.go +++ b/internal/dynamo-browse/ui/model.go @@ -15,10 +15,22 @@ import ( "github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/statusandprompt" "github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/styles" "github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/tableselect" + "github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/utils" "github.com/pkg/errors" + "log" "strings" ) +const ( + ViewModeTablePrimary = 0 + ViewModeTableItemEqual = 1 + ViewModeItemPrimary = 2 + ViewModeItemOnly = 3 + ViewModeTableOnly = 4 + + ViewModeCount = 5 +) + type Model struct { tableReadController *controllers.TableReadController tableWriteController *controllers.TableWriteController @@ -27,9 +39,12 @@ type Model struct { statusAndPrompt *statusandprompt.StatusAndPrompt tableSelect *tableselect.Model + mainViewIndex int + root tea.Model tableView *dynamotableview.Model itemView *dynamoitemview.Model + mainView tea.Model } func NewModel( @@ -42,7 +57,7 @@ func NewModel( dtv := dynamotableview.New(uiStyles) div := dynamoitemview.New(itemRendererService, uiStyles) - mainView := layout.NewVBox(layout.LastChildFixedAt(13), dtv, div) + mainView := layout.NewVBox(layout.LastChildFixedAt(14), dtv, div) itemEdit := dynamoitemedit.NewModel(mainView) statusAndPrompt := statusandprompt.New(itemEdit, "", uiStyles.StatusAndPrompt) @@ -131,6 +146,7 @@ func NewModel( root: root, tableView: dtv, itemView: div, + mainView: mainView, } } @@ -140,6 +156,9 @@ func (m Model) Init() tea.Cmd { func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { + case controllers.SetTableItemView: + cmd := m.setMainViewIndex(msg.ViewIndex) + return m, cmd case controllers.ResultSetUpdated: return m, m.tableView.Refresh() case tea.KeyMsg: @@ -161,6 +180,14 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, m.tableReadController.Filter case "backspace": return m, m.tableReadController.ViewBack + case "w": + return m, func() tea.Msg { + return controllers.SetTableItemView{ViewIndex: utils.Cycle(m.mainViewIndex, 1, ViewModeCount)} + } + case "W": + return m, func() tea.Msg { + return controllers.SetTableItemView{ViewIndex: utils.Cycle(m.mainViewIndex, -1, ViewModeCount)} + } //case "e": // m.itemEdit.Visible() // return m, nil @@ -180,3 +207,28 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (m Model) View() string { return m.root.View() } + +func (m *Model) setMainViewIndex(viewIndex int) tea.Cmd { + log.Printf("setting view index = %v", viewIndex) + + var newMainView tea.Model + switch viewIndex { + case ViewModeTablePrimary: + newMainView = layout.NewVBox(layout.LastChildFixedAt(14), m.tableView, m.itemView) + case ViewModeTableItemEqual: + newMainView = layout.NewVBox(layout.EqualSize(), m.tableView, m.itemView) + case ViewModeItemPrimary: + newMainView = layout.NewVBox(layout.FirstChildFixedAt(7), m.tableView, m.itemView) + case ViewModeItemOnly: + newMainView = layout.NewZStack(m.itemView, m.tableView) + case ViewModeTableOnly: + newMainView = layout.NewZStack(m.tableView, m.tableView) + default: + newMainView = m.mainView + } + + m.mainViewIndex = viewIndex + m.mainView = newMainView + m.itemEdit.SetSubmodel(m.mainView) + return m.tableView.Refresh() +} diff --git a/internal/dynamo-browse/ui/teamodels/dynamoitemedit/model.go b/internal/dynamo-browse/ui/teamodels/dynamoitemedit/model.go index 2bbd7de..a827dd8 100644 --- a/internal/dynamo-browse/ui/teamodels/dynamoitemedit/model.go +++ b/internal/dynamo-browse/ui/teamodels/dynamoitemedit/model.go @@ -107,3 +107,8 @@ func (m *Model) Resize(w, h int) layout.ResizingModel { func (m *Model) Visible() { m.visible = true } + +func (m *Model) SetSubmodel(submodel tea.Model) { + m.submodel = submodel + m.Resize(m.w, m.h) +} diff --git a/internal/dynamo-browse/ui/teamodels/layout/boxsize.go b/internal/dynamo-browse/ui/teamodels/layout/boxsize.go index c5f8757..4a11d85 100644 --- a/internal/dynamo-browse/ui/teamodels/layout/boxsize.go +++ b/internal/dynamo-browse/ui/teamodels/layout/boxsize.go @@ -24,6 +24,21 @@ func (l equalSize) childSize(idx, cnt, available int) int { return childrenHeight } +func FirstChildFixedAt(size int) BoxSize { + return firstChildFixedAt{size} +} + +type firstChildFixedAt struct { + firstChildSize int +} + +func (l firstChildFixedAt) childSize(idx, cnt, available int) int { + if idx == 0 { + return l.firstChildSize + } + return (equalSize{}).childSize(idx, cnt-1, available-l.firstChildSize) +} + func LastChildFixedAt(size int) BoxSize { return lastChildFixedAt{size} } diff --git a/internal/dynamo-browse/ui/teamodels/layout/zstack.go b/internal/dynamo-browse/ui/teamodels/layout/zstack.go new file mode 100644 index 0000000..88860b6 --- /dev/null +++ b/internal/dynamo-browse/ui/teamodels/layout/zstack.go @@ -0,0 +1,61 @@ +package layout + +import ( + tea "github.com/charmbracelet/bubbletea" + "github.com/lmika/audax/internal/dynamo-browse/ui/teamodels/utils" +) + +type ZStack struct { + visibleModel tea.Model + focusedModel tea.Model + otherModels []tea.Model +} + +func NewZStack(visibleModel tea.Model, focusedModel tea.Model, otherModels ...tea.Model) ZStack { + return ZStack{ + visibleModel: visibleModel, + focusedModel: focusedModel, + otherModels: otherModels, + } +} + +func (vb ZStack) Init() tea.Cmd { + var cc utils.CmdCollector + cc.Collect(vb.visibleModel, vb.visibleModel.Init()) + cc.Collect(vb.focusedModel, vb.focusedModel.Init()) + for _, c := range vb.otherModels { + cc.Collect(c, c.Init()) + } + return cc.Cmd() +} + +func (vb ZStack) Update(msg tea.Msg) (m tea.Model, cmd tea.Cmd) { + switch msg.(type) { + case tea.KeyMsg: + // Only the focused model gets keyboard events + vb.focusedModel, cmd = vb.focusedModel.Update(msg) + return vb, cmd + } + + // All other messages go to each model + var cc utils.CmdCollector + vb.visibleModel = cc.Collect(vb.visibleModel.Update(msg)) + vb.focusedModel = cc.Collect(vb.focusedModel.Update(msg)) + for i, c := range vb.otherModels { + vb.otherModels[i] = cc.Collect(c.Update(msg)) + } + return vb, cc.Cmd() +} + +func (vb ZStack) View() string { + return vb.visibleModel.View() +} + +func (vb ZStack) Resize(w, h int) ResizingModel { + vb.visibleModel = Resize(vb.visibleModel, w, h) + vb.focusedModel = Resize(vb.focusedModel, w, h) + for i := range vb.otherModels { + vb.otherModels[i] = Resize(vb.otherModels[i], w, h) + } + return vb +} diff --git a/internal/dynamo-browse/ui/teamodels/utils/minmax.go b/internal/dynamo-browse/ui/teamodels/utils/minmax.go index 720c39f..2fbb42f 100644 --- a/internal/dynamo-browse/ui/teamodels/utils/minmax.go +++ b/internal/dynamo-browse/ui/teamodels/utils/minmax.go @@ -6,3 +6,17 @@ func Max(x, y int) int { } return y } + +func Cycle(n int, by int, max int) int { + by = by % max + if by > 0 { + return (n + by) % max + } else if by < 0 { + wn := n + by + if wn < 0 { + return max + wn + } + return wn + } + return n +}