Skip to content

Commit

Permalink
Row select toggle event (#111)
Browse files Browse the repository at this point in the history
* Row select toggle event

* Update example
  • Loading branch information
Evertras committed Jun 23, 2022
1 parent 2cb4d63 commit 3802e8a
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 25 deletions.
35 changes: 11 additions & 24 deletions examples/events/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,6 @@ var (
elementWater: "#44f",
elementPlant: "#8b8",
}

customBorder = table.Border{
Top: "─",
Left: "│",
Right: "│",
Bottom: "─",

TopRight: "╮",
TopLeft: "╭",
BottomRight: "╯",
BottomLeft: "╰",

TopJunction: "┬",
LeftJunction: "├",
RightJunction: "┤",
BottomJunction: "┴",
InnerJunction: "┼",

InnerDivider: "│",
}
)

type Pokemon struct {
Expand Down Expand Up @@ -102,6 +82,8 @@ type Model struct {
pokeTable table.Model

currentPokemonData Pokemon

lastSelectedEvent table.UserEventRowSelectToggled
}

func NewModel() Model {
Expand All @@ -126,10 +108,11 @@ func NewModel() Model {
table.NewColumn(columnKeyName, "Name", 13),
table.NewColumn(columnKeyElement, "Element", 10),
}).WithRows(rows).
Border(customBorder).
BorderRounded().
WithBaseStyle(styleBase).
WithPageSize(4).
Focused(true),
Focused(true).
SelectableRows(true),
currentPokemonData: pokemon[0],
}
}
Expand All @@ -148,7 +131,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
cmds = append(cmds, cmd)

for _, e := range m.pokeTable.GetLastUpdateUserEvents() {
switch e.(type) {
switch e := e.(type) {
case table.UserEventHighlightedIndexChanged:
// We can pretend this is an async data retrieval, but really we already
// have the data, so just return it after some fake delay. Also note
Expand All @@ -161,6 +144,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

return selectedPokemon
})

case table.UserEventRowSelectToggled:
m.lastSelectedEvent = e
}
}

Expand All @@ -182,7 +168,8 @@ func (m Model) View() string {
view := lipgloss.JoinVertical(
lipgloss.Left,
styleSubtle.Render("Press q or ctrl+c to quit"),
fmt.Sprintf("%s (%s)", m.currentPokemonData.Name, m.currentPokemonData.Element),
fmt.Sprintf("Highlighted (200 ms delay): %s (%s)", m.currentPokemonData.Name, m.currentPokemonData.Element),
fmt.Sprintf("Last selected event: %d (%v)", m.lastSelectedEvent.RowIndex, m.lastSelectedEvent.IsSelected),
lipgloss.NewStyle().Foreground(lipgloss.Color("#8c8")).
Render(":D %"+fmt.Sprintf("%.1f", m.currentPokemonData.PositiveSentimentPercent)),
lipgloss.NewStyle().Foreground(lipgloss.Color("#c88")).
Expand Down
8 changes: 8 additions & 0 deletions table/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,11 @@ type UserEventHighlightedIndexChanged struct {
// SelectedRow is the row index that is now selected
SelectedRowIndex int
}

// UserEventRowSelectToggled indicates that the user has either selected or
// deselected a row by toggling the selection. The event contains information
// about which row index was selected and whether it was selected or deselected.
type UserEventRowSelectToggled struct {
RowIndex int
IsSelected bool
}
75 changes: 75 additions & 0 deletions table/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,78 @@ func TestUserEventHighlightedIndexChanged(t *testing.T) {
events = model.GetLastUpdateUserEvents()
assert.Len(t, events, 0, "There's no row to change to for an empty table, event shouldn't exist")
}

// nolint: funlen // This is a bunch of checks in a row, this is fine
func TestUserEventRowSelectToggled(t *testing.T) {
// Don't need any actual row data for this
empty := RowData{}

model := New([]Column{}).
Focused(true).
WithRows(
[]Row{
NewRow(empty),
NewRow(empty),
NewRow(empty),
NewRow(empty),
},
).
SelectableRows(true)

hitDown := func() {
model, _ = model.Update(tea.KeyMsg{Type: tea.KeyDown})
}

hitSelectToggle := func() {
model, _ = model.Update(tea.KeyMsg{Type: tea.KeySpace})
}

checkEvent := func(events []UserEvent, expectedRowIndex int, expectedSelectionState bool) {
if len(events) != 1 {
assert.FailNow(t, "Asked to check events with len of not 1, test is bad")
}

switch event := events[0].(type) {
case UserEventRowSelectToggled:
assert.Equal(t, expectedRowIndex, event.RowIndex, "Row index wrong")
assert.Equal(t, expectedSelectionState, event.IsSelected, "Selection state wrong")

default:
assert.Failf(t, "Event is not expected type UserEventRowSelectToggled", "%+v", event)
}
}

events := model.GetLastUpdateUserEvents()
assert.Len(t, events, 0, "Should be empty when nothing has happened")

// Try initial selection
hitSelectToggle()
events = model.GetLastUpdateUserEvents()
assert.Len(t, events, 1, "Missing event for selection toggle")
checkEvent(events, 0, true)

// Do some no-op
model, _ = model.Update(nil)
events = model.GetLastUpdateUserEvents()
assert.Len(t, events, 0, "Events not cleared between Updates")

// Check deselection
hitSelectToggle()
events = model.GetLastUpdateUserEvents()
assert.Len(t, events, 1, "Missing event to toggle select for second time")
checkEvent(events, 0, false)

// Try one row down... note that the row change event should clear after the
// first keypress
hitDown()
hitSelectToggle()
events = model.GetLastUpdateUserEvents()
assert.Len(t, events, 1, "Missing event after scrolling down")
checkEvent(events, 1, true)

// Check edge case of empty table
model = model.WithRows([]Row{})
hitSelectToggle()
events = model.GetLastUpdateUserEvents()
assert.Len(t, events, 0, "There's no row to select for an empty table, event shouldn't exist")
}
9 changes: 8 additions & 1 deletion table/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,16 @@ func (m *Model) toggleSelect() {
rows := make([]Row, len(m.GetVisibleRows()))
copy(rows, m.GetVisibleRows())

rows[m.rowCursorIndex].selected = !rows[m.rowCursorIndex].selected
currentSelectedState := rows[m.rowCursorIndex].selected

rows[m.rowCursorIndex].selected = !currentSelectedState

m.rows = rows

m.appendUserEvent(UserEventRowSelectToggled{
RowIndex: m.rowCursorIndex,
IsSelected: !currentSelectedState,
})
}

func (m Model) updateFilterTextInput(msg tea.Msg) (Model, tea.Cmd) {
Expand Down

0 comments on commit 3802e8a

Please sign in to comment.