Add menu browse display conditional on state

This commit is contained in:
lash 2023-04-08 11:31:05 +01:00
parent 97dc090619
commit a7add69f18
Signed by untrusted user who does not match committer: lash
GPG Key ID: 21D2E7BB88C2A746
4 changed files with 123 additions and 12 deletions

View File

@ -18,7 +18,6 @@ type Resource interface {
GetTemplate(sym string, sizer *Sizer) (string, error) // Get the template for a given symbol. GetTemplate(sym string, sizer *Sizer) (string, error) // Get the template for a given symbol.
GetCode(sym string) ([]byte, error) // Get the bytecode for the given symbol. GetCode(sym string) ([]byte, error) // Get the bytecode for the given symbol.
PutMenu(string, string) error // Add a menu item. PutMenu(string, string) error // Add a menu item.
ShiftMenu() (string, string, error) // Remove and return the first menu item in list.
SetMenuBrowse(string, string, bool) error // Set menu browser display details. SetMenuBrowse(string, string, bool) error // Set menu browser display details.
RenderTemplate(sym string, values map[string]string, idx uint16, sizer *Sizer) (string, error) // Render the given data map using the template of the symbol. RenderTemplate(sym string, values map[string]string, idx uint16, sizer *Sizer) (string, error) // Render the given data map using the template of the symbol.
RenderMenu() (string, error) // Render the current state of menu RenderMenu() (string, error) // Render the current state of menu
@ -30,6 +29,8 @@ type MenuResource struct {
menu [][2]string menu [][2]string
next [2]string next [2]string
prev [2]string prev [2]string
canNext bool
canPrev bool
sinkValues []string sinkValues []string
codeFunc CodeFunc codeFunc CodeFunc
templateFunc TemplateFunc templateFunc TemplateFunc
@ -68,12 +69,22 @@ func(m *MenuResource) SetMenuBrowse(selector string, title string, back bool) er
entry := [2]string{selector, title} entry := [2]string{selector, title}
if back { if back {
m.prev = entry m.prev = entry
m.canPrev = true
} else { } else {
m.next = entry m.next = entry
m.canNext = true
} }
return nil return nil
} }
//func(m *MenuResource) putNext() error {
// return m.PutMenu(m.next[0], m.next[1])
//}
//
//func(m *MenuResource) putPrevious() error {
// return m.PutMenu(m.prev[0], m.prev[1])
//}
// PutMenu adds a menu option to the menu rendering. // PutMenu adds a menu option to the menu rendering.
func(m *MenuResource) PutMenu(selector string, title string) error { func(m *MenuResource) PutMenu(selector string, title string) error {
m.menu = append(m.menu, [2]string{selector, title}) m.menu = append(m.menu, [2]string{selector, title})
@ -81,10 +92,9 @@ func(m *MenuResource) PutMenu(selector string, title string) error {
return nil return nil
} }
// PutMenu removes and returns the first of remaining menu options. // removes and returns the first of remaining menu options.
// // fails if menu is empty.
// Fails if menu is empty. func(m *MenuResource) shiftMenu() (string, string, error) {
func(m *MenuResource) ShiftMenu() (string, string, error) {
if len(m.menu) == 0 { if len(m.menu) == 0 {
return "", "", fmt.Errorf("menu is empty") return "", "", fmt.Errorf("menu is empty")
} }
@ -93,14 +103,36 @@ func(m *MenuResource) ShiftMenu() (string, string, error) {
return r[0], r[1], nil return r[0], r[1], nil
} }
// add available browse options.
func(m *MenuResource) applyPage() error {
if m.canNext {
err := m.PutMenu(m.next[0], m.next[1])
if err != nil {
return err
}
}
if m.canPrev {
err := m.PutMenu(m.prev[0], m.prev[1])
if err != nil {
return err
}
}
return nil
}
// RenderMenu returns the full current state of the menu as a string. // RenderMenu returns the full current state of the menu as a string.
// //
// After this has been executed, the state of the menu will be empty. // After this has been executed, the state of the menu will be empty.
func(m *MenuResource) RenderMenu() (string, error) { func(m *MenuResource) RenderMenu() (string, error) {
err := m.applyPage()
if err != nil {
return "", err
}
r := "" r := ""
for true { for true {
l := len(r) l := len(r)
choice, title, err := m.ShiftMenu() choice, title, err := m.shiftMenu()
if err != nil { if err != nil {
break break
} }

View File

@ -20,10 +20,25 @@ func NewStateResource(st *state.State) *StateResource {
} }
} }
func(s *StateResource) WithState(st *state.State) *StateResource { func(sr *StateResource) WithState(st *state.State) *StateResource {
if s.st != nil { if sr.st != nil {
panic("state already set") panic("state already set")
} }
s.st = st sr.st = st
return s return sr
}
func(sr *StateResource) SetMenuBrowse(selector string, title string, back bool) error {
var err error
next, prev := sr.st.Sides()
if back {
if prev {
err = sr.Resource.SetMenuBrowse(selector, title, true)
}
} else if next {
err = sr.Resource.SetMenuBrowse(selector, title, false)
}
return err
} }

View File

@ -12,3 +12,62 @@ func TestStateResourceInit(t *testing.T) {
_ = ToStateResource(rs).WithState(&st) _ = ToStateResource(rs).WithState(&st)
_ = NewStateResource(&st) _ = NewStateResource(&st)
} }
func TestStateBrowse(t *testing.T) {
st := state.NewState(0)
st.Down("root")
rs := NewStateResource(&st)
rs.PutMenu("1", "foo")
rs.PutMenu("2", "bar")
err := rs.SetMenuBrowse("11", "next", false)
if err != nil {
t.Fatal(err)
}
err = rs.SetMenuBrowse("22", "prev", true)
if err != nil {
t.Fatal(err)
}
s, err := rs.RenderMenu()
if err != nil {
t.Fatal(err)
}
expect := `1:foo
2:bar
11:next`
if s != expect {
t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", expect, s)
}
idx, err := st.Next()
if err != nil {
t.Fatal(err)
}
if idx != 1 {
t.Fatalf("expected idx 1, got %v", idx)
}
rs = NewStateResource(&st)
rs.PutMenu("1", "foo")
rs.PutMenu("2", "bar")
err = rs.SetMenuBrowse("11", "next", false)
if err != nil {
t.Fatal(err)
}
err = rs.SetMenuBrowse("22", "prev", true)
if err != nil {
t.Fatal(err)
}
s, err = rs.RenderMenu()
if err != nil {
t.Fatal(err)
}
expect = `1:foo
2:bar
11:next
22:prev`
if s != expect {
t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", expect, s)
}
}

View File

@ -204,7 +204,7 @@ func(st State) WithOutputSize(outputSize uint32) State {
} }
// Where returns the current active rendering symbol. // Where returns the current active rendering symbol.
func(st State) Where() (string, uint16) { func(st *State) Where() (string, uint16) {
if len(st.execPath) == 0 { if len(st.execPath) == 0 {
return "", 0 return "", 0
} }
@ -213,11 +213,13 @@ func(st State) Where() (string, uint16) {
} }
// Next moves to the next sink page index. // Next moves to the next sink page index.
func(st State) Next() (uint16, error) { func(st *State) Next() (uint16, error) {
if len(st.execPath) == 0 { if len(st.execPath) == 0 {
return 0, fmt.Errorf("state root node not yet defined") return 0, fmt.Errorf("state root node not yet defined")
} }
st.sizeIdx += 1 st.sizeIdx += 1
s, idx := st.Where()
log.Printf("next page for %s: %v", s, idx)
return st.sizeIdx, nil return st.sizeIdx, nil
} }
@ -232,6 +234,8 @@ func(st *State) Previous() (uint16, error) {
return 0, fmt.Errorf("already at first index") return 0, fmt.Errorf("already at first index")
} }
st.sizeIdx -= 1 st.sizeIdx -= 1
s, idx := st.Where()
log.Printf("previous page for %s: %v", s, idx)
return st.sizeIdx, nil return st.sizeIdx, nil
} }
@ -243,6 +247,7 @@ func(st *State) Sides() (bool, bool) {
return false, false return false, false
} }
next := true next := true
log.Printf("sides %v", st.sizeIdx)
if st.sizeIdx == 0 { if st.sizeIdx == 0 {
return next, false return next, false
} }