User can now select table cells

This commit is contained in:
Sasha Koshka 2023-04-03 22:22:29 -04:00
parent ebefcb03b3
commit b357768c36
2 changed files with 98 additions and 26 deletions

View File

@ -2,6 +2,7 @@ package containers
import "image"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/input"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
@ -10,7 +11,7 @@ import "git.tebibyte.media/sashakoshka/tomo/default/config"
type tableCell struct {
tomo.Element
artist.Pattern
tomo.Pattern
image.Rectangle
}
@ -34,10 +35,14 @@ type TableContainer struct {
contentBounds image.Rectangle
forcedMinimumWidth int
forcedMinimumHeight int
selectedColumn int
selectedRow int
config config.Wrapped
theme theme.Wrapped
onSelect func ()
onScrollBoundsChange func ()
}
@ -48,8 +53,10 @@ func NewTableContainer (
element *TableContainer,
) {
element = &TableContainer {
topHeading: topHeading,
leftHeading: leftHeading,
topHeading: topHeading,
leftHeading: leftHeading,
selectedColumn: -1,
selectedRow: -1,
}
element.theme.Case = tomo.C("tomo", "tableContainer")
@ -153,6 +160,17 @@ func (element *TableContainer) Resize (columns, rows int) {
element.redoAll()
}
// Selected returns the column and row of the cell that is currently selected.
// If no cell is selected, this method will return (-1, -1).
func (element *TableContainer) Selected () (column, row int) {
return element.selectedColumn, element.selectedRow
}
// OnSelect sets a function to be called when the user selects a table cell.
func (element *TableContainer) OnSelect (callback func ()) {
element.onSelect = callback
}
// Warp runs the specified callback, deferring all layout and rendering updates
// until the callback has finished executing. This allows for aplications to
// perform batch gui updates without flickering and stuff.
@ -212,14 +230,42 @@ func (element *TableContainer) NotifyMinimumSizeChange (child tomo.Element) {
func (element *TableContainer) DrawBackground (bounds image.Rectangle) {
if !bounds.Overlaps(element.core.Bounds()) { return }
for _, row := range element.grid {
for _, child := range row {
for rowIndex, row := range element.grid {
for columnIndex, child := range row {
if bounds.Overlaps(child.Rectangle) {
child.Draw(canvas.Cut(element.core, bounds), child.Rectangle)
element.theme.Pattern (
child.Pattern,
element.state(columnIndex, rowIndex)).
Draw(canvas.Cut(element.core, bounds), child.Rectangle)
return
}}}
}
func (element *TableContainer) HandleMouseDown (x, y int, button input.Button) {
element.Propagator.HandleMouseDown(x, y, button)
if button != input.ButtonLeft { return }
for rowIndex, row := range element.grid {
for columnIndex, child := range row {
if image.Pt(x, y).In(child.Rectangle) {
selected :=
rowIndex == element.selectedRow &&
columnIndex == element.selectedColumn
if selected { return }
oldColumn, oldRow := element.selectedColumn, element.selectedRow
element.selectedColumn, element.selectedRow = columnIndex, rowIndex
if oldColumn >= 0 && oldRow >= 0 {
element.core.DamageRegion(element.redoCell(oldColumn, oldRow))
}
element.core.DamageRegion(element.redoCell(columnIndex, rowIndex))
if element.onSelect != nil {
element.onSelect()
}
return
}}}
}
func (element *TableContainer) hook (child tomo.Element) {
if child0, ok := child.(tomo.Themeable); ok {
child0.SetTheme(element.theme.Theme)
@ -245,6 +291,36 @@ func (element *TableContainer) rebuildChildList (list []tomo.Element) {
}}
}
func (element *TableContainer) state (column, row int) (state tomo.State) {
if column == element.selectedColumn && row == element.selectedRow {
state.On = true
}
return
}
func (element *TableContainer) redoCell (column, row int) image.Rectangle {
padding := element.theme.Padding(tomo.PatternTableCell)
cell := element.grid[row][column]
pattern := element.theme.Pattern (
cell.Pattern, element.state(column, row))
if cell.Element != nil {
// give child canvas portion
innerCellBounds := padding.Apply(cell.Rectangle)
artist.DrawShatter (
element.core, pattern,
cell.Rectangle, innerCellBounds)
cell.DrawTo (
canvas.Cut(element.core, innerCellBounds),
innerCellBounds,
element.childDrawCallback)
} else {
// draw cell pattern in empty cells
pattern.Draw(element.core, cell.Rectangle)
}
return cell.Rectangle
}
func (element *TableContainer) redoAll () {
if element.warping || !element.core.HasImage() {
element.updateMinimumSize()
@ -294,7 +370,7 @@ func (element *TableContainer) redoAll () {
x := float64(bounds.Min.X)
y := float64(bounds.Min.Y)
for rowIndex, row := range element.grid {
for columnIndex, child := range row {
for columnIndex, _ := range row {
width := columnWidths[columnIndex]
height := rowHeights[rowIndex]
cellBounds := image.Rect (
@ -310,26 +386,10 @@ func (element *TableContainer) redoAll () {
} else {
id = tomo.PatternTableCell
}
pattern := element.theme.Pattern(id, tomo.State { })
element.grid[rowIndex][columnIndex].Rectangle = cellBounds
element.grid[rowIndex][columnIndex].Pattern = pattern
element.grid[rowIndex][columnIndex].Pattern = id
if child.Element != nil {
// give child canvas portion
innerCellBounds := padding.Apply(cellBounds)
artist.DrawShatter (
element.core, pattern,
cellBounds, innerCellBounds)
child.DrawTo (
canvas.Cut(element.core, innerCellBounds),
innerCellBounds,
func (region image.Rectangle) {
element.core.DamageRegion(region)
})
} else {
// draw cell pattern in empty cells
pattern.Draw(element.core, cellBounds)
}
element.redoCell(columnIndex, rowIndex)
x += float64(width)
}
@ -371,3 +431,7 @@ func (element *TableContainer) updateMinimumSize () {
element.core.SetMinimumSize(minWidth, minHeight)
}
func (element *TableContainer) childDrawCallback (region image.Rectangle) {
element.core.DamageRegion(region)
}

View File

@ -29,10 +29,18 @@ func run () {
}
index ++
}}
table.Set(2, 1, elements.NewButton("Look, I'm a button!"))
statusLabel := elements.NewLabel("Selected: none", false)
table.OnSelect (func () {
column, row := table.Selected()
statusLabel.SetText (
fmt.Sprintf("Selected: %d, %d",
column, row))
})
container.Adopt(table, true)
container.Adopt(statusLabel, false)
window.Adopt(container)
window.OnClose(tomo.Stop)