package dialogs
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"git.brettb.xyz/goinv/client/internal/ui/style"
|
|
"git.brettb.xyz/goinv/client/internal/ui/utils"
|
|
"github.com/gdamore/tcell/v2"
|
|
"github.com/rivo/tview"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type ConfirmDialog struct {
|
|
*tview.Box
|
|
logger *zap.Logger
|
|
layout *tview.Flex
|
|
textview *tview.TextView
|
|
form *tview.Form
|
|
x int
|
|
y int
|
|
width int
|
|
height int
|
|
message string
|
|
display bool
|
|
cancelHandler func()
|
|
selectHandler func()
|
|
}
|
|
|
|
func NewConfirmDialog(logger *zap.Logger) *ConfirmDialog {
|
|
dialog := &ConfirmDialog{
|
|
Box: tview.NewBox(),
|
|
logger: logger,
|
|
display: false,
|
|
}
|
|
|
|
dialog.textview = tview.NewTextView().
|
|
SetDynamicColors(true).
|
|
SetWrap(true).
|
|
SetTextAlign(tview.AlignLeft)
|
|
|
|
dialog.textview.SetBackgroundColor(style.DialogBgColor)
|
|
dialog.textview.SetTextColor(style.DialogFgColor)
|
|
|
|
dialog.form = tview.NewForm().
|
|
AddButton("Cancel", nil).
|
|
AddButton(" OK ", nil).
|
|
SetButtonsAlign(tview.AlignRight)
|
|
dialog.form.SetBackgroundColor(style.DialogBgColor)
|
|
dialog.form.SetButtonBackgroundColor(style.ButtonBgColor)
|
|
dialog.form.SetButtonTextColor(style.ButtonFgColor)
|
|
|
|
activatedStyle := tcell.StyleDefault.
|
|
Background(style.ButtonSelectedBgColor).
|
|
Foreground(style.ButtonSelectedFgColor)
|
|
|
|
dialog.form.SetButtonActivatedStyle(activatedStyle)
|
|
|
|
dialog.layout = tview.NewFlex().SetDirection(tview.FlexRow)
|
|
dialog.layout.SetBorder(true)
|
|
dialog.layout.SetBorderColor(style.DialogBorderColor)
|
|
dialog.layout.SetBackgroundColor(style.DialogBgColor)
|
|
|
|
return dialog
|
|
}
|
|
|
|
func (d *ConfirmDialog) Display() {
|
|
d.display = true
|
|
|
|
d.form.SetFocus(1)
|
|
}
|
|
|
|
func (d *ConfirmDialog) IsDisplay() bool {
|
|
return d.display
|
|
}
|
|
|
|
func (d *ConfirmDialog) Hide() {
|
|
d.textview.SetText("")
|
|
d.message = ""
|
|
d.display = false
|
|
}
|
|
|
|
func (d *ConfirmDialog) SetTitle(title string) {
|
|
d.layout.SetTitle(strings.ToUpper(title))
|
|
d.layout.SetTitleColor(style.DialogFgColor)
|
|
}
|
|
|
|
func (d *ConfirmDialog) SetText(message string) {
|
|
d.message = message
|
|
d.textview.Clear()
|
|
|
|
msg := "\n" + message
|
|
|
|
d.textview.SetText(msg)
|
|
d.textview.ScrollToBeginning()
|
|
d.setRect()
|
|
}
|
|
|
|
func (d *ConfirmDialog) Focus(delegate func(tview.Primitive)) {
|
|
delegate(d.form)
|
|
}
|
|
|
|
func (d *ConfirmDialog) HasFocus() bool {
|
|
return d.form.HasFocus()
|
|
}
|
|
|
|
func (d *ConfirmDialog) SetRect(x, y, width, height int) {
|
|
d.x = x + DialogPadding
|
|
d.y = y + DialogPadding
|
|
d.width = width - (2 * DialogPadding) //nolint:gomnd
|
|
d.height = height - (2 * DialogPadding) //nolint:gomnd
|
|
d.setRect()
|
|
}
|
|
|
|
func (d *ConfirmDialog) setRect() {
|
|
maxHeight := d.height
|
|
maxWidth := d.width
|
|
messageHeight := len(strings.Split(d.message, "\n"))
|
|
messageWidth := getMessageWidth(d.message)
|
|
|
|
layoutHeight := messageHeight + 2 //nolint:gomnd
|
|
|
|
if maxHeight > layoutHeight+DialogFormHeight {
|
|
d.height = layoutHeight + DialogFormHeight + 2 //nolint:gomnd
|
|
} else {
|
|
d.height = maxHeight
|
|
layoutHeight = d.height - DialogFormHeight - 2 //nolint:gomnd
|
|
}
|
|
|
|
if maxHeight > d.height {
|
|
emptyHeight := (maxHeight - d.height) / 2 //nolint:gomnd
|
|
d.y += emptyHeight
|
|
}
|
|
|
|
if d.width > DialogMinWidth {
|
|
if messageWidth < DialogMinWidth {
|
|
d.width = DialogMinWidth + 2 //nolint:gomnd
|
|
} else if messageWidth < d.width {
|
|
d.width = messageWidth + 2 //nolint:gomnd
|
|
}
|
|
}
|
|
|
|
if maxWidth > d.width {
|
|
emptyWidth := (maxWidth - d.width) / 2 //nolint:gomnd
|
|
d.x += emptyWidth
|
|
}
|
|
|
|
msgLayout := tview.NewFlex().SetDirection(tview.FlexColumn)
|
|
msgLayout.AddItem(utils.EmptyBoxSpace(style.DialogBgColor), 1, 0, false)
|
|
msgLayout.AddItem(d.textview, 0, 1, true)
|
|
msgLayout.AddItem(utils.EmptyBoxSpace(style.DialogBgColor), 1, 0, false)
|
|
|
|
d.layout.Clear()
|
|
d.layout.AddItem(msgLayout, layoutHeight, 0, true)
|
|
d.layout.AddItem(d.form, DialogFormHeight, 0, true)
|
|
|
|
d.Box.SetRect(d.x, d.y, d.width, d.height)
|
|
}
|
|
|
|
// Draw draws this primitive onto the screen.
|
|
func (d *ConfirmDialog) Draw(screen tcell.Screen) {
|
|
if !d.display {
|
|
return
|
|
}
|
|
|
|
d.Box.DrawForSubclass(screen, d)
|
|
|
|
x, y, width, height := d.Box.GetInnerRect()
|
|
d.layout.SetRect(x, y, width, height)
|
|
d.layout.Draw(screen)
|
|
}
|
|
|
|
func (d *ConfirmDialog) InputHandler() func(*tcell.EventKey, func(tview.Primitive)) {
|
|
return d.WrapInputHandler(func(event *tcell.EventKey, setFocus func(tview.Primitive)) {
|
|
d.logger.Sugar().Debugf("confirm dialog event %v received", event)
|
|
if event.Key() == utils.CloseDialogKey.EventKey() {
|
|
d.cancelHandler()
|
|
|
|
return
|
|
}
|
|
|
|
if formHandler := d.form.InputHandler(); formHandler != nil {
|
|
formHandler(event, setFocus)
|
|
|
|
return
|
|
}
|
|
})
|
|
}
|
|
|
|
func (d *ConfirmDialog) SetCancelFunc(handler func()) *ConfirmDialog {
|
|
d.cancelHandler = handler
|
|
cancelButton := d.form.GetButton(d.form.GetButtonCount() - 2)
|
|
cancelButton.SetSelectedFunc(handler)
|
|
|
|
return d
|
|
}
|
|
|
|
func (d *ConfirmDialog) SetSelectedFunc(handler func()) *ConfirmDialog {
|
|
d.selectHandler = handler
|
|
enterButton := d.form.GetButton(d.form.GetButtonCount() - 1)
|
|
enterButton.SetSelectedFunc(handler)
|
|
|
|
return d
|
|
}
|