grid

package
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 17, 2026 License: LGPL-2.1 Imports: 17 Imported by: 0

Documentation

Overview

Package grid provides StringGrid — a terminal-mode data grid with rows, named columns, in-place cell editing, mouse navigation, per- column alignment and validation, multi-cell selection, click-to-sort headers, an optional filter row, copy-to-clipboard, column resize and reorder via mouse drag, frozen leading columns, CSV import / export, and a virtual-data-source mode for huge datasets.

Ported from Grid.pas (TStringGrid). The Pascal version's per-cell undo log isn't here yet (that's editor scope); everything else from the FVTest grid-test page is.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Alignment

type Alignment int

Alignment picks how a cell's text aligns within its column.

const (
	AlignLeft Alignment = iota
	AlignCenter
	AlignRight
)

type CSVOptions

type CSVOptions struct {
	Delimiter           rune   // zero → ','
	LineEnd             string // zero → "\n"
	AutoDetectDelimiter bool
	IncludeHeader       bool // export header row; import treats first row as data
}

CSVOptions controls CSV import / export. Zero value is minimal and boring (`CSVOptions{}` → comma, LF, no header). Use DefaultCSVOptions for spreadsheet-style output (CRLF + header). AutoDetectDelimiter, on import only, sniffs the first non-empty line for the most frequent of {',', ';', '\t'} and overrides Delimiter.

func DefaultCSVOptions

func DefaultCSVOptions() CSVOptions

DefaultCSVOptions returns the spreadsheet-style configuration: comma delimiter, CRLF line endings, header on export / import.

type Cell

type Cell struct{ Col, Row int }

Cell coords. (0, 0) is the top-left data cell — the header row / column don't have addresses in this scheme.

type Column

type Column struct {
	Title    string
	Width    int
	MinWidth int // 0 = no lower clamp on resize / auto-fit
	MaxWidth int // 0 = no upper clamp
	Align    Alignment
	Color    uint16 // per-column override; 0 = use the grid default
	ReadOnly bool
	Sortable bool
	// Hidden, when true, suppresses rendering / hit-testing for this
	// column while keeping it in the data + filters. Zero value
	// (Column{}) is visible — flipping the sense from a previous
	// Visible bool removes the New()-time "force every column on"
	// kludge that prevented constructing initially-hidden columns.
	Hidden       bool
	DefaultValue string // used by AddRow() / SetRowCount() to fill new cells
	Validator    validators.Validator
	Compare      func(a, b string) int // typed comparison; nil = string compare
}

Column describes one column. Validator (optional) runs on commit of an edit; rejection bounces the user back into edit mode. Sortable can be cleared to lock a column out of header-click sorting. The optional Compare hook is used for typed sorts (e.g. numeric); when nil, the grid falls back to lexicographic string compare.

type SelectionMode

type SelectionMode int

SelectionMode controls how selections expand. Cell = a single cell (anchor == focus). Range = a rectangular block. Row = full row(s).

const (
	SelectCell SelectionMode = iota
	SelectRange
	SelectRow
)

type SortDirection

type SortDirection int

SortDirection — Asc, Desc, or None (unsorted).

const (
	SortNone SortDirection = iota
	SortAsc
	SortDesc
)

type SortKey

type SortKey struct {
	Col int
	Dir SortDirection
}

SortKey is one entry in a multi-column sort. Multiple keys form a lexicographic comparison: when the primary key ties, the secondary breaks the tie, and so on.

type StringGrid

type StringGrid struct {
	views.Base

	Columns []Column

	// Selection. Focus is the "active" corner the cursor moves; Anchor
	// is the opposite end of the range. Cell vs Range vs Row is the
	// Mode toggle.
	Anchor, Focus Cell
	Mode          SelectionMode

	Top       int // first visible row (in visible/filtered index space)
	LeftCol   int // first visible column (in column-order space)
	HasHeader bool

	// FixedCols pins the first N columns so they don't scroll
	// horizontally. The pin is visual only — Anchor/Focus still
	// address pinned columns the same as any others.
	FixedCols int

	// FixedRows pins the first N rows (in visible / post-sort order) so
	// they stay on screen even when the body scrolls.
	FixedRows int

	// ShowFilter toggles the per-column filter row below the header.
	// Filters[i] is the case-insensitive substring required in column i
	// (empty = no filter).
	ShowFilter bool
	Filters    []string

	// ShowRowMarker paints a "►" glyph over the leading padding cell of
	// the focused row, so the active row stays visible even when focus
	// moves elsewhere on the screen. Purely cosmetic — doesn't change
	// column geometry or hit-testing.
	ShowRowMarker bool

	// Visual toggles. All default to true via New(); callers can flip
	// any of them off to get a stripped-down look.
	ShowGridLines       bool // "│" column dividers between cells
	ShowZebra           bool // alternating row backgrounds
	ShowHeaderUnderline bool // the "─" row under the header titles

	// Behavior toggles. All default to true.
	ReadOnly         bool // disables every mutation path from input
	AllowResize      bool // mouse-drag on column separator
	AllowReorder     bool // mouse-drag on column header
	AllowDragSelect  bool // mouse-drag on cells extends selection
	AllowWheelScroll bool // wheel scrolls the body

	// Sort state. SortKeys[0] is the primary sort column; subsequent
	// entries break ties. Empty = unsorted. SortCol / SortDir mirror
	// the primary key for back-compat with existing display code.
	SortKeys []SortKey
	SortCol  int
	SortDir  SortDirection

	// FindText is the active incremental-search substring (set by
	// FindFirst / FindNext); used purely for cell highlighting.
	FindText string

	// Per-cell color hook. Called for every data cell during Draw with
	// the base attr the grid would use; returning a non-zero override
	// is painted instead. Useful for conditional formatting / heatmaps.
	OnCellAttr func(row, col int, base uint16) uint16

	// Edit callbacks. OnBeforeEdit can deny an edit by returning false.
	// OnAfterEdit fires after a successful commit. OnCellFocused fires
	// when MoveTo / arrow keys / mouse change Focus.
	OnBeforeEdit  func(row, col int, current string) bool
	OnAfterEdit   func(row, col int, oldVal, newVal string)
	OnCellFocused func(row, col int)

	// Modified is set true after any data-mutating edit and cleared by
	// SetRows / LoadCSV / SaveCSV / ClearModified.
	Modified bool

	// Virtual mode. When OnGetCell is non-nil, rows is ignored and the
	// callback supplies cell data on demand. VirtualRowCount is the
	// reported total row count in this mode.
	OnGetCell       func(row, col int) string
	OnSetCell       func(row, col int, value string)
	VirtualRowCount int

	HScroll *views.ScrollBar
	VScroll *views.ScrollBar
	// contains filtered or unexported fields
}

StringGrid is a 2D grid of text cells.

func New

func New(bounds geom.Rect, cols []Column, h, v *views.ScrollBar) *StringGrid

New constructs an empty grid with the given columns. All visual / behavior toggles default to "on" — turn the ones you don't want off individually rather than passing a flags blob.

func (*StringGrid) AddRow

func (g *StringGrid) AddRow(values []string)

AddRow appends a row. Missing cells are filled from each column's DefaultValue (or "" when unset). Sets the Modified flag.

func (*StringGrid) AddSortKey

func (g *StringGrid) AddSortKey(col int)

AddSortKey appends col as a secondary sort key, or — if col is already in the chain — cycles its direction (Asc → Desc → remove). Used by Shift-click on header to build multi-column sorts.

func (*StringGrid) AutoFitAll

func (g *StringGrid) AutoFitAll()

AutoFitAll auto-fits every visible column. Convenience wrapper.

func (*StringGrid) AutoFitColumn

func (g *StringGrid) AutoFitColumn(col int)

AutoFitColumn scans every currently-visible row, plus the column title, and resizes the column so the widest entry fits without truncation. Clamped by MinWidth / MaxWidth and the 3-cell global minimum. Triggered by double-clicking the column separator.

func (*StringGrid) Cell

func (g *StringGrid) Cell(row, col int) string

Cell returns the displayed cell at (visible-row, col). Use this for reading what the user sees, not for editing internal state.

func (*StringGrid) ClearFilters

func (g *StringGrid) ClearFilters()

ClearFilters wipes all filter strings.

func (*StringGrid) ClearModified

func (g *StringGrid) ClearModified()

ClearModified resets the dirty-data flag. Use it after persisting the grid through a non-CSV path that the grid can't detect itself.

func (*StringGrid) ClearSort

func (g *StringGrid) ClearSort()

ClearSort drops every sort key.

func (*StringGrid) ColCount

func (g *StringGrid) ColCount() int

ColCount returns the column count.

func (*StringGrid) CopySelection

func (g *StringGrid) CopySelection()

CopySelection copies the selected cells to the clipboard as TSV. Rows are separated by '\n', cells by '\t'. Multi-line cell contents have their tabs/newlines stripped so the output stays one cell per field — TV cells are single-line anyway.

func (*StringGrid) CycleSort

func (g *StringGrid) CycleSort(col int)

CycleSort advances col through asc → desc → unsorted. Used by a plain header click. Only fires when the column is Sortable.

func (*StringGrid) Draw

func (g *StringGrid) Draw()

Draw paints header (if any), optional filter row, then visible rows.

func (*StringGrid) ExtendTo

func (g *StringGrid) ExtendTo(col, row int)

ExtendTo moves the focus end of the selection, keeping the anchor fixed. Shift+arrow / Shift+click are the entry points.

func (*StringGrid) FindNext

func (g *StringGrid) FindNext(dir int) bool

FindNext jumps Focus to the next cell whose text contains FindText. dir = +1 for forward, -1 for backward. Wraps. No-op when FindText is empty or no match exists. Returns true on a successful jump.

func (*StringGrid) GetTypeID

func (g *StringGrid) GetTypeID() string

GetTypeID for serial registry.

func (*StringGrid) HandleEvent

func (g *StringGrid) HandleEvent(ev *drivers.Event)

HandleEvent dispatches keyboard / mouse events.

func (*StringGrid) HasActiveFilters

func (g *StringGrid) HasActiveFilters() bool

HasActiveFilters returns true if any column has a non-empty filter.

func (*StringGrid) LoadCSV

func (g *StringGrid) LoadCSV(r io.Reader, opts CSVOptions) error

LoadCSV parses CSV from r and replaces the grid's rows. Uses encoding/csv so malformed input (notably EOF inside a quoted field) surfaces as an error — the previous hand-rolled parser silently accepted truncated quotes.

func (*StringGrid) MoveTo

func (g *StringGrid) MoveTo(col, row int)

MoveTo sets the active cell + collapses selection to it.

func (*StringGrid) PasteClipboard

func (g *StringGrid) PasteClipboard()

PasteClipboard pastes the clipboard's TSV (or single line) into the grid starting at the focused cell. Empty / no clipboard is a no-op. Honors grid ReadOnly. Auto-expands the row count if the paste overflows past the end (non-virtual mode only).

func (*StringGrid) RawRowAt

func (g *StringGrid) RawRowAt(visRow int) int

RawRowAt maps a visible row index to its underlying raw row. Returns -1 if visRow is out of range. Use this when you need to edit the underlying storage (e.g. RemoveRow) and only have a visible-row index from Focus / a mouse hit.

func (*StringGrid) RawRowCount

func (g *StringGrid) RawRowCount() int

RawRowCount returns the unfiltered row count (virtual or in-memory).

func (*StringGrid) RemoveRow

func (g *StringGrid) RemoveRow(raw int)

RemoveRow drops the raw row at the given index from the underlying store. No-op in virtual mode (the caller's data source owns the rows there). Selection is clamped after the deletion.

func (*StringGrid) ResetColumnWidth

func (g *StringGrid) ResetColumnWidth(col int)

ResetColumnWidth restores the column to MinWidth (when set) or 12. Useful after a long auto-fit or manual drag the user wants to undo.

func (*StringGrid) RowCount

func (g *StringGrid) RowCount() int

RowCount returns the number of VISIBLE rows (after filtering / sorting). For the underlying raw count, use RawRowCount.

func (*StringGrid) SaveCSV

func (g *StringGrid) SaveCSV(w io.Writer, opts CSVOptions) error

SaveCSV writes the grid's data to w using encoding/csv. The export reflects the current filter/sort (visible rows in their displayed order) and includes all columns — Column.Hidden is visual state, not a data filter.

LineEnd only respects "\n" vs "\r\n"; encoding/csv.Writer doesn't expose finer line-ending control. Other values are interpreted as CRLF if they contain '\r', else LF.

func (*StringGrid) SetCell

func (g *StringGrid) SetCell(row, col int, value string)

SetCell updates the (row, col) value. In non-virtual mode it mutates the backing slice (and expands it if needed). In virtual mode it calls OnSetCell. Sets Modified and fires OnAfterEdit when the value actually changes.

func (*StringGrid) SetFilter

func (g *StringGrid) SetFilter(col int, text string)

SetFilter sets the filter substring for column col. Empty value clears it.

func (*StringGrid) SetFind

func (g *StringGrid) SetFind(needle string)

SetFind installs a case-insensitive incremental-search needle. Matching cells light up; FindNext jumps the cursor between them. Empty needle clears the highlight.

func (*StringGrid) SetRows

func (g *StringGrid) SetRows(rows [][]string)

SetRows replaces all cell data. Clears the Modified flag because the new data is the baseline by definition.

func (*StringGrid) Sort

func (g *StringGrid) Sort(col int, dir SortDirection)

Sort sets the active sort column and direction. Call with (col, SortNone) to clear sorting. Replaces any existing multi-key sort; use AddSortKey to extend instead.

func (*StringGrid) ToggleColumnVisible

func (g *StringGrid) ToggleColumnVisible(col int)

ToggleColumnVisible flips Visible for col. The grid keeps the column's underlying data; it just stops rendering / hit-testing it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL