crib/cardstackwidget.go
2020-10-03 21:26:32 -07:00

164 lines
4.4 KiB
Go

package main
import (
"math"
"sync"
"github.com/gdamore/tcell/v2"
"gitlab.com/tslocum/cview"
"gitlab.com/tslocum/joker"
)
const (
cardWidth = 15
cardHeight = 13
cardBufferX = 6
)
type cardStackWidget struct {
*cview.Box
Cards []*cardWidget
EverSelectable bool
Text string
maxSelection int // TODO != 0 unnecessary?
sync.RWMutex
}
func newCardStackWidget() *cardStackWidget {
c := cardStackWidget{Box: cview.NewBox()}
return &c
}
func (c *cardStackWidget) SetMaxSelection(maxSelection int) {
c.Lock()
defer c.Unlock()
c.maxSelection = maxSelection
}
func (c *cardStackWidget) GetMaxSelection() int {
c.RLock()
defer c.RUnlock()
return c.maxSelection
}
func (c *cardStackWidget) SetCards(cards joker.Cards) {
c.Lock()
defer c.Unlock()
current := make(joker.Cards, len(c.Cards))
for i := range c.Cards {
current[i] = c.Cards[i].Card
}
if current.Equal(cards) {
return
}
c.Cards = make([]*cardWidget, len(cards))
for i := 0; i < len(cards); i++ {
c.Cards[i] = newCardWidget(cards[i], throwCard)
}
}
func (c *cardStackWidget) Draw(screen tcell.Screen) {
c.Box.Draw(screen)
c.RLock()
defer c.RUnlock()
cardOffsetY := 1
lastOffsetY := 1
if !c.EverSelectable {
cardOffsetY = 0
lastOffsetY = 0
}
stackX, stackY, _, _ := c.GetInnerRect()
for i, cardWidget := range c.Cards {
lastOffsetY = cardOffsetY
cardOffsetY = 1
if c.Cards[i].selected || !c.EverSelectable {
cardOffsetY = 0
}
cardWidget.SetRect(stackX+(i*cardBufferX), stackY+cardOffsetY, cardWidth, cardHeight)
cardWidget.Draw(screen)
// Fix borders
if i > 0 && cardOffsetY == lastOffsetY {
screen.SetContent(stackX+(i*cardBufferX), stackY+cardOffsetY, tcell.RuneTTee, nil, tcell.StyleDefault)
}
if i > 0 && (cardOffsetY == lastOffsetY) {
screen.SetContent(stackX+(i*cardBufferX), (stackY+cardOffsetY+cardHeight)-1, tcell.RuneBTee, nil, tcell.StyleDefault)
}
if i > 0 && !cardWidget.selected && c.Cards[i-1].selected {
screen.SetContent(stackX+(i*cardBufferX), (stackY+cardOffsetY+cardHeight)-2, tcell.RuneRTee, nil, tcell.StyleDefault)
}
if i > 0 && cardWidget.selected && !c.Cards[i-1].selected {
screen.SetContent(stackX+(i*cardBufferX), stackY+cardOffsetY+1, tcell.RuneRTee, nil, tcell.StyleDefault)
screen.SetContent(stackX+(i*cardBufferX)+(cardBufferX)+2, (stackY+cardOffsetY+cardHeight)-1, tcell.RuneTTee, nil, tcell.StyleDefault)
}
if i > 0 && (i > 1 && !cardWidget.selected && c.Cards[i-1].selected && !c.Cards[i-2].selected) {
screen.SetContent(stackX+(i*cardBufferX), (stackY+cardOffsetY+cardHeight)-1, tcell.RuneBTee, nil, tcell.StyleDefault)
}
if i > 0 && (i > 1 && cardWidget.selected && c.Cards[i-1].selected && !c.Cards[i-2].selected) {
screen.SetContent(stackX+(i*cardBufferX)+2, (stackY+cardOffsetY+cardHeight)-1, tcell.RuneTTee, nil, tcell.StyleDefault)
}
if i > 0 && (i > 1 && cardWidget.selected && !c.Cards[i-1].selected && c.Cards[i-2].selected) {
screen.SetContent(stackX+(i*cardBufferX), stackY+cardOffsetY, tcell.RuneTTee, nil, tcell.StyleDefault)
}
if i > 0 && (i > 1 && !cardWidget.selected && !c.Cards[i-1].selected && c.Cards[i-2].selected) {
screen.SetContent(stackX+(i*cardBufferX)+2, stackY+cardOffsetY, tcell.RuneBTee, nil, tcell.StyleDefault)
}
}
if c.Text != "" && len(c.Cards) > 0 {
cview.Print(screen, c.Text, (stackX+((len(c.Cards)-1)*cardBufferX))+(cardWidth/2), stackY, math.MaxInt64, cview.AlignLeft, tcell.ColorDefault)
cview.Print(screen, c.Text, (stackX+((len(c.Cards)-1)*cardBufferX))+(cardWidth/2), (stackY+cardHeight)-1, math.MaxInt64, cview.AlignLeft, tcell.ColorDefault)
}
}
// MouseHandler returns the mouse handler for this primitive.
func (c *cardStackWidget) MouseHandler() func(action cview.MouseAction, event *tcell.EventMouse, setFocus func(p cview.Primitive)) (consumed bool, capture cview.Primitive) {
return c.WrapMouseHandler(func(action cview.MouseAction, event *tcell.EventMouse, setFocus func(p cview.Primitive)) (consumed bool, capture cview.Primitive) {
if !c.InRect(event.Position()) {
return false, nil
}
c.Lock()
defer c.Unlock()
for i := range c.Cards {
card := c.Cards[(len(c.Cards)-1)-i]
if card.InRect(event.Position()) {
if !card.selected {
selected := 0
for i := range c.Cards {
if c.Cards[i].selected {
selected++
}
}
if selected >= c.maxSelection {
return // TODO Show error
}
}
return card.MouseHandler()(action, event, setFocus)
}
}
return
})
}