initial commit

This commit is contained in:
2024-01-18 00:03:13 -06:00
commit 8654ded7a0
34 changed files with 2650 additions and 0 deletions

View File

@@ -0,0 +1,300 @@
package dialogs
import (
"fmt"
"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"
)
const (
cmdWidthOffset = 6
)
const (
cmdTableFocus = 0 + iota
cmdFormFocus
)
type CommandDialog struct {
*tview.Box
layout *tview.Flex
table *tview.Table
form *tview.Form
logger *zap.Logger
display bool
options [][]string
width int
height int
focusElement int
selectedStyle tcell.Style
cancelHandler func()
selectHandler func()
}
func NewCommandDialog(logger *zap.Logger, options [][]string) *CommandDialog {
form := tview.NewForm().
AddButton("Cancel", nil).
SetButtonsAlign(tview.AlignRight)
form.SetBackgroundColor(style.DialogBgColor)
form.SetButtonBackgroundColor(style.ButtonBgColor)
form.SetButtonTextColor(style.ButtonFgColor)
activatedStyle := tcell.StyleDefault.
Background(style.ButtonSelectedBgColor).
Foreground(style.ButtonSelectedFgColor)
form.SetButtonActivatedStyle(activatedStyle)
cmdsTable := tview.NewTable()
cmdsTable.SetBackgroundColor(style.DialogBgColor)
cmdWidth := 0
cmdsTable.SetCell(0, 0,
tview.NewTableCell(fmt.Sprintf("[%s::b]COMMAND", style.GetColorHex(style.TableHeaderFgColor))).
SetExpansion(1).
SetBackgroundColor(style.TableHeaderBgColor).
SetTextColor(style.TableHeaderFgColor).
SetAlign(tview.AlignLeft).
SetSelectable(false))
cmdsTable.SetCell(0, 1,
tview.NewTableCell(fmt.Sprintf("[%s::b]DESCRIPTION", style.GetColorHex(style.TableHeaderFgColor))).
SetExpansion(1).
SetBackgroundColor(style.TableHeaderBgColor).
SetTextColor(style.TableHeaderFgColor).
SetAlign(tview.AlignCenter).
SetSelectable(false))
col1Width := 0
col2Width := 0
for i, option := range options {
cmdsTable.SetCell(i+1, 0,
tview.NewTableCell(option[0]).
SetAlign(tview.AlignLeft).
SetSelectable(true).SetTextColor(style.DialogFgColor))
cmdsTable.SetCell(i+1, 1,
tview.NewTableCell(option[1]).
SetAlign(tview.AlignLeft).
SetSelectable(true).SetTextColor(style.DialogFgColor))
if len(option[0]) > col1Width {
col1Width = len(option[0])
}
if len(option[1]) > col2Width {
col2Width = len(option[1])
}
}
cmdWidth = col1Width + col2Width + 2
cmdsTable.SetFixed(1, 1)
cmdsTable.SetSelectable(true, false)
cmdsTable.SetBackgroundColor(style.DialogBgColor)
cmdLayout := tview.NewFlex().SetDirection(tview.FlexColumn)
cmdLayout.AddItem(utils.EmptyBoxSpace(style.DialogBgColor), 1, 0, false)
cmdLayout.AddItem(cmdsTable, 0, 1, true)
cmdLayout.AddItem(utils.EmptyBoxSpace(style.DialogBgColor), 1, 0, false)
layout := tview.NewFlex().SetDirection(tview.FlexRow)
layout.AddItem(cmdLayout, 0, 1, true)
layout.AddItem(form, DialogFormHeight, 0, true)
layout.SetBorder(true)
layout.SetBorderColor(style.DialogBorderColor)
layout.SetBackgroundColor(style.DialogBgColor)
selectedStyle := tcell.StyleDefault.
Background(style.TableSelectedBgColor).
Foreground(style.TableSelectedFgColor)
cmdsTable.SetSelectedStyle(selectedStyle)
return &CommandDialog{
Box: tview.NewBox().SetBorder(false),
layout: layout,
table: cmdsTable,
form: form,
display: false,
options: options,
width: cmdWidth + cmdWidthOffset,
height: len(options) + TableHeightOffset + DialogFormHeight,
focusElement: cmdTableFocus,
selectedStyle: selectedStyle,
logger: logger,
}
}
// GetSelectedItem returns selected row item.
func (cmd *CommandDialog) GetSelectedItem() string {
row, _ := cmd.table.GetSelection()
if row >= 0 {
return cmd.options[row-1][0]
}
return ""
}
// GetCommandCount returns number of commands
func (cmd *CommandDialog) GetCommandCount() int {
return cmd.table.GetRowCount()
}
// Display this primitive.
func (cmd *CommandDialog) Display() {
cmd.table.Select(1, 0)
cmd.form.SetFocus(1)
cmd.display = true
}
// Hide this primitive
func (cmd *CommandDialog) Hide() {
cmd.display = false
cmd.focusElement = cmdTableFocus
cmd.table.SetSelectedStyle(cmd.selectedStyle)
}
// HasFocus returns whether this primitive has focus
func (cmd *CommandDialog) HasFocus() bool {
return utils.CheckFocus(cmd.table, cmd.form)
}
func (cmd *CommandDialog) IsDisplay() bool {
return cmd.display
}
func (cmd *CommandDialog) Focus(delegate func(tview.Primitive)) {
if cmd.focusElement == cmdTableFocus {
delegate(cmd.table)
return
}
button := cmd.form.GetButton(cmd.form.GetButtonCount() - 1)
button.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if event.Key() == utils.SwitchFocusKey.Key {
cmd.focusElement = cmdTableFocus
cmd.Focus(delegate)
cmd.form.SetFocus(0)
return nil
}
return event
})
delegate(cmd.form)
}
func (cmd *CommandDialog) InputHandler() func(event *tcell.EventKey, setFocus func(primitive tview.Primitive)) {
return cmd.WrapInputHandler(func(event *tcell.EventKey, setFocus func(primitive tview.Primitive)) {
cmd.logger.Sugar().Debugf("command dialog event %v received", event)
if event.Key() == utils.CloseDialogKey.Key {
cmd.cancelHandler()
return
}
if event.Key() == utils.SwitchFocusKey.Key {
cmd.setFocusElement()
}
if cmd.form.HasFocus() {
if formHandler := cmd.form.InputHandler(); formHandler != nil {
formHandler(event, setFocus)
return
}
}
if cmd.table.HasFocus() {
if event.Key() == tcell.KeyEnter {
cmd.selectHandler()
return
}
if tableHandler := cmd.table.InputHandler(); tableHandler != nil {
tableHandler(event, setFocus)
return
}
}
})
}
// SetSelectedFunc sets the form enter button selected function
func (cmd *CommandDialog) SetSelectedFunc(handler func()) *CommandDialog {
cmd.selectHandler = handler
return cmd
}
// SetCancelFunc sets form cancel button selected function.
func (cmd *CommandDialog) SetCancelFunc(handler func()) *CommandDialog {
cmd.cancelHandler = handler
cancelButton := cmd.form.GetButton(cmd.form.GetButtonCount() - 1)
cancelButton.SetSelectedFunc(handler)
return cmd
}
// SetRect set rects for this primitive
func (cmd *CommandDialog) SetRect(x, y, width, height int) {
ws := (width - cmd.width) / 2
hs := (height - cmd.height) / 2
dy := y + hs
bWidth := cmd.width
if cmd.width > width {
ws = 0
bWidth = width - 1
}
bHeight := cmd.height
if cmd.height > height {
dy = y + 1
bHeight = height - 1
}
cmd.Box.SetRect(x+ws, dy, bWidth, bHeight)
x, y, width, height = cmd.Box.GetInnerRect()
cmd.layout.SetRect(x, y, width, height)
}
func (cmd *CommandDialog) Draw(screen tcell.Screen) {
if !cmd.display {
return
}
cmd.Box.DrawForSubclass(screen, cmd)
cmd.layout.Draw(screen)
}
func (cmd *CommandDialog) setFocusElement() {
if cmd.focusElement == cmdTableFocus {
cmd.focusElement = cmdFormFocus
cmd.table.SetSelectedStyle(tcell.StyleDefault.
Background(style.DialogBgColor).
Foreground(style.DialogFgColor))
} else {
cmd.focusElement = cmdTableFocus
cmd.table.SetSelectedStyle(cmd.selectedStyle)
}
}

View File

@@ -0,0 +1,203 @@
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
}

View File

@@ -0,0 +1,106 @@
package dialogs
import (
"fmt"
"git.brettb.xyz/goinv/client/internal/ui/style"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
"go.uber.org/zap"
)
type ErrorDialog struct {
*tview.Box
logger *zap.Logger
modal *tview.Modal
title string
message string
display bool
}
func NewErrorDialog(logger *zap.Logger) *ErrorDialog {
bgColor := style.ErrorDialogBgColor
dialog := ErrorDialog{
Box: tview.NewBox(),
logger: logger,
modal: tview.NewModal().SetBackgroundColor(bgColor).AddButtons([]string{"OK"}),
display: false,
}
dialog.modal.SetButtonBackgroundColor(style.ErrorDialogButtonBgColor)
dialog.modal.SetDoneFunc(func(buttonIndex int, buttonLabel string) {
dialog.Hide()
})
return &dialog
}
func (e *ErrorDialog) Display() {
e.display = true
}
func (e *ErrorDialog) Hide() {
e.SetText("")
e.title = ""
e.message = ""
e.display = false
}
func (e *ErrorDialog) IsDisplay() bool {
return e.display
}
func (e *ErrorDialog) SetText(message string) {
e.message = message
}
func (e *ErrorDialog) SetTitle(title string) {
e.title = title
}
func (e *ErrorDialog) HasFocus() bool {
return e.modal.HasFocus()
}
func (e *ErrorDialog) Focus(delegate func(tview.Primitive)) {
delegate(e.modal)
}
func (e *ErrorDialog) InputHandler() func(*tcell.EventKey, func(tview.Primitive)) {
return e.WrapInputHandler(func(event *tcell.EventKey, setFocus func(tview.Primitive)) {
e.logger.Sugar().Debugf("error dialog event %v received", event)
if modalHandler := e.modal.InputHandler(); modalHandler != nil {
modalHandler(event, setFocus)
return
}
})
}
func (e *ErrorDialog) SetRect(x, y, width, height int) {
e.Box.SetRect(x, y, width, height)
}
func (e *ErrorDialog) Draw(screen tcell.Screen) {
hFgColor := style.FgColor
headerColor := style.GetColorHex(hFgColor)
var errorMessage string
if e.title != "" {
errorMessage = fmt.Sprintf("[%s::b]%s[-::-]\n", headerColor, e.title)
}
errorMessage += e.message
e.modal.SetText(errorMessage)
e.modal.Draw(screen)
}
func (e *ErrorDialog) SetDoneFunc(handler func()) *ErrorDialog {
e.modal.SetDoneFunc(func(buttonIndex int, buttonLabel string) {
handler()
})
return e
}

View File

@@ -0,0 +1,238 @@
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
}

View File

@@ -0,0 +1,128 @@
package dialogs
import (
"fmt"
"strings"
"git.brettb.xyz/goinv/client/internal/ui/style"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
"go.uber.org/zap"
)
const (
prgCell = "▉"
prgMinWidth = 40
)
type ProgressDialog struct {
*tview.Box
logger *zap.Logger
x int
y int
width int
height int
counterValue int
display bool
}
func NewProgressDialog(logger *zap.Logger) *ProgressDialog {
return &ProgressDialog{
logger: logger,
Box: tview.NewBox().
SetBorder(true).
SetBorderColor(style.DialogBorderColor),
display: false,
}
}
func (d *ProgressDialog) SetTitle(title string) {
d.Box.SetTitle(title)
}
func (d *ProgressDialog) Draw(screen tcell.Screen) {
if !d.display || d.height < 3 {
return
}
d.Box.DrawForSubclass(screen, d)
x, y, width, _ := d.Box.GetInnerRect()
tickStr := d.tickStr(width)
tview.Print(screen, tickStr, x, y, width, tview.AlignLeft, style.PrgBarBgColor)
}
func (d *ProgressDialog) SetRect(x, y, width, height int) {
d.x = x
d.y = y
d.width = width
if d.width > prgMinWidth {
d.width = prgMinWidth
spaceWidth := (width - d.width) / 2
d.x = x + spaceWidth
}
if height > 3 {
d.height = 3
spaceHeight := (height - d.height) / 2
d.y = y + spaceHeight
}
d.Box.SetRect(d.x, d.y, d.width, d.height)
}
func (d *ProgressDialog) Hide() {
d.display = false
}
func (d *ProgressDialog) Display() {
d.counterValue = 0
d.display = true
}
func (d *ProgressDialog) IsDisplay() bool {
return d.display
}
func (d *ProgressDialog) Focus(delegate func(tview.Primitive)) {}
func (d *ProgressDialog) HasFocus() bool {
return d.Box.HasFocus()
}
func (d *ProgressDialog) InputHandler() func(*tcell.EventKey, func(tview.Primitive)) {
return d.WrapInputHandler(func(e *tcell.EventKey, setFocus func(tview.Primitive)) {
d.logger.Sugar().Debugf("progress dialog event %v received", e)
})
}
func (d *ProgressDialog) tickStr(max int) string {
barColor := style.GetColorHex(style.PrgBarColor)
counter := d.counterValue
if counter < max-4 {
d.counterValue++
} else {
d.counterValue = 0
}
prgHeadStr := ""
hWidth := 0
prgEndStr := ""
prgStr := ""
for i := 0; i < d.counterValue; i++ {
prgHeadStr += fmt.Sprintf("[black::]%s", prgCell)
hWidth++
}
prgStr = strings.Repeat(prgCell, 4)
for i := 0; i < max+hWidth; i++ {
prgEndStr += fmt.Sprintf("[black::]%s", prgCell)
}
progress := fmt.Sprintf("%s[%s::]%s%s", prgHeadStr, barColor, prgStr, prgEndStr)
return progress
}

View File

@@ -0,0 +1,42 @@
package dialogs
import (
"strings"
"github.com/rivo/tview"
)
const (
DialogFormHeight = 3
DialogMinWidth = 40
DialogPadding = 3
TableHeightOffset = 3
)
type Dialog interface {
tview.Primitive
Display()
Hide()
IsDisplay() bool
}
func getMessageWidth(message string) int {
var messageWidth int
for _, msg := range strings.Split(message, "\n") {
if len(msg) > messageWidth {
messageWidth = len(msg)
}
}
return messageWidth
}
func CheckDialogFocus(dialogs ...Dialog) bool {
for _, dia := range dialogs {
if dia.HasFocus() {
return true
}
}
return false
}