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 MessageDialog struct { *tview.Box logger *zap.Logger layout *tview.Flex infoType *tview.InputField textView *tview.TextView form *tview.Form display bool message string cancelHandler func() } type messageInfo int const ( MessageGeneric messageInfo = iota ) func NewMessageDialog(logger *zap.Logger, text string) *MessageDialog { dialog := MessageDialog{ Box: tview.NewBox(), logger: logger, infoType: tview.NewInputField(), display: false, message: text, } dialog.infoType.SetBackgroundColor(style.ButtonBgColor) dialog.infoType.SetFieldStyle(tcell.StyleDefault. Background(style.ButtonBgColor). Foreground(style.ButtonFgColor)) dialog.infoType.SetLabelStyle(tcell.StyleDefault. Background(style.ButtonBgColor). Foreground(style.ButtonFgColor)) dialog.textView = tview.NewTextView(). SetDynamicColors(true). SetWrap(true). SetTextAlign(tview.AlignLeft) dialog.textView.SetBackgroundColor(style.DialogSubBoxBgColor) dialog.textView.SetBorderColor(style.DialogSubBoxBorderColor) dialog.textView.SetBorder(true) dialog.textView.SetTextStyle(tcell.StyleDefault. Background(style.DialogSubBoxBgColor). Foreground(style.DialogSubBoxFgColor)) tlayout := tview.NewFlex().SetDirection(tview.FlexColumn) tlayout.AddItem(utils.EmptyBoxSpace(style.DialogBgColor), 1, 0, false) tlayout.AddItem(tview.NewFlex().SetDirection(tview.FlexRow). AddItem(dialog.infoType, 1, 0, false). AddItem(utils.EmptyBoxSpace(style.DialogBgColor), 1, 0, false). AddItem(dialog.textView, 0, 1, true), 0, 1, true) tlayout.AddItem(utils.EmptyBoxSpace(style.DialogBgColor), 1, 0, false) dialog.form = tview.NewForm(). AddButton("Cancel", nil). SetButtonsAlign(tview.AlignRight) dialog.form.SetFocus(0) dialog.form.SetBackgroundColor(style.DialogBgColor) dialog.form.SetButtonBackgroundColor(style.ButtonBgColor) dialog.form.SetButtonTextColor(style.ButtonFgColor) dialog.form.SetButtonActivatedStyle(tcell.StyleDefault. Background(style.ButtonSelectedBgColor). Foreground(style.ButtonSelectedFgColor)) dialog.layout = tview.NewFlex().SetDirection(tview.FlexRow) dialog.layout.AddItem(utils.EmptyBoxSpace(style.DialogBgColor), 1, 0, false) dialog.layout.AddItem(tlayout, 0, 1, true) dialog.layout.AddItem(dialog.form, DialogFormHeight, 0, true) dialog.layout.SetBorder(true) dialog.layout.SetBorderColor(style.DialogBorderColor) dialog.layout.SetBackgroundColor(style.DialogBgColor) dialog.layout.SetTitleColor(style.DialogFgColor) return &dialog } func (d *MessageDialog) Display() { d.display = true } func (d *MessageDialog) IsDisplay() bool { return d.display } func (d *MessageDialog) Hide() { d.message = "" d.textView.SetText("") d.display = false } func (d *MessageDialog) SetTitle(title string) { d.layout.SetTitle(strings.ToUpper(title)) } func (d *MessageDialog) SetText(headerType messageInfo, headerMessage string, message string) { msgTypeLabel := "" switch headerType { case MessageGeneric: msgTypeLabel = "SYSTEM:" } if msgTypeLabel != "" { d.infoType.SetLabel("[::b]" + msgTypeLabel) d.infoType.SetLabelWidth(len(msgTypeLabel) + 1) d.infoType.SetText(headerMessage) } d.message = message d.textView.Clear() if d.message == "" { d.textView.SetBorder(false) d.textView.SetText("") } else { //d.textView.SetTextColor(style.DialogFgColor) //d.textView.SetBackgroundColor(style.DialogSubBoxBorderColor) //d.textView.SetBorder(true) //d.textView.SetBorderColor(style.DialogBorderColor) //d.textView.SetTextStyle(tcell.StyleDefault. // Background(style.DialogSubBoxBorderColor). // Foreground(style.ButtonFgColor)) d.textView.SetBorder(true) d.textView.SetText(message) } d.textView.ScrollToBeginning() } func (d *MessageDialog) TextScrollToEnd() { d.textView.ScrollToEnd() } func (d *MessageDialog) Focus(delegate func(tview.Primitive)) { delegate(d.form) } func (d *MessageDialog) HasFocus() bool { return utils.CheckFocus(d.form, d.textView, d.Box) } func (d *MessageDialog) SetRect(x, y, width, height int) { messageHeight := 0 if d.message != "" { messageHeight = len(strings.Split(d.message, "\n")) } messageWidth := getMessageWidth(d.message) headerWidth := len(d.infoType.GetText()) + len(d.infoType.GetLabel()) + 4 if messageWidth < headerWidth { messageWidth = headerWidth } dWidth := width - (2 * DialogPadding) if messageWidth+4 < dWidth { dWidth = messageWidth + 4 } if DialogMinWidth < width && dWidth < DialogMinWidth { dWidth = DialogMinWidth } emptySpace := (width - dWidth) / 2 dX := x + emptySpace dHeight := messageHeight + DialogFormHeight + DialogPadding + 4 if dHeight > height { dHeight = height - DialogPadding - 1 } textviewHeight := dHeight - DialogFormHeight - 2 hs := (height - dHeight) / 2 dY := y + hs d.Box.SetRect(dX, dY, dWidth, dHeight) d.layout.ResizeItem(d.textView, textviewHeight, 0) } func (d *MessageDialog) 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 *MessageDialog) InputHandler() func(*tcell.EventKey, func(tview.Primitive)) { return d.WrapInputHandler(func(event *tcell.EventKey, setFocus func(tview.Primitive)) { d.logger.Sugar().Debugf("message dialog event %v received", event) if event.Key() == utils.CloseDialogKey.EventKey() || event.Key() == tcell.KeyEnter { d.cancelHandler() return } if event.Key() == utils.SwitchFocusKey.EventKey() { if formHandler := d.form.InputHandler(); formHandler != nil { formHandler(event, setFocus) return } } if textHandler := d.textView.InputHandler(); textHandler != nil { textHandler(event, setFocus) return } }) } func (d *MessageDialog) SetCancelFunc(handler func()) *MessageDialog { d.cancelHandler = handler return d }