[GH-ISSUE #455] Table: modified selected row when scrollup/down if last/frist row is selected #326

Closed
opened 2026-03-04 01:04:01 +03:00 by kerem · 3 comments
Owner

Originally created by @Chen-Haohuang on GitHub (Jun 5, 2020).
Original GitHub issue: https://github.com/rivo/tview/issues/455

When I select the first/last row showed in table, I can't scroll down/up.
Maybe you can try this in Table.MouseHandler

case MouseScrollUp:
	t.trackEnd = false
	if t.selectedRow >= t.fixedRows && t.selectedRow+1 >= t.rowOffset+t.visibleRows && t.rowOffset > 0 {
		t.selectedRow--
	}
	t.rowOffset--
	consumed = true
case MouseScrollDown:
	if t.selectedRow >= t.fixedRows && t.rowOffset+1 > t.selectedRow-t.fixedRows {
		t.selectedRow++
	}
	t.rowOffset++
	consumed = true
Originally created by @Chen-Haohuang on GitHub (Jun 5, 2020). Original GitHub issue: https://github.com/rivo/tview/issues/455 When I select the first/last row showed in table, I can't scroll down/up. Maybe you can try this in Table.MouseHandler ```go case MouseScrollUp: t.trackEnd = false if t.selectedRow >= t.fixedRows && t.selectedRow+1 >= t.rowOffset+t.visibleRows && t.rowOffset > 0 { t.selectedRow-- } t.rowOffset-- consumed = true case MouseScrollDown: if t.selectedRow >= t.fixedRows && t.rowOffset+1 > t.selectedRow-t.fixedRows { t.selectedRow++ } t.rowOffset++ consumed = true ```
kerem closed this issue 2026-03-04 01:04:02 +03:00
Author
Owner

@Chen-Haohuang commented on GitHub (Jun 5, 2020):

Additionally, I think we need to really select the cell (other than just TUI show selected) when we click the cell.

func (t *Table) MouseHandler() func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
	return t.WrapMouseHandler(func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
		if !t.InRect(event.Position()) {
			return false, nil
		}
		// Process mouse event.
		previouslySelectedRow, previouslySelectedColumn := t.selectedRow, t.selectedColumn
		var (
			getCell = func(row, column int) *TableCell {
				if row < 0 || column < 0 || row >= len(t.cells) || column >= len(t.cells[row]) {
					return nil
				}
				return t.cells[row][column]
			}
		)
		switch action {
		case MouseLeftClick:
			setFocus(t)
			atX, atY := event.Position()
			t.selectedRow, t.selectedColumn = t.indexAtPoint(atX, atY)
		case WheelDown:
			if t.selectedRow >= t.fixedRows && t.rowOffset+1 > t.selectedRow-t.fixedRows {
				t.selectedRow++
			}
			t.rowOffset++
		case WheelUp:
			t.trackEnd = false
			if t.selectedRow >= t.fixedRows && t.selectedRow+1 >= t.rowOffset+t.visibleRows && t.rowOffset > 0 {
				t.selectedRow--
			}
			t.rowOffset--
		case WheelLeft:
			_, _, space, _ := t.GetInnerRect()
			visibleColumns := 0
			for c := 0; c < t.lastColumn; c++ {
				if c < t.fixedColumns || c >= t.fixedColumns+t.columnOffset {
					cell := t.GetCell(0, c)
					if space > cell.width {
						space -= cell.width
						if cell.Expansion == 0 {
							space -= 1
						} else {
							space -= cell.Expansion
						}
					} else {
						visibleColumns = c
					}
				}
			}
			if t.selectedColumn >= t.fixedColumns && t.selectedColumn+1 >= t.columnOffset+visibleColumns && t.columnOffset > 0 {
				t.selectedColumn--
			}
			t.columnOffset--
		case WheelRight:
			if t.selectedColumn >= t.fixedColumns && t.columnOffset+1 > t.selectedColumn-t.fixedColumns {
				t.selectedRow++
			}
			t.columnOffset++
		default:
			return true, nil
		}
		cell := getCell(t.selectedRow, t.selectedColumn)
		if cell == nil || cell.NotSelectable {
			return true, nil
		}
		if (t.rowsSelectable || t.columnsSelectable) && t.selected != nil {
			t.selected(t.selectedRow, t.selectedColumn)
		}
		// If the selection has changed, notify the handler.
		if t.selectionChanged != nil &&
			(t.rowsSelectable && previouslySelectedRow != t.selectedRow ||
				t.columnsSelectable && previouslySelectedColumn != t.selectedColumn) {
			t.selectionChanged(t.selectedRow, t.selectedColumn)
		}

		return true, nil
	})
}
<!-- gh-comment-id:639317698 --> @Chen-Haohuang commented on GitHub (Jun 5, 2020): Additionally, I think we need to really select the cell (other than just TUI show selected) when we click the cell. ```go func (t *Table) MouseHandler() func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) { return t.WrapMouseHandler(func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) { if !t.InRect(event.Position()) { return false, nil } // Process mouse event. previouslySelectedRow, previouslySelectedColumn := t.selectedRow, t.selectedColumn var ( getCell = func(row, column int) *TableCell { if row < 0 || column < 0 || row >= len(t.cells) || column >= len(t.cells[row]) { return nil } return t.cells[row][column] } ) switch action { case MouseLeftClick: setFocus(t) atX, atY := event.Position() t.selectedRow, t.selectedColumn = t.indexAtPoint(atX, atY) case WheelDown: if t.selectedRow >= t.fixedRows && t.rowOffset+1 > t.selectedRow-t.fixedRows { t.selectedRow++ } t.rowOffset++ case WheelUp: t.trackEnd = false if t.selectedRow >= t.fixedRows && t.selectedRow+1 >= t.rowOffset+t.visibleRows && t.rowOffset > 0 { t.selectedRow-- } t.rowOffset-- case WheelLeft: _, _, space, _ := t.GetInnerRect() visibleColumns := 0 for c := 0; c < t.lastColumn; c++ { if c < t.fixedColumns || c >= t.fixedColumns+t.columnOffset { cell := t.GetCell(0, c) if space > cell.width { space -= cell.width if cell.Expansion == 0 { space -= 1 } else { space -= cell.Expansion } } else { visibleColumns = c } } } if t.selectedColumn >= t.fixedColumns && t.selectedColumn+1 >= t.columnOffset+visibleColumns && t.columnOffset > 0 { t.selectedColumn-- } t.columnOffset-- case WheelRight: if t.selectedColumn >= t.fixedColumns && t.columnOffset+1 > t.selectedColumn-t.fixedColumns { t.selectedRow++ } t.columnOffset++ default: return true, nil } cell := getCell(t.selectedRow, t.selectedColumn) if cell == nil || cell.NotSelectable { return true, nil } if (t.rowsSelectable || t.columnsSelectable) && t.selected != nil { t.selected(t.selectedRow, t.selectedColumn) } // If the selection has changed, notify the handler. if t.selectionChanged != nil && (t.rowsSelectable && previouslySelectedRow != t.selectedRow || t.columnsSelectable && previouslySelectedColumn != t.selectedColumn) { t.selectionChanged(t.selectedRow, t.selectedColumn) } return true, nil }) } ```
Author
Owner

@rivo commented on GitHub (Sep 15, 2020):

I don't understand any of what you're writing here. What is that code? You're using global variables that don't exist in my package (e.g. "WheelRight"). Where did you take this code from?

Please explain your problem with tview first before offering any "solution" code. It would be best if you posted brief example code that illustrates where things are not working like you expect them to.

<!-- gh-comment-id:692631462 --> @rivo commented on GitHub (Sep 15, 2020): I don't understand any of what you're writing here. What is that code? You're using global variables that don't exist in my package (e.g. "WheelRight"). Where did you take this code from? Please explain your problem with `tview` first before offering any "solution" code. It would be best if you posted brief example code that illustrates where things are not working like you expect them to.
Author
Owner

@rivo commented on GitHub (Jan 11, 2021):

If this topic is still relevant, please open a new issue with your answer and reference this one.

<!-- gh-comment-id:757953943 --> @rivo commented on GitHub (Jan 11, 2021): If this topic is still relevant, please open a new issue with your answer and reference this one.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/tview#326
No description provided.