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 }